Skip to content

Commit 94f9f71

Browse files
committed
Resetting Schema and Catalog, when connection returend to pool
When a connection is taken from the pool and schema and/or catalog will be changed, the schema/catalog is not reset. So the next one will get a connection, that is not in the expected schema/catalog
1 parent 23508d4 commit 94f9f71

File tree

3 files changed

+129
-10
lines changed

3 files changed

+129
-10
lines changed

ebean-datasource/src/main/java/io/ebean/datasource/pool/ConnectionDelegator.java

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
abstract class ConnectionDelegator implements Connection {
88

99
private final Connection delegate;
10-
protected String currentSchema;
1110

1211
ConnectionDelegator(Connection delegate) {
1312
this.delegate = delegate;
@@ -20,12 +19,6 @@ Connection delegate() {
2019
return delegate;
2120
}
2221

23-
@Override
24-
public final void setSchema(String schema) throws SQLException {
25-
delegate.setSchema(schema);
26-
currentSchema = schema;
27-
}
28-
2922
@Override
3023
public final String getSchema() throws SQLException {
3124
return delegate.getSchema();

ebean-datasource/src/main/java/io/ebean/datasource/pool/PooledConnection.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,13 @@ final class PooledConnection extends ConnectionDelegator {
8282
*/
8383
private boolean failoverToReadOnly;
8484
private boolean resetAutoCommit;
85+
private boolean resetSchema;
86+
private boolean resetCatalog;
87+
private String currentSchema;
88+
private String currentCatalog;
89+
private final String originalSchema;
90+
private final String originalCatalog;
91+
8592
private long startUseTime;
8693
private long lastUseTime;
8794
/**
@@ -106,7 +113,7 @@ final class PooledConnection extends ConnectionDelegator {
106113
* close() will return the connection back to the pool , while
107114
* closeDestroy() will close() the underlining connection properly.
108115
*/
109-
PooledConnection(ConnectionPool pool, int uniqueId, Connection connection) {
116+
PooledConnection(ConnectionPool pool, int uniqueId, Connection connection) throws SQLException {
110117
super(connection);
111118
this.pool = pool;
112119
this.connection = connection;
@@ -115,6 +122,8 @@ final class PooledConnection extends ConnectionDelegator {
115122
this.maxStackTrace = pool.maxStackTraceSize();
116123
this.creationTime = System.currentTimeMillis();
117124
this.lastUseTime = creationTime;
125+
this.currentSchema = this.originalSchema = connection.getSchema();
126+
this.currentCatalog = this.originalCatalog = connection.getCatalog();
118127
pool.inc();
119128
}
120129

@@ -130,6 +139,8 @@ final class PooledConnection extends ConnectionDelegator {
130139
this.maxStackTrace = 0;
131140
this.creationTime = System.currentTimeMillis();
132141
this.lastUseTime = creationTime;
142+
this.currentSchema = this.originalSchema = "DEFAULT";
143+
this.currentCatalog = this.originalCatalog = "DEFAULT";
133144
}
134145

135146
/**
@@ -272,7 +283,7 @@ void returnPreparedStatement(ExtendedPreparedStatement pstmt) {
272283
*/
273284
@Override
274285
public PreparedStatement prepareStatement(String sql, int returnKeysFlag) throws SQLException {
275-
String key = sql + ':' + currentSchema + ':' + returnKeysFlag;
286+
String key = sql + ':' + currentSchema + ':' + currentCatalog + ':' + returnKeysFlag;
276287
return prepareStatement(sql, true, returnKeysFlag, key);
277288
}
278289

@@ -281,7 +292,7 @@ public PreparedStatement prepareStatement(String sql, int returnKeysFlag) throws
281292
*/
282293
@Override
283294
public PreparedStatement prepareStatement(String sql) throws SQLException {
284-
String key = sql + ':' + currentSchema;
295+
String key = sql + ':' + currentSchema + ':' + currentCatalog;
285296
return prepareStatement(sql, false, 0, key);
286297
}
287298

@@ -411,6 +422,16 @@ public void close() throws SQLException {
411422
resetIsolationReadOnlyRequired = false;
412423
}
413424

425+
if (resetSchema) {
426+
connection.setSchema(originalSchema);
427+
resetSchema = false;
428+
}
429+
430+
if (resetCatalog) {
431+
connection.setCatalog(originalCatalog);
432+
resetCatalog = false;
433+
}
434+
414435
// the connection is assumed GOOD so put it back in the pool
415436
lastUseTime = System.currentTimeMillis();
416437
connection.clearWarnings();
@@ -511,6 +532,7 @@ public void setReadOnly(boolean readOnly) throws SQLException {
511532
connection.setReadOnly(readOnly);
512533
}
513534

535+
514536
/**
515537
* Also note the Isolation level needs to be reset when put back into the pool.
516538
*/
@@ -673,11 +695,23 @@ public void setAutoCommit(boolean autoCommit) throws SQLException {
673695
}
674696
}
675697

698+
@Override
699+
public void setSchema(String schema) throws SQLException {
700+
if (status == STATUS_IDLE) {
701+
throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setSchema()");
702+
}
703+
currentSchema = schema;
704+
resetSchema = true;
705+
connection.setSchema(schema);
706+
}
707+
676708
@Override
677709
public void setCatalog(String catalog) throws SQLException {
678710
if (status == STATUS_IDLE) {
679711
throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setCatalog()");
680712
}
713+
currentCatalog = catalog;
714+
resetCatalog = true;
681715
connection.setCatalog(catalog);
682716
}
683717

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
package io.ebean.datasource.pool;
2+
3+
import io.ebean.datasource.DataSourceConfig;
4+
import org.junit.jupiter.api.AfterEach;
5+
import org.junit.jupiter.api.BeforeEach;
6+
import org.junit.jupiter.api.Test;
7+
8+
import java.sql.Connection;
9+
import java.sql.ResultSet;
10+
import java.sql.SQLException;
11+
import java.sql.Statement;
12+
13+
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
14+
15+
class SchemaTest {
16+
17+
private final ConnectionPool pool;
18+
19+
SchemaTest() {
20+
pool = createPool();
21+
}
22+
23+
private ConnectionPool createPool() {
24+
DataSourceConfig config = new DataSourceConfig();
25+
config.setUrl("jdbc:h2:mem:tests");
26+
config.setUsername("sa");
27+
config.setPassword("");
28+
config.setMinConnections(2);
29+
config.setMaxConnections(4);
30+
31+
return new ConnectionPool("test", config);
32+
}
33+
34+
@BeforeEach
35+
void initTables() throws SQLException {
36+
try (Connection conn = pool.getConnection()) {
37+
Statement statement = conn.createStatement();
38+
statement.execute("CREATE TABLE test (name VARCHAR(255))");
39+
statement.execute("INSERT INTO test (name) VALUES ('default schema')");
40+
statement.execute("CREATE SCHEMA SCHEMA1");
41+
statement.execute("CREATE SCHEMA SCHEMA2");
42+
conn.commit();
43+
}
44+
try (Connection conn = pool.getConnection()) {
45+
String orig = conn.getSchema();
46+
conn.setSchema("SCHEMA1");
47+
Statement statement = conn.createStatement();
48+
statement.execute("CREATE TABLE test (name VARCHAR(255))");
49+
statement.execute("INSERT INTO test (name) VALUES ('schema1')");
50+
conn.setSchema("SCHEMA2");
51+
statement.execute("CREATE TABLE test (name VARCHAR(255))");
52+
statement.execute("INSERT INTO test (name) VALUES ('schema2')");
53+
conn.setSchema(orig);
54+
conn.commit();
55+
}
56+
}
57+
58+
@AfterEach
59+
void after() {
60+
pool.shutdown();
61+
}
62+
63+
@Test
64+
void getConnectionWithSchemaSwitch() throws SQLException {
65+
try (Connection conn = pool.getConnection()) {
66+
Statement statement = conn.createStatement();
67+
ResultSet rs = statement.executeQuery("SELECT name FROM test");
68+
assertThat(rs.next()).isTrue();
69+
assertThat(rs.getString("name")).isEqualTo("default schema");
70+
}
71+
try (Connection conn = pool.getConnection()) {
72+
conn.setSchema("SCHEMA1");
73+
Statement statement = conn.createStatement();
74+
ResultSet rs = statement.executeQuery("SELECT name FROM test");
75+
assertThat(rs.next()).isTrue();
76+
assertThat(rs.getString("name")).isEqualTo("schema1");
77+
}
78+
try (Connection conn = pool.getConnection()) {
79+
conn.setSchema("SCHEMA2");
80+
Statement statement = conn.createStatement();
81+
ResultSet rs = statement.executeQuery("SELECT name FROM test");
82+
assertThat(rs.next()).isTrue();
83+
assertThat(rs.getString("name")).isEqualTo("schema2");
84+
}
85+
try (Connection conn = pool.getConnection()) {
86+
Statement statement = conn.createStatement();
87+
ResultSet rs = statement.executeQuery("SELECT name FROM test");
88+
assertThat(rs.next()).isTrue();
89+
assertThat(rs.getString("name")).isEqualTo("default schema");
90+
}
91+
}
92+
}

0 commit comments

Comments
 (0)