Skip to content

Commit 825b0bc

Browse files
authored
Merge pull request #105 from ebean-orm/feature/change-schema-reset
Use pool schema/catalog for original values, lazy initialise originalSchema if required
2 parents 5e21cbf + a8d736f commit 825b0bc

File tree

9 files changed

+118
-24
lines changed

9 files changed

+118
-24
lines changed

ebean-datasource-api/src/main/java/io/ebean/datasource/DataSourceBuilder.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,6 +249,11 @@ default DataSourceBuilder schema(String schema) {
249249
return setSchema(schema);
250250
}
251251

252+
/**
253+
* Set the default database catalog to use.
254+
*/
255+
DataSourceBuilder catalog(String catalog);
256+
252257
/**
253258
* @deprecated - migrate to {@link #driver(String)}.
254259
*/
@@ -812,6 +817,11 @@ interface Settings extends DataSourceBuilder {
812817
*/
813818
String getSchema();
814819

820+
/**
821+
* Return the database catalog.
822+
*/
823+
String catalog();
824+
815825
/**
816826
* Return the driver instance to use.
817827
*/

ebean-datasource-api/src/main/java/io/ebean/datasource/DataSourceConfig.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ public class DataSourceConfig implements DataSourceBuilder.Settings {
3636
private String password;
3737
private String password2;
3838
private String schema;
39+
private String catalog;
3940
private Driver driver;
4041
private Class<? extends Driver> driverClass;
4142
private String driverClassName;
@@ -103,6 +104,7 @@ public DataSourceConfig copy() {
103104
copy.password = password;
104105
copy.password2 = password2;
105106
copy.schema = schema;
107+
copy.catalog = catalog;
106108
copy.platform = platform;
107109
copy.ownerUsername = ownerUsername;
108110
copy.ownerPassword = ownerPassword;
@@ -171,6 +173,9 @@ public DataSourceConfig setDefaults(DataSourceBuilder builder) {
171173
if (schema == null) {
172174
schema = other.getSchema();
173175
}
176+
if (catalog == null) {
177+
catalog = other.catalog();
178+
}
174179
if (minConnections == 2 && other.getMinConnections() < 2) {
175180
minConnections = other.getMinConnections();
176181
}
@@ -307,6 +312,17 @@ public DataSourceConfig setSchema(String schema) {
307312
return this;
308313
}
309314

315+
@Override
316+
public String catalog() {
317+
return catalog;
318+
}
319+
320+
@Override
321+
public DataSourceConfig catalog(String catalog) {
322+
this.catalog = catalog;
323+
return this;
324+
}
325+
310326
@Override
311327
public String getDriver() {
312328
return driverClassName;
@@ -740,6 +756,7 @@ private void loadSettings(ConfigPropertiesHelper properties) {
740756
password = properties.get("password", password);
741757
password2 = properties.get("password2", password2);
742758
schema = properties.get("schema", schema);
759+
catalog = properties.get("catalog", catalog);
743760
platform = properties.get("platform", platform);
744761
ownerUsername = properties.get("ownerUsername", ownerUsername);
745762
ownerPassword = properties.get("ownerPassword", ownerPassword);

ebean-datasource-api/src/test/java/io/ebean/datasource/DataSourceConfigTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ public void copy() {
7777
source.setUrl("url");
7878
source.setReadOnlyUrl("readOnlyUrl");
7979
source.setSchema("sch");
80+
source.catalog("cat");
8081

8182
Map<String,String> customSource = new LinkedHashMap<>();
8283
customSource.put("a","a");
@@ -90,6 +91,7 @@ public void copy() {
9091
assertEquals("url", copy.getUrl());
9192
assertEquals("readOnlyUrl", copy.getReadOnlyUrl());
9293
assertEquals("sch", copy.getSchema());
94+
assertEquals("cat", copy.catalog());
9395
assertEquals(42, copy.getMinConnections());
9496
assertEquals(45, copy.getMaxConnections());
9597

@@ -113,6 +115,7 @@ public void defaults() {
113115
assertThat(readOnly.getUsername()).isEqualTo(config.getUsername());
114116
assertThat(readOnly.getPassword()).isEqualTo(config.getPassword());
115117
assertThat(readOnly.getSchema()).isEqualTo(config.getSchema());
118+
assertThat(readOnly.catalog()).isEqualTo(config.catalog());
116119
assertThat(readOnly.getMinConnections()).isEqualTo(config.getMinConnections());
117120
assertThat(readOnly.getCustomProperties()).containsKeys("useSSL");
118121
}
@@ -258,6 +261,7 @@ private static void assertConfigValues(DataSourceBuilder.Settings config) {
258261
assertThat(config.getUsername()).isEqualTo("myusername");
259262
assertThat(config.getPassword()).isEqualTo("mypassword");
260263
assertThat(config.getSchema()).isEqualTo("myschema");
264+
assertThat(config.catalog()).isEqualTo("mycat");
261265
assertThat(config.getApplicationName()).isEqualTo("myApp");
262266
Properties clientInfo = config.getClientInfo();
263267
assertThat(clientInfo.getProperty("ClientUser")).isEqualTo("ciu");

ebean-datasource-api/src/test/resources/example.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
datasource.foo.username=myusername
22
datasource.foo.password=mypassword
33
datasource.foo.schema=myschema
4+
datasource.foo.catalog=mycat
45
datasource.foo.url=myUrl
56
datasource.foo.readOnlyUrl=myReadOnlyUrl
67
datasource.foo.applicationName=myApp

ebean-datasource-api/src/test/resources/example2.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
bar.username=myusername
22
bar.password=mypassword
33
bar.schema=myschema
4+
bar.catalog=mycat
45
bar.url=myUrl
56
bar.readOnlyUrl=myReadOnlyUrl
67
bar.applicationName=myApp

ebean-datasource-api/src/test/resources/example3.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
username=myusername
22
password=mypassword
33
schema=myschema
4+
catalog=mycat
45
url=myUrl
56
readOnlyUrl=myReadOnlyUrl
67
applicationName=myApp

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ final class ConnectionPool implements DataSourcePool {
4242
private final List<String> initSql;
4343
private final String user;
4444
private final String schema;
45+
private final String catalog;
4546
private final String heartbeatSql;
4647
private final int heartbeatFreqSecs;
4748
private final int heartbeatTimeoutSeconds;
@@ -119,6 +120,7 @@ final class ConnectionPool implements DataSourcePool {
119120
this.clientInfo = params.getClientInfo();
120121
this.queue = new PooledConnectionQueue(this);
121122
this.schema = params.getSchema();
123+
this.catalog = params.catalog();
122124
this.user = params.getUsername();
123125
this.shutdownOnJvmExit = params.isShutdownOnJvmExit();
124126
this.source = DriverDataSource.of(name, params);
@@ -251,6 +253,14 @@ public int size() {
251253
return size.get();
252254
}
253255

256+
String schema() {
257+
return schema;
258+
}
259+
260+
String catalog() {
261+
return catalog;
262+
}
263+
254264
/**
255265
* Increment the current pool size.
256266
*/
@@ -388,6 +398,9 @@ private Connection initConnection(Connection conn) throws SQLException {
388398
if (readOnly) {
389399
conn.setReadOnly(true);
390400
}
401+
if (catalog != null) {
402+
conn.setCatalog(catalog);
403+
}
391404
if (schema != null) {
392405
conn.setSchema(schema);
393406
}

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

Lines changed: 69 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,32 @@ final class PooledConnection extends ConnectionDelegator {
5757

5858
private static final int RO_MYSQL_1290 = 1290;
5959

60+
/**
61+
* Constant for schema/catalog, when we are in SCHEMA_CATALOG_UNKNOWN state
62+
* This is used for correct cache key computation. (We cannot use 'null'
63+
* here, as we might get a collision in edge cases)
64+
*/
65+
private static final String UNKNOWN = "@unknown";
66+
67+
/**
68+
* The schema/catalog is unknown, that means, we have not yet touched the
69+
* value on the underlying connection.
70+
* We do not have to restore it.
71+
*/
72+
private static final int SCHEMA_CATALOG_UNKNOWN = 0;
73+
74+
/**
75+
* The schema/catalog is changed. The original value has to be restored on
76+
* close()
77+
*/
78+
private static final int SCHEMA_CATALOG_CHANGED = 1;
79+
80+
/**
81+
* We know the original value of the underlying connection, but there is no
82+
* demand to restore it.
83+
*/
84+
private static final int SCHEMA_CATALOG_KNOWN = 2;
85+
6086
private final String name;
6187
private final ConnectionPool pool;
6288
private final Connection connection;
@@ -82,12 +108,16 @@ final class PooledConnection extends ConnectionDelegator {
82108
*/
83109
private boolean failoverToReadOnly;
84110
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;
111+
private int schemaState = SCHEMA_CATALOG_UNKNOWN;
112+
private int catalogState = SCHEMA_CATALOG_UNKNOWN;
113+
114+
// this is used for cache computation
115+
private String cacheKeySchema = UNKNOWN;
116+
private String cacheKeyCatalog = UNKNOWN;
117+
118+
// original values are lazily initialized and restored on close()
119+
private String originalSchema;
120+
private String originalCatalog;
91121

92122
private long startUseTime;
93123
private long lastUseTime;
@@ -118,12 +148,20 @@ final class PooledConnection extends ConnectionDelegator {
118148
this.pool = pool;
119149
this.connection = connection;
120150
this.name = pool.name() + uniqueId;
151+
this.originalSchema = pool.schema();
152+
this.originalCatalog = pool.catalog();
153+
if (originalSchema != null) {
154+
this.schemaState = SCHEMA_CATALOG_KNOWN;
155+
this.cacheKeySchema = originalSchema;
156+
}
157+
if (originalCatalog != null) {
158+
this.catalogState = SCHEMA_CATALOG_KNOWN;
159+
this.cacheKeyCatalog = originalCatalog;
160+
}
121161
this.pstmtCache = new PstmtCache(pool.pstmtCacheSize());
122162
this.maxStackTrace = pool.maxStackTraceSize();
123163
this.creationTime = System.currentTimeMillis();
124164
this.lastUseTime = creationTime;
125-
this.currentSchema = this.originalSchema = connection.getSchema();
126-
this.currentCatalog = this.originalCatalog = connection.getCatalog();
127165
pool.inc();
128166
}
129167

@@ -139,8 +177,6 @@ final class PooledConnection extends ConnectionDelegator {
139177
this.maxStackTrace = 0;
140178
this.creationTime = System.currentTimeMillis();
141179
this.lastUseTime = creationTime;
142-
this.currentSchema = this.originalSchema = "DEFAULT";
143-
this.currentCatalog = this.originalCatalog = "DEFAULT";
144180
}
145181

146182
/**
@@ -283,7 +319,7 @@ void returnPreparedStatement(ExtendedPreparedStatement pstmt) {
283319
*/
284320
@Override
285321
public PreparedStatement prepareStatement(String sql, int returnKeysFlag) throws SQLException {
286-
String key = sql + ':' + currentSchema + ':' + currentCatalog + ':' + returnKeysFlag;
322+
String key = sql + ':' + cacheKeySchema + ':' + cacheKeyCatalog + ':' + returnKeysFlag;
287323
return prepareStatement(sql, true, returnKeysFlag, key);
288324
}
289325

@@ -292,7 +328,7 @@ public PreparedStatement prepareStatement(String sql, int returnKeysFlag) throws
292328
*/
293329
@Override
294330
public PreparedStatement prepareStatement(String sql) throws SQLException {
295-
String key = sql + ':' + currentSchema + ':' + currentCatalog;
331+
String key = sql + ':' + cacheKeySchema + ':' + cacheKeyCatalog;
296332
return prepareStatement(sql, false, 0, key);
297333
}
298334

@@ -422,14 +458,17 @@ public void close() throws SQLException {
422458
resetIsolationReadOnlyRequired = false;
423459
}
424460

425-
if (resetSchema) {
426-
connection.setSchema(originalSchema);
427-
resetSchema = false;
461+
if (catalogState == SCHEMA_CATALOG_CHANGED) {
462+
connection.setCatalog(originalCatalog);
463+
cacheKeyCatalog = originalCatalog;
464+
catalogState = SCHEMA_CATALOG_KNOWN;
428465
}
429466

430-
if (resetCatalog) {
431-
connection.setCatalog(originalCatalog);
432-
resetCatalog = false;
467+
if (schemaState == SCHEMA_CATALOG_CHANGED) {
468+
connection.setSchema(originalSchema);
469+
// we can use original value for cache computation from now on
470+
cacheKeySchema = originalSchema;
471+
schemaState = SCHEMA_CATALOG_KNOWN;
433472
}
434473

435474
// the connection is assumed GOOD so put it back in the pool
@@ -700,8 +739,13 @@ public void setSchema(String schema) throws SQLException {
700739
if (status == STATUS_IDLE) {
701740
throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setSchema()");
702741
}
703-
currentSchema = schema;
704-
resetSchema = true;
742+
if (schemaState == SCHEMA_CATALOG_UNKNOWN) {
743+
// lazily initialise the originalSchema
744+
originalSchema = getSchema();
745+
// state would be KNOWN here
746+
}
747+
schemaState = SCHEMA_CATALOG_CHANGED;
748+
cacheKeySchema = schema;
705749
connection.setSchema(schema);
706750
}
707751

@@ -710,8 +754,11 @@ public void setCatalog(String catalog) throws SQLException {
710754
if (status == STATUS_IDLE) {
711755
throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setCatalog()");
712756
}
713-
currentCatalog = catalog;
714-
resetCatalog = true;
757+
if (schemaState == SCHEMA_CATALOG_UNKNOWN) {
758+
originalCatalog = getCatalog();
759+
}
760+
catalogState = SCHEMA_CATALOG_CHANGED;
761+
cacheKeyCatalog = catalog;
715762
connection.setCatalog(catalog);
716763
}
717764

ebean-datasource/src/test/java/io/ebean/datasource/test/PostgresInitTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ void test_with_clientInfo() throws SQLException {
8181
void test_with_applicationNameAndSchema() throws SQLException {
8282
DataSourceConfig ds = new DataSourceConfig();
8383
ds.setUrl("jdbc:postgresql://127.0.0.1:9999/app");
84-
ds.setSchema("fred");
84+
ds.setSchema("public");
8585
ds.setUsername("db_owner");
8686
ds.setPassword("test");
8787
ds.setApplicationName("my-application-name");
@@ -112,7 +112,7 @@ void test_with_applicationNameAndSchema() throws SQLException {
112112
void test_password2() throws SQLException {
113113
DataSourceConfig ds = new DataSourceConfig();
114114
ds.setUrl("jdbc:postgresql://127.0.0.1:9999/app");
115-
ds.setSchema("fred");
115+
ds.setSchema("public");
116116
ds.setUsername("db_owner");
117117
ds.setPassword("test");
118118
ds.setPassword2("newRolledPassword");

0 commit comments

Comments
 (0)