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/30 11:05:24 UTC

svn commit: r1591216 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/dictionary/ engine/org/apache/derby/impl/sql/catalog/ engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/impl/sql/execute/ storeless/org/apache/derby/i...

Author: kahatlen
Date: Wed Apr 30 09:05:23 2014
New Revision: 1591216

URL: http://svn.apache.org/r1591216
Log:
DERBY-6370: dblook doesn't schema-qualify identifiers in trigger actions

Rewrite the triggered SQL statement and the WHEN clause of a trigger
so that all identifiers are fully qualified, before they are stored in
SYS.SYSTRIGGERS and SYS.SYSSTATEMENTS. This way, dblook is able to use
the information in the system tables to produce DDL that is
independent of the schema in which it is executed.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
    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/AggregateNode.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/FromBaseTable.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NextSequenceNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OffsetOrderVisitor.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java
    db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net_territory.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test_territory.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/derived.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerGeneralTest.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/iapi/sql/dictionary/DataDictionary.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/DataDictionary.java Wed Apr 30 09:05:23 2014
@@ -1309,6 +1309,16 @@ public interface DataDictionary
 	 * 	false if here because an invalidated row level trigger with 
 	 *  REFERENCEd columns has been fired and hence trigger action
 	 *  sql associated with SPSDescriptor may be invalid too.
+     *
+     * @param replacements a list that will be populated with objects that
+     *  describe how {@code triggerDefinition} has been transformed into
+     *  the returned SQL text. Each element in the list will contain four
+     *  integers. The first two describe the begin and end offset of the
+     *  replaced text in the {@code triggerDefinition}. The last two describe
+     *  the begin and end offset of the replacement text in the returned
+     *  string. The begin offsets are inclusive, whereas the end offsets are
+     *  exclusive. The list can be {@code null} if the caller does not care
+     *  about this information.
 	 * 
 	 * @return Transformed trigger action sql
 	 * @throws StandardException
@@ -1323,7 +1333,8 @@ public interface DataDictionary
 			int actionOffset,
 			TableDescriptor triggerTableDescriptor,
 			int triggerEventMask,
-			boolean createTriggerTime)
+            boolean createTriggerTime,
+            List<int[]> replacements)
 	throws StandardException;
 	
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TriggerDescriptor.java Wed Apr 30 09:05:23 2014
@@ -410,7 +410,8 @@ public class TriggerDescriptor extends U
 					0,
 					td,
 					-1,
