diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java index cd16c6c4..5c47edc2 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java @@ -20,6 +20,7 @@ import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.SQLException; +import java.sql.Savepoint; import java.sql.Statement; import java.sql.Wrapper; import java.util.HashSet; @@ -51,6 +52,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy private FastList openStatements; private boolean forceClose; + private boolean commitStateDirty; private boolean isAnythingDirty; private boolean isAutoCommitDirty; private boolean isCatalogDirty; @@ -92,7 +94,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy /** {@inheritDoc} */ @Override - public PoolBagEntry getPoolBagEntry() + public final PoolBagEntry getPoolBagEntry() { return bagEntry; } @@ -127,6 +129,13 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy } } + /** {@inheritDoc} */ + @Override + public final void markCommitStateDirty() + { + commitStateDirty = true; + } + // *********************************************************************** // Internal methods // *********************************************************************** @@ -138,7 +147,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy } } - private T trackStatement(T statement) + private final T trackStatement(T statement) { openStatements.add(statement); @@ -190,7 +199,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy } try { - if (!delegate.getAutoCommit()) { + if (commitStateDirty && !delegate.getAutoCommit()) { delegate.rollback(); } @@ -218,170 +227,122 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy /** {@inheritDoc} */ @Override - public final Statement createStatement() throws SQLException + public Statement createStatement() throws SQLException { - checkClosed(); - try { - Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement()); - return trackStatement(proxyStatement); - } - catch (SQLException e) { - throw checkException(e); - } + Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement()); + return trackStatement(proxyStatement); } /** {@inheritDoc} */ @Override - public final Statement createStatement(int resultSetType, int concurrency) throws SQLException + public Statement createStatement(int resultSetType, int concurrency) throws SQLException { - checkClosed(); - try { - Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, concurrency)); - return trackStatement(proxyStatement); - } - catch (SQLException e) { - throw checkException(e); - } + Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, concurrency)); + return trackStatement(proxyStatement); } /** {@inheritDoc} */ @Override - public final Statement createStatement(int resultSetType, int concurrency, int holdability) throws SQLException + public Statement createStatement(int resultSetType, int concurrency, int holdability) throws SQLException { - checkClosed(); - try { - Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, concurrency, holdability)); - return trackStatement(proxyStatement); - } - catch (SQLException e) { - throw checkException(e); - } + Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, concurrency, holdability)); + return trackStatement(proxyStatement); } /** {@inheritDoc} */ @Override - public final CallableStatement prepareCall(String sql) throws SQLException + public CallableStatement prepareCall(String sql) throws SQLException { - checkClosed(); - try { - CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql)); - return trackStatement(pcs); - } - catch (SQLException e) { - throw checkException(e); - } + CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql)); + return trackStatement(pcs); } /** {@inheritDoc} */ @Override - public final CallableStatement prepareCall(String sql, int resultSetType, int concurrency) throws SQLException + public CallableStatement prepareCall(String sql, int resultSetType, int concurrency) throws SQLException { - checkClosed(); - try { - CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, concurrency)); - return trackStatement(pcs); - } - catch (SQLException e) { - throw checkException(e); - } + CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, concurrency)); + return trackStatement(pcs); } /** {@inheritDoc} */ @Override - public final CallableStatement prepareCall(String sql, int resultSetType, int concurrency, int holdability) throws SQLException + public CallableStatement prepareCall(String sql, int resultSetType, int concurrency, int holdability) throws SQLException { - checkClosed(); - try { - CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, concurrency, holdability)); - return trackStatement(pcs); - } - catch (SQLException e) { - throw checkException(e); - } + CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, concurrency, holdability)); + return trackStatement(pcs); } /** {@inheritDoc} */ @Override - public final PreparedStatement prepareStatement(String sql) throws SQLException + public PreparedStatement prepareStatement(String sql) throws SQLException { - checkClosed(); - try { - PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql)); - return trackStatement(proxyPreparedStatement); - } - catch (SQLException e) { - throw checkException(e); - } + PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql)); + return trackStatement(proxyPreparedStatement); } /** {@inheritDoc} */ @Override - public final PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException + public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { - checkClosed(); - try { - PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, autoGeneratedKeys)); - return trackStatement(proxyPreparedStatement); - } - catch (SQLException e) { - throw checkException(e); - } + PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, autoGeneratedKeys)); + return trackStatement(proxyPreparedStatement); } /** {@inheritDoc} */ @Override - public final PreparedStatement prepareStatement(String sql, int resultSetType, int concurrency) throws SQLException + public PreparedStatement prepareStatement(String sql, int resultSetType, int concurrency) throws SQLException { - checkClosed(); - try { - PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, concurrency)); - return trackStatement(proxyPreparedStatement); - } - catch (SQLException e) { - throw checkException(e); - } + PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, concurrency)); + return trackStatement(proxyPreparedStatement); } /** {@inheritDoc} */ @Override - public final PreparedStatement prepareStatement(String sql, int resultSetType, int concurrency, int holdability) throws SQLException + public PreparedStatement prepareStatement(String sql, int resultSetType, int concurrency, int holdability) throws SQLException { - checkClosed(); - try { - PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, concurrency, holdability)); - return trackStatement(proxyPreparedStatement); - } - catch (SQLException e) { - throw checkException(e); - } + PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, concurrency, holdability)); + return trackStatement(proxyPreparedStatement); } /** {@inheritDoc} */ @Override - public final PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException + public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { - checkClosed(); - try { - PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnIndexes)); - return trackStatement(proxyPreparedStatement); - } - catch (SQLException e) { - throw checkException(e); - } + PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnIndexes)); + return trackStatement(proxyPreparedStatement); } /** {@inheritDoc} */ @Override - public final PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException + public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { - checkClosed(); - try { - PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames)); - return trackStatement(proxyPreparedStatement); - } - catch (SQLException e) { - throw checkException(e); - } + PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames)); + return trackStatement(proxyPreparedStatement); + } + + /** {@inheritDoc} */ + @Override + public void commit() throws SQLException + { + delegate.commit(); + commitStateDirty = false; + } + + /** {@inheritDoc} */ + @Override + public void rollback() throws SQLException + { + delegate.rollback(); + commitStateDirty = false; + } + + /** {@inheritDoc} */ + @Override + public void rollback(Savepoint savepoint) throws SQLException + { + delegate.rollback(savepoint); + commitStateDirty = false; } /** {@inheritDoc} */ @@ -402,61 +363,38 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy /** {@inheritDoc} */ @Override - public final void setAutoCommit(boolean autoCommit) throws SQLException + public void setAutoCommit(boolean autoCommit) throws SQLException { - checkClosed(); - try { - delegate.setAutoCommit(autoCommit); - isAnythingDirty = true; - isAutoCommitDirty = (autoCommit != parentPool.isAutoCommit); - } - catch (SQLException e) { - throw checkException(e); - } + delegate.setAutoCommit(autoCommit); + isAnythingDirty = true; + isAutoCommitDirty = (autoCommit != parentPool.isAutoCommit); } /** {@inheritDoc} */ @Override - public final void setReadOnly(boolean readOnly) throws SQLException + public void setReadOnly(boolean readOnly) throws SQLException { - checkClosed(); - try { - delegate.setReadOnly(readOnly); - isAnythingDirty = true; - isReadOnlyDirty = (readOnly != parentPool.isReadOnly); - } - catch (SQLException e) { - throw checkException(e); - } + delegate.setReadOnly(readOnly); + isAnythingDirty = true; + isReadOnlyDirty = (readOnly != parentPool.isReadOnly); } /** {@inheritDoc} */ @Override - public final void setTransactionIsolation(int level) throws SQLException + public void setTransactionIsolation(int level) throws SQLException { - checkClosed(); - try { - delegate.setTransactionIsolation(level); - isAnythingDirty = true; - isTransactionIsolationDirty = (level != parentPool.transactionIsolation); - } - catch (SQLException e) { - throw checkException(e); - } + delegate.setTransactionIsolation(level); + isAnythingDirty = true; + isTransactionIsolationDirty = (level != parentPool.transactionIsolation); } + /** {@inheritDoc} */ @Override - public final void setCatalog(String catalog) throws SQLException + public void setCatalog(String catalog) throws SQLException { - checkClosed(); - try { - delegate.setCatalog(catalog); - isAnythingDirty = true; - isCatalogDirty = (catalog != null && !catalog.equals(parentPool.catalog)) || (catalog == null && parentPool.catalog != null); - } - catch (SQLException e) { - throw checkException(e); - } + delegate.setCatalog(catalog); + isAnythingDirty = true; + isCatalogDirty = (catalog != null && !catalog.equals(parentPool.catalog)) || (catalog == null && parentPool.catalog != null); } /** {@inheritDoc} */ diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java index 3dfa597a..7bd3c8ea 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java @@ -53,4 +53,9 @@ public interface IHikariConnectionProxy extends Connection * @param statement the Statement to remove from tracking */ void untrackStatement(Statement statement); + + /** + * Sets the commit state of the connection to dirty. + */ + void markCommitStateDirty(); } diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java index dc3dd4f5..fa1001f5 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java @@ -19,6 +19,7 @@ package com.zaxxer.hikari.proxy; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.Statement; import java.util.HashSet; import java.util.Set; @@ -83,6 +84,7 @@ public final class JavassistProxyFactory // Cast is not needed for these methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { throw checkException(e); } }"; generateProxyClass(Statement.class, StatementProxy.class, methodBody); + generateProxyClass(ResultSet.class, ResultSetProxy.class, methodBody); // For these we have to cast the delegate methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { throw checkException(e); } }"; @@ -108,6 +110,9 @@ public final class JavassistProxyFactory else if ("getProxyCallableStatement".equals(methodName)) { method.setBody("{return new " + packageName + ".CallableStatementJavassistProxy($$);}"); } + else if ("getProxyResultSet".equals(methodName)) { + method.setBody("{return new " + packageName + ".ResultSetJavassistProxy($$);}"); + } } proxyCt.toClass(classPool.getClassLoader(), getClass().getProtectionDomain()); @@ -128,13 +133,11 @@ public final class JavassistProxyFactory // Make a set of method signatures we inherit implementation for, so we don't generate delegates for these Set superSigs = new HashSet(); for (CtMethod method : superClassCt.getMethods()) { - if ((method.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT) { + if ((method.getModifiers() & Modifier.FINAL) == Modifier.FINAL) { superSigs.add(method.getName() + method.getSignature()); } } - methodBody = methodBody.replace("cast", primaryInterface.getName()); - Set methods = new HashSet(); Set> interfaces = ClassLoaderUtils.getAllInterfaces(primaryInterface); for (Class intf : interfaces) { @@ -159,10 +162,21 @@ public final class JavassistProxyFactory // Clone the method we want to inject into CtMethod method = CtNewMethod.copy(intfMethod, targetCt, null); + String modifiedBody = methodBody; + + // If the super-Proxy has concrete methods (non-abstract), transform the call into a simple super.method() call + CtMethod superMethod = superClassCt.getMethod(intfMethod.getName(), intfMethod.getSignature()); + if ((superMethod.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT) { + modifiedBody = modifiedBody.replace("((cast) ", ""); + modifiedBody = modifiedBody.replace("delegate", "super"); + modifiedBody = modifiedBody.replace("super)", "super"); + } + + modifiedBody = modifiedBody.replace("cast", primaryInterface.getName()); + // Generate a method that simply invokes the same method on the delegate - String modifiedBody; if (isThrowsSqlException(intfMethod)) { - modifiedBody = methodBody.replace("method", method.getName()); + modifiedBody = modifiedBody.replace("method", method.getName()); } else { modifiedBody = "{ return ((cast) delegate).method($$); }".replace("method", method.getName()).replace("cast", primaryInterface.getName()); diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java index 0112f169..3e7d7bb1 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java @@ -17,6 +17,8 @@ package com.zaxxer.hikari.proxy; import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; /** * This is the proxy class for java.sql.PreparedStatement. @@ -34,4 +36,36 @@ public abstract class PreparedStatementProxy extends StatementProxy implements P // Overridden java.sql.PreparedStatement Methods // ********************************************************************** + /** {@inheritDoc} */ + @Override + public boolean execute() throws SQLException + { + connection.markCommitStateDirty(); + return ((PreparedStatement) delegate).execute(); + } + + /** {@inheritDoc} */ + @Override + public ResultSet executeQuery() throws SQLException + { + connection.markCommitStateDirty(); + ResultSet resultSet = ((PreparedStatement) delegate).executeQuery(); + return ProxyFactory.getProxyResultSet(connection, resultSet); + } + + /** {@inheritDoc} */ + @Override + public int executeUpdate() throws SQLException + { + connection.markCommitStateDirty(); + return ((PreparedStatement) delegate).executeUpdate(); + } + + /** {@inheritDoc} */ + @Override + public long executeLargeUpdate() throws SQLException + { + connection.markCommitStateDirty(); + return ((PreparedStatement) delegate).executeLargeUpdate(); + } } diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java index 49056a9a..4f6f2bbe 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java @@ -19,6 +19,7 @@ package com.zaxxer.hikari.proxy; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.Statement; import com.zaxxer.hikari.pool.HikariPool; @@ -69,4 +70,10 @@ public final class ProxyFactory // Body is injected by JavassistProxyFactory return null; } + + static ResultSet getProxyResultSet(final ConnectionProxy connection, final ResultSet resultSet) + { + // Body is injected by JavassistProxyFactory + return null; + } } diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java new file mode 100644 index 00000000..eb9af03e --- /dev/null +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013, 2014 Brett Wooldridge + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.zaxxer.hikari.proxy; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Wrapper; + +/** + * This is the proxy class for java.sql.ResultSet. + * + * @author Brett Wooldridge + */ +public abstract class ResultSetProxy implements ResultSet +{ + protected final ConnectionProxy connection; + protected final ResultSet delegate; + + protected ResultSetProxy(ConnectionProxy connection, ResultSet resultSet) + { + this.connection = connection; + this.delegate = resultSet; + } + + protected final SQLException checkException(SQLException e) + { + return connection.checkException(e); + } + + // ********************************************************************** + // Overridden java.sql.ResultSet Methods + // ********************************************************************** + + /** {@inheritDoc} */ + @Override + public void updateRow() throws SQLException + { + connection.markCommitStateDirty(); + delegate.updateRow(); + } + + /** {@inheritDoc} */ + @Override + public void insertRow() throws SQLException + { + connection.markCommitStateDirty(); + delegate.insertRow(); + } + + /** {@inheritDoc} */ + @Override + public void deleteRow() throws SQLException + { + connection.markCommitStateDirty(); + delegate.deleteRow(); + } + + /** {@inheritDoc} */ + @Override + @SuppressWarnings("unchecked") + public final T unwrap(Class iface) throws SQLException + { + if (iface.isInstance(delegate)) { + return (T) delegate; + } + else if (delegate instanceof Wrapper) { + return (T) delegate.unwrap(iface); + } + + throw new SQLException("Wrapped ResultSet is not an instance of " + iface); + } +} diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java index 6b4aa90f..bbabdc39 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java @@ -17,6 +17,7 @@ package com.zaxxer.hikari.proxy; import java.sql.Connection; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.sql.Wrapper; @@ -28,12 +29,12 @@ import java.sql.Wrapper; */ public abstract class StatementProxy implements Statement { - protected final IHikariConnectionProxy connection; + protected final ConnectionProxy connection; protected final Statement delegate; private boolean isClosed; - protected StatementProxy(IHikariConnectionProxy connection, Statement statement) + protected StatementProxy(ConnectionProxy connection, Statement statement) { this.connection = connection; this.delegate = statement; @@ -69,11 +70,133 @@ public abstract class StatementProxy implements Statement /** {@inheritDoc} */ @Override - public final Connection getConnection() throws SQLException + public Connection getConnection() throws SQLException { return connection; } + /** {@inheritDoc} */ + @Override + public boolean execute(String sql) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.execute(sql); + } + + /** {@inheritDoc} */ + @Override + public boolean execute(String sql, int autoGeneratedKeys) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.execute(sql, autoGeneratedKeys); + } + + /** {@inheritDoc} */ + @Override + public ResultSet executeQuery(String sql) throws SQLException + { + connection.markCommitStateDirty(); + ResultSet resultSet = delegate.executeQuery(sql); + return ProxyFactory.getProxyResultSet(connection, resultSet); + } + + /** {@inheritDoc} */ + @Override + public int executeUpdate(String sql) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeUpdate(sql); + } + + /** {@inheritDoc} */ + @Override + public int[] executeBatch() throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeBatch(); + } + + /** {@inheritDoc} */ + @Override + public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeUpdate(sql, autoGeneratedKeys); + } + + /** {@inheritDoc} */ + @Override + public int executeUpdate(String sql, int[] columnIndexes) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeUpdate(sql, columnIndexes); + } + + /** {@inheritDoc} */ + @Override + public int executeUpdate(String sql, String[] columnNames) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeUpdate(sql, columnNames); + } + + /** {@inheritDoc} */ + @Override + public boolean execute(String sql, int[] columnIndexes) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.execute(sql, columnIndexes); + } + + /** {@inheritDoc} */ + @Override + public boolean execute(String sql, String[] columnNames) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.execute(sql, columnNames); + } + + /** {@inheritDoc} */ + @Override + public long[] executeLargeBatch() throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeLargeBatch(); + } + + /** {@inheritDoc} */ + @Override + public long executeLargeUpdate(String sql) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeLargeUpdate(sql); + } + + /** {@inheritDoc} */ + @Override + public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeLargeUpdate(sql, autoGeneratedKeys); + } + + /** {@inheritDoc} */ + @Override + public long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeLargeUpdate(sql, columnIndexes); + } + + /** {@inheritDoc} */ + @Override + public long executeLargeUpdate(String sql, String[] columnNames) throws SQLException + { + connection.markCommitStateDirty(); + return delegate.executeLargeUpdate(sql, columnNames); + } + + /** {@inheritDoc} */ @Override @SuppressWarnings("unchecked") public final T unwrap(Class iface) throws SQLException diff --git a/hikaricp-java6/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java b/hikaricp-java6/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java index 7c014cb2..89d65d9f 100644 --- a/hikaricp-java6/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java +++ b/hikaricp-java6/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java @@ -244,6 +244,9 @@ public final class PoolUtilities catch (AbstractMethodError e) { IS_JDBC40 = false; } + catch (NoSuchMethodError e) { + IS_JDBC40 = false; + } } return IS_JDBC40; @@ -265,10 +268,13 @@ public final class PoolUtilities connection.getNetworkTimeout(); // This will throw AbstractMethodError or SQLException in the case of a non-JDBC 41 compliant driver IS_JDBC41 = true; } + catch (SQLFeatureNotSupportedException e) { + IS_JDBC41 = false; + } catch (AbstractMethodError e) { IS_JDBC41 = false; } - catch (SQLFeatureNotSupportedException e) { + catch (NoSuchMethodError e) { IS_JDBC41 = false; } } @@ -289,10 +295,13 @@ public final class PoolUtilities try { statement.setQueryTimeout(timeoutSec); } + catch (SQLFeatureNotSupportedException e) { + queryTimeoutSupported = false; + } catch (AbstractMethodError e) { queryTimeoutSupported = false; } - catch (SQLFeatureNotSupportedException e) { + catch (NoSuchMethodError e) { queryTimeoutSupported = false; } } diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java index abfbce42..5c47edc2 100644 --- a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java +++ b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ConnectionProxy.java @@ -131,7 +131,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy /** {@inheritDoc} */ @Override - public final void setCommitStateDirty() + public final void markCommitStateDirty() { commitStateDirty = true; } diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java index 70d1ab33..7bd3c8ea 100644 --- a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java +++ b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/IHikariConnectionProxy.java @@ -57,5 +57,5 @@ public interface IHikariConnectionProxy extends Connection /** * Sets the commit state of the connection to dirty. */ - void setCommitStateDirty(); + void markCommitStateDirty(); } diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java index d36cd34c..86550bd5 100644 --- a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java +++ b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/JavassistProxyFactory.java @@ -19,6 +19,7 @@ package com.zaxxer.hikari.proxy; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.Statement; import java.util.HashSet; import java.util.Set; @@ -83,6 +84,7 @@ public final class JavassistProxyFactory // Cast is not needed for these methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { throw checkException(e); } }"; generateProxyClass(Statement.class, StatementProxy.class, methodBody); + generateProxyClass(ResultSet.class, ResultSetProxy.class, methodBody); // For these we have to cast the delegate methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { throw checkException(e); } }"; @@ -108,6 +110,9 @@ public final class JavassistProxyFactory case "getProxyCallableStatement": method.setBody("{return new " + packageName + ".CallableStatementJavassistProxy($$);}"); break; + case "getProxyResultSet": + method.setBody("{return new " + packageName + ".ResultSetJavassistProxy($$);}"); + break; } } @@ -160,6 +165,7 @@ public final class JavassistProxyFactory String modifiedBody = methodBody; + // If the super-Proxy has concrete methods (non-abstract), transform the call into a simple super.method() call CtMethod superMethod = superClassCt.getMethod(intfMethod.getName(), intfMethod.getSignature()); if ((superMethod.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT) { modifiedBody = modifiedBody.replace("((cast) ", ""); diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java index 236467ab..3e7d7bb1 100644 --- a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java +++ b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/PreparedStatementProxy.java @@ -40,7 +40,7 @@ public abstract class PreparedStatementProxy extends StatementProxy implements P @Override public boolean execute() throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return ((PreparedStatement) delegate).execute(); } @@ -48,15 +48,16 @@ public abstract class PreparedStatementProxy extends StatementProxy implements P @Override public ResultSet executeQuery() throws SQLException { - connection.setCommitStateDirty(); - return ((PreparedStatement) delegate).executeQuery(); + connection.markCommitStateDirty(); + ResultSet resultSet = ((PreparedStatement) delegate).executeQuery(); + return ProxyFactory.getProxyResultSet(connection, resultSet); } /** {@inheritDoc} */ @Override public int executeUpdate() throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return ((PreparedStatement) delegate).executeUpdate(); } @@ -64,7 +65,7 @@ public abstract class PreparedStatementProxy extends StatementProxy implements P @Override public long executeLargeUpdate() throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return ((PreparedStatement) delegate).executeLargeUpdate(); } } diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java index 49056a9a..4f6f2bbe 100644 --- a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java +++ b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ProxyFactory.java @@ -19,6 +19,7 @@ package com.zaxxer.hikari.proxy; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.PreparedStatement; +import java.sql.ResultSet; import java.sql.Statement; import com.zaxxer.hikari.pool.HikariPool; @@ -69,4 +70,10 @@ public final class ProxyFactory // Body is injected by JavassistProxyFactory return null; } + + static ResultSet getProxyResultSet(final ConnectionProxy connection, final ResultSet resultSet) + { + // Body is injected by JavassistProxyFactory + return null; + } } diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java new file mode 100644 index 00000000..eb9af03e --- /dev/null +++ b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/ResultSetProxy.java @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2013, 2014 Brett Wooldridge + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.zaxxer.hikari.proxy; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Wrapper; + +/** + * This is the proxy class for java.sql.ResultSet. + * + * @author Brett Wooldridge + */ +public abstract class ResultSetProxy implements ResultSet +{ + protected final ConnectionProxy connection; + protected final ResultSet delegate; + + protected ResultSetProxy(ConnectionProxy connection, ResultSet resultSet) + { + this.connection = connection; + this.delegate = resultSet; + } + + protected final SQLException checkException(SQLException e) + { + return connection.checkException(e); + } + + // ********************************************************************** + // Overridden java.sql.ResultSet Methods + // ********************************************************************** + + /** {@inheritDoc} */ + @Override + public void updateRow() throws SQLException + { + connection.markCommitStateDirty(); + delegate.updateRow(); + } + + /** {@inheritDoc} */ + @Override + public void insertRow() throws SQLException + { + connection.markCommitStateDirty(); + delegate.insertRow(); + } + + /** {@inheritDoc} */ + @Override + public void deleteRow() throws SQLException + { + connection.markCommitStateDirty(); + delegate.deleteRow(); + } + + /** {@inheritDoc} */ + @Override + @SuppressWarnings("unchecked") + public final T unwrap(Class iface) throws SQLException + { + if (iface.isInstance(delegate)) { + return (T) delegate; + } + else if (delegate instanceof Wrapper) { + return (T) delegate.unwrap(iface); + } + + throw new SQLException("Wrapped ResultSet is not an instance of " + iface); + } +} diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java index 9d878e9f..bbabdc39 100644 --- a/hikaricp/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java +++ b/hikaricp/src/main/java/com/zaxxer/hikari/proxy/StatementProxy.java @@ -29,12 +29,12 @@ import java.sql.Wrapper; */ public abstract class StatementProxy implements Statement { - protected final IHikariConnectionProxy connection; + protected final ConnectionProxy connection; protected final Statement delegate; private boolean isClosed; - protected StatementProxy(IHikariConnectionProxy connection, Statement statement) + protected StatementProxy(ConnectionProxy connection, Statement statement) { this.connection = connection; this.delegate = statement; @@ -79,7 +79,7 @@ public abstract class StatementProxy implements Statement @Override public boolean execute(String sql) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.execute(sql); } @@ -87,7 +87,7 @@ public abstract class StatementProxy implements Statement @Override public boolean execute(String sql, int autoGeneratedKeys) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.execute(sql, autoGeneratedKeys); } @@ -95,15 +95,16 @@ public abstract class StatementProxy implements Statement @Override public ResultSet executeQuery(String sql) throws SQLException { - connection.setCommitStateDirty(); - return delegate.executeQuery(sql); + connection.markCommitStateDirty(); + ResultSet resultSet = delegate.executeQuery(sql); + return ProxyFactory.getProxyResultSet(connection, resultSet); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeUpdate(sql); } @@ -111,7 +112,7 @@ public abstract class StatementProxy implements Statement @Override public int[] executeBatch() throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeBatch(); } @@ -119,7 +120,7 @@ public abstract class StatementProxy implements Statement @Override public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeUpdate(sql, autoGeneratedKeys); } @@ -127,7 +128,7 @@ public abstract class StatementProxy implements Statement @Override public int executeUpdate(String sql, int[] columnIndexes) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeUpdate(sql, columnIndexes); } @@ -135,7 +136,7 @@ public abstract class StatementProxy implements Statement @Override public int executeUpdate(String sql, String[] columnNames) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeUpdate(sql, columnNames); } @@ -143,7 +144,7 @@ public abstract class StatementProxy implements Statement @Override public boolean execute(String sql, int[] columnIndexes) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.execute(sql, columnIndexes); } @@ -151,7 +152,7 @@ public abstract class StatementProxy implements Statement @Override public boolean execute(String sql, String[] columnNames) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.execute(sql, columnNames); } @@ -159,7 +160,7 @@ public abstract class StatementProxy implements Statement @Override public long[] executeLargeBatch() throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeLargeBatch(); } @@ -167,7 +168,7 @@ public abstract class StatementProxy implements Statement @Override public long executeLargeUpdate(String sql) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeLargeUpdate(sql); } @@ -175,7 +176,7 @@ public abstract class StatementProxy implements Statement @Override public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeLargeUpdate(sql, autoGeneratedKeys); } @@ -183,7 +184,7 @@ public abstract class StatementProxy implements Statement @Override public long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeLargeUpdate(sql, columnIndexes); } @@ -191,7 +192,7 @@ public abstract class StatementProxy implements Statement @Override public long executeLargeUpdate(String sql, String[] columnNames) throws SQLException { - connection.setCommitStateDirty(); + connection.markCommitStateDirty(); return delegate.executeLargeUpdate(sql, columnNames); } diff --git a/hikaricp/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java b/hikaricp/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java index 56c912be..c309db71 100644 --- a/hikaricp/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java +++ b/hikaricp/src/main/java/com/zaxxer/hikari/util/PoolUtilities.java @@ -220,7 +220,7 @@ public final class PoolUtilities connection.isValid(5); // This will throw AbstractMethodError or SQLException in the case of a non-JDBC 41 compliant driver IS_JDBC40 = true; } - catch (AbstractMethodError | SQLFeatureNotSupportedException e) { + catch (NoSuchMethodError | AbstractMethodError | SQLFeatureNotSupportedException e) { IS_JDBC40 = false; } } @@ -244,7 +244,7 @@ public final class PoolUtilities connection.getNetworkTimeout(); // This will throw AbstractMethodError or SQLException in the case of a non-JDBC 41 compliant driver IS_JDBC41 = true; } - catch (AbstractMethodError | SQLFeatureNotSupportedException e) { + catch (NoSuchMethodError | AbstractMethodError | SQLFeatureNotSupportedException e) { IS_JDBC41 = false; } } @@ -265,7 +265,7 @@ public final class PoolUtilities try { statement.setQueryTimeout(timeoutSec); } - catch (AbstractMethodError | SQLFeatureNotSupportedException e) { + catch (NoSuchMethodError | AbstractMethodError | SQLFeatureNotSupportedException e) { queryTimeoutSupported = false; } }