-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Use pool schema/catalog for original values, lazy initialise originalSchema if required #105
Changes from 8 commits
74b6d65
f9466b1
b3077ee
536d15e
b427700
921b428
b053076
6e5d442
a8d736f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -57,6 +57,32 @@ final class PooledConnection extends ConnectionDelegator { | |
|
||
private static final int RO_MYSQL_1290 = 1290; | ||
|
||
/** | ||
* Constant for schema/catalog, when we are in SCHEMA_CATALOG_UNKNOWN state | ||
* This is used for correct cache key computation. (We cannot use 'null' | ||
* here, as we might get a collision in edge cases) | ||
*/ | ||
private static final String UNKNOWN = "@unknown"; | ||
|
||
/** | ||
* The schema/catalog is unknown, that means, we have not yet touched the | ||
* value on the underlying connection. | ||
* We do not have to restore it. | ||
*/ | ||
private static final int SCHEMA_CATALOG_UNKNOWN = 0; | ||
|
||
/** | ||
* The schema/catalog is changed. The original value has to be restored on | ||
* close() | ||
*/ | ||
private static final int SCHEMA_CATALOG_CHANGED = 1; | ||
|
||
/** | ||
* We know the original value of the underlying connection, but there is no | ||
* demand to restore it. | ||
*/ | ||
private static final int SCHEMA_CATALOG_KNOWN = 2; | ||
|
||
private final String name; | ||
private final ConnectionPool pool; | ||
private final Connection connection; | ||
|
@@ -82,12 +108,16 @@ final class PooledConnection extends ConnectionDelegator { | |
*/ | ||
private boolean failoverToReadOnly; | ||
private boolean resetAutoCommit; | ||
private boolean resetSchema; | ||
private boolean resetCatalog; | ||
private String currentSchema; | ||
private String currentCatalog; | ||
private final String originalSchema; | ||
private final String originalCatalog; | ||
private int schemaState = SCHEMA_CATALOG_UNKNOWN; | ||
private int catalogState = SCHEMA_CATALOG_UNKNOWN; | ||
|
||
// this is used for cache computation | ||
private String cacheKeySchema = UNKNOWN; | ||
private String cacheKeyCatalog = UNKNOWN; | ||
|
||
// original values are lazily initialized and restored on close() | ||
private String originalSchema; | ||
private String originalCatalog; | ||
|
||
private long startUseTime; | ||
private long lastUseTime; | ||
|
@@ -118,12 +148,23 @@ final class PooledConnection extends ConnectionDelegator { | |
this.pool = pool; | ||
this.connection = connection; | ||
this.name = pool.name() + uniqueId; | ||
this.originalSchema = pool.schema(); | ||
this.originalCatalog = pool.catalog(); | ||
if (originalSchema != null) { | ||
schemaState = SCHEMA_CATALOG_KNOWN; | ||
this.cacheKeySchema = originalSchema; | ||
// if schema & catalog is defined, we can be sure, that connection is initialized properly | ||
assert originalSchema.equals(connection.getSchema()) : "Connection is in the wrong schema: " + connection.getSchema() + ", expected: " + originalSchema; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What do you think about these asserts? On the one hand, I think they are good because you can see, for example, if you specify a non-existent schema in the PoolConfiguration (at least pg returns null in that case). On the other hand, they could cause problems if the schema is returned in uppercase, for example. I would keep them in until someone provides a use case. (and the user can disable assertions anyway) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I've honestly changed my mind a couple of times on these asserts. On one hand they look useful, but on the other they can throw SQLException and fail on case but only with asserts enabled, and if the driver allows setting unknown schema etc maybe its best to just allow that. So I'm thinking of removing them. That really means that we are leaving it up to developers to set original schema and catalog appropriately and to test that themselves as needed. |
||
} | ||
if (originalCatalog != null) { | ||
catalogState = SCHEMA_CATALOG_KNOWN; | ||
this.cacheKeyCatalog = originalCatalog; | ||
assert originalCatalog.equals(connection.getCatalog()) : "Connection is in the wrong catalog: " + connection.getCatalog() + ", expected: " + originalCatalog; | ||
} | ||
this.pstmtCache = new PstmtCache(pool.pstmtCacheSize()); | ||
this.maxStackTrace = pool.maxStackTraceSize(); | ||
this.creationTime = System.currentTimeMillis(); | ||
this.lastUseTime = creationTime; | ||
this.currentSchema = this.originalSchema = connection.getSchema(); | ||
this.currentCatalog = this.originalCatalog = connection.getCatalog(); | ||
pool.inc(); | ||
} | ||
|
||
|
@@ -139,8 +180,6 @@ final class PooledConnection extends ConnectionDelegator { | |
this.maxStackTrace = 0; | ||
this.creationTime = System.currentTimeMillis(); | ||
this.lastUseTime = creationTime; | ||
this.currentSchema = this.originalSchema = "DEFAULT"; | ||
this.currentCatalog = this.originalCatalog = "DEFAULT"; | ||
} | ||
|
||
/** | ||
|
@@ -283,7 +322,7 @@ void returnPreparedStatement(ExtendedPreparedStatement pstmt) { | |
*/ | ||
@Override | ||
public PreparedStatement prepareStatement(String sql, int returnKeysFlag) throws SQLException { | ||
String key = sql + ':' + currentSchema + ':' + currentCatalog + ':' + returnKeysFlag; | ||
String key = sql + ':' + cacheKeySchema + ':' + cacheKeyCatalog + ':' + returnKeysFlag; | ||
return prepareStatement(sql, true, returnKeysFlag, key); | ||
} | ||
|
||
|
@@ -292,7 +331,7 @@ public PreparedStatement prepareStatement(String sql, int returnKeysFlag) throws | |
*/ | ||
@Override | ||
public PreparedStatement prepareStatement(String sql) throws SQLException { | ||
String key = sql + ':' + currentSchema + ':' + currentCatalog; | ||
String key = sql + ':' + cacheKeySchema + ':' + cacheKeyCatalog; | ||
return prepareStatement(sql, false, 0, key); | ||
} | ||
|
||
|
@@ -422,14 +461,17 @@ public void close() throws SQLException { | |
resetIsolationReadOnlyRequired = false; | ||
} | ||
|
||
if (resetSchema) { | ||
if (schemaState == SCHEMA_CATALOG_CHANGED) { | ||
connection.setSchema(originalSchema); | ||
resetSchema = false; | ||
// we can use original value for cache computation from now on | ||
cacheKeySchema = originalSchema; | ||
schemaState = SCHEMA_CATALOG_KNOWN; | ||
} | ||
|
||
if (resetCatalog) { | ||
if (catalogState == SCHEMA_CATALOG_CHANGED) { | ||
connection.setCatalog(originalCatalog); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Important: We should switch the order here. First restore catalog, then restore schema. See other comment By the way, I can imagine an edge case here again: Postgres fails silently, if I call So if you set up your pool, that
I think we would be overdoing it here if we also covered this special case, because it is really a stupid idea to delete the main schema There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes, I'm good with that. I'll make that change.
I agree. We can leave that sort of case with developers to own. |
||
resetCatalog = false; | ||
cacheKeyCatalog = originalCatalog; | ||
catalogState = SCHEMA_CATALOG_KNOWN; | ||
} | ||
|
||
// the connection is assumed GOOD so put it back in the pool | ||
|
@@ -700,8 +742,13 @@ public void setSchema(String schema) throws SQLException { | |
if (status == STATUS_IDLE) { | ||
throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setSchema()"); | ||
} | ||
currentSchema = schema; | ||
resetSchema = true; | ||
if (schemaState == SCHEMA_CATALOG_UNKNOWN) { | ||
// lazily initialise the originalSchema | ||
originalSchema = getSchema(); | ||
rbygrave marked this conversation as resolved.
Show resolved
Hide resolved
|
||
// state would be KNOWN here | ||
} | ||
schemaState = SCHEMA_CATALOG_CHANGED; | ||
cacheKeySchema = schema; | ||
connection.setSchema(schema); | ||
} | ||
|
||
|
@@ -710,8 +757,11 @@ public void setCatalog(String catalog) throws SQLException { | |
if (status == STATUS_IDLE) { | ||
throw new SQLException(IDLE_CONNECTION_ACCESSED_ERROR + "setCatalog()"); | ||
} | ||
currentCatalog = catalog; | ||
resetCatalog = true; | ||
if (schemaState == SCHEMA_CATALOG_UNKNOWN) { | ||
originalCatalog = getCatalog(); | ||
} | ||
catalogState = SCHEMA_CATALOG_CHANGED; | ||
cacheKeyCatalog = catalog; | ||
connection.setCatalog(catalog); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Every day I think of something new. 🤣 Do you think the order is important? I could imagine that you have to change the catalog first before you can change the schema, because the schema does not exist in the current catalog, for example. We did it right here. But not in
close()
. From my gut feeling, I would say change the catalog first, then the schema