Author: dag
Date: Tue Aug 12 06:15:57 2008
New Revision: 685141
URL: http://svn.apache.org/viewvc?rev=685141&view=rev
Log:
DERBY-48 A connection request that has a default schema that is being created by another transaction
will fail to connect
Patch derby-48b, which limits the use of a subtransaction to the
initial default schema, other implicit schema creation is
transactional. A new testcase is added to show the latter.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LazyDefaultSchemaCreationTest.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java?rev=685141&r1=685140&r2=685141&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/conn/LanguageConnectionContext.java
Tue Aug 12 06:15:57 2008
@@ -498,6 +498,15 @@
*/
public String getCurrentSchemaName(Activation a);
+
+ /**
+ * Return true if this schema name is the initial default schema for the
+ * current session.
+ * @param schemaName
+ * @return true
+ */
+ public boolean isInitialDefaultSchema(String schemaName);
+
/**
* Get the identity column value most recently generated.
*
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java?rev=685141&r1=685140&r2=685141&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/conn/GenericLanguageConnectionContext.java
Tue Aug 12 06:15:57 2008
@@ -1853,6 +1853,16 @@
return s.getSchemaName();
}
+
+ /**
+ * @see LanguageConnectionContext#isInitialDefaultSchema
+ */
+ public boolean isInitialDefaultSchema(String schemaName) {
+ return cachedInitialDefaultSchemaDescr.getSchemaName().
+ equals(schemaName);
+ }
+
+
/**
* @see LanguageConnectionContext#setDefaultSchema(SchemaDescriptor sd)
*/
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java?rev=685141&r1=685140&r2=685141&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLConstantAction.java
Tue Aug 12 06:15:57 2008
@@ -104,81 +104,98 @@
CreateSchemaConstantAction csca
= new CreateSchemaConstantAction(schemaName, (String) null);
- // DERBY-48: This operation creates a schema and we don't
- // want to hold a lock for SYSSCHEMAS for the duration of
- // the user transaction, so we perform the creation in a
- // nested transaction if possible.
- TransactionController useTc = null;
- TransactionController nestedTc = null;
-
- try {
- nestedTc = tc.startNestedUserTransaction(false);
- useTc = nestedTc;
- } catch (StandardException e) {
- if (SanityManager.DEBUG) {
- SanityManager.THROWASSERT(
- "Unexpected: not able to start nested transaction " +
- "to auto-create schema", e);
- }
- useTc = tc;
- }
+ if (activation.getLanguageConnectionContext().
+ isInitialDefaultSchema(schemaName)) {
+ // DERBY-48: This operation creates the user's initial default
+ // schema and we don't want to hold a lock for SYSSCHEMAS for
+ // the duration of the user transaction, so we perform the
+ // creation in a nested transaction if possible.
+ TransactionController useTc = null;
+ TransactionController nestedTc = null;
- // Try max twice: if nested transaction times out, try
- // again in the outer transaction because it may be a
- // self-lock, that is, the outer transaction may hold some
- // lock(s) that make the nested transaction attempt to set
- // a write lock time out. Trying it again in the outer
- // transaction will then succeed. If the reason is some
- // other transaction barring us, trying again in the outer
- // transaction will possibly time out again.
- //
- // Also, if creating a nested transaction failed, only try
- // once in the outer transaction.
- while (true) {
try {
- csca.executeConstantAction(activation, useTc);
- } catch (StandardException se) {
- if (se.getMessageId().equals(SQLState.LOCK_TIMEOUT)) {
- // We don't test for SQLState.DEADLOCK or
- // .LOCK_TIMEOUT_LOG here because a) if it is a
- // deadlock, it may be better to expose it, and b)
- // LOCK_TIMEOUT_LOG happens when the app has set
- // derby.locks.deadlockTrace=true, in which case we
- // don't want to mask the timeout. So in both the
- // latter cases we just throw.
- if (useTc == nestedTc) {
+ nestedTc = tc.startNestedUserTransaction(false);
+ useTc = nestedTc;
+ } catch (StandardException e) {
+ if (SanityManager.DEBUG) {
+ SanityManager.THROWASSERT(
+ "Unexpected: not able to start nested transaction " +
+ "to auto-create schema", e);
+ }
+ useTc = tc;
+ }
- // clean up after use of nested transaction,
- // then try again in outer transaction
- useTc = tc;
+ // Try max twice: if nested transaction times out, try
+ // again in the outer transaction because it may be a
+ // self-lock, that is, the outer transaction may hold some
+ // lock(s) that make the nested transaction attempt to set
+ // a write lock time out. Trying it again in the outer
+ // transaction will then succeed. If the reason is some
+ // other transaction barring us, trying again in the outer
+ // transaction will possibly time out again.
+ //
+ // Also, if creating a nested transaction failed, only try
+ // once in the outer transaction.
+ while (true) {
+ try {
+ csca.executeConstantAction(activation, useTc);
+ } catch (StandardException se) {
+ if (se.getMessageId().equals(SQLState.LOCK_TIMEOUT)) {
+ // We don't test for SQLState.DEADLOCK or
+ // .LOCK_TIMEOUT_LOG here because a) if it is a
+ // deadlock, it may be better to expose it, and b)
+ // LOCK_TIMEOUT_LOG happens when the app has set
+ // derby.locks.deadlockTrace=true, in which case we
+ // don't want to mask the timeout. So in both the
+ // latter cases we just throw.
+ if (useTc == nestedTc) {
+
+ // clean up after use of nested transaction,
+ // then try again in outer transaction
+ useTc = tc;
+ nestedTc.destroy();
+ continue;
+ }
+ } else if (se.getMessageId()
+ .equals(SQLState.LANG_OBJECT_ALREADY_EXISTS)) {
+ // Ignore "Schema already exists". Another thread has
+ // probably created it after we checked for it
+ break;
+ }
+
+ // We got an non-expected exception, either in
+ // the nested transaction or in the outer
+ // transaction; we had better pass that on
+ if (useTc == nestedTc) {
nestedTc.destroy();
- continue;
}
- } else if (se.getMessageId()
+
+ throw se;
+ }
+ break;
+ }
+
+ // We either succeeded or got LANG_OBJECT_ALREADY_EXISTS.
+ // Clean up if we did this in a nested transaction.
+ if (useTc == nestedTc) {
+ nestedTc.commit();
+ nestedTc.destroy();
+ }
+ } else {
+ // create the schema in the user transaction always
+ try {
+ csca.executeConstantAction(activation);
+ } catch (StandardException se) {
+ if (se.getMessageId()
.equals(SQLState.LANG_OBJECT_ALREADY_EXISTS)) {
// Ignore "Schema already exists". Another thread has
// probably created it after we checked for it
- break;
- }
-
- // We got an non-expected exception, either in
- // the nested transaction or in the outer
- // transaction; we had better pass that on
- if (useTc == nestedTc) {
- nestedTc.destroy();
+ } else {
+ throw se;
}
-
- throw se;
}
- break;
}
- // We either succeeded or got LANG_OBJECT_ALREADY_EXISTS.
- // Clean up if we did this in a nested transaction.
- if (useTc == nestedTc) {
- nestedTc.commit();
- nestedTc.destroy();
- }
sd = dd.getSchemaDescriptor(schemaName, tc, true);
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LazyDefaultSchemaCreationTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LazyDefaultSchemaCreationTest.java?rev=685141&r1=685140&r2=685141&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LazyDefaultSchemaCreationTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/LazyDefaultSchemaCreationTest.java
Tue Aug 12 06:15:57 2008
@@ -208,7 +208,40 @@
}
}
- protected void tearDown() throws Exception {
+ /**
+ * Test that implicit schema creation of other schemas besides
+ * the initial default schema is still transactional.
+ */
+ public void testOtherImplicitSchemaCreation () throws SQLException
+ {
+ Connection c1 = openUserConnection("newuser");
+ c1.setAutoCommit(false);
+ Statement s1 = c1.createStatement();
+
+ // Will auto-create schema OTHERSCHEMA:
+ s1.executeUpdate("create table otherschema.t1(i int)");
+ s1.close();
+
+ JDBC.assertSingleValueResultSet(
+ c1.createStatement().executeQuery(
+ "select schemaname from sys.sysschemas " +
+ "where schemaname='OTHERSCHEMA'"),
+ "OTHERSCHEMA");
+
+ c1.rollback();
+
+ JDBC.assertEmpty(
+ c1.createStatement().executeQuery(
+ "select schemaname from sys.sysschemas " +
+ "where schemaname='OTHERSCHEMA'"));
+
+ c1.rollback();
+ c1.close();
+ }
+
+
+
+protected void tearDown() throws Exception {
try {
createStatement().executeUpdate("drop schema newuser restrict");
} catch (SQLException e) {
|