diff --git a/pom.xml b/pom.xml index 2e199e5b..06e8cca1 100644 --- a/pom.xml +++ b/pom.xml @@ -7,6 +7,7 @@ false + 0.31.0 4.1.0 6.0.1 5.2.10.Final @@ -262,6 +263,53 @@ + + + io.fabric8 + docker-maven-plugin + ${docker.maven.plugin.fabric8.version} + + default + true + + + + db + postgres:9 + + + database system is ready to accept connections + + + + DB + yellow + + + + + + + + + + start + pre-integration-test + + build + start + + + + stop + post-integration-test + + stop + + + + + org.jacoco jacoco-maven-plugin @@ -303,6 +351,20 @@ + + org.apache.maven.plugins + maven-failsafe-plugin + 3.0.0-M3 + + + + integration-test + verify + + + + + org.apache.felix maven-bundle-plugin diff --git a/src/main/java/com/zaxxer/hikari/pool/ProxyConnection.java b/src/main/java/com/zaxxer/hikari/pool/ProxyConnection.java index 11983409..db8b12bf 100644 --- a/src/main/java/com/zaxxer/hikari/pool/ProxyConnection.java +++ b/src/main/java/com/zaxxer/hikari/pool/ProxyConnection.java @@ -287,6 +287,7 @@ public abstract class ProxyConnection implements Connection return ProxyFactory.getProxyStatement(this, trackStatement(delegate.createStatement(resultSetType, concurrency, holdability))); } + /** {@inheritDoc} */ @Override public CallableStatement prepareCall(String sql) throws SQLException @@ -355,7 +356,7 @@ public abstract class ProxyConnection implements Connection public DatabaseMetaData getMetaData() throws SQLException { markCommitStateDirty(); - return delegate.getMetaData(); + return ProxyFactory.getProxyDatabaseMetaData(this, delegate.getMetaData()); } /** {@inheritDoc} */ diff --git a/src/main/java/com/zaxxer/hikari/pool/ProxyDatabaseMetaData.java b/src/main/java/com/zaxxer/hikari/pool/ProxyDatabaseMetaData.java new file mode 100644 index 00000000..dd406bb7 --- /dev/null +++ b/src/main/java/com/zaxxer/hikari/pool/ProxyDatabaseMetaData.java @@ -0,0 +1,242 @@ +package com.zaxxer.hikari.pool; + +import java.sql.Connection; +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.SQLException; + +public abstract class ProxyDatabaseMetaData implements DatabaseMetaData +{ + protected final ProxyConnection connection; + + @SuppressWarnings("WeakerAccess") + protected final DatabaseMetaData delegate; + + ProxyDatabaseMetaData(ProxyConnection connection, DatabaseMetaData metaData) + { + this.connection = connection; + this.delegate = metaData; + } + + @SuppressWarnings("unused") + final SQLException checkException(SQLException e) + { + return connection.checkException(e); + } + + /** {@inheritDoc} */ + @Override + public final String toString() + { + final String delegateToString = delegate.toString(); + return this.getClass().getSimpleName() + '@' + System.identityHashCode(this) + " wrapping " + delegateToString; + } + + // ********************************************************************** + // Overridden java.sql.DatabaseMetaData Methods + // ********************************************************************** + + /** {@inheritDoc} */ + @Override + public final Connection getConnection() + { + return connection; + } + + @Override + public ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException { + ResultSet resultSet = delegate.getProcedures(catalog, schemaPattern, procedureNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException { + ResultSet resultSet = delegate.getProcedureColumns(catalog, schemaPattern, procedureNamePattern, columnNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String[] types) throws SQLException { + ResultSet resultSet = delegate.getTables(catalog, schemaPattern, tableNamePattern, types); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getSchemas() throws SQLException { + ResultSet resultSet = delegate.getSchemas(); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getCatalogs() throws SQLException { + ResultSet resultSet = delegate.getCatalogs(); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getTableTypes() throws SQLException { + ResultSet resultSet = delegate.getTableTypes(); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + ResultSet resultSet = delegate.getColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException { + ResultSet resultSet = delegate.getColumnPrivileges(catalog, schema, table, columnNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getTablePrivileges(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + ResultSet resultSet = delegate.getTablePrivileges(catalog, schemaPattern, tableNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException { + ResultSet resultSet = delegate.getBestRowIdentifier(catalog, schema, table, scope, nullable); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getVersionColumns(String catalog, String schema, String table) throws SQLException { + ResultSet resultSet = delegate.getVersionColumns(catalog, schema, table); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getPrimaryKeys(String catalog, String schema, String table) throws SQLException { + ResultSet resultSet = delegate.getPrimaryKeys(catalog, schema, table); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getImportedKeys(String catalog, String schema, String table) throws SQLException { + ResultSet resultSet = delegate.getImportedKeys(catalog, schema, table); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getExportedKeys(String catalog, String schema, String table) throws SQLException { + ResultSet resultSet = delegate.getExportedKeys(catalog, schema, table); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTable, String foreignCatalog, String foreignSchema, String foreignTable) throws SQLException { + ResultSet resultSet = delegate.getCrossReference(parentCatalog, parentSchema, parentTable, foreignCatalog, foreignSchema, foreignTable); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getTypeInfo() throws SQLException { + ResultSet resultSet = delegate.getTypeInfo(); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException { + ResultSet resultSet = delegate.getIndexInfo(catalog, schema, table, unique, approximate); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getUDTs(String catalog, String schemaPattern, String typeNamePattern, int[] types) throws SQLException { + ResultSet resultSet = delegate.getUDTs(catalog, schemaPattern, typeNamePattern, types); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getSuperTypes(String catalog, String schemaPattern, String typeNamePattern) throws SQLException { + ResultSet resultSet = delegate.getSuperTypes(catalog, schemaPattern, typeNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getSuperTables(String catalog, String schemaPattern, String tableNamePattern) throws SQLException { + ResultSet resultSet = delegate.getSuperTables(catalog, schemaPattern, tableNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getAttributes(String catalog, String schemaPattern, String typeNamePattern, String attributeNamePattern) throws SQLException { + ResultSet resultSet = delegate.getAttributes(catalog, schemaPattern, typeNamePattern, attributeNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getSchemas(String catalog, String schemaPattern) throws SQLException { + ResultSet resultSet = delegate.getSchemas(catalog, schemaPattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getClientInfoProperties() throws SQLException { + ResultSet resultSet = delegate.getClientInfoProperties(); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getFunctions(String catalog, String schemaPattern, String functionNamePattern) throws SQLException { + ResultSet resultSet = delegate.getFunctions(catalog, schemaPattern, functionNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getFunctionColumns(String catalog, String schemaPattern, String functionNamePattern, String columnNamePattern) throws SQLException { + ResultSet resultSet = delegate.getFunctionColumns(catalog, schemaPattern, functionNamePattern, columnNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + @Override + public ResultSet getPseudoColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException { + ResultSet resultSet = delegate.getPseudoColumns(catalog, schemaPattern, tableNamePattern, columnNamePattern); + ProxyStatement statement = (ProxyStatement) ProxyFactory.getProxyStatement(connection, resultSet.getStatement()); + return ProxyFactory.getProxyResultSet(connection, statement, resultSet); + } + + /** {@inheritDoc} */ + @Override + @SuppressWarnings("unchecked") + public final T unwrap(Class iface) throws SQLException + { + if (iface.isInstance(delegate)) { + return (T) delegate; + } + else if (delegate != null) { + return delegate.unwrap(iface); + } + + throw new SQLException("Wrapped DatabaseMetaData is not an instance of " + iface); + } +} diff --git a/src/main/java/com/zaxxer/hikari/pool/ProxyFactory.java b/src/main/java/com/zaxxer/hikari/pool/ProxyFactory.java index 4a074da7..467d15f9 100644 --- a/src/main/java/com/zaxxer/hikari/pool/ProxyFactory.java +++ b/src/main/java/com/zaxxer/hikari/pool/ProxyFactory.java @@ -16,11 +16,7 @@ package com.zaxxer.hikari.pool; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.Statement; +import java.sql.*; import com.zaxxer.hikari.util.FastList; @@ -78,4 +74,10 @@ public final class ProxyFactory // Body is replaced (injected) by JavassistProxyFactory throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run."); } + + static DatabaseMetaData getProxyDatabaseMetaData(final ProxyConnection connection, final DatabaseMetaData metaData) + { + // Body is replaced (injected) by JavassistProxyFactory + throw new IllegalStateException("You need to run the CLI build and you need target/classes in your classpath to run."); + } } diff --git a/src/main/java/com/zaxxer/hikari/util/JavassistProxyFactory.java b/src/main/java/com/zaxxer/hikari/util/JavassistProxyFactory.java index 5a09e271..d31abf21 100644 --- a/src/main/java/com/zaxxer/hikari/util/JavassistProxyFactory.java +++ b/src/main/java/com/zaxxer/hikari/util/JavassistProxyFactory.java @@ -18,23 +18,14 @@ package com.zaxxer.hikari.util; import java.io.IOException; import java.lang.reflect.Array; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.Statement; +import java.sql.*; import java.util.ArrayList; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; -import com.zaxxer.hikari.pool.ProxyCallableStatement; -import com.zaxxer.hikari.pool.ProxyConnection; -import com.zaxxer.hikari.pool.ProxyFactory; -import com.zaxxer.hikari.pool.ProxyPreparedStatement; -import com.zaxxer.hikari.pool.ProxyResultSet; -import com.zaxxer.hikari.pool.ProxyStatement; +import com.zaxxer.hikari.pool.*; import javassist.*; import javassist.bytecode.ClassFile; @@ -66,6 +57,7 @@ public final class JavassistProxyFactory generateProxyClass(Connection.class, ProxyConnection.class.getName(), methodBody); generateProxyClass(Statement.class, ProxyStatement.class.getName(), methodBody); generateProxyClass(ResultSet.class, ProxyResultSet.class.getName(), methodBody); + generateProxyClass(DatabaseMetaData.class, ProxyDatabaseMetaData.class.getName(), methodBody); // For these we have to cast the delegate methodBody = "{ try { return ((cast) delegate).method($$); } catch (SQLException e) { throw checkException(e); } }"; @@ -82,24 +74,27 @@ public final class JavassistProxyFactory CtClass proxyCt = classPool.getCtClass("com.zaxxer.hikari.pool.ProxyFactory"); for (CtMethod method : proxyCt.getMethods()) { switch (method.getName()) { - case "getProxyConnection": - method.setBody("{return new " + packageName + ".HikariProxyConnection($$);}"); - break; - case "getProxyStatement": - method.setBody("{return new " + packageName + ".HikariProxyStatement($$);}"); - break; - case "getProxyPreparedStatement": - method.setBody("{return new " + packageName + ".HikariProxyPreparedStatement($$);}"); - break; - case "getProxyCallableStatement": - method.setBody("{return new " + packageName + ".HikariProxyCallableStatement($$);}"); - break; - case "getProxyResultSet": - method.setBody("{return new " + packageName + ".HikariProxyResultSet($$);}"); - break; - default: - // unhandled method - break; + case "getProxyConnection": + method.setBody("{return new " + packageName + ".HikariProxyConnection($$);}"); + break; + case "getProxyStatement": + method.setBody("{return new " + packageName + ".HikariProxyStatement($$);}"); + break; + case "getProxyPreparedStatement": + method.setBody("{return new " + packageName + ".HikariProxyPreparedStatement($$);}"); + break; + case "getProxyCallableStatement": + method.setBody("{return new " + packageName + ".HikariProxyCallableStatement($$);}"); + break; + case "getProxyResultSet": + method.setBody("{return new " + packageName + ".HikariProxyResultSet($$);}"); + break; + case "getProxyDatabaseMetaData": + method.setBody("{return new " + packageName + ".HikariProxyDatabaseMetaData($$);}"); + break; + default: + // unhandled method + break; } }