Changeset: 5540793628d6 for monetdb-java URL: https://dev.monetdb.org/hg/monetdb-java?cmd=changeset;node=5540793628d6 Modified Files: src/main/java/org/monetdb/jdbc/MonetConnection.java src/main/java/org/monetdb/jdbc/MonetStatement.java Branch: default Log Message:
Improve code when setting query timeout. It used to call the sys.settimeout(bigint) which is deprecated as of release Jun2020 (11.37.7) and replaced by new sys.setquerytimeout(int). As the server call was done from two places MonetConnection.isValid() and MonetStatement.internalExecute(), I created a single utlity method which is now called instead. diffs (254 lines): diff --git a/src/main/java/org/monetdb/jdbc/MonetConnection.java b/src/main/java/org/monetdb/jdbc/MonetConnection.java --- a/src/main/java/org/monetdb/jdbc/MonetConnection.java +++ b/src/main/java/org/monetdb/jdbc/MonetConnection.java @@ -142,7 +142,7 @@ public class MonetConnection private boolean treatClobAsVarChar = true; /** The last set query timeout on the server as used by Statement, PreparedStatement and CallableStatement */ - protected int lastSetQueryTimeout = 0; // 0 means no timeout, which is the default on the server + protected int lastSetQueryTimeout; // 0 means no timeout, which is the default on the server /** @@ -1311,7 +1311,7 @@ public class MonetConnection } } } catch (SQLException se) { - String msg = se.getMessage(); + final String msg = se.getMessage(); // System.out.println(se.getSQLState() + " Con.isValid(): " + msg); if (msg != null && msg.equalsIgnoreCase("Current transaction is aborted (please ROLLBACK)")) { // Must use equalsIgnoreCase() here because up to Jul2017 release 'Current' was 'current' so with lowercase c. @@ -1321,22 +1321,18 @@ public class MonetConnection } /* ignore stmt errors/exceptions, we are only testing if the connection is still alive and usable */ } finally { + closeResultsetStatement(rs, stmt); /* when changed, reset the original server timeout value on the server */ if (timeout > 0 && original_timeout != this.lastSetQueryTimeout) { this.lastSetQueryTimeout = original_timeout; - Statement stmt2 = null; try { /* we have to set in the server explicitly, because the test 'queryTimeout != connection.lastSetQueryTimeout' on MonetStatement.internalExecute(sql) won't pass and the server won't be set back */ - stmt2 = this.createStatement(); - stmt2.execute("CALL \"sys\".\"settimeout\"(" + this.lastSetQueryTimeout + ")"); + setQueryTimeout(original_timeout); } catch (SQLException se) { /* ignore stmt errors/exceptions, we are only testing if the connection is still alive and usable */ - } finally { - closeResultsetStatement(null, stmt2); } } - closeResultsetStatement(rs, stmt); } return isValid; } @@ -1636,6 +1632,43 @@ public class MonetConnection //== internal helper methods which do not belong to the JDBC interface /** + * Local helper method to test whether the Connection object is closed + * When closed it throws an SQLException + */ + private void checkNotClosed() throws SQLException { + if (closed) + throw new SQLException("Connection is closed", "M1M20"); + } + + /** + * Utility method to call sys.setquerytimeout(int); procedure on the connected server. + * It is called from: MonetConnection.isValid() and MonetStatement.internalExecute() + */ + void setQueryTimeout(final int millis) throws SQLException { + if (millis < 0) + throw new SQLException("query timeout milliseconds is less than zero", "M1M05"); + + checkNotClosed(); + Statement st = null; + try { + // as of release Jun2020 (11.37.7) the function sys.settimeout(bigint) is deprecated and replaced by new sys.setquerytimeout(int) + final boolean postJun2020 = (getDatabaseMajorVersion() >=11) && (getDatabaseMinorVersion() >= 37); + final String callstmt = postJun2020 ? "CALL sys.\"setquerytimeout\"(" + millis + ")" + : "CALL sys.\"settimeout\"(" + millis + ")"; + // for debug: System.out.println("Before: " + callstmt); + st = createStatement(); + st.execute(callstmt); + // for debug: System.out.println("After : " + callstmt); + + this.lastSetQueryTimeout = millis; + } + /* do not catch SQLException here, as we want to know it when it fails */ + finally { + closeResultsetStatement(null, st); + } + } + + /** * @return whether the JDBC BLOB type should be mapped to VARBINARY type. * This allows generic JDBC programs to fetch Blob data via getBytes() * instead of getBlob() and Blob.getBinaryStream() to reduce overhead. @@ -1656,15 +1689,6 @@ public class MonetConnection } /** - * Local helper method to test whether the Connection object is closed - * When closed it throws an SQLException - */ - private void checkNotClosed() throws SQLException { - if (closed) - throw new SQLException("Connection is closed", "M1M20"); - } - - /** * @return the MonetDB JDBC Connection URL (without user name and password). * It is called from: getURL()in MonetDatabaseMetaData */ @@ -1699,8 +1723,6 @@ public class MonetConnection private String env_current_user; private String env_monet_version; private int maxConnections; - private int databaseMajorVersion; - private int databaseMinorVersion; /** * Utility method to fetch 3 mserver environment values combined in one query for efficiency. @@ -1757,6 +1779,17 @@ public class MonetConnection } /** + * @return the maximum number of active connections possible at one time; + * a result of zero means that there is no limit or the limit is not known + * It is called from: MonetDatabaseMetaData + */ + int getMaxConnections() throws SQLException { + if (maxConnections == 0) + getEnvValues(); + return maxConnections; + } + + /** * @return the MonetDB Database Server version string. * It is called from: MonetDatabaseMetaData */ @@ -1769,9 +1802,11 @@ public class MonetConnection return ""; } + private int databaseMajorVersion; /** * @return the MonetDB Database Server major version number. - * It is called from: MonetDatabaseMetaData + * The number is extracted from the env_monet_version the first time and cached for next calls. + * It is called from: MonetDatabaseMetaData and MonetConnection */ int getDatabaseMajorVersion() throws SQLException { if (databaseMajorVersion == 0) { @@ -1790,9 +1825,11 @@ public class MonetConnection return databaseMajorVersion; } + private int databaseMinorVersion; /** * @return the MonetDB Database Server minor version number. - * It is called from: MonetDatabaseMetaData + * The number is extracted from the env_monet_version the first time and cached for next calls. + * It is called from: MonetDatabaseMetaData and MonetConnection */ int getDatabaseMinorVersion() throws SQLException { if (databaseMinorVersion == 0) { @@ -1815,17 +1852,6 @@ public class MonetConnection return databaseMinorVersion; } - /** - * @return the maximum number of active connections possible at one time; - * a result of zero means that there is no limit or the limit is not known - * It is called from: MonetDatabaseMetaData - */ - int getMaxConnections() throws SQLException { - if (maxConnections == 0) - getEnvValues(); - return maxConnections; - } - // Internal cache for determining if system table sys.privilege_codes (new as of Jul2017 release) exists on connected server private boolean queriedPrivilege_codesTable = false; @@ -2090,17 +2116,17 @@ public class MonetConnection * if we close this Response */ private boolean destroyOnClose; /** the offset to be used on Xexport queries */ - private int blockOffset = 0; + private int blockOffset; /** A parser for header lines */ private final HeaderLineParser hlp; /** A boolean array telling whether the headers are set or not */ private final boolean[] isSet; - private static final int NAMES = 0; - private static final int TYPES = 1; - private static final int TABLES = 2; - private static final int LENS = 3; + private static final int NAMES = 0; + private static final int TYPES = 1; + private static final int TABLES = 2; + private static final int LENS = 3; /** diff --git a/src/main/java/org/monetdb/jdbc/MonetStatement.java b/src/main/java/org/monetdb/jdbc/MonetStatement.java --- a/src/main/java/org/monetdb/jdbc/MonetStatement.java +++ b/src/main/java/org/monetdb/jdbc/MonetStatement.java @@ -62,11 +62,11 @@ public class MonetStatement /** Whether this Statement should be closed if the last ResultSet closes */ private boolean closeOnCompletion = false; /** The timeout (in sec) for the query to return, 0 means no timeout */ - private int queryTimeout = 0; + private int queryTimeout; /** The size of the blocks of results to ask for at the server */ - private int fetchSize = 0; + private int fetchSize; /** The maximum number of rows to return in a ResultSet, 0 indicates unlimited */ - private long maxRows = 0; + private long maxRows; /** The type of ResultSet to produce; i.e. forward only, random access */ private int resultSetType = MonetResultSet.DEF_RESULTSETTYPE; /** The suggested direction of fetching data (implemented but not used) */ @@ -75,8 +75,8 @@ public class MonetStatement private int resultSetConcurrency = MonetResultSet.DEF_CONCURRENCY; /** A List to hold all queries of a batch */ - private ArrayList<String> batch = null; - private ReentrantLock batchLock = null; + private ArrayList<String> batch; + private ReentrantLock batchLock; /** @@ -431,23 +431,7 @@ public class MonetStatement if (queryTimeout != connection.lastSetQueryTimeout) { // set requested/changed queryTimeout on the server side first - Statement st = null; - try { - st = connection.createStatement(); - final String callstmt = "CALL \"sys\".\"settimeout\"(" + queryTimeout + ")"; - // for debug: System.out.println("Before: " + callstmt); - st.execute(callstmt); - // for debug: System.out.println("After : " + callstmt); - connection.lastSetQueryTimeout = queryTimeout; - } - /* do not catch SQLException here, as we want to know it when it fails */ - finally { - if (st != null) { - try { - st.close(); - } catch (SQLException e) { /* ignore */ } - } - } + connection.setQueryTimeout(queryTimeout); } // create a container for the result _______________________________________________ checkin-list mailing list checkin-list@monetdb.org https://www.monetdb.org/mailman/listinfo/checkin-list