-                    false);
+                    false,
+                    null);
 
             if (isWhenClause) {
                 // The WHEN clause is not a full SQL statement, just a search

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=1591216&r1=1591215&r2=1591216&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 Wed Apr 30 09:05:23 2014
@@ -153,7 +153,7 @@ import org.apache.derby.iapi.util.IdUtil
 import org.apache.derby.impl.services.daemon.IndexStatisticsDaemonImpl;
 import org.apache.derby.impl.services.locks.Timeout;
 import org.apache.derby.impl.sql.compile.ColumnReference;
-import org.apache.derby.impl.sql.compile.OffsetOrderVisitor;
+import org.apache.derby.impl.sql.compile.QueryTreeNode;
 import org.apache.derby.impl.sql.compile.TableName;
 import org.apache.derby.impl.sql.depend.BasicDependencyManager;
 import org.apache.derby.impl.sql.execute.JarUtil;
@@ -4742,7 +4742,8 @@ public final class	DataDictionaryImpl
 			int actionOffset,
 			TableDescriptor triggerTableDescriptor,
 			int triggerEventMask,
-			boolean createTriggerTime
+            boolean createTriggerTime,
+            List<int[]> replacements
 			) throws StandardException
 	{
 		// If we are dealing with database created in 10.8 and prior,
@@ -4751,8 +4752,8 @@ public final class	DataDictionaryImpl
 		// all columns are getting read from the trigger table. We
 		// need to do this to maintain backward compatibility. 
 		boolean in10_9_orHigherVersion = checkVersion(DataDictionary.DD_VERSION_DERBY_10_9,null);
-		
-		StringBuffer newText = new StringBuffer();
+
+        StringBuilder newText = new StringBuilder();
 		int start = 0;
 
 		//Total Number of columns in the trigger table
@@ -4814,13 +4815,9 @@ public final class	DataDictionaryImpl
 
 		/* we need to sort on position in string, beetle 4324
 		 */
-        OffsetOrderVisitor<ColumnReference> visitor =
-                new OffsetOrderVisitor<ColumnReference>(ColumnReference.class,
-                        actionOffset,
-                        actionOffset + triggerDefinition.length());
-        actionStmt.accept(visitor);
-        SortedSet<ColumnReference> refs = visitor.getNodes();
-		
+        SortedSet<ColumnReference> refs = getTransitionVariables(
+                actionStmt, oldReferencingName, newReferencingName);
+
 		if (createTriggerTime) {
 			//The purpose of following array(triggerActionColsOnly) is to
 			//identify all the columns from the trigger action which are
@@ -4880,16 +4877,6 @@ public final class	DataDictionaryImpl
             for (ColumnReference ref : refs)
 			{
 				TableName tableName = ref.getQualifiedTableName();
-                if (!isTransitionVariable(
-                        tableName, oldReferencingName, newReferencingName))
-				{
-					continue;
-				}
-
-				if (tableName.getBeginOffset() == -1)
-				{
-					continue;
-				}
 
 				checkInvalidTriggerReference(tableName.getTableName(),
 						oldReferencingName,
@@ -4970,21 +4957,13 @@ public final class	DataDictionaryImpl
         for (ColumnReference ref : refs)
 		{
 			TableName tableName = ref.getQualifiedTableName();
-            if (!isTransitionVariable(
-                    tableName, oldReferencingName, newReferencingName))
-			{
-				continue;
-			}
-				
-			int tokBeginOffset = tableName.getBeginOffset();
-			if (tokBeginOffset == -1)
-			{
-				continue;
-			}
+            int tableBeginOffset = tableName.getBeginOffset() - actionOffset;
 
 			String colName = ref.getColumnName();
 
-			newText.append(triggerDefinition.substring(start, tokBeginOffset-actionOffset));
+            // Add whatever we've seen after the previous replacement.
+            newText.append(triggerDefinition, start, tableBeginOffset);
+
 			int colPositionInRuntimeResultSet = -1;
 			ColumnDescriptor triggerColDesc = triggerTableDescriptor.getColumnDescriptor(colName);
             //DERBY-5121 We can come here if the column being used in trigger
@@ -5034,23 +5013,67 @@ public final class	DataDictionaryImpl
 			} else
 				colPositionInRuntimeResultSet=colPositionInTriggerTable;
 
+            // Add the replacement code that accesses a value in the
+            // transition variable.
+            final int replacementOffset = newText.length();
 			newText.append(genColumnReferenceSQL(triggerTableDescriptor, colName, 
 					tableName.getTableName(), 
 					tableName.getTableName().equals(oldReferencingName),
 					colPositionInRuntimeResultSet));
 
             start = ref.getEndOffset() + 1 - actionOffset;
+
+            if (replacements != null) {
+                // Record that we have made a change.
+                replacements.add(new int[] {
+                    tableBeginOffset,  // offset to replaced text
+                    start,             // offset to token after replaced text
+                    replacementOffset, // offset to replacement
+                    newText.length()   // offset to token after replacement
+                });
+            }
 		}
+
 		//By this point, we are finished transforming the trigger action if
 		//it has any references to old/new transition variables.
-		if (start < triggerDefinition.length())
-		{
-			newText.append(triggerDefinition.substring(start));
-		}
+        newText.append(triggerDefinition, start, triggerDefinition.length());
+
 		return newText.toString();
 	}
 
     /**
+     * Get all columns that reference transition variables in triggers.
+     * The columns should be returned in the same order as in the SQL text.
+     *
+     * @param node the node in which to look for transition variables
+     * @param oldReferencingName the name of the old transition variable
+     * @param newReferencingName the name of the new transition variable
+     * @return all references to transition variables
+     */
+    private static SortedSet<ColumnReference> getTransitionVariables(
+        Visitable node, String oldReferencingName, String newReferencingName)
+        throws StandardException
+    {
+        // First get all column references.
+        SortedSet<ColumnReference> refs =
+            ((QueryTreeNode) node).getOffsetOrderedNodes(ColumnReference.class);
+
+        // Then remove all that are not referencing a transition variable.
+        Iterator<ColumnReference> it = refs.iterator();
+        while (it.hasNext()) {
+            TableName tableName = it.next().getQualifiedTableName();
+            if (!isTransitionVariable(
+                    tableName, oldReferencingName, newReferencingName)) {
+                it.remove();
+            }
+        }
+
+        // Return what's left. Should be all references to transition
+        // variables.
+        return refs;
+    }
+
+    /**
      * Check if a table name is actually a transition variable.
      *
      * @param tableName the table name to check

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/AggregateNode.java Wed Apr 30 09:05:23 2014
@@ -70,6 +70,7 @@ class AggregateNode extends UnaryOperato
      *
      * @param operand the value expression for the aggregate
      * @param uadClass the class of the user aggregate definition
+     * @param alias the name by which the aggregate was called
      * @param distinct boolean indicating whether this is distinct
 	 *					or not.
      * @param aggregateName the name of the aggregate from the user's
@@ -80,13 +81,12 @@ class AggregateNode extends UnaryOperato
      AggregateNode(
             ValueNode operand,
             UserAggregateDefinition uadClass,
+            TableName alias,
             boolean distinct,
             String aggregateName,
             ContextManager cm) throws StandardException {
-        super(operand, cm);
-        this.aggregateName = aggregateName;
+        this(operand, alias, distinct, aggregateName, cm);
         setUserDefinedAggregate(uadClass);
-        this.distinct = distinct;
     }
 
     /**
@@ -293,6 +293,12 @@ class AggregateNode extends UnaryOperato
         if ( userAggregateName != null )
         {
             userAggregateName.bind( dd );
+        }
+
+        // If this is a user-defined aggregate that hasn't been bound yet,
+        // bind it now.
+        if (userAggregateName != null && uad == null)
+        {
 
             AliasDescriptor ad = resolveAggregate
                 (

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=1591216&r1=1591215&r2=1591216&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 Wed Apr 30 09:05:23 2014
@@ -22,10 +22,11 @@
 package	org.apache.derby.impl.sql.compile;
 
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashSet;
 import java.util.List;
+import java.util.SortedSet;
+import java.util.TreeSet;
 import org.apache.derby.catalog.UUID;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
@@ -68,8 +69,8 @@ class CreateTriggerNode extends DDLState
 	private	String				whenText;
 	private	StatementNode		actionNode;
 	private	String				actionText;
-    private final String        originalWhenText;
-    private final String        originalActionText;
+    private String              originalWhenText;
+    private String              originalActionText;
     private final int           whenOffset;
     private final int           actionOffset;
     private ProviderInfo[]      providerInfo;
@@ -220,6 +221,32 @@ class CreateTriggerNode extends DDLState
 	private boolean oldTableInReferencingClause;
 	private boolean newTableInReferencingClause;
 
+    /**
+     * <p>
+     * A list that describes how the original SQL text of the trigger action
+     * statement was modified when transition tables and transition variables
+     * were replaced by VTI calls. Each element in the list contains four
+     * integers describing positions where modifications have happened. The
+     * first two integers are begin and end positions of a transition table
+     * or transition variable in {@link #originalActionText the original SQL
+     * text}. The last two integers are begin and end positions of the
+     * corresponding replacement in {@link #actionText the transformed SQL
+     * text}.
+     * </p>
+     *
+     * <p>
+     * Begin positions are inclusive and end positions are exclusive.
+     * </p>
+     */
+    private final ArrayList<int[]>
+            actionTransformations = new ArrayList<int[]>();
+
+    /**
+     * Structure that has the same shape as {@code actionTransformations},
+     * except that it describes the transformations in the WHEN clause.
+     */
+    private final ArrayList<int[]>
+            whenClauseTransformations = new ArrayList<int[]>();
 
 	/**
      * Constructor for a CreateTriggerNode
@@ -374,6 +401,18 @@ class CreateTriggerNode extends DDLState
 		*/
 		boolean needInternalSQL = bindReferencesClause(dd);
 
+        // Get all the names of SQL objects referenced by the triggered
+        // SQL statement and the WHEN clause. Since some of the TableName
+        // nodes may be eliminated from the node tree during the bind phase,
+        // we collect the nodes before the nodes have been bound. The
+        // names will be used later when we normalize the trigger text
+        // that will be stored in the system tables.
+        SortedSet<TableName> actionNames =
+                actionNode.getOffsetOrderedNodes(TableName.class);
+        SortedSet<TableName> whenNames = (whenClause != null)
+                ? whenClause.getOffsetOrderedNodes(TableName.class)
+                : null;
+
         ProviderList prevAPL =
                 compilerContext.getCurrentAuxiliaryProviderList();
         ProviderList apl = new ProviderList();
@@ -419,6 +458,9 @@ class CreateTriggerNode extends DDLState
             compilerContext.setCurrentAuxiliaryProviderList(prevAPL);
 		}
 
+        // Qualify identifiers before storing them (DERBY-5901/DERBY-6370).
+        qualifyNames(actionNames, whenNames);
+
 		/* 
 		** Statement is dependent on the TableDescriptor 
 		*/
@@ -604,8 +646,8 @@ class CreateTriggerNode extends DDLState
 					actionOffset,
 					triggerTableDescriptor,
 					triggerEventMask,
-					true
-					);			
+                    true,
+                    actionTransformations);
 
             // If there is a WHEN clause, we need to transform its text too.
             if (whenClause != null) {
@@ -614,7 +656,8 @@ class CreateTriggerNode extends DDLState
                             whenClause, oldTableName, newTableName,
                             originalWhenText, referencedColInts,
                             referencedColsInTriggerAction, whenOffset,
-                            triggerTableDescriptor, triggerEventMask, true);
+                            triggerTableDescriptor, triggerEventMask, true,
+                            whenClauseTransformations);
             }
 
 			//Now that we know what columns we need for REFERENCEd columns in
