diff --git a/migration/i8.2/oracle/202101190630_IDEMPIERE-4653.sql b/migration/i8.2/oracle/202101190630_IDEMPIERE-4653.sql new file mode 100644 index 0000000000..7cb3c13b3f --- /dev/null +++ b/migration/i8.2/oracle/202101190630_IDEMPIERE-4653.sql @@ -0,0 +1,10 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- Jan 19, 2021, 1:34:10 PM MYT +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 ('E','The window tab took too long to return results.',0,0,'Y',TO_DATE('2021-01-19 13:34:09','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-01-19 13:34:09','YYYY-MM-DD HH24:MI:SS'),100,200659,'GridTabLoadTimeoutError','D','f016a5f8-3783-4640-b713-8f0e1b4d3bb6') +; + +SELECT register_migration_script('202101190630_IDEMPIERE-4653.sql') FROM dual +; + diff --git a/migration/i8.2/postgresql/202101190630_IDEMPIERE-4653.sql b/migration/i8.2/postgresql/202101190630_IDEMPIERE-4653.sql new file mode 100644 index 0000000000..8bc6ad5566 --- /dev/null +++ b/migration/i8.2/postgresql/202101190630_IDEMPIERE-4653.sql @@ -0,0 +1,7 @@ +-- Jan 19, 2021, 1:34:10 PM MYT +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 ('E','The window tab took too long to return results.',0,0,'Y',TO_TIMESTAMP('2021-01-19 13:34:09','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-01-19 13:34:09','YYYY-MM-DD HH24:MI:SS'),100,200659,'GridTabLoadTimeoutError','D','f016a5f8-3783-4640-b713-8f0e1b4d3bb6') +; + +SELECT register_migration_script('202101190630_IDEMPIERE-4653.sql') FROM dual +; + diff --git a/org.adempiere.base/src/org/adempiere/exceptions/DBException.java b/org.adempiere.base/src/org/adempiere/exceptions/DBException.java index e378d9f1e2..93fc4794b5 100644 --- a/org.adempiere.base/src/org/adempiere/exceptions/DBException.java +++ b/org.adempiere.base/src/org/adempiere/exceptions/DBException.java @@ -199,9 +199,18 @@ public class DBException extends AdempiereException * @param e */ public static boolean isTimeout(Exception e) { - if (DB.isPostgreSQL()) - return isSQLState(e, "57014"); - return isErrorCode(e, 1013); + SQLException se = null; + if (e instanceof SQLException) { + se = (SQLException) e; + } else if (e.getCause() != null && e.getCause() instanceof SQLException) { + se = (SQLException) e.getCause(); + } + + if (se != null) { + return DB.getDatabase().isQueryTimeout(se); + } else { + return false; + } } /** diff --git a/org.adempiere.base/src/org/compiere/model/GridTab.java b/org.adempiere.base/src/org/compiere/model/GridTab.java index eed0971397..54adb7d3a4 100644 --- a/org.adempiere.base/src/org/compiere/model/GridTab.java +++ b/org.adempiere.base/src/org/compiere/model/GridTab.java @@ -112,7 +112,7 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable /** * */ - private static final long serialVersionUID = 8443012394354164942L; + private static final long serialVersionUID = 5086068543834849233L; public static final String DEFAULT_STATUS_MESSAGE = "NavigateOrUpdate"; @@ -3469,4 +3469,12 @@ public class GridTab implements DataStatusListener, Evaluatee, Serializable return max > 0 && noRecords > max; } // isQueryMax + /*** + * reset to empty + */ + public void reset() { + m_mTable.reset(); + setCurrentRow(0, true); + } + } // GridTab diff --git a/org.adempiere.base/src/org/compiere/model/GridTable.java b/org.adempiere.base/src/org/compiere/model/GridTable.java index 6028912fc5..2dc3e15963 100644 --- a/org.adempiere.base/src/org/compiere/model/GridTable.java +++ b/org.adempiere.base/src/org/compiere/model/GridTable.java @@ -49,7 +49,6 @@ import java.util.logging.Level; import javax.swing.event.TableModelListener; import javax.swing.table.AbstractTableModel; -import org.adempiere.exceptions.AdempiereException; import org.adempiere.exceptions.DBException; import org.adempiere.util.ServerContext; import org.compiere.Adempiere; @@ -104,7 +103,11 @@ public class GridTable extends AbstractTableModel /** * */ - private static final long serialVersionUID = -3190218965990521698L; + private static final long serialVersionUID = -1869219003783467319L; + + public static final int DEFAULT_GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS = 30; + + public static final String LOAD_TIMEOUT_ERROR_MESSAGE = "GridTabLoadTimeoutError"; public static final String DATA_REFRESH_MESSAGE = "Refreshed"; public static final String DATA_UPDATE_COPIED_MESSAGE = "UpdateCopied"; @@ -1087,7 +1090,7 @@ public class GridTable extends AbstractTableModel // need to wait for data read into buffer int loops = 0; //wait for [timeout] seconds - int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, 30, Env.getAD_Client_ID(Env.getCtx())); + int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, DEFAULT_GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, Env.getAD_Client_ID(Env.getCtx())); while (row >= m_sort.size() && m_loaderFuture != null && !m_loaderFuture.isDone() && loops < timeout) { if (log.isLoggable(Level.FINE)) log.fine("Waiting for loader row=" + row + ", size=" + m_sort.size()); @@ -1107,7 +1110,9 @@ public class GridTable extends AbstractTableModel } if (row >= m_sort.size()) { log.warning("Reached " + timeout + " seconds timeout loading row " + (row+1) + " for SQL=" + m_SQL); - throw new IllegalStateException("Timeout loading row " + (row+1)); + //adjust row count + m_rowCount = m_sort.size(); + throw new DBException("GridTabLoadTimeoutError"); } } @@ -3550,18 +3555,16 @@ public class GridTable extends AbstractTableModel { pstmt = DB.prepareStatement(m_SQL_Count, null); 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())); + if (timeout > 0) + pstmt.setQueryTimeout(timeout); rs = pstmt.executeQuery(); if (rs.next()) rows = rs.getInt(1); } catch (SQLException e0) { - // Zoom Query may have invalid where clause - if (DBException.isInvalidIdentifierError(e0)) - log.warning("Count - " + e0.getLocalizedMessage() + "\nSQL=" + m_SQL_Count); - else - throw new AdempiereException(e0); - return 0; + throw new DBException(e0); } finally { @@ -3602,6 +3605,9 @@ public class GridTable extends AbstractTableModel if (m_virtual) m_pstmt.setFetchSize(100); setParameter (m_pstmt, false); + 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) + m_pstmt.setQueryTimeout(timeout); m_rs = m_pstmt.executeQuery(); } catch (SQLException e) @@ -4042,4 +4048,25 @@ public class GridTable extends AbstractTableModel { return m_rowChanged; } + + /** + * reset to empty + */ + public void reset() + { + if (m_buffer != null) + m_buffer.clear(); + m_changed = false; + m_rowChanged = -1; + if (m_sort != null) + m_sort.clear(); + if (m_virtualBuffer != null) + m_virtualBuffer.clear(); + m_rowCount = 0; + m_rowData = null; + m_oldValue = null; + m_inserting = false; + m_lastSortColumnIndex = -1; + m_lastSortedAscending = false; + } } diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java index 122b5c3768..b5b391ad4a 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/ADTabpanel.java @@ -29,6 +29,7 @@ import java.util.logging.Level; import org.adempiere.base.Core; import org.adempiere.exceptions.AdempiereException; +import org.adempiere.exceptions.DBException; import org.adempiere.util.Callback; import org.adempiere.webui.AdempiereIdGenerator; import org.adempiere.webui.AdempiereWebUI; @@ -1161,9 +1162,23 @@ DataStatusListener, IADTabpanel, IdSpace, IFieldEditorContainer public void query (boolean onlyCurrentRows, int onlyCurrentDays, int maxRows) { boolean open = gridTab.isOpen(); - gridTab.query(onlyCurrentRows, onlyCurrentDays, maxRows); - if (listPanel.isVisible() && !open) - gridTab.getTableModel().fireTableDataChanged(); + try + { + gridTab.query(onlyCurrentRows, onlyCurrentDays, maxRows); + if (listPanel.isVisible() && !open) + gridTab.getTableModel().fireTableDataChanged(); + } + catch (Exception e) + { + if (DBException.isTimeout(e)) + { + FDialog.error(windowNo, GridTable.LOAD_TIMEOUT_ERROR_MESSAGE); + } + else + { + FDialog.error(windowNo, e.getMessage()); + } + } } /** diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java index b40dbcec0a..ae68f09ed0 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/adwindow/AbstractADWindowContent.java @@ -32,6 +32,7 @@ import java.util.Properties; import java.util.TreeMap; import java.util.logging.Level; +import org.adempiere.exceptions.DBException; import org.adempiere.util.Callback; import org.adempiere.webui.AdempiereIdGenerator; import org.adempiere.webui.AdempiereWebUI; @@ -1919,11 +1920,22 @@ public abstract class AbstractADWindowContent extends AbstractUIPart implements /** * @param fireEvent */ - protected void doOnRefresh(final boolean fireEvent) { + protected void doOnRefresh(final boolean fireEvent) { IADTabpanel headerTab = adTabbox.getSelectedTabpanel(); IADTabpanel detailTab = adTabbox.getSelectedDetailADTabpanel(); - adTabbox.getSelectedGridTab().dataRefreshAll(fireEvent, true); - adTabbox.getSelectedGridTab().refreshParentTabs(); + try { + adTabbox.getSelectedGridTab().dataRefreshAll(fireEvent, true); + } catch (Exception e) { + if (DBException.isTimeout(e)) { + FDialog.error(getWindowNo(), "GridTabLoadTimeoutError"); + } else { + FDialog.error(getWindowNo(), "Error", e.getMessage()); + } + adTabbox.getSelectedGridTab().reset(); + return; + } + + adTabbox.getSelectedGridTab().refreshParentTabs(); headerTab.dynamicDisplay(0); if (detailTab != null) { diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java index dfe5f546b2..b12afeb7bf 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/window/FindWindow.java @@ -80,6 +80,7 @@ import org.adempiere.webui.util.ZKUpdateUtil; import org.compiere.model.GridField; import org.compiere.model.GridFieldVO; import org.compiere.model.GridTab; +import org.compiere.model.GridTable; import org.compiere.model.Lookup; import org.compiere.model.MColumn; import org.compiere.model.MLookup; @@ -88,6 +89,7 @@ import org.compiere.model.MLookupInfo; import org.compiere.model.MProduct; import org.compiere.model.MQuery; import org.compiere.model.MRole; +import org.compiere.model.MSysConfig; import org.compiere.model.MTable; import org.compiere.model.MUserQuery; import org.compiere.model.SystemIDs; @@ -2471,20 +2473,31 @@ public class FindWindow extends Window implements EventListener, ValueCha if (log.isLoggable(Level.INFO)) Env.setContext(Env.getCtx(), m_targetWindowNo, TABNO, GridTab.CTX_FindSQL, finalSQL); - // Execute Qusery + // Execute Query + int timeout = MSysConfig.getIntValue(MSysConfig.GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, + GridTable.DEFAULT_GRIDTABLE_LOAD_TIMEOUT_IN_SECONDS, Env.getAD_Client_ID(Env.getCtx())); m_total = 999999; Statement stmt = null; ResultSet rs = null; try { stmt = DB.createStatement(); + if (timeout > 0) + stmt.setQueryTimeout(timeout); rs = stmt.executeQuery(finalSQL); if (rs.next()) m_total = rs.getInt(1); } catch (SQLException e) { - throw new DBException(e); + if (DB.getDatabase().isQueryTimeout(e)) + { + throw new DBException(Msg.getMsg(Env.getCtx(), GridTable.LOAD_TIMEOUT_ERROR_MESSAGE)); + } + else + { + throw new DBException(e); + } } finally {