diff --git a/src/main/java/com/alibaba/druid/mock/MockConnection.java b/src/main/java/com/alibaba/druid/mock/MockConnection.java index 348cfabf43..2c8b775162 100644 --- a/src/main/java/com/alibaba/druid/mock/MockConnection.java +++ b/src/main/java/com/alibaba/druid/mock/MockConnection.java @@ -35,24 +35,24 @@ import java.util.Properties; public class MockConnection implements Connection { - // private final static Log LOG = LogFactory.getLog(MockConnection.class); + // private final static Log LOG = LogFactory.getLog(MockConnection.class); - private boolean autoCommit = false; - private boolean closed = false; - private boolean readOnly = false; - private String catalog = null; - private int transactionIsolation; - private SQLWarning warning; - private int holdability; + private boolean autoCommit = false; + private boolean closed = false; + private boolean readOnly = false; + private String catalog = null; + private int transactionIsolation; + private SQLWarning warning; + private int holdability; - private MockDriver driver; + private MockDriver driver; - private Properties connectProperties; + private Properties connectProperties; - private long id; + private long id; - private final long createdTimeMillis = System.currentTimeMillis(); - private long lastActiveTimeMillis = System.currentTimeMillis(); + private final long createdTimeMillis = System.currentTimeMillis(); + private long lastActiveTimeMillis = System.currentTimeMillis(); public MockConnection(){ this(null); @@ -116,21 +116,37 @@ public class MockConnection implements Connection { @Override public Statement createStatement() throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockStatement(this); } @Override public PreparedStatement prepareStatement(String sql) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockPreparedStatement(this, sql); } @Override public CallableStatement prepareCall(String sql) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockCallableStatement(this, sql); } @Override public String nativeSQL(String sql) throws SQLException { + if (closed) { + throw new SQLException(); + } + return sql; } @@ -216,17 +232,29 @@ public class MockConnection implements Connection { @Override public Statement createStatement(int resultSetType, int resultSetConcurrency) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockStatement(this); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockPreparedStatement(this, sql); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockCallableStatement(this, sql); } @@ -273,33 +301,57 @@ public class MockConnection implements Connection { @Override public Statement createStatement(int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockStatement(this); } @Override public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockPreparedStatement(this, sql); } @Override public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency, int resultSetHoldability) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockCallableStatement(this, sql); } @Override public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockPreparedStatement(this, sql); } @Override public PreparedStatement prepareStatement(String sql, int[] columnIndexes) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockPreparedStatement(this, sql); } @Override public PreparedStatement prepareStatement(String sql, String[] columnNames) throws SQLException { + if (closed) { + throw new SQLException(); + } + return new MockPreparedStatement(this, sql); } diff --git a/src/main/java/com/alibaba/druid/pool/PoolableConnection.java b/src/main/java/com/alibaba/druid/pool/PoolableConnection.java index 76fbaa9191..1ecf3ae69c 100644 --- a/src/main/java/com/alibaba/druid/pool/PoolableConnection.java +++ b/src/main/java/com/alibaba/druid/pool/PoolableConnection.java @@ -510,11 +510,11 @@ public class PoolableConnection implements PooledConnection, Connection { @SuppressWarnings("unchecked") @Override public T unwrap(Class iface) throws SQLException { - if (conn == null) { + if (iface == null) { return null; } - if (iface == PoolableConnection.class) { + if (iface.isInstance(this)) { return (T) this; } @@ -523,7 +523,11 @@ public class PoolableConnection implements PooledConnection, Connection { @Override public boolean isWrapperFor(Class iface) throws SQLException { - if (iface == PoolableConnection.class) { + if (iface == null) { + return false; + } + + if (iface.isInstance(this)) { return true; } diff --git a/src/test/java/com/alibaba/druid/bvt/pool/basic/ConnectionTest4.java b/src/test/java/com/alibaba/druid/bvt/pool/basic/ConnectionTest4.java new file mode 100644 index 0000000000..279ea5b4fc --- /dev/null +++ b/src/test/java/com/alibaba/druid/bvt/pool/basic/ConnectionTest4.java @@ -0,0 +1,121 @@ +package com.alibaba.druid.bvt.pool.basic; + +import java.sql.Connection; +import java.sql.Date; +import java.sql.ResultSet; +import java.sql.SQLException; + +import junit.framework.Assert; +import junit.framework.TestCase; + +import com.alibaba.druid.mock.MockDriver; +import com.alibaba.druid.pool.DruidDataSource; +import com.alibaba.druid.pool.PoolableConnection; +import com.alibaba.druid.stat.DruidDataSourceStatManager; +import com.alibaba.druid.stat.JdbcStatContext; +import com.alibaba.druid.stat.JdbcStatManager; + +public class ConnectionTest4 extends TestCase { + + private MockDriver driver; + private DruidDataSource dataSource; + + protected void setUp() throws Exception { + Assert.assertEquals(0, DruidDataSourceStatManager.getInstance().getDataSourceList().size()); + + driver = new MockDriver(); + + dataSource = new DruidDataSource(); + dataSource.setUrl("jdbc:mock:xxx"); + dataSource.setDriver(driver); + dataSource.setInitialSize(1); + dataSource.setMaxActive(2); + dataSource.setMaxIdle(2); + dataSource.setMinIdle(1); + dataSource.setMinEvictableIdleTimeMillis(300 * 1000); // 300 / 10 + dataSource.setTimeBetweenEvictionRunsMillis(180 * 1000); // 180 / 10 + dataSource.setTestWhileIdle(true); + dataSource.setTestOnBorrow(false); + dataSource.setValidationQuery("SELECT 1"); + dataSource.setFilters("stat,trace"); + dataSource.setPoolPreparedStatements(true); + + JdbcStatContext context = new JdbcStatContext(); + context.setTraceEnable(true); + JdbcStatManager.getInstance().setStatContext(context); + } + + protected void tearDown() throws Exception { + dataSource.close(); + Assert.assertEquals(0, DruidDataSourceStatManager.getInstance().getDataSourceList().size()); + + JdbcStatManager.getInstance().setStatContext(null); + } + + public void test_basic() throws Exception { + PoolableConnection conn = dataSource.getConnection().unwrap(PoolableConnection.class); + + Assert.assertEquals(null, conn.unwrap(Date.class)); + Assert.assertEquals(conn, conn.unwrap(Connection.class)); + + Assert.assertEquals(true, conn.isWrapperFor(PoolableConnection.class)); + Assert.assertEquals(true, conn.isWrapperFor(Connection.class)); + + conn.close(); + } + + public void test_prepareStatement_error() throws Exception { + PoolableConnection conn = dataSource.getConnection().unwrap(PoolableConnection.class); + + conn.getConnection().close(); + + { + SQLException error = null; + try { + conn.prepareStatement("SELECT 1"); + } catch (SQLException ex) { + error = ex; + } + Assert.assertNotNull(error); + } + + conn.close(); + } + + public void test_prepareStatement_error2() throws Exception { + PoolableConnection conn = dataSource.getConnection().unwrap(PoolableConnection.class); + + conn.getConnection().close(); + + { + SQLException error = null; + try { + conn.prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); + } catch (SQLException ex) { + error = ex; + } + Assert.assertNotNull(error); + } + + conn.close(); + } + + public void test_prepareStatement_error3() throws Exception { + PoolableConnection conn = dataSource.getConnection().unwrap(PoolableConnection.class); + + conn.getConnection().close(); + + { + SQLException error = null; + try { + conn.prepareStatement("SELECT 1", ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY, + ResultSet.HOLD_CURSORS_OVER_COMMIT); + } catch (SQLException ex) { + error = ex; + } + Assert.assertNotNull(error); + } + + conn.close(); + } +}