@@ -629,10 +672,12 @@ class CreateTriggerNode extends DDLState
 		{
 			//This is a table level trigger	        
             transformedActionText = transformStatementTriggerText(
-                    actionNode, originalActionText, actionOffset);
+                    actionNode, originalActionText, actionOffset,
+                    actionTransformations);
             if (whenClause != null) {
                 transformedWhenText = transformStatementTriggerText(
-                        whenClause, originalWhenText, whenOffset);
+                        whenClause, originalWhenText, whenOffset,
+                        whenClauseTransformations);
             }
 		}
 
@@ -661,6 +706,146 @@ class CreateTriggerNode extends DDLState
 		return regenNode;
 	}
 
+    /**
+     * Make sure all references to SQL schema objects (such as tables and
+     * functions) in the SQL fragments that will be stored in the SPS and
+     * in the trigger descriptor, are fully qualified with a schema name.
+     *
+     * @param actionNames all the TableName nodes found in the triggered
+     *                    SQL statement
+     * @param whenNames   all the Table Name nodes found in the WHEN clause
+     */
+    private void qualifyNames(SortedSet<TableName> actionNames,
+                              SortedSet<TableName> whenNames)
+            throws StandardException {
+
+        StringBuilder original = new StringBuilder();
+        StringBuilder transformed = new StringBuilder();
+
+        // Qualify the names in the action text.
+        qualifyNames(actionNode, actionNames, originalActionText, actionText,
+                     actionTransformations, original, transformed);
+        originalActionText = original.toString();
+        actionText = transformed.toString();
+
+        // Do the same for the WHEN clause, if there is one.
+        if (whenClause != null) {
+            original.setLength(0);
+            transformed.setLength(0);
+            qualifyNames(whenClause, whenNames, originalWhenText, whenText,
+                         whenClauseTransformations, original, transformed);
+            originalWhenText = original.toString();
+            whenText = transformed.toString();
+        }
+    }
+
+    /**
+     * Qualify all names SQL object names in original and transformed SQL
+     * text for an action or a WHEN clause.
+     *
+     * @param node the query tree node for the transformed version of the
+     *   SQL text, in a bound state
+     * @param tableNames all the TableName nodes in the transformed text,
+     *   in the order in which they appear in the SQL text
+     * @param originalText the original SQL text
+     * @param transformedText the transformed SQL text (with VTI calls for
+     *   transition tables or transition variables)
+     * @param replacements a data structure that describes how {@code
+     *   originalText} was transformed into {@code transformedText}
+     * @param newOriginal where to store the normalized version of the
+     *   original text
+     * @param newTransformed where to store the normalized version of the
+     *   transformed text
+     */
+    private void qualifyNames(
+            QueryTreeNode node,
+            SortedSet<TableName> tableNames,
+            String originalText,
+            String transformedText,
+            List<int[]> replacements,
+            StringBuilder newOriginal,
+            StringBuilder newTransformed) throws StandardException {
+
+        int originalPos = 0;
+        int transformedPos = 0;
+
+        for (TableName name : tableNames) {
+
+            String qualifiedName = name.getFullSQLName();
+
+            int beginOffset = name.getBeginOffset() - node.getBeginOffset();
+            int tokenLength = name.getEndOffset() + 1 - name.getBeginOffset();
+
+            // For the transformed text, use the positions from the node.
+            newTransformed.append(transformedText, transformedPos, beginOffset);
+            newTransformed.append(qualifiedName);
+            transformedPos = beginOffset + tokenLength;
+
+            // For the original text, we need to adjust the positions to
+            // compensate for the changes in the transformed text.
+            Integer origBeginOffset =
+                    getOriginalPosition(replacements, beginOffset);
+            if (origBeginOffset != null) {
+                newOriginal.append(originalText, originalPos, origBeginOffset);
+                newOriginal.append(qualifiedName);
+                originalPos = origBeginOffset + tokenLength;
+            }
+        }
+
+        newTransformed.append(
+                transformedText, transformedPos, transformedText.length());
+        newOriginal.append(originalText, originalPos, originalText.length());
+    }
+
+    /**
+     * Translate a position from the transformed trigger text
+     * ({@link #actionText} or {@link #whenText}) to the corresponding
+     * position in the original trigger text ({@link #originalActionText}
+     * or {@link #originalWhenText}).
+     *
+     * @param replacements a data structure that describes the relationship
+     *   between positions in the original and the transformed text
+     * @param transformedPosition the position to translate
+     * @return the position in the original text, or {@code null} if there
+     *   is no corresponding position in the original text (for example if
+     *   it points to a token that was added to the transformed text and
+     *   does not exist in the original text)
+     */
+    private static Integer getOriginalPosition(
+            List<int[]> replacements, int transformedPosition) {
+
+        // Find the last change before the position we want to translate.
+        for (int i = replacements.size() - 1; i >= 0; i--) {
+            int[] offsets = replacements.get(i);
+
+            // offset[0] is the begin offset of the replaced text
+            // offset[1] is the end offset of the replaced text
+            // offset[2] is the begin offset of the replacement text
+            // offset[3] is the end offset of the replacement text
+
+            // Skip those changes that come after the position we
+            // want to translate.
+            if (transformedPosition >= offsets[2]) {
+                if (transformedPosition < offsets[3]) {
+                    // The position points inside a changed portion of the
+                    // SQL text, so there's no corresponding position in the
+                    // original text. Return null.
+                    return null;
+                } else {
+                    // The position points after the end of the changed text,
+                    // which means it's in a portion that's common to the
+                    // original and the transformed text. Translate between
+                    // the two.
+                    return offsets[1] + (transformedPosition - offsets[3]);
+                }
+            }
+        }
+
+        // The position is before any of the transformations, so the position
+        // is the same in the original and the transformed text.
+        return transformedPosition;
+    }
+
 	/*
 	 * 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
@@ -701,13 +886,20 @@ class CreateTriggerNode extends DDLState
      *   triggered SQL statement
      * @param offset the offset of the WHEN clause or the triggered SQL
      *   statement within the CREATE TRIGGER statement
+     * @param replacements list that will be populated with int arrays that
+     *   describe how the original text was transformed. The int arrays
+     *   contain the begin (inclusive) and end (exclusive) positions of the
+     *   original text that got replaced and of the replacement text, so that
+     *   positions in the transformed text can be mapped to positions in the
+     *   original text.
      * @return internal syntax for accessing before or after image of
      *   the changed rows
      * @throws StandardException if an error happens while performing the
      *   transformation
      */
     private String transformStatementTriggerText(
-            Visitable node, String originalText, int offset)
+            Visitable node, String originalText, int offset,
+            List<int[]> replacements)
         throws StandardException
     {
         int start = 0;
@@ -716,31 +908,20 @@ class CreateTriggerNode extends DDLState
         // For a statement trigger, we find all FromBaseTable nodes. If
         // the from table is NEW or OLD (or user designated alternates
         // REFERENCING), we turn them into a trigger table VTI.
-        CollectNodesVisitor<FromBaseTable> visitor =
-                new CollectNodesVisitor<FromBaseTable>(FromBaseTable.class);
-        node.accept(visitor);
-        List<FromBaseTable> tabs = visitor.getList();
-        Collections.sort(tabs, OFFSET_COMPARATOR);
-        for (FromBaseTable fromTable : tabs) {
+        for (FromBaseTable fromTable : getTransitionTables(node)) {
             String baseTableName = fromTable.getBaseTableName();
-            if (!isTransitionTable(fromTable)) {
-                // baseTableName is not the NEW or OLD table, so no need
-                // to do anything. Skip this table.
-                continue;
-            }
-
             int tokBeginOffset = fromTable.getTableNameField().getBeginOffset();
             int tokEndOffset = fromTable.getTableNameField().getEndOffset();
-            if (tokBeginOffset == -1) {
-                // Unknown offset. Skip this table.
-                continue;
-            }
+            int nextTokenStart = tokEndOffset - offset + 1;
 
             // Check if this transition table is allowed in this trigger type.
             checkInvalidTriggerReference(baseTableName);
 
-            // Replace the transition table name with a VTI.
+            // The text up to the transition table name should be kept.
             newText.append(originalText, start, tokBeginOffset - offset);
+
+            // Replace the transition table name with a VTI.
+            final int replacementOffset = newText.length();
             newText.append(baseTableName.equals(oldTableName)
                 ? "new org.apache.derby.catalog.TriggerOldTransitionRows() "
                 : "new org.apache.derby.catalog.TriggerNewTransitionRows() ");
@@ -752,15 +933,63 @@ class CreateTriggerNode extends DDLState
                 newText.append(baseTableName).append(' ');
             }
 
-            start = tokEndOffset - offset + 1;
+            // Record that we have made a change.
+            replacements.add(new int[] {
+                tokBeginOffset - offset,  // offset to original token
+                nextTokenStart,           // offset to next token
+                replacementOffset,        // offset to replacement
+                newText.length()          // offset to token after replacement
+            });
+
+            start = nextTokenStart;
         }
 
+        // Finally, add everything found after the last transition table
+        // unchanged.
         newText.append(originalText, start, originalText.length());
 
         return newText.toString();
     }
 
     /**
+     * Get all transition tables referenced by a given node, sorted in the
+     * order in which they appear in the SQL text.
+     *
+     * @param node the node in which to search for transition tables
+     * @return a sorted set of {@code FromBaseTable}s that represent
+     *   transition tables
+     * @throws StandardException if an error occurs
+     */
+    private SortedSet<FromBaseTable> getTransitionTables(Visitable node)
+            throws StandardException {
+
+        CollectNodesVisitor<FromBaseTable> visitor =
+                new CollectNodesVisitor<FromBaseTable>(FromBaseTable.class);
+        node.accept(visitor);
+
+        TreeSet<FromBaseTable> tables =
+                new TreeSet<FromBaseTable>(OFFSET_COMPARATOR);
+
+        for (FromBaseTable fbt : visitor.getList()) {
+            if (!isTransitionTable(fbt)) {
+                // The from table is not the NEW or OLD table, so no need
+                // to do anything. Skip this table.
+                continue;
+            }
+
+            int tokBeginOffset = fbt.getTableNameField().getBeginOffset();
+            if (tokBeginOffset == -1) {
+                // Unknown offset. Skip this table.
+                continue;
+            }
+
+            tables.add(fbt);
+        }
+
+        return tables;
+    }
+
+    /**
      * Check if a table represents one of the transition tables.
      *
      * @param fbt the table to check

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromBaseTable.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromBaseTable.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromBaseTable.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromBaseTable.java Wed Apr 30 09:05:23 2014
@@ -2335,6 +2335,8 @@ class FromBaseTable extends FromTable
 						   FromList fromListParam) 
 					throws StandardException
 	{
+        tableName.bind(dataDictionary);
+
         TableDescriptor tabDescr = bindTableDescriptor();
 
         if (tabDescr.getTableType() == TableDescriptor.VTI_TYPE) {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NextSequenceNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NextSequenceNode.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NextSequenceNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/NextSequenceNode.java Wed Apr 30 09:05:23 2014
@@ -87,6 +87,7 @@ class NextSequenceNode extends ValueNode
         }
 
         // lookup sequence object in the data dictionary
+        sequenceName.bind(getDataDictionary());
         SchemaDescriptor sd = getSchemaDescriptor(sequenceName.getSchemaName());
         sequenceDescriptor = getDataDictionary().getSequenceDescriptor(sd, sequenceName.getTableName());
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OffsetOrderVisitor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OffsetOrderVisitor.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OffsetOrderVisitor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/OffsetOrderVisitor.java Wed Apr 30 09:05:23 2014
@@ -37,7 +37,7 @@ import org.apache.derby.shared.common.sa
  *
  * @param <T> the type of nodes to collect
  */
