comparison src/main/java/org/monetdb/jdbc/MonetConnection.java @ 408:5540793628d6

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.
author Martin van Dinther <martin.van.dinther@monetdbsolutions.com>
date Thu, 07 Jan 2021 21:31:03 +0100 (2021-01-07)
parents 40a1db14dca5
children 1e278695fe54
comparison
equal deleted inserted replaced
407:40a1db14dca5 408:5540793628d6
140 private boolean treatBlobAsVarBinary = true; 140 private boolean treatBlobAsVarBinary = true;
141 /** Whether or not CLOB is mapped to Types.VARCHAR instead of Types.CLOB within this connection */ 141 /** Whether or not CLOB is mapped to Types.VARCHAR instead of Types.CLOB within this connection */
142 private boolean treatClobAsVarChar = true; 142 private boolean treatClobAsVarChar = true;
143 143
144 /** The last set query timeout on the server as used by Statement, PreparedStatement and CallableStatement */ 144 /** The last set query timeout on the server as used by Statement, PreparedStatement and CallableStatement */
145 protected int lastSetQueryTimeout = 0; // 0 means no timeout, which is the default on the server 145 protected int lastSetQueryTimeout; // 0 means no timeout, which is the default on the server
146 146
147 147
148 /** 148 /**
149 * Constructor of a Connection for MonetDB. At this moment the 149 * Constructor of a Connection for MonetDB. At this moment the
150 * current implementation limits itself to storing the given host, 150 * current implementation limits itself to storing the given host,
1309 if (rs != null && rs.next()) { 1309 if (rs != null && rs.next()) {
1310 isValid = true; 1310 isValid = true;
1311 } 1311 }
1312 } 1312 }
1313 } catch (SQLException se) { 1313 } catch (SQLException se) {
1314 String msg = se.getMessage(); 1314 final String msg = se.getMessage();
1315 // System.out.println(se.getSQLState() + " Con.isValid(): " + msg); 1315 // System.out.println(se.getSQLState() + " Con.isValid(): " + msg);
1316 if (msg != null && msg.equalsIgnoreCase("Current transaction is aborted (please ROLLBACK)")) { 1316 if (msg != null && msg.equalsIgnoreCase("Current transaction is aborted (please ROLLBACK)")) {
1317 // Must use equalsIgnoreCase() here because up to Jul2017 release 'Current' was 'current' so with lowercase c. 1317 // Must use equalsIgnoreCase() here because up to Jul2017 release 'Current' was 'current' so with lowercase c.
1318 // It changed to 'Current' after Jul2017 release. We need to support all server versions. 1318 // It changed to 'Current' after Jul2017 release. We need to support all server versions.
1319 // SQLState = 25005 1319 // SQLState = 25005
1320 isValid = true; 1320 isValid = true;
1321 } 1321 }
1322 /* ignore stmt errors/exceptions, we are only testing if the connection is still alive and usable */ 1322 /* ignore stmt errors/exceptions, we are only testing if the connection is still alive and usable */
1323 } finally { 1323 } finally {
1324 closeResultsetStatement(rs, stmt);
1324 /* when changed, reset the original server timeout value on the server */ 1325 /* when changed, reset the original server timeout value on the server */
1325 if (timeout > 0 && original_timeout != this.lastSetQueryTimeout) { 1326 if (timeout > 0 && original_timeout != this.lastSetQueryTimeout) {
1326 this.lastSetQueryTimeout = original_timeout; 1327 this.lastSetQueryTimeout = original_timeout;
1327 Statement stmt2 = null;
1328 try { 1328 try {
1329 /* we have to set in the server explicitly, because the test 'queryTimeout != connection.lastSetQueryTimeout' 1329 /* we have to set in the server explicitly, because the test 'queryTimeout != connection.lastSetQueryTimeout'
1330 on MonetStatement.internalExecute(sql) won't pass and the server won't be set back */ 1330 on MonetStatement.internalExecute(sql) won't pass and the server won't be set back */
1331 stmt2 = this.createStatement(); 1331 setQueryTimeout(original_timeout);
1332 stmt2.execute("CALL \"sys\".\"settimeout\"(" + this.lastSetQueryTimeout + ")");
1333 } catch (SQLException se) { 1332 } catch (SQLException se) {
1334 /* ignore stmt errors/exceptions, we are only testing if the connection is still alive and usable */ 1333 /* ignore stmt errors/exceptions, we are only testing if the connection is still alive and usable */
1335 } finally {
1336 closeResultsetStatement(null, stmt2);
1337 } 1334 }
1338 } 1335 }
1339 closeResultsetStatement(rs, stmt);
1340 } 1336 }
1341 return isValid; 1337 return isValid;
1342 } 1338 }
1343 1339
1344 /** 1340 /**
1634 1630
1635 1631
1636 //== internal helper methods which do not belong to the JDBC interface 1632 //== internal helper methods which do not belong to the JDBC interface
1637 1633
1638 /** 1634 /**
1635 * Local helper method to test whether the Connection object is closed
1636 * When closed it throws an SQLException
1637 */
1638 private void checkNotClosed() throws SQLException {
1639 if (closed)
1640 throw new SQLException("Connection is closed", "M1M20");
1641 }
1642
1643 /**
1644 * Utility method to call sys.setquerytimeout(int); procedure on the connected server.
1645 * It is called from: MonetConnection.isValid() and MonetStatement.internalExecute()
1646 */
1647 void setQueryTimeout(final int millis) throws SQLException {
1648 if (millis < 0)
1649 throw new SQLException("query timeout milliseconds is less than zero", "M1M05");
1650
1651 checkNotClosed();
1652 Statement st = null;
1653 try {
1654 // as of release Jun2020 (11.37.7) the function sys.settimeout(bigint) is deprecated and replaced by new sys.setquerytimeout(int)
1655 final boolean postJun2020 = (getDatabaseMajorVersion() >=11) && (getDatabaseMinorVersion() >= 37);
1656 final String callstmt = postJun2020 ? "CALL sys.\"setquerytimeout\"(" + millis + ")"
1657 : "CALL sys.\"settimeout\"(" + millis + ")";
1658 // for debug: System.out.println("Before: " + callstmt);
1659 st = createStatement();
1660 st.execute(callstmt);
1661 // for debug: System.out.println("After : " + callstmt);
1662
1663 this.lastSetQueryTimeout = millis;
1664 }
1665 /* do not catch SQLException here, as we want to know it when it fails */
1666 finally {
1667 closeResultsetStatement(null, st);
1668 }
1669 }
1670
1671 /**
1639 * @return whether the JDBC BLOB type should be mapped to VARBINARY type. 1672 * @return whether the JDBC BLOB type should be mapped to VARBINARY type.
1640 * This allows generic JDBC programs to fetch Blob data via getBytes() 1673 * This allows generic JDBC programs to fetch Blob data via getBytes()
1641 * instead of getBlob() and Blob.getBinaryStream() to reduce overhead. 1674 * instead of getBlob() and Blob.getBinaryStream() to reduce overhead.
1642 * It is called from: MonetResultSet and MonetPreparedStatement 1675 * It is called from: MonetResultSet and MonetPreparedStatement
1643 */ 1676 */
1651 * instead of getClob() and Clob.getCharacterStream() to reduce overhead. 1684 * instead of getClob() and Clob.getCharacterStream() to reduce overhead.
1652 * It is called from: MonetResultSet and MonetPreparedStatement 1685 * It is called from: MonetResultSet and MonetPreparedStatement
1653 */ 1686 */
1654 boolean mapClobAsVarChar() { 1687 boolean mapClobAsVarChar() {
1655 return treatClobAsVarChar; 1688 return treatClobAsVarChar;
1656 }
1657
1658 /**
1659 * Local helper method to test whether the Connection object is closed
1660 * When closed it throws an SQLException
1661 */
1662 private void checkNotClosed() throws SQLException {
1663 if (closed)
1664 throw new SQLException("Connection is closed", "M1M20");
1665 } 1689 }
1666 1690
1667 /** 1691 /**
1668 * @return the MonetDB JDBC Connection URL (without user name and password). 1692 * @return the MonetDB JDBC Connection URL (without user name and password).
1669 * It is called from: getURL()in MonetDatabaseMetaData 1693 * It is called from: getURL()in MonetDatabaseMetaData
1697 1721
1698 // Internal caches for 3 static mserver environment values, so they aren't queried from mserver again and again 1722 // Internal caches for 3 static mserver environment values, so they aren't queried from mserver again and again
1699 private String env_current_user; 1723 private String env_current_user;
1700 private String env_monet_version; 1724 private String env_monet_version;
1701 private int maxConnections; 1725 private int maxConnections;
1702 private int databaseMajorVersion;
1703 private int databaseMinorVersion;
1704 1726
1705 /** 1727 /**
1706 * Utility method to fetch 3 mserver environment values combined in one query for efficiency. 1728 * Utility method to fetch 3 mserver environment values combined in one query for efficiency.
1707 * We currently fetch the env values of: current_user, monet_version and max_clients. 1729 * We currently fetch the env values of: current_user, monet_version and max_clients.
1708 * We cache them such that we do not need to query the server again and again. 1730 * We cache them such that we do not need to query the server again and again.
1755 getEnvValues(); 1777 getEnvValues();
1756 return env_current_user; 1778 return env_current_user;
1757 } 1779 }
1758 1780
1759 /** 1781 /**
1782 * @return the maximum number of active connections possible at one time;
1783 * a result of zero means that there is no limit or the limit is not known
1784 * It is called from: MonetDatabaseMetaData
1785 */
1786 int getMaxConnections() throws SQLException {
1787 if (maxConnections == 0)
1788 getEnvValues();
1789 return maxConnections;
1790 }
1791
1792 /**
1760 * @return the MonetDB Database Server version string. 1793 * @return the MonetDB Database Server version string.
1761 * It is called from: MonetDatabaseMetaData 1794 * It is called from: MonetDatabaseMetaData
1762 */ 1795 */
1763 String getDatabaseProductVersion() throws SQLException { 1796 String getDatabaseProductVersion() throws SQLException {
1764 if (env_monet_version == null) 1797 if (env_monet_version == null)
1767 if (env_monet_version != null) 1800 if (env_monet_version != null)
1768 return env_monet_version; 1801 return env_monet_version;
1769 return ""; 1802 return "";
1770 } 1803 }
1771 1804
1805 private int databaseMajorVersion;
1772 /** 1806 /**
1773 * @return the MonetDB Database Server major version number. 1807 * @return the MonetDB Database Server major version number.
1774 * It is called from: MonetDatabaseMetaData 1808 * The number is extracted from the env_monet_version the first time and cached for next calls.
1809 * It is called from: MonetDatabaseMetaData and MonetConnection
1775 */ 1810 */
1776 int getDatabaseMajorVersion() throws SQLException { 1811 int getDatabaseMajorVersion() throws SQLException {
1777 if (databaseMajorVersion == 0) { 1812 if (databaseMajorVersion == 0) {
1778 if (env_monet_version == null) 1813 if (env_monet_version == null)
1779 getEnvValues(); 1814 getEnvValues();
1788 } 1823 }
1789 } 1824 }
1790 return databaseMajorVersion; 1825 return databaseMajorVersion;
1791 } 1826 }
1792 1827
1828 private int databaseMinorVersion;
1793 /** 1829 /**
1794 * @return the MonetDB Database Server minor version number. 1830 * @return the MonetDB Database Server minor version number.
1795 * It is called from: MonetDatabaseMetaData 1831 * The number is extracted from the env_monet_version the first time and cached for next calls.
1832 * It is called from: MonetDatabaseMetaData and MonetConnection
1796 */ 1833 */
1797 int getDatabaseMinorVersion() throws SQLException { 1834 int getDatabaseMinorVersion() throws SQLException {
1798 if (databaseMinorVersion == 0) { 1835 if (databaseMinorVersion == 0) {
1799 if (env_monet_version == null) 1836 if (env_monet_version == null)
1800 getEnvValues(); 1837 getEnvValues();
1811 // ignore 1848 // ignore
1812 } 1849 }
1813 } 1850 }
1814 } 1851 }
1815 return databaseMinorVersion; 1852 return databaseMinorVersion;
1816 }
1817
1818 /**
1819 * @return the maximum number of active connections possible at one time;
1820 * a result of zero means that there is no limit or the limit is not known
1821 * It is called from: MonetDatabaseMetaData
1822 */
1823 int getMaxConnections() throws SQLException {
1824 if (maxConnections == 0)
1825 getEnvValues();
1826 return maxConnections;
1827 } 1853 }
1828 1854
1829 1855
1830 // Internal cache for determining if system table sys.privilege_codes (new as of Jul2017 release) exists on connected server 1856 // Internal cache for determining if system table sys.privilege_codes (new as of Jul2017 release) exists on connected server
1831 private boolean queriedPrivilege_codesTable = false; 1857 private boolean queriedPrivilege_codesTable = false;
2088 private final boolean cacheSizeSetExplicitly; 2114 private final boolean cacheSizeSetExplicitly;
2089 /** Whether we should send an Xclose command to the server 2115 /** Whether we should send an Xclose command to the server
2090 * if we close this Response */ 2116 * if we close this Response */
2091 private boolean destroyOnClose; 2117 private boolean destroyOnClose;
2092 /** the offset to be used on Xexport queries */ 2118 /** the offset to be used on Xexport queries */
2093 private int blockOffset = 0; 2119 private int blockOffset;
2094 2120
2095 /** A parser for header lines */ 2121 /** A parser for header lines */
2096 private final HeaderLineParser hlp; 2122 private final HeaderLineParser hlp;
2097 2123
2098 /** A boolean array telling whether the headers are set or not */ 2124 /** A boolean array telling whether the headers are set or not */
2099 private final boolean[] isSet; 2125 private final boolean[] isSet;
2100 private static final int NAMES = 0; 2126 private static final int NAMES = 0;
2101 private static final int TYPES = 1; 2127 private static final int TYPES = 1;
2102 private static final int TABLES = 2; 2128 private static final int TABLES = 2;
2103 private static final int LENS = 3; 2129 private static final int LENS = 3;
2104 2130
2105 2131
2106 /** 2132 /**
2107 * Sole constructor, which requires a MonetConnection parent to 2133 * Sole constructor, which requires a MonetConnection parent to
2108 * be given. 2134 * be given.