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
This commit is contained in:
hengsin 2021-01-19 10:25:13 +08:00 committed by GitHub
parent 1afe4fe0c6
commit 59b83c3361
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 115 additions and 6 deletions

View File

@ -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
;

View File

@ -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
;

View File

@ -20,6 +20,7 @@ import java.math.BigDecimal;
import java.sql.Connection; import java.sql.Connection;
import java.sql.Driver; import java.sql.Driver;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.SQLTimeoutException;
import java.sql.Timestamp; import java.sql.Timestamp;
import javax.sql.DataSource; import javax.sql.DataSource;
@ -468,6 +469,13 @@ public interface AdempiereDatabase
*/ */
public String getSQLModify (MTable table, MColumn column, boolean setNullOption); 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 } // AdempiereDatabase

View File

@ -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_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_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_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_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_LOGIN_ALLOW_REMEMBER_ME = "ZK_LOGIN_ALLOW_REMEMBER_ME";
public static final String ZK_LOGO_LARGE = "ZK_LOGO_LARGE"; public static final String ZK_LOGO_LARGE = "ZK_LOGO_LARGE";

View File

@ -1930,6 +1930,9 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
*/ */
protected boolean testCount(boolean promptError) 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(); long start = System.currentTimeMillis();
String dynWhere = getSQLWhere(); String dynWhere = getSQLWhere();
StringBuilder sql = new StringBuilder (m_sqlMain); StringBuilder sql = new StringBuilder (m_sqlMain);
@ -1972,7 +1975,17 @@ public class InfoWindow extends InfoPanel implements ValueChangeListener, EventL
} }
catch (Exception e) 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; m_count = -2;
} }
finally finally

View File

@ -67,6 +67,7 @@ import org.adempiere.webui.part.ITabOnSelectHandler;
import org.adempiere.webui.part.WindowContainer; import org.adempiere.webui.part.WindowContainer;
import org.adempiere.webui.session.SessionManager; import org.adempiere.webui.session.SessionManager;
import org.adempiere.webui.util.ZKUpdateUtil; import org.adempiere.webui.util.ZKUpdateUtil;
import org.adempiere.webui.window.FDialog;
import org.compiere.minigrid.ColumnInfo; import org.compiere.minigrid.ColumnInfo;
import org.compiere.minigrid.IDColumn; import org.compiere.minigrid.IDColumn;
import org.compiere.model.GridField; import org.compiere.model.GridField;
@ -122,6 +123,7 @@ import org.zkoss.zul.ext.Sortable;
*/ */
public abstract class InfoPanel extends Window implements EventListener<Event>, WTableModelListener, Sortable<Object>, IHelpContext public abstract class InfoPanel extends Window implements EventListener<Event>, WTableModelListener, Sortable<Object>, IHelpContext
{ {
protected static final String INFO_QUERY_TIME_OUT_ERROR = "InfoQueryTimeOutError";
/** /**
* *
*/ */
@ -312,7 +314,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
try { try {
int t = Integer.parseInt(pair[1]); int t = Integer.parseInt(pair[1]);
if (t > 0) if (t > 0)
this.queryTimeout = t; setFixedQueryTimeout(t);
} catch (Exception e) {} } catch (Exception e) {}
} else if (pair[0].equalsIgnoreCase("pagesize")) { } else if (pair[0].equalsIgnoreCase("pagesize")) {
try { try {
@ -327,6 +329,15 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
} }
} }
/**
* 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() private void init()
{ {
if (isLookup()) if (isLookup())
@ -465,6 +476,7 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
protected boolean isAutoComplete = false; protected boolean isAutoComplete = false;
protected int queryTimeout = 0; protected int queryTimeout = 0;
protected boolean useQueryTimeoutFromSysConfig = true;
protected String autoCompleteSearchColumn = null; protected String autoCompleteSearchColumn = null;
@ -898,6 +910,9 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
} }
private List<Object> readLine(int start, int end) { private List<Object> 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 //cacheStart & cacheEnd - 1 based index, start & end - 0 based index
if (getCacheStart() >= 1 && cacheEnd > getCacheStart()) if (getCacheStart() >= 1 && cacheEnd > getCacheStart())
{ {
@ -996,7 +1011,17 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
catch (SQLException e) 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 finally
@ -1239,6 +1264,9 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
*/ */
protected boolean testCount() 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(); long start = System.currentTimeMillis();
String dynWhere = getSQLWhere(); String dynWhere = getSQLWhere();
StringBuilder sql = new StringBuilder (m_sqlCount); StringBuilder sql = new StringBuilder (m_sqlCount);
@ -1262,6 +1290,8 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
try try
{ {
pstmt = DB.prepareStatement(countSql, null); pstmt = DB.prepareStatement(countSql, null);
if (queryTimeout > 0)
pstmt.setQueryTimeout(queryTimeout);
setParameters (pstmt, true); setParameters (pstmt, true);
rs = pstmt.executeQuery(); rs = pstmt.executeQuery();
@ -1269,8 +1299,18 @@ public abstract class InfoPanel extends Window implements EventListener<Event>,
m_count = rs.getInt(1); m_count = rs.getInt(1);
} }
catch (Exception e) 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; m_count = -2;
} }
finally finally

View File

@ -1532,4 +1532,12 @@ public class DB_Oracle implements AdempiereDatabase
// //
return sql.toString(); return sql.toString();
} // getSQLModify } // 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 } // DB_Oracle

View File

@ -1422,4 +1422,11 @@ public class DB_PostgreSQL implements AdempiereDatabase
return sql.toString(); return sql.toString();
} // getSQLModify } // 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 } // DB_PostgreSQL