-public class OffsetOrderVisitor<T extends QueryTreeNode> implements Visitor {
+class OffsetOrderVisitor<T extends QueryTreeNode> implements Visitor {
 
     /** Comparator that orders nodes by ascending begin offset. */
     private static final Comparator<QueryTreeNode>
@@ -61,7 +61,7 @@ public class OffsetOrderVisitor<T extend
      * @param low the lowest begin offset to accept (inclusive)
      * @param high the highest end offset to accept (exclusive)
      */
-    public OffsetOrderVisitor(Class<T> nodeClass, int low, int high) {
+    OffsetOrderVisitor(Class<T> nodeClass, int low, int high) {
         this.nodeClass = nodeClass;
         this.lowOffset = low;
         this.highOffset = high;
@@ -103,7 +103,7 @@ public class OffsetOrderVisitor<T extend
         return false;
     }
 
-    public SortedSet<T> getNodes() {
+    SortedSet<T> getNodes() {
         return nodes;
     }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/QueryTreeNode.java Wed Apr 30 09:05:23 2014
@@ -25,6 +25,7 @@ import java.sql.Types;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.SortedSet;
 import org.apache.derby.catalog.AliasInfo;
 import org.apache.derby.catalog.TypeDescriptor;
 import org.apache.derby.catalog.types.RowMultiSetImpl;
@@ -1569,15 +1570,22 @@ public abstract class QueryTreeNode impl
         }
     }
 
-}
-
-
-
-
-
-
-
-
-
-
+    /**
+     * Get all child nodes of a specific type, and return them in the order
+     * in which they appear in the SQL text.
+     *
+     * @param <N> the type of node to look for
+     * @param type the type of node to look for
+     * @return all nodes of the specified type
+     * @throws StandardException if an error occurs
+     */
+    public <N extends QueryTreeNode>
+        SortedSet<N> getOffsetOrderedNodes(Class<N> type)
+                throws StandardException {
+        OffsetOrderVisitor<N> visitor = new OffsetOrderVisitor<N>(
+                type, getBeginOffset(), getEndOffset() + 1);
+        accept(visitor);
+        return visitor.getNodes();
+    }
 
+}

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/StaticMethodCallNode.java Wed Apr 30 09:05:23 2014
@@ -246,6 +246,7 @@ class StaticMethodCallNode extends Metho
                 resolvedAggregate = new AggregateNode(
                      ((SQLToJavaValueNode) methodParms[ 0 ]).getSQLValueNode(),
                      new UserAggregateDefinition( ad ), 
+                     procedureName,
                      false,
                      ad.getJavaClassName(),
                      getContextManager()

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj Wed Apr 30 09:05:23 2014
@@ -2872,6 +2872,8 @@ Statement( String statementSQLText, Obje
 {
 	statementNode = StatementPart(null) <EOF>
 	{
+        statementNode.setBeginOffset(0);
+        statementNode.setEndOffset(statementSQLText.length() - 1);
 		return statementNode;
 	}
 }
@@ -2892,6 +2894,8 @@ SearchCondition(String sqlFragment) thro
 {
     valueNode = valueExpression() <EOF>
     {
+        valueNode.setBeginOffset(0);
+        valueNode.setEndOffset(sqlFragment.length() - 1);
         return valueNode;
     }
 }
@@ -11219,6 +11223,8 @@ triggerDefinition() throws StandardExcep
 	{
 		actionEnd = getToken(0).endOffset;
 		actionBegin = tokenHolder[0].beginOffset;
+        actionNode.setBeginOffset(actionBegin);
+        actionNode.setEndOffset(actionEnd);
 
 		// No DML in action node for BEFORE triggers.
 		if (isBefore.booleanValue() && (actionNode instanceof DMLModStatementNode)) {
@@ -11249,6 +11255,8 @@ triggerDefinition() throws StandardExcep
             // 10.11 or higher.
             checkVersion(DataDictionary.DD_VERSION_DERBY_10_11, "WHEN");
             whenOffset = whenOpen.endOffset + 1;
+            whenClause.setBeginOffset(whenOffset);
+            whenClause.setEndOffset(whenClose.beginOffset - 1);
             whenText = StringUtil.slice(statementSQLText,
                     whenOffset, whenClose.beginOffset - 1, false);
         }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/AlterTableConstantAction.java Wed Apr 30 09:05:23 2014
@@ -1916,7 +1916,8 @@ class AlterTableConstantAction extends D
 				0,
 				trd.getTableDescriptor(),
 				trd.getTriggerEventMask(),
-                true);
+                true,
+                null);
 
             if (isWhenClause) {
                 // The WHEN clause is not a full SQL statement, just a search

Modified: db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java (original)
+++ db/derby/code/trunk/java/storeless/org/apache/derby/impl/storeless/EmptyDictionary.java Wed Apr 30 09:05:23 2014
@@ -517,7 +517,8 @@ public class EmptyDictionary implements 
 			int actionOffset,
 			TableDescriptor td,
 			int triggerEventMask,
-			boolean createTriggerTime)
+            boolean createTriggerTime,
+            List<int[]> replacements)
 	throws StandardException {
 		// Auto-generated method stub
 		return null;

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net.out?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net.out Wed Apr 30 09:05:23 2014
@@ -1881,7 +1881,7 @@ APP
 APP
 T
 <validityflag>
-insert into removed select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
+insert into "APP"."REMOVED" select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
 <systemid>
 APP
 null
@@ -1891,7 +1891,7 @@ null
 APP
 T
 <validityflag>
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 <systemid>
 APP
 null
@@ -1901,7 +1901,7 @@ null
 APP
 T
 <validityflag>
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 <systemid>
 APP
 null
@@ -2237,7 +2237,7 @@ X
 null
 <systemid>
 (1)
-insert into removed select * from old where x not in (select x from new where x < 10)
+insert into "APP"."REMOVED" select * from old where x not in (select x from new where x < 10)
 true
 true
 OLD
@@ -2256,7 +2256,7 @@ T3
 null
 <systemid>
 null
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 false
 false
 null
@@ -2294,7 +2294,7 @@ tWithKeys
 null
 <systemid>
 (1,2)
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 false
 false
 null

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net_territory.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net_territory.out?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net_territory.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/dblook_test_net_territory.out Wed Apr 30 09:05:23 2014
@@ -1881,7 +1881,7 @@ APP
 APP
 T
 <validityflag>
-insert into removed select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
+insert into "APP"."REMOVED" select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
 <systemid>
 APP
 null
@@ -1891,7 +1891,7 @@ null
 APP
 T
 <validityflag>
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 <systemid>
 APP
 null
@@ -1901,7 +1901,7 @@ null
 APP
 T
 <validityflag>
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 <systemid>
 APP
 null
@@ -2237,7 +2237,7 @@ X
 null
 <systemid>
 (1)
-insert into removed select * from old where x not in (select x from new where x < 10)
+insert into "APP"."REMOVED" select * from old where x not in (select x from new where x < 10)
 true
 true
 OLD
@@ -2256,7 +2256,7 @@ T3
 null
 <systemid>
 null
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 false
 false
 null
@@ -2294,7 +2294,7 @@ tWithKeys
 null
 <systemid>
 (1,2)
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 false
 false
 null

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test.out?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test.out Wed Apr 30 09:05:23 2014
@@ -1874,7 +1874,7 @@ APP
 APP
 T
 <validityflag>
-insert into removed select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
+insert into "APP"."REMOVED" select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
 <systemid>
 APP
 null
@@ -1884,7 +1884,7 @@ null
 APP
 T
 <validityflag>
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 <systemid>
 APP
 null
@@ -1894,7 +1894,7 @@ null
 APP
 T
 <validityflag>
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 <systemid>
 APP
 null
@@ -2230,7 +2230,7 @@ X
 null
 <systemid>
 (1)
-insert into removed select * from old where x not in (select x from new where x < 10)
+insert into "APP"."REMOVED" select * from old where x not in (select x from new where x < 10)
 true
 true
 OLD
@@ -2249,7 +2249,7 @@ T3
 null
 <systemid>
 null
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 false
 false
 null
@@ -2287,7 +2287,7 @@ tWithKeys
 null
 <systemid>
 (1,2)
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 false
 false
 null
@@ -4238,7 +4238,7 @@ APP
 APP
 T
 <validityflag>
-insert into removed select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
+insert into "APP"."REMOVED" select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
 <systemid>
 APP
 null
@@ -4248,7 +4248,7 @@ null
 APP
 T
 <validityflag>
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 <systemid>
 APP
 null
@@ -4258,7 +4258,7 @@ null
 APP
 T
 <validityflag>
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 <systemid>
 APP
 null
@@ -4594,7 +4594,7 @@ X
 null
 <systemid>
 (1)
-insert into removed select * from old where x not in (select x from new where x < 10)
+insert into "APP"."REMOVED" select * from old where x not in (select x from new where x < 10)
 true
 true
 OLD
@@ -4613,7 +4613,7 @@ T3
 null
 <systemid>
 null
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 false
 false
 null
@@ -4651,7 +4651,7 @@ tWithKeys
 null
 <systemid>
 (1,2)
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 false
 false
 null
@@ -6337,8 +6337,8 @@ SET SCHEMA "APP"
 -- ----------------------------------------------
 -- DDL Statements for triggers
 -- ----------------------------------------------
-CREATE TRIGGER "APP"."TRIGONE" AFTER INSERT ON "BAR"."T1" FOR EACH ROW update bar.t1 set i = 4 where i = 2
-CREATE TRIGGER "APP"."TRIGTWO" AFTER INSERT ON "BAR"."T1" REFERENCING NEW AS NEW FOR EACH ROW WHEN (new.i > 4) delete from bar.t1 where i = 2
+CREATE TRIGGER "APP"."TRIGONE" AFTER INSERT ON "BAR"."T1" FOR EACH ROW update "BAR"."T1" set i = 4 where i = 2
+CREATE TRIGGER "APP"."TRIGTWO" AFTER INSERT ON "BAR"."T1" REFERENCING NEW AS NEW FOR EACH ROW WHEN (new.i > 4) delete from "BAR"."T1" where i = 2
 ############## End File Contents ################
 File dblook.log was empty.
 ************
@@ -6500,8 +6500,8 @@ SET SCHEMA "APP" #
 -- ----------------------------------------------
 -- DDL Statements for triggers
 -- ----------------------------------------------
-CREATE TRIGGER "APP"."TRIGONE" AFTER INSERT ON "BAR"."T1" FOR EACH ROW update bar.t1 set i = 4 where i = 2 #
-CREATE TRIGGER "APP"."TRIGTWO" AFTER INSERT ON "BAR"."T1" REFERENCING NEW AS NEW FOR EACH ROW WHEN (new.i > 4) delete from bar.t1 where i = 2 #
+CREATE TRIGGER "APP"."TRIGONE" AFTER INSERT ON "BAR"."T1" FOR EACH ROW update "BAR"."T1" set i = 4 where i = 2 #
+CREATE TRIGGER "APP"."TRIGTWO" AFTER INSERT ON "BAR"."T1" REFERENCING NEW AS NEW FOR EACH ROW WHEN (new.i > 4) delete from "BAR"."T1" where i = 2 #
 ************
 Msg Test 5
 ************
@@ -6534,17 +6534,17 @@ CREATE TABLE "APP"."T1" ("X" INTEGER)
 -- ----------------------------------------------
 -- DDL Statements for triggers
 -- ----------------------------------------------
-CREATE TRIGGER "APP"."TR13" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR14" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR15" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR16" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR17" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR18" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR19" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR20" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR21" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR22" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR23" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR24" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR13" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR14" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR15" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR16" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR17" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR18" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR19" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR20" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR21" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR22" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR23" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR24" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
 ############## End File Contents ################
 [ Done. ]

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test_territory.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test_territory.out?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test_territory.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/dblook_test_territory.out Wed Apr 30 09:05:23 2014
@@ -1874,7 +1874,7 @@ APP
 APP
 T
 <validityflag>
-insert into removed select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
+insert into "APP"."REMOVED" select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
 <systemid>
 APP
 null
@@ -1884,7 +1884,7 @@ null
 APP
 T
 <validityflag>
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 <systemid>
 APP
 null
@@ -1894,7 +1894,7 @@ null
 APP
 T
 <validityflag>
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 <systemid>
 APP
 null
@@ -2230,7 +2230,7 @@ X
 null
 <systemid>
 (1)
-insert into removed select * from old where x not in (select x from new where x < 10)
+insert into "APP"."REMOVED" select * from old where x not in (select x from new where x < 10)
 true
 true
 OLD
@@ -2249,7 +2249,7 @@ T3
 null
 <systemid>
 null
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 false
 false
 null
@@ -2287,7 +2287,7 @@ tWithKeys
 null
 <systemid>
 (1,2)
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 false
 false
 null
@@ -4238,7 +4238,7 @@ APP
 APP
 T
 <validityflag>
-insert into removed select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
+insert into "APP"."REMOVED" select * from new org.apache.derby.catalog.TriggerOldTransitionRows() OLD  where x not in (select x from new org.apache.derby.catalog.TriggerNewTransitionRows() NEW  where x < 10)
 <systemid>
 APP
 null
@@ -4248,7 +4248,7 @@ null
 APP
 T
 <validityflag>
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 <systemid>
 APP
 null
@@ -4258,7 +4258,7 @@ null
 APP
 T
 <validityflag>
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 <systemid>
 APP
 null
@@ -4594,7 +4594,7 @@ X
 null
 <systemid>
 (1)
-insert into removed select * from old where x not in (select x from new where x < 10)
+insert into "APP"."REMOVED" select * from old where x not in (select x from new where x < 10)
 true
 true
 OLD
@@ -4613,7 +4613,7 @@ T3
 null
 <systemid>
 null
-update bar.t4 set j=8 where i=2
+update "BAR"."T4" set j=8 where i=2
 false
 false
 null
@@ -4651,7 +4651,7 @@ tWithKeys
 null
 <systemid>
 (1,2)
-select c from bar."tWithKeys"
+select c from "BAR"."tWithKeys"
 false
 false
 null
@@ -6337,8 +6337,8 @@ SET SCHEMA "APP"
 -- ----------------------------------------------
 -- DDL Statements for triggers
 -- ----------------------------------------------
-CREATE TRIGGER "APP"."TRIGONE" AFTER INSERT ON "BAR"."T1" FOR EACH ROW update bar.t1 set i = 4 where i = 2
-CREATE TRIGGER "APP"."TRIGTWO" AFTER INSERT ON "BAR"."T1" REFERENCING NEW AS NEW FOR EACH ROW WHEN (new.i > 4) delete from bar.t1 where i = 2
+CREATE TRIGGER "APP"."TRIGONE" AFTER INSERT ON "BAR"."T1" FOR EACH ROW update "BAR"."T1" set i = 4 where i = 2
+CREATE TRIGGER "APP"."TRIGTWO" AFTER INSERT ON "BAR"."T1" REFERENCING NEW AS NEW FOR EACH ROW WHEN (new.i > 4) delete from "BAR"."T1" where i = 2
 ############## End File Contents ################
 File dblook.log was empty.
 ************
@@ -6500,8 +6500,8 @@ SET SCHEMA "APP" #
 -- ----------------------------------------------
 -- DDL Statements for triggers
 -- ----------------------------------------------
-CREATE TRIGGER "APP"."TRIGONE" AFTER INSERT ON "BAR"."T1" FOR EACH ROW update bar.t1 set i = 4 where i = 2 #
-CREATE TRIGGER "APP"."TRIGTWO" AFTER INSERT ON "BAR"."T1" REFERENCING NEW AS NEW FOR EACH ROW WHEN (new.i > 4) delete from bar.t1 where i = 2 #
+CREATE TRIGGER "APP"."TRIGONE" AFTER INSERT ON "BAR"."T1" FOR EACH ROW update "BAR"."T1" set i = 4 where i = 2 #
+CREATE TRIGGER "APP"."TRIGTWO" AFTER INSERT ON "BAR"."T1" REFERENCING NEW AS NEW FOR EACH ROW WHEN (new.i > 4) delete from "BAR"."T1" where i = 2 #
 ************
 Msg Test 5
 ************
@@ -6534,17 +6534,17 @@ CREATE TABLE "APP"."T1" ("X" INTEGER)
 -- ----------------------------------------------
 -- DDL Statements for triggers
 -- ----------------------------------------------
-CREATE TRIGGER "APP"."TR13" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR14" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR15" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR16" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR17" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR18" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR19" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR20" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR21" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR22" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR23" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
-CREATE TRIGGER "APP"."TR24" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from sys.systables natural join sys.sysschemas where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR13" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR14" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR15" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR16" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR17" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR18" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR19" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR20" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR21" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR22" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR23" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
+CREATE TRIGGER "APP"."TR24" AFTER UPDATE ON "APP"."T1" REFERENCING NEW_TABLE AS NEW FOR EACH STATEMENT select * from "SYS"."SYSTABLES" natural join "SYS"."SYSSCHEMAS" where exists(select * from new where x > 100)
 ############## End File Contents ################
 [ Done. ]

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/derived.out
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/derived.out?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/derived.out (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/derived.out Wed Apr 30 09:05:23 2014
@@ -31,9 +31,9 @@ ij> -- tests without a derived table
 -- negative tests
 -- # of columns does not match
 select aa from s ss (aa);
-ERROR 42X32: The number of columns in the derived column list must match the number of columns in table 'S'.
+ERROR 42X32: The number of columns in the derived column list must match the number of columns in table 'APP.S'.
 ij> select aa from s ss (aa, bb, cc, dd, ee, ff, gg);
-ERROR 42X32: The number of columns in the derived column list must match the number of columns in table 'S'.
+ERROR 42X32: The number of columns in the derived column list must match the number of columns in table 'APP.S'.
 ij> -- duplicate names in derived column list
 select aa from s ss (aa, ee, bb, cc, dd, aa);
 ERROR 42X33: The derived column list contains a duplicate column name 'AA'.

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerGeneralTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerGeneralTest.java?rev=1591216&r1=1591215&r2=1591216&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerGeneralTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/TriggerGeneralTest.java Wed Apr 30 09:05:23 2014
@@ -653,7 +653,7 @@ public final class TriggerGeneralTest ex
         rs.next();
         assertEquals("tt1       ", rs.getString(1));
         assertEquals(
-            "insert into trighistory (\"cOlUmN1\", \"cOlUmN2  \", " +
+            "insert into \"APP\".\"TRIGHISTORY\" (\"cOlUmN1\", \"cOlUmN2  \", " +
                 "\"cOlUmN3\"\"\"\"  \") " +
             "values (new.\"cOlUmN1\" + 5, \"NEW\".\"cOlUmN2  \" * "
                 + "new.\"cOlUmN3\"\"\"\"  \", 5)",
@@ -694,7 +694,7 @@ public final class TriggerGeneralTest ex
 
         rs.next();
         assertEquals("tt1       ", rs.getString(1));
-        assertEquals("insert into trighistory (\"cOlUmN1\", \"cOlUmN2 "
+        assertEquals("insert into \"APP\".\"TRIGHISTORY\" (\"cOlUmN1\", \"cOlUmN2 "
                 + " \", \"cOlUmN3\"\"\"\"  \") values "
                 + "(new.\"cOlUmN1\" + new.\"cOlUmN1\", "
                 + "\"NEW\".\"cOlUmN2  \" * new.\"cOlUmN3\"\"\"\"  "

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=1591216&r1=1591215&r2=1591216&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 Wed Apr 30 09:05:23 2014
@@ -2436,4 +2436,113 @@ public class TriggerTest extends BaseJDB
                 s.executeQuery("select * from d6543_2 order by x"),
                 new String[][] { {"1"}, {"2"}, {"2"}, {"2"}, {"2"}, {"3"} });
     }
+
+    /**
+     * DERBY-6370: Test that trigger actions are stored with qualified names
+     * in SYSTRIGGERS and SYSSTATEMENTS.
+     */
+    public void testQualifiedNamesInSystemTables() throws SQLException {
+        Statement s = createStatement();
+        s.execute("create schema d6370");
+        s.execute("set schema d6370");
+        s.execute("create table t1(x int, y int, z int)");
+        s.execute("create table t2(x int, y int, z int)");
+        s.execute("create table t3(x int, y int, z int)");
+        s.execute("create table syn_table(x int, y int, z int)");
+        s.execute("create table view_table(x int, y int, z int)");
+
+        s.execute("create function f(x int) returns int language java "
+                + "parameter style java external name 'java.lang.Math.abs'");
+        s.execute("create procedure p() language java parameter style java "
+                + "external name '" + getClass().getName()
+                + ".dummyProc' no sql");
+        s.execute("create function tf() returns table (x int) "
+                + "language java parameter style derby_jdbc_result_set "
+                + "external name '" + getClass().getName()
+                + ".dummyTableFunction' no sql");
+        s.execute("create derby aggregate intmode for int external name '"
+                + ModeAggregate.class.getName() + "'");
+        s.execute("create sequence seq");
+        s.execute("create synonym syn for syn_table");
+        s.execute("create view v(x) as select x from view_table");
+        s.execute("create type tp external name 'java.util.List' language java");
+        s.execute("create table tp_t1(x tp)");
+        s.execute("create table tp_t2(x tp)");
+
+        // Create triggers referencing all of the objects above.
+        s.execute("create trigger tr01 no cascade before insert on t1 "
+                + "when (exists(select f(y) from v join t1 t on v.x = t.x)) "
+                + "call p()");
+        s.execute("create trigger tr02 after insert on t1 "
+                + "when (exists(select * from table(tf()) t)) "
+                + "insert into t2(z) select 1 from t1");
+        s.execute("create trigger tr03 after delete on t1 "
+                + "insert into t2(z) select intmode(x) from syn");
+        s.execute("create trigger tr04 after insert on tp_t1 "
+                + "referencing new as new for each row "
+                + "insert into tp_t2 values new.x, cast(null as tp)");
+        s.execute("create trigger tr05 after insert on t1 "
+                + "referencing new table as new "
+                + "when (next value for seq < 1000) "
+                + "insert into t2(y) select a.z from new a, t1 b, new c, t1 d");
+
+        // Table names in the SET clause of an UPDATE statement don't get
+        // qualified because of oddities in the way such statements are
+        // bound. Probably related to DERBY-6558.
+        s.execute("create trigger tr06 after insert on t1 "
+                + "update t2 set t2.x = t2.y");
+        // Same with target columns in INSERT statements.
+        s.execute("create trigger tr07 after insert on t1 "
+                + "insert into t2 (t2.x, t2.y) values (1, default)");
+
+        s.execute("create trigger tr08 after update on t1 "
+                + "delete from t2 where t2.x = t2.y");
+        s.execute("create trigger tr09 after delete on t1 "
+                + "merge into t2 using t3 on t2.x = t3.x "
+                + "when matched and t3.y = 5 then update set t2.x = t3.y "
+                + "when not matched then insert values (t3.x, t3.y, t3.z)");
+        s.execute("create trigger tr10 after insert on t1 "
+                + "referencing new as new for each row update t2 set x = "
+                + "(select count(*) from t1 where new.x = t2.x)");
+
+        // Now create two triggers that both reference the SIN function
+        // without specifying the schema. Create a SIN function in the
+        // current schema between the creation of the two triggers. The
+        // first trigger should reference SYSFUN.SIN, and the second one
+        // should reference D6370.SIN. See also DERBY-5901.
+        s.execute("create trigger tr11 after insert on t1 for each row "
+                + "values sin(0)");
+        s.execute("create function sin(x double) returns double language java "
+                + "parameter style java external name 'java.lang.Math.sin'");
+        s.execute("create trigger tr12 after insert on t1 for each row "
+                + "values sin(0)");
+
+        String[][] expectedRows = {
+            {"TR01", "exists(select \"D6370\".\"F\"(y) from \"D6370\".\"V\" join \"D6370\".\"T1\" t on \"V\".x = \"T\".x)", "VALUES exists(select \"D6370\".\"F\"(y) from \"D6370\".\"V\" join \"D6370\".\"T1\" t on \"V\".x = \"T\".x)", "call \"D6370\".\"P\"()", "call \"D6370\".\"P\"()"},
+            {"TR02", "exists(select * from table(\"D6370\".\"TF\"()) t)", "VALUES exists(select * from table(\"D6370\".\"TF\"()) t)", "insert into \"D6370\".\"T2\"(z) select 1 from \"D6370\".\"T1\"", "insert into \"D6370\".\"T2\"(z) select 1 from \"D6370\".\"T1\""},
+            {"TR03", null, null, "insert into \"D6370\".\"T2\"(z) select \"D6370\".\"INTMODE\"(x) from \"D6370\".\"SYN\"", "insert into \"D6370\".\"T2\"(z) select \"D6370\".\"INTMODE\"(x) from \"D6370\".\"SYN\""},
+            {"TR04", null, null, "insert into \"D6370\".\"TP_T2\" values new.x, cast(null as \"D6370\".\"TP\")", "insert into \"D6370\".\"TP_T2\" values CAST (org.apache.derby.iapi.db.Factory::getTriggerExecutionContext().getNewRow().getObject(1) AS \"D6370\".\"TP\") , cast(null as \"D6370\".\"TP\")"},
+            {"TR05", "next value for \"D6370\".\"SEQ\" < 1000", "VALUES next value for \"D6370\".\"SEQ\" < 1000", "insert into \"D6370\".\"T2\"(y) select \"A\".z from new a, \"D6370\".\"T1\" b, new c, \"D6370\".\"T1\" d", "insert into \"D6370\".\"T2\"(y) select \"A\".z from new org.apache.derby.catalog.TriggerNewTransitionRows()  a, \"D6370\".\"T1\" b, new org.apache.derby.catalog.TriggerNewTransitionRows()  c, \"D6370\".\"T1\" d"},
+            {"TR06", null, null, "update \"D6370\".\"T2\" set t2.x = \"T2\".y", "update \"D6370\".\"T2\" set t2.x = \"T2\".y"},
+            {"TR07", null, null, "insert into \"D6370\".\"T2\" (t2.x, t2.y) values (1, default)", "insert into \"D6370\".\"T2\" (t2.x, t2.y) values (1, default)"},
+            {"TR08", null, null, "delete from \"D6370\".\"T2\" where \"D6370\".\"T2\".x = \"D6370\".\"T2\".y", "delete from \"D6370\".\"T2\" where \"D6370\".\"T2\".x = \"D6370\".\"T2\".y"},
+            {"TR09", null, null, "merge into \"D6370\".\"T2\" using \"D6370\".\"T3\" on \"D6370\".\"T2\".x = \"D6370\".\"T3\".x when matched and \"D6370\".\"T3\".y = 5 then update set t2.x = \"D6370\".\"T3\".y when not matched then insert values (\"D6370\".\"T3\".x, \"D6370\".\"T3\".y, \"D6370\".\"T3\".z)", "merge into \"D6370\".\"T2\" using \"D6370\".\"T3\" on \"D6370\".\"T2\".x = \"D6370\".\"T3\".x when matched and \"D6370\".\"T3\".y = 5 then update set t2.x = \"D6370\".\"T3\".y when not matched then insert values (\"D6370\".\"T3\".x, \"D6370\".\"T3\".y, \"D6370\".\"T3\".z)"},
+            {"TR10", null, null, "update \"D6370\".\"T2\" set x = (select count(*) from \"D6370\".\"T1\" where new.x = \"D6370\".\"T2\".x)", "update \"D6370\".\"T2\" set x = (select count(*) from \"D6370\".\"T1\" where CAST (org.apache.derby.iapi.db.Factory::getTriggerExecutionContext().getNewRow().getObject(1) AS INTEGER)  = \"D6370\".\"T2\".x)"},
+            {"TR11", null, null, "values \"SYSFUN\".\"SIN\"(0)", "values \"SYSFUN\".\"SIN\"(0)"},
+            {"TR12", null, null, "values \"D6370\".\"SIN\"(0)", "values \"D6370\".\"SIN\"(0)"},
+        };
+        ResultSet rs = s.executeQuery(
+                "select triggername, whenclausetext, "
+                + "s1.text, triggerdefinition, s2.text "
+                + "from sys.systriggers join sys.sysschemas using (schemaid) "
+                + "left join sys.sysstatements s1 on whenstmtid = stmtid "
+                + "join sys.sysstatements s2 on actionstmtid = s2.stmtid "
+                + "where schemaname = 'D6370' order by triggername");
+        JDBC.assertFullResultSet(rs, expectedRows);
+
+        // Fire the triggers.
+        // disabled due to DERBY-6554
+        //s.execute("insert into t1 values (1,2,3)");
+        s.execute("insert into tp_t1 values cast(null as tp)");
+    }
 }