From 59b83c33614d5b53cc0c84be30f6d109bd221edb Mon Sep 17 00:00:00 2001 From: hengsin Date: Tue, 19 Jan 2021 10:25:13 +0800 Subject: [PATCH] IDEMPIERE-4628 Implement configurable query timeout for info window (#532) * IDEMPIERE-4628 Implement configurable query timeout for info window * IDEMPIERE-4628 Implement configurable query timeout for info window Move migration script from i8.2z to i8.2 --- .../oracle/202001180600_IDEMPIERE-4628.sql | 18 +++++++ .../202001180600_IDEMPIERE-4628.sql | 14 ++++++ .../org/compiere/db/AdempiereDatabase.java | 10 +++- .../src/org/compiere/model/MSysConfig.java | 1 + .../org/adempiere/webui/info/InfoWindow.java | 15 +++++- .../org/adempiere/webui/panel/InfoPanel.java | 48 +++++++++++++++++-- .../src/org/compiere/db/DB_Oracle.java | 8 ++++ .../src/org/compiere/db/DB_PostgreSQL.java | 7 +++ 8 files changed, 115 insertions(+), 6 deletions(-) create mode 100644 migration/i8.2/oracle/202001180600_IDEMPIERE-4628.sql create mode 100644 migration/i8.2/postgresql/202001180600_IDEMPIERE-4628.sql diff --git a/migration/i8.2/oracle/202001180600_IDEMPIERE-4628.sql b/migration/i8.2/oracle/202001180600_IDEMPIERE-4628.sql new file mode 100644 index 0000000000..521da49547 --- /dev/null +++ b/migration/i8.2/oracle/202001180600_IDEMPIERE-4628.sql @@ -0,0 +1,18 @@ +SET SQLBLANKLINES ON +SET DEFINE OFF + +-- Jan 18, 2021, 1:40:41 PM MYT +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 (200169,0,0,TO_DATE('2021-01-18 13:40:40','YYYY-MM-DD HH24:MI:SS'),TO_DATE('2021-01-18 13:40:40','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_INFO_QUERY_TIME_OUT','120','Query timeout in seconds for info window. 0 means no timeout.','D','C','f5953385-1c8a-4df2-92dd-ad46aaeefb8e') +; + +-- Jan 18, 2021, 1:47:51 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 search took too long to return results. Please refine your search criteria.',0,0,'Y',TO_DATE('2021-01-18 13:47:50','YYYY-MM-DD HH24:MI:SS'),100,TO_DATE('2021-01-18 13:47:50','YYYY-MM-DD HH24:MI:SS'),100,200655,'INFO_QUERY_TIME_OUT_ERROR','D','ea2c33af-7c98-4208-8ed0-ea59b7f0ec58') +; + +-- Jan 18, 2021, 2:20:33 PM MYT +UPDATE AD_Message SET Value='InfoQueryTimeOutError',Updated=TO_DATE('2021-01-18 14:20:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200655 +; + +SELECT register_migration_script('202001180600_IDEMPIERE-4628.sql') FROM dual +; + diff --git a/migration/i8.2/postgresql/202001180600_IDEMPIERE-4628.sql b/migration/i8.2/postgresql/202001180600_IDEMPIERE-4628.sql new file mode 100644 index 0000000000..7d8474e06b --- /dev/null +++ b/migration/i8.2/postgresql/202001180600_IDEMPIERE-4628.sql @@ -0,0 +1,14 @@ +-- Jan 18, 2021, 1:40:41 PM MYT +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 (200169,0,0,TO_TIMESTAMP('2021-01-18 13:40:40','YYYY-MM-DD HH24:MI:SS'),TO_TIMESTAMP('2021-01-18 13:40:40','YYYY-MM-DD HH24:MI:SS'),100,100,'Y','ZK_INFO_QUERY_TIME_OUT','120','Query timeout in seconds for info window. 0 means no timeout.','D','C','f5953385-1c8a-4df2-92dd-ad46aaeefb8e') +; + +-- Jan 18, 2021, 1:47:51 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 search took too long to return results. Please refine your search criteria.',0,0,'Y',TO_TIMESTAMP('2021-01-18 13:47:50','YYYY-MM-DD HH24:MI:SS'),100,TO_TIMESTAMP('2021-01-18 13:47:50','YYYY-MM-DD HH24:MI:SS'),100,200655,'INFO_QUERY_TIME_OUT_ERROR','D','ea2c33af-7c98-4208-8ed0-ea59b7f0ec58') +; + +-- Jan 18, 2021, 2:20:33 PM MYT +UPDATE AD_Message SET Value='InfoQueryTimeOutError',Updated=TO_TIMESTAMP('2021-01-18 14:20:33','YYYY-MM-DD HH24:MI:SS'),UpdatedBy=100 WHERE AD_Message_ID=200655 +; + +SELECT register_migration_script('202001180600_IDEMPIERE-4628.sql') FROM dual +; diff --git a/org.adempiere.base/src/org/compiere/db/AdempiereDatabase.java b/org.adempiere.base/src/org/compiere/db/AdempiereDatabase.java index 67a7c911ec..5eeafbc29d 100644 --- a/org.adempiere.base/src/org/compiere/db/AdempiereDatabase.java +++ b/org.adempiere.base/src/org/compiere/db/AdempiereDatabase.java @@ -20,6 +20,7 @@ import java.math.BigDecimal; import java.sql.Connection; import java.sql.Driver; import java.sql.SQLException; +import java.sql.SQLTimeoutException; import java.sql.Timestamp; import javax.sql.DataSource; @@ -468,6 +469,13 @@ public interface AdempiereDatabase */ public String getSQLModify (MTable table, MColumn column, boolean setNullOption); - + /** + * + * @param ex + * @return true if ex is caused by query timeout + */ + public default boolean isQueryTimeout(SQLException ex) { + return ex instanceof SQLTimeoutException; + } } // AdempiereDatabase diff --git a/org.adempiere.base/src/org/compiere/model/MSysConfig.java b/org.adempiere.base/src/org/compiere/model/MSysConfig.java index 877f5a7690..acd96572ba 100644 --- a/org.adempiere.base/src/org/compiere/model/MSysConfig.java +++ b/org.adempiere.base/src/org/compiere/model/MSysConfig.java @@ -186,6 +186,7 @@ public class MSysConfig extends X_AD_SysConfig public static final String ZK_GRID_MOBILE_SHOW_CURRENT_ROW_INDICATOR = "ZK_GRID_MOBILE_SHOW_CURRENT_ROW_INDICATOR"; public static final String ZK_GRID_VIEW_USE_DEFER_RENDERING = "ZK_GRID_VIEW_USE_DEFER_RENDERING"; public static final String ZK_INFO_NUM_PAGE_PRELOAD = "ZK_INFO_NUM_PAGE_PRELOAD"; + public static final String ZK_INFO_QUERY_TIME_OUT = "ZK_INFO_QUERY_TIME_OUT"; public static final String ZK_LOGIN_ALLOW_CHROME_SAVE_PASSWORD = "ZK_LOGIN_ALLOW_CHROME_SAVE_PASSWORD"; public static final String ZK_LOGIN_ALLOW_REMEMBER_ME = "ZK_LOGIN_ALLOW_REMEMBER_ME"; public static final String ZK_LOGO_LARGE = "ZK_LOGO_LARGE"; diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java index 7d98e2c9a4..b35ebb330e 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/info/InfoWindow.java @@ -1930,6 +1930,9 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL */ protected boolean testCount(boolean promptError) { + if (useQueryTimeoutFromSysConfig) + queryTimeout = MSysConfig.getIntValue(MSysConfig.ZK_INFO_QUERY_TIME_OUT, 0, Env.getAD_Client_ID(Env.getCtx())); + long start = System.currentTimeMillis(); String dynWhere = getSQLWhere(); StringBuilder sql = new StringBuilder (m_sqlMain); @@ -1972,7 +1975,17 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL } catch (Exception e) { - log.log(Level.SEVERE, countSql, e); + if (e instanceof SQLException && DB.getDatabase().isQueryTimeout((SQLException) e)) + { + if (log.isLoggable(Level.INFO)) + log.log(Level.INFO, countSql, e); + FDialog.error(p_WindowNo, INFO_QUERY_TIME_OUT_ERROR); + } + else + { + log.log(Level.SEVERE, countSql, e); + FDialog.error(p_WindowNo, "DBExecuteError", e.getMessage()); + } m_count = -2; } finally diff --git a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPanel.java b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPanel.java index 64db66ed77..a78b6aeb8c 100644 --- a/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPanel.java +++ b/org.adempiere.ui.zk/WEB-INF/src/org/adempiere/webui/panel/InfoPanel.java @@ -67,6 +67,7 @@ import org.adempiere.webui.part.ITabOnSelectHandler; import org.adempiere.webui.part.WindowContainer; import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.util.ZKUpdateUtil; +import org.adempiere.webui.window.FDialog; import org.compiere.minigrid.ColumnInfo; import org.compiere.minigrid.IDColumn; import org.compiere.model.GridField; @@ -122,6 +123,7 @@ import org.zkoss.zul.ext.Sortable; */ public abstract class InfoPanel extends Window implements EventListener, WTableModelListener, Sortable, IHelpContext { + protected static final String INFO_QUERY_TIME_OUT_ERROR = "InfoQueryTimeOutError"; /** * */ @@ -312,7 +314,7 @@ public abstract class InfoPanel extends Window implements EventListener, try { int t = Integer.parseInt(pair[1]); if (t > 0) - this.queryTimeout = t; + setFixedQueryTimeout(t); } catch (Exception e) {} } else if (pair[0].equalsIgnoreCase("pagesize")) { try { @@ -327,6 +329,15 @@ public abstract class InfoPanel extends Window implements EventListener, } } + /** + * set fixed query timeout value, overwrite the value from sysconfig + * @param timeout + */ + public void setFixedQueryTimeout(int timeout) { + this.queryTimeout = timeout; + useQueryTimeoutFromSysConfig = false; + } + private void init() { if (isLookup()) @@ -465,6 +476,7 @@ public abstract class InfoPanel extends Window implements EventListener, protected boolean isAutoComplete = false; protected int queryTimeout = 0; + protected boolean useQueryTimeoutFromSysConfig = true; protected String autoCompleteSearchColumn = null; @@ -898,6 +910,9 @@ public abstract class InfoPanel extends Window implements EventListener, } private List readLine(int start, int end) { + if (useQueryTimeoutFromSysConfig) + queryTimeout = MSysConfig.getIntValue(MSysConfig.ZK_INFO_QUERY_TIME_OUT, 0, Env.getAD_Client_ID(Env.getCtx())); + //cacheStart & cacheEnd - 1 based index, start & end - 0 based index if (getCacheStart() >= 1 && cacheEnd > getCacheStart()) { @@ -996,7 +1011,17 @@ public abstract class InfoPanel extends Window implements EventListener, catch (SQLException e) { - log.log(Level.SEVERE, dataSql, e); + if (DB.getDatabase().isQueryTimeout(e)) + { + if (log.isLoggable(Level.INFO)) + log.log(Level.INFO, dataSql, e); + FDialog.error(p_WindowNo, INFO_QUERY_TIME_OUT_ERROR); + } + else + { + log.log(Level.SEVERE, dataSql, e); + FDialog.error(p_WindowNo, "DBExecuteError", e.getMessage()); + } } finally @@ -1239,6 +1264,9 @@ public abstract class InfoPanel extends Window implements EventListener, */ protected boolean testCount() { + if (useQueryTimeoutFromSysConfig) + queryTimeout = MSysConfig.getIntValue(MSysConfig.ZK_INFO_QUERY_TIME_OUT, 0, Env.getAD_Client_ID(Env.getCtx())); + long start = System.currentTimeMillis(); String dynWhere = getSQLWhere(); StringBuilder sql = new StringBuilder (m_sqlCount); @@ -1262,6 +1290,8 @@ public abstract class InfoPanel extends Window implements EventListener, try { pstmt = DB.prepareStatement(countSql, null); + if (queryTimeout > 0) + pstmt.setQueryTimeout(queryTimeout); setParameters (pstmt, true); rs = pstmt.executeQuery(); @@ -1269,8 +1299,18 @@ public abstract class InfoPanel extends Window implements EventListener, m_count = rs.getInt(1); } catch (Exception e) - { - log.log(Level.SEVERE, countSql, e); + { + if (e instanceof SQLException && DB.getDatabase().isQueryTimeout((SQLException) e)) + { + if (log.isLoggable(Level.INFO)) + log.log(Level.INFO, countSql, e); + FDialog.error(p_WindowNo, INFO_QUERY_TIME_OUT_ERROR); + } + else + { + log.log(Level.SEVERE, countSql, e); + FDialog.error(p_WindowNo, "DBExecuteError", e.getMessage()); + } m_count = -2; } finally diff --git a/org.compiere.db.oracle.provider/src/org/compiere/db/DB_Oracle.java b/org.compiere.db.oracle.provider/src/org/compiere/db/DB_Oracle.java index 0680cb1ab3..170a8a9d97 100644 --- a/org.compiere.db.oracle.provider/src/org/compiere/db/DB_Oracle.java +++ b/org.compiere.db.oracle.provider/src/org/compiere/db/DB_Oracle.java @@ -1532,4 +1532,12 @@ public class DB_Oracle implements AdempiereDatabase // return sql.toString(); } // getSQLModify + + @Override + public boolean isQueryTimeout(SQLException ex) { + //java.sql.SQLTimeoutException: ORA-01013: user requested cancel of current operation + return "72000".equals(ex.getSQLState()) && ex.getErrorCode() == 1013; + } + + } // DB_Oracle diff --git a/org.compiere.db.postgresql.provider/src/org/compiere/db/DB_PostgreSQL.java b/org.compiere.db.postgresql.provider/src/org/compiere/db/DB_PostgreSQL.java index fa58d1a0b2..0b9fc3f6cc 100755 --- a/org.compiere.db.postgresql.provider/src/org/compiere/db/DB_PostgreSQL.java +++ b/org.compiere.db.postgresql.provider/src/org/compiere/db/DB_PostgreSQL.java @@ -1422,4 +1422,11 @@ public class DB_PostgreSQL implements AdempiereDatabase return sql.toString(); } // getSQLModify + @Override + public boolean isQueryTimeout(SQLException ex) { + //org.postgresql.util.PSQLException: ERROR: canceling statement due to user request | SQL Code: 0 | SQL State: 57014 + return "57014".equals(ex.getSQLState()); + } + + } // DB_PostgreSQL