You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ka...@apache.org on 2014/04/10 08:26:47 UTC
svn commit: r1586226 - in /db/derby/code/trunk/java:
engine/org/apache/derby/impl/sql/catalog/
engine/org/apache/derby/impl/sql/compile/
testing/org/apache/derbyTesting/functionTests/tests/lang/
Author: kahatlen
Date: Thu Apr 10 06:26:46 2014
New Revision: 1586226
URL: http://svn.apache.org/r1586226
Log:
DERBY-6540: Schema-qualified table names could be mistaken for transition tables
Don't treat schema-qualified table names as transition tables, as
transition table names are always unqualified.
Modified:
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java
db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java
db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java?rev=1586226&r1=1586225&r2=1586226&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/catalog/DataDictionaryImpl.java Thu Apr 10 06:26:46 2014
@@ -4879,9 +4879,8 @@ public final class DataDictionaryImpl
for (ColumnReference ref : refs)
{
TableName tableName = ref.getQualifiedTableName();
- if ((tableName == null) ||
- ((oldReferencingName == null || !oldReferencingName.equals(tableName.getTableName())) &&
- (newReferencingName == null || !newReferencingName.equals(tableName.getTableName()))))
+ if (!isTransitionVariable(
+ tableName, oldReferencingName, newReferencingName))
{
continue;
}
@@ -4970,9 +4969,8 @@ public final class DataDictionaryImpl
for (ColumnReference ref : refs)
{
TableName tableName = ref.getQualifiedTableName();
- if ((tableName == null) ||
- ((oldReferencingName == null || !oldReferencingName.equals(tableName.getTableName())) &&
- (newReferencingName == null || !newReferencingName.equals(tableName.getTableName()))))
+ if (!isTransitionVariable(
+ tableName, oldReferencingName, newReferencingName))
{
continue;
}
@@ -5052,6 +5050,37 @@ public final class DataDictionaryImpl
return newText.toString();
}
+ /**
+ * Check if a table name is actually a transition variable.
+ *
+ * @param tableName the table name to check
+ * @param oldReferencingName the name of the old transition variable
+ * @param newReferencingName the name of the new transition variable
+ * @return {@code true} if the table name is a transition variable,
+ * {@code false} otherwise
+ */
+ private static boolean isTransitionVariable(TableName tableName,
+ String oldReferencingName, String newReferencingName) {
+ if (tableName != null) {
+ if (tableName.hasSchema()) {
+ // DERBY-6540: Schema-qualified names are not transition
+ // variables.
+ return false;
+ }
+
+ // If there is no schema, and the name is equal to the old or
+ // the new transition variable, then it is a transition variable.
+ String name = tableName.getTableName();
+ if (name != null) {
+ return name.equals(oldReferencingName)
+ || name.equals(newReferencingName);
+ }
+ }
+
+ // Otherwise, it is not a transition variable.
+ return false;
+ }
+
/*
* The arrary passed will have either -1 or a column position as it's
* elements. If the array only has -1 as for all it's elements, then
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java?rev=1586226&r1=1586225&r2=1586226&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CreateTriggerNode.java Thu Apr 10 06:26:46 2014
@@ -21,7 +21,6 @@
package org.apache.derby.impl.sql.compile;
-import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
@@ -724,9 +723,7 @@ class CreateTriggerNode extends DDLState
Collections.sort(tabs, OFFSET_COMPARATOR);
for (FromBaseTable fromTable : tabs) {
String baseTableName = fromTable.getBaseTableName();
- if (baseTableName == null
- || (!baseTableName.equals(oldTableName)
- && !baseTableName.equals(newTableName))) {
+ if (!isTransitionTable(fromTable)) {
// baseTableName is not the NEW or OLD table, so no need
// to do anything. Skip this table.
continue;
@@ -763,6 +760,28 @@ class CreateTriggerNode extends DDLState
return newText.toString();
}
+ /**
+ * Check if a table represents one of the transition tables.
+ *
+ * @param fbt the table to check
+ * @return {@code true} if {@code fbt} represents either the old or
+ * the new transition table, {@code false} otherwise
+ */
+ private boolean isTransitionTable(FromBaseTable fbt) {
+ // DERBY-6540: It can only be a transition table if the name
+ // is not schema qualified.
+ if (!fbt.getOrigTableName().hasSchema()) {
+ String baseTableName = fbt.getBaseTableName();
+ if (baseTableName != null) {
+ return baseTableName.equals(oldTableName) ||
+ baseTableName.equals(newTableName);
+ }
+ }
+
+ // Table name didn't match a transition table.
+ return false;
+ }
+
/*
* Forbid references to generated columns in the actions of BEFORE triggers.
* This is DERBY-3948, enforcing the following section of the SQL standard:
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java?rev=1586226&r1=1586225&r2=1586226&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/TableName.java Thu Apr 10 06:26:46 2014
@@ -102,8 +102,7 @@ public class TableName extends QueryTree
*
* @return true if this instance was initialized with not null schemaName
*/
-
- boolean hasSchema(){
+ public boolean hasSchema() {
return hasSchema;
}
Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java?rev=1586226&r1=1586225&r2=1586226&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerTest.java Thu Apr 10 06:26:46 2014
@@ -2324,4 +2324,92 @@ public class TriggerTest extends BaseJDB
public static ResultSet dummyTableFunction() {
return null;
}
+
+ public void testDerby6540TransitionTableNameClash() throws SQLException {
+ setAutoCommit(false);
+ Statement s = createStatement();
+ s.execute("create table d6540_t1(x int)");
+ s.execute("create table d6540_t2(y int)");
+ s.execute("create table d6540_t3(z int)");
+
+ // Test name clash for statement level triggers.
+
+ // The following statement used to fail before DERBY-6540 because
+ // APP.D6540_T2 was mistaken for the transition table D6540_T2. Since
+ // the transition table does not have a column Y, it would fail with
+ // an error message saying that column Y is not in any table in the
+ // FROM list.
+ s.execute("create trigger d6540_tr after insert on d6540_t1 "
+ + "referencing new table as d6540_t2 "
+ + "insert into d6540_t3 select x from d6540_t2 "
+ + "union all select y from app.d6540_t2");
+
+ // Verify that the trigger does what it is supposed to do.
+ PreparedStatement selT3
+ = prepareStatement("select * from d6540_t3 order by z");
+ JDBC.assertEmpty(selT3.executeQuery());
+
+ s.execute("insert into d6540_t1 values 1");
+ JDBC.assertSingleValueResultSet(selT3.executeQuery(), "1");
+
+ s.execute("insert into d6540_t2 values 2, 3");
+ s.execute("insert into d6540_t1 values 4, 5");
+ JDBC.assertFullResultSet(
+ selT3.executeQuery(),
+ new String[][] { {"1"}, {"2"}, {"3"}, {"4"}, {"5"} });
+
+ // Revert tables to clean state before we go on.
+ s.execute("truncate table d6540_t1");
+ s.execute("truncate table d6540_t2");
+ s.execute("truncate table d6540_t3");
+ s.execute("drop trigger d6540_tr");
+
+ // Test name clash for row level triggers.
+
+ // The following statement used to fail before DERBY-6540, with an
+ // error message saying that column Y was not in any of the tables
+ // in the FROM list.
+ s.execute("create trigger d6540_tr after insert on d6540_t1 "
+ + "referencing new as d6540_t2 for each row "
+ + "insert into d6540_t3 select * from app.d6540_t2 "
+ + "where d6540_t2.x = app.d6540_t2.y");
+
+ // Verify that the trigger works.
+ JDBC.assertEmpty(selT3.executeQuery());
+
+ s.execute("insert into d6540_t1 values 1");
+ JDBC.assertEmpty(selT3.executeQuery());
+
+ s.execute("insert into d6540_t2 values 1, 2, 3");
+ s.execute("insert into d6540_t1 values 2, 3, 4");
+ JDBC.assertFullResultSet(
+ selT3.executeQuery(), new String[][] { {"2"}, {"3"} });
+
+ // Verify that row level triggers still don't need to qualify
+ // table names that are the same as a transition variable, if they
+ // appear in the from list (since the transition variable cannot be
+ // used in the from list, so there is no ambiguity).
+ s.execute("drop trigger d6540_tr");
+ s.execute("create table d6540_t4(c1 int, c2 int)");
+ s.execute("create trigger d6540_tr after insert on d6540_t1 "
+ + "referencing new as d6540_t2 for each row "
+ + "insert into d6540_t4 select y, d6540_t2.x from d6540_t2");
+ s.execute("insert into d6540_t1 values 1");
+ JDBC.assertFullResultSet(
+ s.executeQuery("select * from d6540_t4 order by c1"),
+ new String[][] {
+ { "1", "1" },
+ { "2", "1" },
+ { "3", "1" },
+ });
+
+ // Finally, verify that a transition table or transition variable
+ // cannot have a schema.
+ assertCompileError(SYNTAX_ERROR,
+ "create trigger d6540_tr1 after insert on d6540_t1 "
+ + "referencing new table as app.n values 1");
+ assertCompileError(SYNTAX_ERROR,
+ "create trigger d6540_tr2 after insert on d6540_t1 "
+ + "referencing new as app.n for each row values 1");
+ }
}