IDEMPIERE-6123 Query in search window causing slowness and load spikes in the database (FHCA-5356) (#2340)
* IDEMPIERE-6123 Query in search window causing slowness and load spikes in the database (FHCA-5356) * - create SysConfig - add Dialog when reaching max query records * - minor fix comment - add timeout management to MLookup query * - Fix for the GridTable.Loader.Open issue * - add SysConfig and Messages - add showing error message when the number of records loaded in background exceed the allowed - add timeout to GridTable.fillBuffer --------- Co-authored-by: hengsin <hengsin@gmail.com>
This commit is contained in:
parent
766ca60cd4
commit
42e998ff7d
|
|
@ -0,0 +1,22 @@
|
||||||
|
-- IDEMPIERE-6123 Query in search window causing slowness and load spikes in the database (FHCA-5356)
|
||||||
|
SELECT register_migration_script('202404302320_IDEMPIERE-6123.sql') FROM dual;
|
||||||
|
|
||||||
|
SET SQLBLANKLINES ON
|
||||||
|
SET DEFINE OFF
|
||||||
|
|
||||||
|
-- Apr 30, 2024, 11:20:08 PM CEST
|
||||||
|
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200244,0,0,TO_TIMESTAMP('2024-04-30 23:20:08','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2024-04-30 23:20:08','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','GRIDTABLE_INITIAL_COUNT_TIMEOUT_IN_SECONDS','1','Timeout for the initial count on windows','D','C','5fae1af7-74ca-41d8-bbd3-d506c6c23b6a')
|
||||||
|
;
|
||||||
|
|
||||||
|
-- Apr 30, 2024, 11:22:16 PM CEST
|
||||||
|
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200245,0,0,TO_TIMESTAMP('2024-04-30 23:22:16','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2024-04-30 23:22:16','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','GLOBAL_MAX_QUERY_RECORDS','100000','Maximum number of records allowed to search in a window, can be overriden per Role or Tab','D','C','840fb67c-4609-41f2-9e20-e0ea9d839065')
|
||||||
|
;
|
||||||
|
|
||||||
|
-- Apr 30, 2024, 11:23:28 PM CEST
|
||||||
|
UPDATE AD_Message SET MsgText='The query returned more records than allowed, consider adding more filters.',Updated=TO_TIMESTAMP('2024-04-30 23:23:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=852
|
||||||
|
;
|
||||||
|
|
||||||
|
-- Apr 30, 2024, 11:24:06 PM CEST
|
||||||
|
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','The initial count query timed out, loading records ...',0,0,'Y',TO_TIMESTAMP('2024-04-30 23:24:06','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2024-04-30 23:24:06','YYYY-MM-DD HH24:MI:SS'),100,200887,'CountQueryTimeoutLoadBackground','D','988292d7-175f-41c2-b560-43d62b8326a9')
|
||||||
|
;
|
||||||
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
-- IDEMPIERE-6123 Query in search window causing slowness and load spikes in the database (FHCA-5356)
|
||||||
|
SELECT register_migration_script('202404302320_IDEMPIERE-6123.sql') FROM dual;
|
||||||
|
|
||||||
|
-- Apr 30, 2024, 11:20:08 PM CEST
|
||||||
|
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200244,0,0,TO_TIMESTAMP('2024-04-30 23:20:08','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2024-04-30 23:20:08','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','GRIDTABLE_INITIAL_COUNT_TIMEOUT_IN_SECONDS','1','Timeout for the initial count on windows','D','C','5fae1af7-74ca-41d8-bbd3-d506c6c23b6a')
|
||||||
|
;
|
||||||
|
|
||||||
|
-- Apr 30, 2024, 11:22:16 PM CEST
|
||||||
|
INSERT INTO AD_SysConfig (AD_SysConfig_ID,AD_Client_ID,AD_Org_ID,Created,Updated,CreatedBy,UpdatedBy,IsActive,Name,Value,Description,EntityType,ConfigurationLevel,AD_SysConfig_UU) VALUES (200245,0,0,TO_TIMESTAMP('2024-04-30 23:22:16','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2024-04-30 23:22:16','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','GLOBAL_MAX_QUERY_RECORDS','100000','Maximum number of records allowed to search in a window, can be overriden per Role or Tab','D','C','840fb67c-4609-41f2-9e20-e0ea9d839065')
|
||||||
|
;
|
||||||
|
|
||||||
|
-- Apr 30, 2024, 11:23:28 PM CEST
|
||||||
|
UPDATE AD_Message SET MsgText='The query returned more records than allowed, consider adding more filters.',Updated=TO_TIMESTAMP('2024-04-30 23:23:28','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=852
|
||||||
|
;
|
||||||
|
|
||||||
|
-- Apr 30, 2024, 11:24:06 PM CEST
|
||||||
|
INSERT INTO AD_Message (MsgType,MsgText,AD_Client_ID,AD_Org_ID,IsActive,Created,CreatedBy,Updated,UpdatedBy,AD_Message_ID,Value,EntityType,AD_Message_UU) VALUES ('I','The initial count query timed out, loading records ...',0,0,'Y',TO_TIMESTAMP('2024-04-30 23:24:06','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2024-04-30 23:24:06','YYYY-MM-DD HH24:MI:SS'),100,200887,'CountQueryTimeoutLoadBackground','D','988292d7-175f-41c2-b560-43d62b8326a9')
|
||||||
|
;
|
||||||
|
|
||||||
|
|
@ -257,10 +257,9 @@ public final class DataStatusEvent extends EventObject implements Serializable
|
||||||
retValue.append(m_currentRow+1);
|
retValue.append(m_currentRow+1);
|
||||||
// of
|
// of
|
||||||
retValue.append("/");
|
retValue.append("/");
|
||||||
if (m_allLoaded)
|
if (! m_allLoaded)
|
||||||
|
retValue.append(m_loadedRows).append("->");
|
||||||
retValue.append(m_totalRows);
|
retValue.append(m_totalRows);
|
||||||
else
|
|
||||||
retValue.append(m_loadedRows).append("->").append(m_totalRows);
|
|
||||||
//
|
//
|
||||||
return retValue.toString();
|
return retValue.toString();
|
||||||
} // getMessage
|
} // getMessage
|
||||||
|
|
@ -358,6 +357,7 @@ public final class DataStatusEvent extends EventObject implements Serializable
|
||||||
e.m_changedColumn == m_changedColumn &&
|
e.m_changedColumn == m_changedColumn &&
|
||||||
Util.equals(e.m_columnName, m_columnName) &&
|
Util.equals(e.m_columnName, m_columnName) &&
|
||||||
e.m_currentRow == m_currentRow &&
|
e.m_currentRow == m_currentRow &&
|
||||||
|
e.m_loadedRows == m_loadedRows &&
|
||||||
e.isInitEdit == isInitEdit;
|
e.isInitEdit == isInitEdit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -235,6 +235,8 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
|
||||||
public static final String CTX_IsLookupOnlySelection = "_TabInfo_IsLookupOnlySelection";
|
public static final String CTX_IsLookupOnlySelection = "_TabInfo_IsLookupOnlySelection";
|
||||||
public static final String CTX_IsAllowAdvancedLookup = "_TabInfo_IsAllowAdvancedLookup";
|
public static final String CTX_IsAllowAdvancedLookup = "_TabInfo_IsAllowAdvancedLookup";
|
||||||
|
|
||||||
|
public static final int DEFAULT_GLOBAL_MAX_QUERY_RECORDS = 100000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tab loader for Tabs > 0
|
* Tab loader for Tabs > 0
|
||||||
*/
|
*/
|
||||||
|
|
@ -2544,20 +2546,23 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
|
||||||
}
|
}
|
||||||
// Row Count
|
// Row Count
|
||||||
int rows = getRowCount();
|
int rows = getRowCount();
|
||||||
if (rows == 0)
|
if (rows == 0 && !m_mTable.isLoading())
|
||||||
{
|
{
|
||||||
log.fine("No Rows");
|
log.fine("No Rows");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (newRow >= rows)
|
if (newRow >= rows)
|
||||||
|
{
|
||||||
|
if (!m_mTable.isLoading())
|
||||||
{
|
{
|
||||||
newRow = rows-1;
|
newRow = rows-1;
|
||||||
if (log.isLoggable(Level.FINE)) log.fine("Set to max Row: " + newRow);
|
if (log.isLoggable(Level.FINE)) log.fine("Set to max Row: " + newRow);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
else if (newRow < 0)
|
else if (newRow < 0)
|
||||||
{
|
{
|
||||||
newRow = 0;
|
newRow = 0;
|
||||||
log.fine("Set to first Row");
|
if (log.isLoggable(Level.FINE)) log.fine("Set to first Row");
|
||||||
}
|
}
|
||||||
|
|
||||||
m_mTable.waitLoadingForRow(newRow);
|
m_mTable.waitLoadingForRow(newRow);
|
||||||
|
|
@ -3556,6 +3561,9 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable
|
||||||
int tabMaxQueryRecords = m_vo.MaxQueryRecords;
|
int tabMaxQueryRecords = m_vo.MaxQueryRecords;
|
||||||
if (roleMaxQueryRecords > 0 && (roleMaxQueryRecords < tabMaxQueryRecords || tabMaxQueryRecords == 0))
|
if (roleMaxQueryRecords > 0 && (roleMaxQueryRecords < tabMaxQueryRecords || tabMaxQueryRecords == 0))
|
||||||
tabMaxQueryRecords = roleMaxQueryRecords;
|
tabMaxQueryRecords = roleMaxQueryRecords;
|
||||||
|
if (tabMaxQueryRecords == 0)
|
||||||
|
tabMaxQueryRecords = MSysConfig.getIntValue(MSysConfig.GLOBAL_MAX_QUERY_RECORDS,
|
||||||
|
DEFAULT_GLOBAL_MAX_QUERY_RECORDS, Env.getAD_Client_ID(Env.getCtx()));
|
||||||
return tabMaxQueryRecords;
|
return tabMaxQueryRecords;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,7 @@ import java.util.logging.Level;
|
||||||
import javax.swing.event.TableModelListener;
|
import javax.swing.event.TableModelListener;
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
|
|
||||||
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
import org.adempiere.exceptions.DBException;
|
import org.adempiere.exceptions.DBException;
|
||||||
import org.adempiere.util.ServerContext;
|
import org.adempiere.util.ServerContext;
|
||||||
import org.compiere.Adempiere;
|
import org.compiere.Adempiere;
|
||||||
|
|
@ -95,13 +96,14 @@ public class GridTable extends AbstractTableModel
|
||||||
implements Serializable
|
implements Serializable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* generated serial id
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = -5564364545827057092L;
|
private static final long serialVersionUID = -2602189278069194311L;
|
||||||
|
|
||||||
protected static final String SORTED_DSE_EVENT = "Sorted";
|
protected static final String SORTED_DSE_EVENT = "Sorted";
|
||||||
|
|
||||||
public static final int DEFAULT_GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS = 30;
|
public static final int DEFAULT_GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS = 30;
|
||||||
|
public static final int DEFAULT_GRIDTABLE_COUNT_TIMEOUT_IN_SECONDS = 1;
|
||||||
|
|
||||||
public static final String LOAD_TIMEOUT_ERROR_MESSAGE = "GridTabLoadTimeoutError";
|
public static final String LOAD_TIMEOUT_ERROR_MESSAGE = "GridTabLoadTimeoutError";
|
||||||
|
|
||||||
|
|
@ -169,6 +171,7 @@ public class GridTable extends AbstractTableModel
|
||||||
|
|
||||||
/** Rowcount */
|
/** Rowcount */
|
||||||
private int m_rowCount = 0;
|
private int m_rowCount = 0;
|
||||||
|
private boolean m_rowCountTimeout = false;
|
||||||
/** Has Data changed? */
|
/** Has Data changed? */
|
||||||
private boolean m_changed = false;
|
private boolean m_changed = false;
|
||||||
/** Index of changed row via SetValueAt */
|
/** Index of changed row via SetValueAt */
|
||||||
|
|
@ -426,7 +429,8 @@ public class GridTable extends AbstractTableModel
|
||||||
//IDEMPIERE-5193 Add Limit to Query
|
//IDEMPIERE-5193 Add Limit to Query
|
||||||
if(m_maxRows > 0 && DB.getDatabase().isPagingSupported())
|
if(m_maxRows > 0 && DB.getDatabase().isPagingSupported())
|
||||||
{
|
{
|
||||||
m_SQL = DB.getDatabase().addPagingSQL(m_SQL, 1, m_maxRows);
|
// set to maxRows plus one to trigger FindOverMax on overflow
|
||||||
|
m_SQL = DB.getDatabase().addPagingSQL(m_SQL, 1, m_maxRows+1);
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
@ -645,7 +649,8 @@ public class GridTable extends AbstractTableModel
|
||||||
m_buffer = new ArrayList<Object[]>(m_rowCount+10);
|
m_buffer = new ArrayList<Object[]>(m_rowCount+10);
|
||||||
}
|
}
|
||||||
m_sort = new ArrayList<MSort>(m_rowCount+10);
|
m_sort = new ArrayList<MSort>(m_rowCount+10);
|
||||||
if (m_rowCount > 0)
|
// actual row count or timeout
|
||||||
|
if (m_rowCount > 0 || m_rowCountTimeout)
|
||||||
{
|
{
|
||||||
m_loader.setContext(ServerContext.getCurrentInstance());
|
m_loader.setContext(ServerContext.getCurrentInstance());
|
||||||
m_loaderFuture = Adempiere.getThreadPoolExecutor().submit(m_loader);
|
m_loaderFuture = Adempiere.getThreadPoolExecutor().submit(m_loader);
|
||||||
|
|
@ -1159,7 +1164,7 @@ public class GridTable extends AbstractTableModel
|
||||||
log.warning("Reached " + timeout + " seconds timeout loading row " + (row+1) + " for SQL=" + m_SQL);
|
log.warning("Reached " + timeout + " seconds timeout loading row " + (row+1) + " for SQL=" + m_SQL);
|
||||||
//adjust row count
|
//adjust row count
|
||||||
m_rowCount = m_sort.size();
|
m_rowCount = m_sort.size();
|
||||||
throw new DBException("GridTabLoadTimeoutError");
|
throw new AdempiereException(Msg.getMsg(Env.getCtx(), LOAD_TIMEOUT_ERROR_MESSAGE));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1266,6 +1271,9 @@ public class GridTable extends AbstractTableModel
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
stmt = DB.prepareStatement(sql.toString(), null);
|
stmt = DB.prepareStatement(sql.toString(), null);
|
||||||
|
int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, DEFAULT_GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, Env.getAD_Client_ID(Env.getCtx()));
|
||||||
|
if (timeout > 0)
|
||||||
|
stmt.setQueryTimeout(timeout);
|
||||||
rs = stmt.executeQuery();
|
rs = stmt.executeQuery();
|
||||||
while(rs.next())
|
while(rs.next())
|
||||||
{
|
{
|
||||||
|
|
@ -3015,11 +3023,13 @@ public class GridTable extends AbstractTableModel
|
||||||
rows = 0;
|
rows = 0;
|
||||||
PreparedStatement pstmt = null;
|
PreparedStatement pstmt = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
|
m_rowCountTimeout = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
pstmt = DB.prepareStatement(m_SQL_Count, get_TrxName());
|
pstmt = DB.prepareStatement(m_SQL_Count, get_TrxName());
|
||||||
setParameter (pstmt, true);
|
setParameter (pstmt, true);
|
||||||
int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, DEFAULT_GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, Env.getAD_Client_ID(Env.getCtx()));
|
int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_INITIAL_COUNT_TIMEOUT_IN_SECONDS,
|
||||||
|
DEFAULT_GRIDTABLE_COUNT_TIMEOUT_IN_SECONDS, Env.getAD_Client_ID(Env.getCtx()));
|
||||||
if (timeout > 0)
|
if (timeout > 0)
|
||||||
pstmt.setQueryTimeout(timeout);
|
pstmt.setQueryTimeout(timeout);
|
||||||
rs = pstmt.executeQuery();
|
rs = pstmt.executeQuery();
|
||||||
|
|
@ -3028,6 +3038,12 @@ public class GridTable extends AbstractTableModel
|
||||||
}
|
}
|
||||||
catch (SQLException e0)
|
catch (SQLException e0)
|
||||||
{
|
{
|
||||||
|
if (DB.getDatabase().isQueryTimeout(e0))
|
||||||
|
{
|
||||||
|
m_rowCountTimeout = true;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
throw new DBException(e0);
|
throw new DBException(e0);
|
||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
|
|
@ -3064,11 +3080,7 @@ public class GridTable extends AbstractTableModel
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
m_pstmt = DB.prepareStatement(m_SQL, trxName);
|
m_pstmt = DB.prepareStatement(m_SQL, trxName);
|
||||||
if (this.maxRows > 0 && rows == this.maxRows)
|
//ensure not all rows are fetch into memory for virtual table
|
||||||
{
|
|
||||||
m_pstmt.setMaxRows(this.maxRows);
|
|
||||||
}
|
|
||||||
//ensure not all row is fectch into memory for virtual table
|
|
||||||
if (m_virtual)
|
if (m_virtual)
|
||||||
m_pstmt.setFetchSize(100);
|
m_pstmt.setFetchSize(100);
|
||||||
setParameter (m_pstmt, false);
|
setParameter (m_pstmt, false);
|
||||||
|
|
@ -3079,10 +3091,14 @@ public class GridTable extends AbstractTableModel
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException e)
|
||||||
{
|
{
|
||||||
|
if (DB.getDatabase().isQueryTimeout(e)) {
|
||||||
|
throw new AdempiereException(Msg.getMsg(Env.getCtx(), LOAD_TIMEOUT_ERROR_MESSAGE), e);
|
||||||
|
} else {
|
||||||
log.saveError(e.getLocalizedMessage(), e);
|
log.saveError(e.getLocalizedMessage(), e);
|
||||||
throw new DBException(e);
|
throw new DBException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close RS and Statement
|
* Close RS and Statement
|
||||||
|
|
@ -3118,6 +3134,7 @@ public class GridTable extends AbstractTableModel
|
||||||
* Fill buffer from result set
|
* Fill buffer from result set
|
||||||
*/
|
*/
|
||||||
private void doRun() {
|
private void doRun() {
|
||||||
|
boolean isFindOverMax = false;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
openResultSet();
|
openResultSet();
|
||||||
|
|
@ -3126,6 +3143,11 @@ public class GridTable extends AbstractTableModel
|
||||||
|
|
||||||
while (m_rs.next())
|
while (m_rs.next())
|
||||||
{
|
{
|
||||||
|
if (maxRows > 0 && m_sort.size() == maxRows) {
|
||||||
|
isFindOverMax = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (Thread.interrupted())
|
if (Thread.interrupted())
|
||||||
{
|
{
|
||||||
if (log.isLoggable(Level.FINE)) log.fine("Interrupted");
|
if (log.isLoggable(Level.FINE)) log.fine("Interrupted");
|
||||||
|
|
@ -3149,9 +3171,25 @@ public class GridTable extends AbstractTableModel
|
||||||
}
|
}
|
||||||
m_sort.add(sort);
|
m_sort.add(sort);
|
||||||
|
|
||||||
|
// Start with rowCount=0, inform loading of first row
|
||||||
|
if (m_rowCountTimeout)
|
||||||
|
{
|
||||||
|
m_rowCount++;
|
||||||
|
if (m_rowCount == 1)
|
||||||
|
{
|
||||||
|
DataStatusEvent evt = createDSE();
|
||||||
|
evt.setLoading(m_sort.size());
|
||||||
|
evt.setInfo("CountQueryTimeoutLoadBackground", null, false, true);
|
||||||
|
fireDataStatusChanged(evt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Statement all 1000 rows & sleep
|
// Statement all 1000 rows & sleep
|
||||||
if (m_sort.size() % 1000 == 0)
|
if (m_sort.size() % 1000 == 0)
|
||||||
{
|
{
|
||||||
|
DataStatusEvent evt = createDSE();
|
||||||
|
evt.setLoading(m_sort.size());
|
||||||
|
fireDataStatusChanged(evt);
|
||||||
// give the other processes a chance
|
// give the other processes a chance
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|
@ -3164,9 +3202,6 @@ public class GridTable extends AbstractTableModel
|
||||||
close();
|
close();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
DataStatusEvent evt = createDSE();
|
|
||||||
evt.setLoading(m_sort.size());
|
|
||||||
fireDataStatusChanged(evt);
|
|
||||||
}
|
}
|
||||||
} // while(rs.next())
|
} // while(rs.next())
|
||||||
}
|
}
|
||||||
|
|
@ -3178,6 +3213,17 @@ public class GridTable extends AbstractTableModel
|
||||||
{
|
{
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Background loading without initial rowCount, inform final loaded rows
|
||||||
|
if (m_rowCountTimeout && m_sort.size() > 0)
|
||||||
|
{
|
||||||
|
DataStatusEvent evt = createDSE();
|
||||||
|
evt.setLoading(m_sort.size());
|
||||||
|
if (isFindOverMax)
|
||||||
|
evt.setInfo("FindOverMax", " > " + m_sort.size(), false, true);
|
||||||
|
fireDataStatusChanged(evt);
|
||||||
|
}
|
||||||
|
|
||||||
fireDataStatusIEvent("", "");
|
fireDataStatusIEvent("", "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,9 +58,9 @@ import org.compiere.util.ValueNamePair;
|
||||||
public final class MLookup extends Lookup implements Serializable
|
public final class MLookup extends Lookup implements Serializable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* generated serial id
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = 2288661955135689187L;
|
private static final long serialVersionUID = 3339750658316918418L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MLookup Constructor
|
* MLookup Constructor
|
||||||
|
|
@ -1083,9 +1083,9 @@ public final class MLookup extends Lookup implements Serializable
|
||||||
protected class MLoader extends ContextRunnable implements Serializable
|
protected class MLoader extends ContextRunnable implements Serializable
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* generated serial id
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = -7868426685745727939L;
|
private static final long serialVersionUID = -5752931726580011885L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* MLoader Constructor
|
* MLoader Constructor
|
||||||
|
|
@ -1228,7 +1228,11 @@ public final class MLookup extends Lookup implements Serializable
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
// SELECT Key, Value, Name, IsActive FROM ...
|
// SELECT Key, Value, Name, IsActive FROM ...
|
||||||
pstmt = DB.prepareStatement(sql.toString(), null);
|
String sqlFirstRows = DB.getDatabase().addPagingSQL(sql.toString(), 1, MAX_ROWS+1);
|
||||||
|
pstmt = DB.prepareStatement(sqlFirstRows, null);
|
||||||
|
int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, GridTable.DEFAULT_GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, Env.getAD_Client_ID(Env.getCtx()));
|
||||||
|
if (timeout > 0)
|
||||||
|
pstmt.setQueryTimeout(timeout);
|
||||||
rs = pstmt.executeQuery();
|
rs = pstmt.executeQuery();
|
||||||
|
|
||||||
// Get first ... rows
|
// Get first ... rows
|
||||||
|
|
@ -1237,19 +1241,10 @@ public final class MLookup extends Lookup implements Serializable
|
||||||
{
|
{
|
||||||
if (rows++ > MAX_ROWS)
|
if (rows++ > MAX_ROWS)
|
||||||
{
|
{
|
||||||
StringBuilder s = new StringBuilder().append(m_info.KeyColumn).append(": Loader - Too many records");
|
logLookup(Level.WARNING, "Too many records");
|
||||||
if (m_info.Column_ID > 0)
|
|
||||||
{
|
|
||||||
MColumn mColumn = MColumn.get(m_info.ctx, m_info.Column_ID);
|
|
||||||
String column = mColumn.getColumnName();
|
|
||||||
s.append(", Column=").append(column);
|
|
||||||
String tableName = MTable.getTableName(m_info.ctx, mColumn.getAD_Table_ID());
|
|
||||||
s.append(", Table=").append(tableName);
|
|
||||||
}
|
|
||||||
log.warning(s.toString());
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// check for interrupted every 10 rows
|
// check for interrupted every 20 rows
|
||||||
if (rows % 20 == 0 && Thread.interrupted())
|
if (rows % 20 == 0 && Thread.interrupted())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1294,8 +1289,11 @@ public final class MLookup extends Lookup implements Serializable
|
||||||
}
|
}
|
||||||
catch (SQLException e)
|
catch (SQLException e)
|
||||||
{
|
{
|
||||||
log.log(Level.SEVERE, m_info.KeyColumn + ", " + m_info.Column_ID + " : Loader - " + sql, e);
|
|
||||||
m_allLoaded = false;
|
m_allLoaded = false;
|
||||||
|
if (DB.getDatabase().isQueryTimeout(e))
|
||||||
|
logLookup(Level.WARNING, "Too slow query");
|
||||||
|
else
|
||||||
|
logLookup(Level.SEVERE, e.getLocalizedMessage());
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
DB.close(rs, pstmt);
|
DB.close(rs, pstmt);
|
||||||
|
|
@ -1307,6 +1305,25 @@ public final class MLookup extends Lookup implements Serializable
|
||||||
+ " - ms=" + String.valueOf(System.currentTimeMillis()-m_startTime)
|
+ " - ms=" + String.valueOf(System.currentTimeMillis()-m_startTime)
|
||||||
+ " (" + String.valueOf(System.currentTimeMillis()-startTime) + ")");
|
+ " (" + String.valueOf(System.currentTimeMillis()-startTime) + ")");
|
||||||
} // run
|
} // run
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Log a warning for the lookup problem found
|
||||||
|
* @param problem
|
||||||
|
*/
|
||||||
|
private void logLookup(Level level, String problem) {
|
||||||
|
if (log.isLoggable(level)) {
|
||||||
|
StringBuilder msg = new StringBuilder().append(m_info.KeyColumn).append(": Loader - ").append(problem);
|
||||||
|
if (m_info.Column_ID > 0) {
|
||||||
|
MColumn mColumn = MColumn.get(m_info.ctx, m_info.Column_ID);
|
||||||
|
String column = mColumn.getColumnName();
|
||||||
|
msg.append(", Column=").append(column);
|
||||||
|
String tableName = MTable.getTableName(m_info.ctx, mColumn.getAD_Table_ID());
|
||||||
|
msg.append(", Table=").append(tableName);
|
||||||
|
}
|
||||||
|
log.log(level, msg.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
} // Loader
|
} // Loader
|
||||||
|
|
||||||
} // MLookup
|
} // MLookup
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,7 @@ public class MSysConfig extends X_AD_SysConfig
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
private static final long serialVersionUID = -4149262106340017798L;
|
private static final long serialVersionUID = 8121897973805635995L;
|
||||||
|
|
||||||
/** Constant for Predefine System Configuration Names (in alphabetical order) */
|
/** Constant for Predefine System Configuration Names (in alphabetical order) */
|
||||||
|
|
||||||
|
|
@ -119,7 +119,9 @@ public class MSysConfig extends X_AD_SysConfig
|
||||||
public static final String FORM_SQL_QUERY_LOG_ISSUE = "FORM_SQL_QUERY_LOG_ISSUE";
|
public static final String FORM_SQL_QUERY_LOG_ISSUE = "FORM_SQL_QUERY_LOG_ISSUE";
|
||||||
public static final String FORM_SQL_QUERY_MAX_RECORDS = "FORM_SQL_QUERY_MAX_RECORDS";
|
public static final String FORM_SQL_QUERY_MAX_RECORDS = "FORM_SQL_QUERY_MAX_RECORDS";
|
||||||
public static final String FORM_SQL_QUERY_TIMEOUT_IN_SECONDS = "FORM_SQL_QUERY_TIMEOUT_IN_SECONDS";
|
public static final String FORM_SQL_QUERY_TIMEOUT_IN_SECONDS = "FORM_SQL_QUERY_TIMEOUT_IN_SECONDS";
|
||||||
|
public static final String GLOBAL_MAX_QUERY_RECORDS = "GLOBAL_MAX_QUERY_RECORDS";
|
||||||
public static final String GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS = "GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS";
|
public static final String GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS = "GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS";
|
||||||
|
public static final String GRIDTABLE_INITIAL_COUNT_TIMEOUT_IN_SECONDS = "GRIDTABLE_INITIAL_COUNT_TIMEOUT_IN_SECONDS";
|
||||||
public static final String HTML_REPORT_MINIFY = "HTML_REPORT_MINIFY";
|
public static final String HTML_REPORT_MINIFY = "HTML_REPORT_MINIFY";
|
||||||
public static final String HTML_REPORT_THEME = "HTML_REPORT_THEME";
|
public static final String HTML_REPORT_THEME = "HTML_REPORT_THEME";
|
||||||
public static final String IBAN_VALIDATION = "IBAN_VALIDATION";
|
public static final String IBAN_VALIDATION = "IBAN_VALIDATION";
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,6 @@ import java.util.logging.Level;
|
||||||
|
|
||||||
import org.adempiere.base.Core;
|
import org.adempiere.base.Core;
|
||||||
import org.adempiere.exceptions.AdempiereException;
|
import org.adempiere.exceptions.AdempiereException;
|
||||||
import org.adempiere.exceptions.DBException;
|
|
||||||
import org.adempiere.util.Callback;
|
import org.adempiere.util.Callback;
|
||||||
import org.adempiere.webui.AdempiereIdGenerator;
|
import org.adempiere.webui.AdempiereIdGenerator;
|
||||||
import org.adempiere.webui.AdempiereWebUI;
|
import org.adempiere.webui.AdempiereWebUI;
|
||||||
|
|
@ -1380,24 +1379,10 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer
|
||||||
public void query (boolean onlyCurrentRows, int onlyCurrentDays, int maxRows)
|
public void query (boolean onlyCurrentRows, int onlyCurrentDays, int maxRows)
|
||||||
{
|
{
|
||||||
boolean open = gridTab.isOpen();
|
boolean open = gridTab.isOpen();
|
||||||
try
|
|
||||||
{
|
|
||||||
gridTab.query(onlyCurrentRows, onlyCurrentDays, maxRows);
|
gridTab.query(onlyCurrentRows, onlyCurrentDays, maxRows);
|
||||||
if (listPanel.isVisible() && !open)
|
if (listPanel.isVisible() && !open)
|
||||||
gridTab.getTableModel().fireTableDataChanged();
|
gridTab.getTableModel().fireTableDataChanged();
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
|
||||||
{
|
|
||||||
if (DBException.isTimeout(e))
|
|
||||||
{
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Dialog.error(windowNo, e.getMessage());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset detail data grid for new parent record that's not saved yet.
|
* Reset detail data grid for new parent record that's not saved yet.
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,8 @@ import static org.compiere.model.MSysConfig.ZK_GRID_AFTER_FIND;
|
||||||
import static org.compiere.model.SystemIDs.PROCESS_AD_CHANGELOG_REDO;
|
import static org.compiere.model.SystemIDs.PROCESS_AD_CHANGELOG_REDO;
|
||||||
import static org.compiere.model.SystemIDs.PROCESS_AD_CHANGELOG_UNDO;
|
import static org.compiere.model.SystemIDs.PROCESS_AD_CHANGELOG_UNDO;
|
||||||
|
|
||||||
|
import java.sql.PreparedStatement;
|
||||||
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.text.MessageFormat;
|
import java.text.MessageFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
|
@ -853,15 +855,9 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//
|
//
|
||||||
StringBuffer sql = new StringBuffer("SELECT COUNT(*) FROM ")
|
int no = getRecordCount(mTab, where);
|
||||||
.append(mTab.getTableName());
|
// show find dialog if count timeout/exception
|
||||||
if (where.length() > 0)
|
require = no == -1 ? true : mTab.isQueryRequire(no);
|
||||||
sql.append(" WHERE ").append(where);
|
|
||||||
String finalSQL = MRole.getDefault().addAccessSQL(sql.toString(),
|
|
||||||
mTab.getTableName(), MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
|
|
||||||
int no = DB.getSQLValue(null, finalSQL.toString());
|
|
||||||
//
|
|
||||||
require = mTab.isQueryRequire(no);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Show find window (if required)
|
// Show find window (if required)
|
||||||
|
|
@ -916,6 +912,35 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
|
||||||
}
|
}
|
||||||
} // initialQuery
|
} // initialQuery
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get record count
|
||||||
|
* @param mTab
|
||||||
|
* @param where
|
||||||
|
* @return record count
|
||||||
|
*/
|
||||||
|
private int getRecordCount(GridTab mTab, StringBuffer where) {
|
||||||
|
StringBuffer sql = new StringBuffer("SELECT COUNT(*) FROM ")
|
||||||
|
.append(mTab.getTableName());
|
||||||
|
if (where.length() > 0)
|
||||||
|
sql.append(" WHERE ").append(where);
|
||||||
|
String finalSQL = MRole.getDefault().addAccessSQL(sql.toString(),
|
||||||
|
mTab.getTableName(), MRole.SQL_NOTQUALIFIED, MRole.SQL_RO);
|
||||||
|
int no = -1;
|
||||||
|
int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_INITIAL_COUNT_TIMEOUT_IN_SECONDS,
|
||||||
|
GridTable.DEFAULT_GRIDTABLE_COUNT_TIMEOUT_IN_SECONDS, Env.getAD_Client_ID(Env.getCtx()));
|
||||||
|
try (PreparedStatement stmt = DB.prepareStatement(finalSQL, null)) {
|
||||||
|
if (timeout > 0)
|
||||||
|
stmt.setQueryTimeout(timeout);
|
||||||
|
ResultSet rs = stmt.executeQuery();
|
||||||
|
if (rs.next())
|
||||||
|
no = rs.getInt(1);
|
||||||
|
} catch (SQLException e) {
|
||||||
|
logger.log(Level.WARNING, e.getMessage(), e);
|
||||||
|
no = -1;
|
||||||
|
}
|
||||||
|
return no;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Setup find window UI properties
|
* Setup find window UI properties
|
||||||
* @param findWindow
|
* @param findWindow
|
||||||
|
|
@ -1742,7 +1767,16 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements
|
||||||
{
|
{
|
||||||
//ignore non-ui thread event.
|
//ignore non-ui thread event.
|
||||||
if (Executions.getCurrent() == null)
|
if (Executions.getCurrent() == null)
|
||||||
|
{
|
||||||
|
// Re-post incremental loading event to UI thread
|
||||||
|
if (e.isLoading() && e.getSource() != null && e.getSource().equals(adTabbox.getSelectedGridTab().getTableModel()))
|
||||||
|
{
|
||||||
|
Executions.schedule(getComponent().getDesktop(), evt -> {
|
||||||
|
this.dataStatusChanged(e);
|
||||||
|
}, new Event("onAsynchronousDataStatusChanged"));
|
||||||
|
}
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
boolean detailTab = false;
|
boolean detailTab = false;
|
||||||
if (e.getSource() instanceof GridTable)
|
if (e.getSource() instanceof GridTable)
|
||||||
|
|
|
||||||
|
|
@ -3020,15 +3020,11 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
||||||
|
|
||||||
// Test for no records
|
// Test for no records
|
||||||
if (getNoOfRecords(m_query, true) != 0) {
|
if (getNoOfRecords(m_query, true) != 0) {
|
||||||
if (m_total == COUNTING_RECORDS_TIMED_OUT) {
|
|
||||||
Dialog.error(m_targetWindowNo, "InfoQueryTimeOutError");
|
|
||||||
} else {
|
|
||||||
if (advancedPanel != null) {
|
if (advancedPanel != null) {
|
||||||
advancedPanel.getItems().clear();
|
advancedPanel.getItems().clear();
|
||||||
}
|
}
|
||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // cmd_ok_Simple
|
} // cmd_ok_Simple
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -3098,12 +3094,8 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
||||||
}
|
}
|
||||||
|
|
||||||
if (getNoOfRecords(m_query, true) != 0) {
|
if (getNoOfRecords(m_query, true) != 0) {
|
||||||
if (m_total == COUNTING_RECORDS_TIMED_OUT) {
|
|
||||||
Dialog.error(m_targetWindowNo, "InfoQueryTimeOutError");
|
|
||||||
} else {
|
|
||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} // cmd_ok_Advanced
|
} // cmd_ok_Advanced
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
@ -3150,8 +3142,8 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
||||||
Env.setContext(Env.getCtx(), m_targetWindowNo, TABNO, GridTab.CTX_FindSQL, finalSQL);
|
Env.setContext(Env.getCtx(), m_targetWindowNo, TABNO, GridTab.CTX_FindSQL, finalSQL);
|
||||||
|
|
||||||
// Execute Query
|
// Execute Query
|
||||||
int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS,
|
int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_INITIAL_COUNT_TIMEOUT_IN_SECONDS,
|
||||||
GridTable.DEFAULT_GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, Env.getAD_Client_ID(Env.getCtx()));
|
GridTable.DEFAULT_GRIDTABLE_COUNT_TIMEOUT_IN_SECONDS, Env.getAD_Client_ID(Env.getCtx()));
|
||||||
m_total = 999999;
|
m_total = 999999;
|
||||||
Statement stmt = null;
|
Statement stmt = null;
|
||||||
ResultSet rs = null;
|
ResultSet rs = null;
|
||||||
|
|
@ -3187,12 +3179,12 @@ public class FindWindow extends Window implements EventListener<Event>, ValueCha
|
||||||
// No Records
|
// No Records
|
||||||
if (m_total == 0 && alertRecords)
|
if (m_total == 0 && alertRecords)
|
||||||
Dialog.warn(m_targetWindowNo, "FindZeroRecords", null);
|
Dialog.warn(m_targetWindowNo, "FindZeroRecords", null);
|
||||||
// More then allowed
|
// Load not more than max allow
|
||||||
if (m_gridTab != null && alertRecords && m_total != COUNTING_RECORDS_TIMED_OUT && m_gridTab.isQueryMax(m_total))
|
if (m_gridTab != null && alertRecords && m_total != COUNTING_RECORDS_TIMED_OUT && m_gridTab.isQueryMax(m_total))
|
||||||
{
|
{
|
||||||
Dialog.error(m_targetWindowNo, "FindOverMax",
|
Dialog.info(m_targetWindowNo, "FindOverMax",
|
||||||
m_total + " > " + m_gridTab.getMaxQueryRecords());
|
m_total + " > " + m_gridTab.getMaxQueryRecords());
|
||||||
m_total = 0; // return 0 if more then allowed - teo_sarca [ 1708717 ]
|
m_total = m_gridTab.getMaxQueryRecords();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if (log.isLoggable(Level.CONFIG)) log.config("#" + m_total);
|
if (log.isLoggable(Level.CONFIG)) log.config("#" + m_total);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue