Fix #177 implement full transaction state tracking

pull/180/head
Brett Wooldridge 10 years ago
parent 28662ee045
commit 22389819d5

@ -20,6 +20,7 @@ import java.sql.CallableStatement;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Savepoint;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Wrapper; import java.sql.Wrapper;
import java.util.HashSet; import java.util.HashSet;
@ -51,6 +52,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
private FastList<Statement> openStatements; private FastList<Statement> openStatements;
private boolean forceClose; private boolean forceClose;
private boolean commitStateDirty;
private boolean isAnythingDirty; private boolean isAnythingDirty;
private boolean isAutoCommitDirty; private boolean isAutoCommitDirty;
private boolean isCatalogDirty; private boolean isCatalogDirty;
@ -92,7 +94,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public PoolBagEntry getPoolBagEntry() public final PoolBagEntry getPoolBagEntry()
{ {
return bagEntry; return bagEntry;
} }
@ -127,6 +129,13 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
} }
} }
/** {@inheritDoc} */
@Override
public final void markCommitStateDirty()
{
commitStateDirty = true;
}
// *********************************************************************** // ***********************************************************************
// Internal methods // Internal methods
// *********************************************************************** // ***********************************************************************
@ -138,7 +147,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
} }
} }
private <T extends Statement> T trackStatement(T statement) private final <T extends Statement> T trackStatement(T statement)
{ {
openStatements.add(statement); openStatements.add(statement);
@ -190,7 +199,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
} }
try { try {
if (!delegate.getAutoCommit()) { if (commitStateDirty && !delegate.getAutoCommit()) {
delegate.rollback(); delegate.rollback();
} }
@ -218,170 +227,122 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final Statement createStatement() throws SQLException public Statement createStatement() throws SQLException
{ {
checkClosed(); Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement());
try { return trackStatement(proxyStatement);
Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement());
return trackStatement(proxyStatement);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final Statement createStatement(int resultSetType, int concurrency) throws SQLException public Statement createStatement(int resultSetType, int concurrency) throws SQLException
{ {
checkClosed(); Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, concurrency));
try { return trackStatement(proxyStatement);
Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, concurrency));
return trackStatement(proxyStatement);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @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(); Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, concurrency, holdability));
try { return trackStatement(proxyStatement);
Statement proxyStatement = ProxyFactory.getProxyStatement(this, delegate.createStatement(resultSetType, concurrency, holdability));
return trackStatement(proxyStatement);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final CallableStatement prepareCall(String sql) throws SQLException public CallableStatement prepareCall(String sql) throws SQLException
{ {
checkClosed(); CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql));
try { return trackStatement(pcs);
CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql));
return trackStatement(pcs);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @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(); CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, concurrency));
try { return trackStatement(pcs);
CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, concurrency));
return trackStatement(pcs);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @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(); CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, concurrency, holdability));
try { return trackStatement(pcs);
CallableStatement pcs = ProxyFactory.getProxyCallableStatement(this, delegate.prepareCall(sql, resultSetType, concurrency, holdability));
return trackStatement(pcs);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final PreparedStatement prepareStatement(String sql) throws SQLException public PreparedStatement prepareStatement(String sql) throws SQLException
{ {
checkClosed(); PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql));
try { return trackStatement(proxyPreparedStatement);
PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql));
return trackStatement(proxyPreparedStatement);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException
{ {
checkClosed(); PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, autoGeneratedKeys));
try { return trackStatement(proxyPreparedStatement);
PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, autoGeneratedKeys));
return trackStatement(proxyPreparedStatement);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @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(); PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, concurrency));
try { return trackStatement(proxyPreparedStatement);
PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, concurrency));
return trackStatement(proxyPreparedStatement);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @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(); PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, concurrency, holdability));
try { return trackStatement(proxyPreparedStatement);
PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, resultSetType, concurrency, holdability));
return trackStatement(proxyPreparedStatement);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException
{ {
checkClosed(); PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnIndexes));
try { return trackStatement(proxyPreparedStatement);
PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnIndexes));
return trackStatement(proxyPreparedStatement);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException
{ {
checkClosed(); PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames));
try { return trackStatement(proxyPreparedStatement);
PreparedStatement proxyPreparedStatement = ProxyFactory.getProxyPreparedStatement(this, delegate.prepareStatement(sql, columnNames)); }
return trackStatement(proxyPreparedStatement);
} /** {@inheritDoc} */
catch (SQLException e) { @Override
throw checkException(e); 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} */ /** {@inheritDoc} */
@ -402,61 +363,38 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final void setAutoCommit(boolean autoCommit) throws SQLException public void setAutoCommit(boolean autoCommit) throws SQLException
{ {
checkClosed(); delegate.setAutoCommit(autoCommit);
try { isAnythingDirty = true;
delegate.setAutoCommit(autoCommit); isAutoCommitDirty = (autoCommit != parentPool.isAutoCommit);
isAnythingDirty = true;
isAutoCommitDirty = (autoCommit != parentPool.isAutoCommit);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final void setReadOnly(boolean readOnly) throws SQLException public void setReadOnly(boolean readOnly) throws SQLException
{ {
checkClosed(); delegate.setReadOnly(readOnly);
try { isAnythingDirty = true;
delegate.setReadOnly(readOnly); isReadOnlyDirty = (readOnly != parentPool.isReadOnly);
isAnythingDirty = true;
isReadOnlyDirty = (readOnly != parentPool.isReadOnly);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final void setTransactionIsolation(int level) throws SQLException public void setTransactionIsolation(int level) throws SQLException
{ {
checkClosed(); delegate.setTransactionIsolation(level);
try { isAnythingDirty = true;
delegate.setTransactionIsolation(level); isTransactionIsolationDirty = (level != parentPool.transactionIsolation);
isAnythingDirty = true;
isTransactionIsolationDirty = (level != parentPool.transactionIsolation);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */
@Override @Override
public final void setCatalog(String catalog) throws SQLException public void setCatalog(String catalog) throws SQLException
{ {
checkClosed(); delegate.setCatalog(catalog);
try { isAnythingDirty = true;
delegate.setCatalog(catalog); isCatalogDirty = (catalog != null && !catalog.equals(parentPool.catalog)) || (catalog == null && parentPool.catalog != null);
isAnythingDirty = true;
isCatalogDirty = (catalog != null && !catalog.equals(parentPool.catalog)) || (catalog == null && parentPool.catalog != null);
}
catch (SQLException e) {
throw checkException(e);
}
} }
/** {@inheritDoc} */ /** {@inheritDoc} */

@ -53,4 +53,9 @@ public interface IHikariConnectionProxy extends Connection
* @param statement the Statement to remove from tracking * @param statement the Statement to remove from tracking
*/ */
void untrackStatement(Statement statement); void untrackStatement(Statement statement);
/**
* Sets the commit state of the connection to dirty.
*/
void markCommitStateDirty();
} }

@ -19,6 +19,7 @@ package com.zaxxer.hikari.proxy;
import java.sql.CallableStatement; import java.sql.CallableStatement;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement; import java.sql.Statement;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -83,6 +84,7 @@ public final class JavassistProxyFactory
// Cast is not needed for these // Cast is not needed for these
methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { throw checkException(e); } }"; methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { throw checkException(e); } }";
generateProxyClass(Statement.class, StatementProxy.class, methodBody); generateProxyClass(Statement.class, StatementProxy.class, methodBody);
generateProxyClass(ResultSet.class, ResultSetProxy.class, methodBody);
// For these we have to cast the delegate // For these we have to cast the delegate
methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { throw checkException(e); } }"; 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)) { else if ("getProxyCallableStatement".equals(methodName)) {
method.setBody("{return new " + packageName + ".CallableStatementJavassistProxy($$);}"); method.setBody("{return new " + packageName + ".CallableStatementJavassistProxy($$);}");
} }
else if ("getProxyResultSet".equals(methodName)) {
method.setBody("{return new " + packageName + ".ResultSetJavassistProxy($$);}");
}
} }
proxyCt.toClass(classPool.getClassLoader(), getClass().getProtectionDomain()); 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 // Make a set of method signatures we inherit implementation for, so we don't generate delegates for these
Set<String> superSigs = new HashSet<String>(); Set<String> superSigs = new HashSet<String>();
for (CtMethod method : superClassCt.getMethods()) { 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()); superSigs.add(method.getName() + method.getSignature());
} }
} }
methodBody = methodBody.replace("cast", primaryInterface.getName());
Set<String> methods = new HashSet<String>(); Set<String> methods = new HashSet<String>();
Set<Class<?>> interfaces = ClassLoaderUtils.getAllInterfaces(primaryInterface); Set<Class<?>> interfaces = ClassLoaderUtils.getAllInterfaces(primaryInterface);
for (Class<?> intf : interfaces) { for (Class<?> intf : interfaces) {
@ -159,10 +162,21 @@ public final class JavassistProxyFactory
// Clone the method we want to inject into // Clone the method we want to inject into
CtMethod method = CtNewMethod.copy(intfMethod, targetCt, null); 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 // Generate a method that simply invokes the same method on the delegate
String modifiedBody;
if (isThrowsSqlException(intfMethod)) { if (isThrowsSqlException(intfMethod)) {
modifiedBody = methodBody.replace("method", method.getName()); modifiedBody = modifiedBody.replace("method", method.getName());
} }
else { else {
modifiedBody = "{ return ((cast) delegate).method($$); }".replace("method", method.getName()).replace("cast", primaryInterface.getName()); modifiedBody = "{ return ((cast) delegate).method($$); }".replace("method", method.getName()).replace("cast", primaryInterface.getName());

@ -17,6 +17,8 @@
package com.zaxxer.hikari.proxy; package com.zaxxer.hikari.proxy;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/** /**
* This is the proxy class for java.sql.PreparedStatement. * 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 // 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();
}
} }

@ -19,6 +19,7 @@ package com.zaxxer.hikari.proxy;
import java.sql.CallableStatement; import java.sql.CallableStatement;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement; import java.sql.Statement;
import com.zaxxer.hikari.pool.HikariPool; import com.zaxxer.hikari.pool.HikariPool;
@ -69,4 +70,10 @@ public final class ProxyFactory
// Body is injected by JavassistProxyFactory // Body is injected by JavassistProxyFactory
return null; return null;
} }
static ResultSet getProxyResultSet(final ConnectionProxy connection, final ResultSet resultSet)
{
// Body is injected by JavassistProxyFactory
return null;
}
} }

@ -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> T unwrap(Class<T> 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);
}
}

@ -17,6 +17,7 @@
package com.zaxxer.hikari.proxy; package com.zaxxer.hikari.proxy;
import java.sql.Connection; import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.sql.Statement;
import java.sql.Wrapper; import java.sql.Wrapper;
@ -28,12 +29,12 @@ import java.sql.Wrapper;
*/ */
public abstract class StatementProxy implements Statement public abstract class StatementProxy implements Statement
{ {
protected final IHikariConnectionProxy connection; protected final ConnectionProxy connection;
protected final Statement delegate; protected final Statement delegate;
private boolean isClosed; private boolean isClosed;
protected StatementProxy(IHikariConnectionProxy connection, Statement statement) protected StatementProxy(ConnectionProxy connection, Statement statement)
{ {
this.connection = connection; this.connection = connection;
this.delegate = statement; this.delegate = statement;
@ -69,11 +70,133 @@ public abstract class StatementProxy implements Statement
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final Connection getConnection() throws SQLException public Connection getConnection() throws SQLException
{ {
return connection; 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 @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public final <T> T unwrap(Class<T> iface) throws SQLException public final <T> T unwrap(Class<T> iface) throws SQLException

@ -244,6 +244,9 @@ public final class PoolUtilities
catch (AbstractMethodError e) { catch (AbstractMethodError e) {
IS_JDBC40 = false; IS_JDBC40 = false;
} }
catch (NoSuchMethodError e) {
IS_JDBC40 = false;
}
} }
return IS_JDBC40; 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 connection.getNetworkTimeout(); // This will throw AbstractMethodError or SQLException in the case of a non-JDBC 41 compliant driver
IS_JDBC41 = true; IS_JDBC41 = true;
} }
catch (SQLFeatureNotSupportedException e) {
IS_JDBC41 = false;
}
catch (AbstractMethodError e) { catch (AbstractMethodError e) {
IS_JDBC41 = false; IS_JDBC41 = false;
} }
catch (SQLFeatureNotSupportedException e) { catch (NoSuchMethodError e) {
IS_JDBC41 = false; IS_JDBC41 = false;
} }
} }
@ -289,10 +295,13 @@ public final class PoolUtilities
try { try {
statement.setQueryTimeout(timeoutSec); statement.setQueryTimeout(timeoutSec);
} }
catch (SQLFeatureNotSupportedException e) {
queryTimeoutSupported = false;
}
catch (AbstractMethodError e) { catch (AbstractMethodError e) {
queryTimeoutSupported = false; queryTimeoutSupported = false;
} }
catch (SQLFeatureNotSupportedException e) { catch (NoSuchMethodError e) {
queryTimeoutSupported = false; queryTimeoutSupported = false;
} }
} }

@ -131,7 +131,7 @@ public abstract class ConnectionProxy implements IHikariConnectionProxy
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public final void setCommitStateDirty() public final void markCommitStateDirty()
{ {
commitStateDirty = true; commitStateDirty = true;
} }

@ -57,5 +57,5 @@ public interface IHikariConnectionProxy extends Connection
/** /**
* Sets the commit state of the connection to dirty. * Sets the commit state of the connection to dirty.
*/ */
void setCommitStateDirty(); void markCommitStateDirty();
} }

@ -19,6 +19,7 @@ package com.zaxxer.hikari.proxy;
import java.sql.CallableStatement; import java.sql.CallableStatement;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement; import java.sql.Statement;
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;
@ -83,6 +84,7 @@ public final class JavassistProxyFactory
// Cast is not needed for these // Cast is not needed for these
methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { throw checkException(e); } }"; methodBody = "{ try { return delegate.method($$); } catch (SQLException e) { throw checkException(e); } }";
generateProxyClass(Statement.class, StatementProxy.class, methodBody); generateProxyClass(Statement.class, StatementProxy.class, methodBody);
generateProxyClass(ResultSet.class, ResultSetProxy.class, methodBody);
// For these we have to cast the delegate // For these we have to cast the delegate
methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { throw checkException(e); } }"; methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { throw checkException(e); } }";
@ -108,6 +110,9 @@ public final class JavassistProxyFactory
case "getProxyCallableStatement": case "getProxyCallableStatement":
method.setBody("{return new " + packageName + ".CallableStatementJavassistProxy($$);}"); method.setBody("{return new " + packageName + ".CallableStatementJavassistProxy($$);}");
break; break;
case "getProxyResultSet":
method.setBody("{return new " + packageName + ".ResultSetJavassistProxy($$);}");
break;
} }
} }
@ -160,6 +165,7 @@ public final class JavassistProxyFactory
String modifiedBody = methodBody; 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()); CtMethod superMethod = superClassCt.getMethod(intfMethod.getName(), intfMethod.getSignature());
if ((superMethod.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT) { if ((superMethod.getModifiers() & Modifier.ABSTRACT) != Modifier.ABSTRACT) {
modifiedBody = modifiedBody.replace("((cast) ", ""); modifiedBody = modifiedBody.replace("((cast) ", "");

@ -40,7 +40,7 @@ public abstract class PreparedStatementProxy extends StatementProxy implements P
@Override @Override
public boolean execute() throws SQLException public boolean execute() throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return ((PreparedStatement) delegate).execute(); return ((PreparedStatement) delegate).execute();
} }
@ -48,15 +48,16 @@ public abstract class PreparedStatementProxy extends StatementProxy implements P
@Override @Override
public ResultSet executeQuery() throws SQLException public ResultSet executeQuery() throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return ((PreparedStatement) delegate).executeQuery(); ResultSet resultSet = ((PreparedStatement) delegate).executeQuery();
return ProxyFactory.getProxyResultSet(connection, resultSet);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public int executeUpdate() throws SQLException public int executeUpdate() throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return ((PreparedStatement) delegate).executeUpdate(); return ((PreparedStatement) delegate).executeUpdate();
} }
@ -64,7 +65,7 @@ public abstract class PreparedStatementProxy extends StatementProxy implements P
@Override @Override
public long executeLargeUpdate() throws SQLException public long executeLargeUpdate() throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return ((PreparedStatement) delegate).executeLargeUpdate(); return ((PreparedStatement) delegate).executeLargeUpdate();
} }
} }

@ -19,6 +19,7 @@ package com.zaxxer.hikari.proxy;
import java.sql.CallableStatement; import java.sql.CallableStatement;
import java.sql.Connection; import java.sql.Connection;
import java.sql.PreparedStatement; import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement; import java.sql.Statement;
import com.zaxxer.hikari.pool.HikariPool; import com.zaxxer.hikari.pool.HikariPool;
@ -69,4 +70,10 @@ public final class ProxyFactory
// Body is injected by JavassistProxyFactory // Body is injected by JavassistProxyFactory
return null; return null;
} }
static ResultSet getProxyResultSet(final ConnectionProxy connection, final ResultSet resultSet)
{
// Body is injected by JavassistProxyFactory
return null;
}
} }

@ -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> T unwrap(Class<T> 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);
}
}

@ -29,12 +29,12 @@ import java.sql.Wrapper;
*/ */
public abstract class StatementProxy implements Statement public abstract class StatementProxy implements Statement
{ {
protected final IHikariConnectionProxy connection; protected final ConnectionProxy connection;
protected final Statement delegate; protected final Statement delegate;
private boolean isClosed; private boolean isClosed;
protected StatementProxy(IHikariConnectionProxy connection, Statement statement) protected StatementProxy(ConnectionProxy connection, Statement statement)
{ {
this.connection = connection; this.connection = connection;
this.delegate = statement; this.delegate = statement;
@ -79,7 +79,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public boolean execute(String sql) throws SQLException public boolean execute(String sql) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.execute(sql); return delegate.execute(sql);
} }
@ -87,7 +87,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public boolean execute(String sql, int autoGeneratedKeys) throws SQLException public boolean execute(String sql, int autoGeneratedKeys) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.execute(sql, autoGeneratedKeys); return delegate.execute(sql, autoGeneratedKeys);
} }
@ -95,15 +95,16 @@ public abstract class StatementProxy implements Statement
@Override @Override
public ResultSet executeQuery(String sql) throws SQLException public ResultSet executeQuery(String sql) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeQuery(sql); ResultSet resultSet = delegate.executeQuery(sql);
return ProxyFactory.getProxyResultSet(connection, resultSet);
} }
/** {@inheritDoc} */ /** {@inheritDoc} */
@Override @Override
public int executeUpdate(String sql) throws SQLException public int executeUpdate(String sql) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeUpdate(sql); return delegate.executeUpdate(sql);
} }
@ -111,7 +112,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public int[] executeBatch() throws SQLException public int[] executeBatch() throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeBatch(); return delegate.executeBatch();
} }
@ -119,7 +120,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException public int executeUpdate(String sql, int autoGeneratedKeys) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeUpdate(sql, autoGeneratedKeys); return delegate.executeUpdate(sql, autoGeneratedKeys);
} }
@ -127,7 +128,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public int executeUpdate(String sql, int[] columnIndexes) throws SQLException public int executeUpdate(String sql, int[] columnIndexes) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeUpdate(sql, columnIndexes); return delegate.executeUpdate(sql, columnIndexes);
} }
@ -135,7 +136,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public int executeUpdate(String sql, String[] columnNames) throws SQLException public int executeUpdate(String sql, String[] columnNames) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeUpdate(sql, columnNames); return delegate.executeUpdate(sql, columnNames);
} }
@ -143,7 +144,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public boolean execute(String sql, int[] columnIndexes) throws SQLException public boolean execute(String sql, int[] columnIndexes) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.execute(sql, columnIndexes); return delegate.execute(sql, columnIndexes);
} }
@ -151,7 +152,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public boolean execute(String sql, String[] columnNames) throws SQLException public boolean execute(String sql, String[] columnNames) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.execute(sql, columnNames); return delegate.execute(sql, columnNames);
} }
@ -159,7 +160,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public long[] executeLargeBatch() throws SQLException public long[] executeLargeBatch() throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeLargeBatch(); return delegate.executeLargeBatch();
} }
@ -167,7 +168,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public long executeLargeUpdate(String sql) throws SQLException public long executeLargeUpdate(String sql) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeLargeUpdate(sql); return delegate.executeLargeUpdate(sql);
} }
@ -175,7 +176,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException public long executeLargeUpdate(String sql, int autoGeneratedKeys) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeLargeUpdate(sql, autoGeneratedKeys); return delegate.executeLargeUpdate(sql, autoGeneratedKeys);
} }
@ -183,7 +184,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException public long executeLargeUpdate(String sql, int[] columnIndexes) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeLargeUpdate(sql, columnIndexes); return delegate.executeLargeUpdate(sql, columnIndexes);
} }
@ -191,7 +192,7 @@ public abstract class StatementProxy implements Statement
@Override @Override
public long executeLargeUpdate(String sql, String[] columnNames) throws SQLException public long executeLargeUpdate(String sql, String[] columnNames) throws SQLException
{ {
connection.setCommitStateDirty(); connection.markCommitStateDirty();
return delegate.executeLargeUpdate(sql, columnNames); return delegate.executeLargeUpdate(sql, columnNames);
} }

@ -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 connection.isValid(5); // This will throw AbstractMethodError or SQLException in the case of a non-JDBC 41 compliant driver
IS_JDBC40 = true; IS_JDBC40 = true;
} }
catch (AbstractMethodError | SQLFeatureNotSupportedException e) { catch (NoSuchMethodError | AbstractMethodError | SQLFeatureNotSupportedException e) {
IS_JDBC40 = false; 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 connection.getNetworkTimeout(); // This will throw AbstractMethodError or SQLException in the case of a non-JDBC 41 compliant driver
IS_JDBC41 = true; IS_JDBC41 = true;
} }
catch (AbstractMethodError | SQLFeatureNotSupportedException e) { catch (NoSuchMethodError | AbstractMethodError | SQLFeatureNotSupportedException e) {
IS_JDBC41 = false; IS_JDBC41 = false;
} }
} }
@ -265,7 +265,7 @@ public final class PoolUtilities
try { try {
statement.setQueryTimeout(timeoutSec); statement.setQueryTimeout(timeoutSec);
} }
catch (AbstractMethodError | SQLFeatureNotSupportedException e) { catch (NoSuchMethodError | AbstractMethodError | SQLFeatureNotSupportedException e) {
queryTimeoutSupported = false; queryTimeoutSupported = false;
} }
} }

Loading…
Cancel
Save