db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
Subject svn commit: r1571808 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/compile/ engine/org/apache/derby/impl/sql/compile/ testing/org/apache/derbyTesting/functionTests/tests/lang/
Date Tue, 25 Feb 2014 20:13:01 GMT
Author: rhillegas
Date: Tue Feb 25 20:13:00 2014
New Revision: 1571808

URL: http://svn.apache.org/r1571808
Log:
DERBY-3155: More improvements to column resolution in MERGE statements; tests passed cleanly
for me on derby-3155-30-ab-moreCorrelationNames.diff.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/TagFilter.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.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/FromList.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/TagFilter.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/TagFilter.java?rev=1571808&r1=1571807&r2=1571808&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/TagFilter.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/compile/TagFilter.java Tue Feb
25 20:13:00 2014
@@ -40,6 +40,9 @@ public class TagFilter implements Visita
     /** Tag placed on QueryTreeNodes which need privilege checks for UPDATE statements */
     public  static  final   String      NEED_PRIVS_FOR_UPDATE_STMT = "updatePrivs";
 
+    /** Tag placed on the original ColumnReferences in an UPDATE, before unreferenced columns
are added */
+    public  static  final   String      ORIG_UPDATE_COL = "origUpdateCol";
+
     ///////////////////////////////////////////////////////////////////////////
     //
     //  STATE

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java?rev=1571808&r1=1571807&r2=1571808&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ColumnReference.java
Tue Feb 25 20:13:00 2014
@@ -113,7 +113,7 @@ public class ColumnReference extends Val
      * the SOURCE or TARGET table */
     private int _mergeTableID = MERGE_UNKNOWN;
 
-	/**
+    /**
      * Constructor.
 	 * This one is called by the parser where we could
 	 * be dealing with delimited identifiers.
@@ -352,7 +352,7 @@ public class ColumnReference extends Val
 	{
 		super.copyFields(oldCR);
 
-		_qualifiedTableName = oldCR.getQualifiedTableName();
+		setQualifiedTableName( oldCR.getQualifiedTableName() );
 		tableNumber = oldCR.getTableNumber();
 		columnNumber = oldCR.getColumnNumber();
 		source = oldCR.getSource();
@@ -1309,7 +1309,7 @@ public class ColumnReference extends Val
         super.acceptChildren(v);
 
         if (_qualifiedTableName != null) {
-            _qualifiedTableName = (TableName) _qualifiedTableName.accept(v);
+            setQualifiedTableName( (TableName) _qualifiedTableName.accept(v) );
         }
     }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java?rev=1571808&r1=1571807&r2=1571808&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModStatementNode.java
Tue Feb 25 20:13:00 2014
@@ -376,6 +376,10 @@ abstract class DMLModStatementNode exten
                 null,
                 null,
                 getContextManager());
+        if ( inMatchingClause() )
+        {
+            fbt.setMergeTableID( ColumnReference.MERGE_TARGET );
+        }
 
 		fbt.bindNonVTITables(
 			getDataDictionary(),

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=1571808&r1=1571807&r2=1571808&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 Tue
Feb 25 20:13:00 2014
@@ -3954,7 +3954,6 @@ class FromBaseTable extends FromTable
 			throws StandardException
 	{
 		ResultColumn	 			resultColumn;
-		ValueNode		 			valueNode;
 		TableName		 			exposedName;
 
 		/* Cache exposed name for this table.
@@ -3981,11 +3980,16 @@ class FromBaseTable extends FromTable
 
 			if ((resultColumn = inputRcl.getResultColumn(position)) == null)
 			{	
-                valueNode = new ColumnReference(cd.getColumnName(),
+                ColumnReference cr = new ColumnReference(cd.getColumnName(),
 												exposedName,
 												getContextManager());
+                if ( (getMergeTableID() != ColumnReference.MERGE_UNKNOWN ) )
+                {
+                    cr.setMergeTableID( getMergeTableID() );
+                }
+
                 resultColumn =
-                        new ResultColumn(cd, valueNode, getContextManager());
+                        new ResultColumn(cd, cr, getContextManager());
 			}
 
 			/* Build the ResultColumnList to return */

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java?rev=1571808&r1=1571807&r2=1571808&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromList.java Tue Feb
25 20:13:00 2014
@@ -340,21 +340,27 @@ class FromList extends    QueryTreeNodeV
 		for (int index = 0; index < size; index++)
 		{
 			fromTable = (FromTable) elementAt(index);
-			ResultSetNode newNode = fromTable.bindNonVTITables(dataDictionary, fromListParam);
+			FromTable   newNode = (FromTable) fromTable.bindNonVTITables(dataDictionary, fromListParam);
 			// If the fromTable is a view in the SESSION schema, then we need to save that information
 			// in referencesSessionSchema element. The reason for this is that the view will get
 			// replaced by it's view definition and we will loose the information that the statement
 			// was referencing a SESSION schema object. 
 			if (fromTable.referencesSessionSchema())
+            {
 				referencesSessionSchema = true;
+            }
+            newNode.setMergeTableID( fromTable.getMergeTableID() );
 			setElementAt(newNode, index);
 		}
 		for (int index = 0; index < size; index++)
 		{
 			fromTable = (FromTable) elementAt(index);
-			ResultSetNode newNode = fromTable.bindVTITables(fromListParam);
+			FromTable   newNode = (FromTable) fromTable.bindVTITables(fromListParam);
 			if (fromTable.referencesSessionSchema())
+            {
 				referencesSessionSchema = true;
+            }
+            newNode.setMergeTableID( fromTable.getMergeTableID() );
 			setElementAt(newNode, index);
 		}
 
@@ -637,6 +643,20 @@ class FromList extends    QueryTreeNodeV
 		{
 			fromTable = (FromTable) elementAt(index);
 
+            //
+            // If the MERGE statement has marked its variables, we expect to follow
+            // its judgment. Make sure that we only match SOURCE columns to
+            // SOURCE tables and TARGET columns to TARGET tables.
+            //
+            if (
+                (fromTable.getMergeTableID() != ColumnReference.MERGE_UNKNOWN) &&
+                (columnReference.getMergeTableID() != ColumnReference.MERGE_UNKNOWN) &&
+                (fromTable.getMergeTableID() != columnReference.getMergeTableID())
+                )
+            {
+                continue;
+            }
+
 			/* We can stop if we've found a matching column or table name 
 			 * at the previous nesting level.
 			 */

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java?rev=1571808&r1=1571807&r2=1571808&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/FromTable.java Tue Feb
25 20:13:00 2014
@@ -108,6 +108,9 @@ abstract class FromTable extends ResultS
 
 	/** the original unbound table name */
 	protected TableName origTableName;
+
+    /** for resolving column references in MERGE statements in tough cases*/
+    private int _mergeTableID = ColumnReference.MERGE_UNKNOWN;
 	
 	/**
      * Constructor for a table in a FROM list.
@@ -1168,10 +1171,16 @@ abstract class FromTable extends ResultS
                     exposedName = oldCR.getQualifiedTableName();
                 }
             }
+
+            ColumnReference newCR = new ColumnReference(rc.getName(), exposedName, cm);
+            if ( (oldCR != null ) && (oldCR.getMergeTableID() != ColumnReference.MERGE_UNKNOWN
) )
+            {
+                newCR.setMergeTableID( oldCR.getMergeTableID() );
+            }
             
             ResultColumn newRc = new ResultColumn(
                     rc.getName(),
-                    new ColumnReference(rc.getName(), exposedName, cm),
+                    newCR,
                     cm);
 
             rcList.addResultColumn(newRc);
@@ -1539,6 +1548,12 @@ abstract class FromTable extends ResultS
 		return this.origTableName;
 	}
 
+    /** set the merge table id */
+    void    setMergeTableID( int mergeTableID ) { _mergeTableID = mergeTableID; }
+
+    /** get the merge table id */
+    int     getMergeTableID() { return _mergeTableID; }
+
     @Override
     void acceptChildren(Visitor v) throws StandardException {
         super.acceptChildren(v);

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java?rev=1571808&r1=1571807&r2=1571808&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MatchingClauseNode.java
Tue Feb 25 20:13:00 2014
@@ -209,7 +209,7 @@ public class MatchingClauseNode extends 
         _thenColumns = new ResultColumnList( getContextManager() );
 
         if ( isDeleteClause() ) { bindDelete( dd, fullFromList, targetTable ); }
-        if ( isUpdateClause() ) { bindUpdate( dd, fullFromList, targetTable ); }
+        if ( isUpdateClause() ) { bindUpdate( dd, mergeNode, fullFromList, targetTable );
}
         if ( isInsertClause() ) { bindInsert( dd, mergeNode, fullFromList, targetTable );
}
     }
 
@@ -272,6 +272,11 @@ public class MatchingClauseNode extends 
                 mergeNode.getColumnsInExpression( drivingColumnMap, rc.getExpression(), ColumnReference.MERGE_UNKNOWN
);
             }
         }
+        else if ( isDeleteClause() )
+        {
+            // add all of the THEN columns
+            mergeNode.getColumnsFromList( drivingColumnMap, _thenColumns, ColumnReference.MERGE_TARGET
);
+        }
     }
     
     ////////////////////// UPDATE ///////////////////////////////
@@ -280,17 +285,18 @@ public class MatchingClauseNode extends 
     private void    bindUpdate
         (
          DataDictionary dd,
+         MergeNode  mergeNode,
          FromList fullFromList,
          FromBaseTable targetTable
          )
         throws StandardException
     {
         ResultColumnList    setClauses = realiasSetClauses( targetTable );
-        bindSetClauses( fullFromList, targetTable, setClauses );
+        bindSetClauses( mergeNode, fullFromList, targetTable, setClauses );
 
         TableName   tableName = targetTable.getTableNameField();
         FromList    selectFromList = fullFromList;
-        
+
         SelectNode  selectNode = new SelectNode
             (
              setClauses,
@@ -401,6 +407,7 @@ public class MatchingClauseNode extends 
     /** Bind the SET clauses of an UPDATE action */
     private void    bindSetClauses
         (
+         MergeNode mergeNode,
          FromList fullFromList,
          FromTable targetTable,
          ResultColumnList   setClauses
@@ -411,6 +418,27 @@ public class MatchingClauseNode extends 
         setClauses.replaceOrForbidDefaults( targetTable.getTableDescriptor(), _updateColumns,
true );
 
         bindExpressions( setClauses, fullFromList );
+
+        //
+        // For column resolution later on, columns on the left side
+        // of SET operators are associated with the TARGET table.
+        //
+        for ( int i = 0; i < _updateColumns.size(); i++ )
+        {
+            ResultColumn    rc = _updateColumns.elementAt( i );
+            ColumnReference  cr = rc.getReference();
+            cr.setMergeTableID( ColumnReference.MERGE_TARGET );
+        }
+
+        // Now associate the columns on the right side of SET operators.
+        CollectNodesVisitor<ColumnReference> getCRs =
+            new CollectNodesVisitor<ColumnReference>(ColumnReference.class);
+        _updateColumns.accept(getCRs);
+        List<ColumnReference> colRefs = getCRs.getList();
+        for ( ColumnReference cr : colRefs )
+        {
+            mergeNode.associateColumn( fullFromList, cr, ColumnReference.MERGE_UNKNOWN );
+        }
     }
 
     /**
@@ -738,7 +766,7 @@ public class MatchingClauseNode extends 
      * action.
      * </p>
      */
-    void    bindDeleteThenColumns( ResultColumnList selectList )
+    private void    bindDeleteThenColumns( ResultColumnList selectList )
         throws StandardException
     {
         int     bufferedCount = _thenColumns.size();
@@ -1115,7 +1143,11 @@ public class MatchingClauseNode extends 
             
             if (SanityManager.DEBUG)
             {
-                SanityManager.THROWASSERT( "Can't find select list column corresponding to
" + bufferedCR.getSQLColumnName() );
+                SanityManager.THROWASSERT
+                    (
+                     "Can't find select list column corresponding to " + bufferedCR.getSQLColumnName()
+
+                     " with merge table id = " + bufferedCRMergeTableID
+                     );
             }
         }
         else if ( bufferedExpression instanceof CurrentRowLocationNode )

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java?rev=1571808&r1=1571807&r2=1571808&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/MergeNode.java Tue Feb
25 20:13:00 2014
@@ -254,9 +254,13 @@ public final class MergeNode extends DML
              getContextManager()
              );
         FromTable       dummySourceTable = cloneFromTable( _sourceTable );
+
+        dummyTargetTable.setMergeTableID( ColumnReference.MERGE_TARGET );
+        dummySourceTable.setMergeTableID ( ColumnReference.MERGE_SOURCE );
         
         dummyFromList.addFromTable( dummySourceTable );
         dummyFromList.addFromTable( dummyTargetTable );
+        
         dummyFromList.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(),
getContextManager() ) );
 
         return dummyFromList;
@@ -367,8 +371,8 @@ public final class MergeNode extends DML
             for ( MatchingClauseNode mcn : _matchingClauses )
             {
                 mcn.bindThenColumns( _selectList );
-            }            
-            
+            }
+
             resultSet = new SelectNode
                 (
                  selectList,
@@ -558,7 +562,7 @@ public final class MergeNode extends DML
          )
         throws StandardException
     {
-        String[]    columnNames = getColumns( getExposedName( fromTable ), drivingColumnMap
);
+        String[]    columnNames = getColumns( mergeTableID, drivingColumnMap );
         TableName   tableName = fromTable.getTableName();
 
         for ( int i = 0; i < columnNames.length; i++ )
@@ -572,13 +576,13 @@ public final class MergeNode extends DML
     }
 
     /** Get the column names from the table with the given table number, in sorted order
*/
-    private String[]    getColumns( String exposedName, HashMap<String,ColumnReference>
map )
+    private String[]    getColumns( int mergeTableID, HashMap<String,ColumnReference>
map )
     {
         ArrayList<String>   list = new ArrayList<String>();
 
         for ( ColumnReference cr : map.values() )
         {
-            if ( exposedName.equals( cr.getTableName() ) ) { list.add( cr.getColumnName()
); }
+            if ( cr.getMergeTableID() == mergeTableID ) { list.add( cr.getColumnName() );
}
         }
 
         String[]    retval = new String[ list.size() ];
@@ -605,7 +609,7 @@ public final class MergeNode extends DML
     }
 
     /** Add a list of columns to the the evolving map */
-    private void    getColumnsFromList
+    void    getColumnsFromList
         ( HashMap<String,ColumnReference> map, ResultColumnList rcl, int mergeTableID
)
         throws StandardException
     {
@@ -638,17 +642,30 @@ public final class MergeNode extends DML
          )
         throws StandardException
     {
-        associateColumn( cr, mergeTableID );
+        if ( cr.getTableName() == null )
+        {
+            ResultColumn    rc = _leftJoinFromList.bindColumnReference( cr );
+            TableName       tableName = new TableName( null, rc.getTableName(), getContextManager()
);
+            cr = new ColumnReference( cr.getColumnName(), tableName, getContextManager()
);
+        }
+
+        associateColumn( _leftJoinFromList, cr, mergeTableID );
 
         String  key = makeDCMKey( cr.getTableName(), cr.getColumnName() );
-        if ( map.get( key ) == null )
+
+        ColumnReference mapCR = map.get( key );
+        if ( mapCR != null )
+        {
+            mapCR.setMergeTableID( cr.getMergeTableID() );
+        }
+        else
         {
             map.put( key, cr );
         }
     }
 
     /** Associate a column with the SOURCE or TARGET table */
-    private void    associateColumn( ColumnReference cr, int mergeTableID )
+    void    associateColumn( FromList fromList, ColumnReference cr, int mergeTableID )
         throws StandardException
     {
         if ( mergeTableID != ColumnReference.MERGE_UNKNOWN )    { cr.setMergeTableID( mergeTableID
); }
@@ -657,11 +674,11 @@ public final class MergeNode extends DML
             // we have to figure out which table the column is in
             String  columnsTableName = cr.getTableName();
 
-            if ( ((FromTable)_leftJoinFromList.elementAt( SOURCE_TABLE_INDEX )).getMatchingColumn(
cr ) != null )
+            if ( ((FromTable) fromList.elementAt( SOURCE_TABLE_INDEX )).getMatchingColumn(
cr ) != null )
             {
                 cr.setMergeTableID( ColumnReference.MERGE_SOURCE );
             }
-            else if ( ((FromTable)_leftJoinFromList.elementAt( TARGET_TABLE_INDEX )).getMatchingColumn(
cr ) != null )
+            else if ( ((FromTable) fromList.elementAt( TARGET_TABLE_INDEX )).getMatchingColumn(
cr ) != null )
             {
                 cr.setMergeTableID( ColumnReference.MERGE_TARGET );
             }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java?rev=1571808&r1=1571807&r2=1571808&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java Tue
Feb 25 20:13:00 2014
@@ -195,6 +195,12 @@ public final class UpdateNode extends DM
 			}
 		}
 
+        //
+        // First step in associating added columns with the TARGET table of
+        // a MERGE statement. Here we identify the columns which were NOT ADDED.
+        //
+        if ( inMatchingClause() ) { tagOriginalResultSetColumns(); }
+
         // collect lists of objects which will require privilege checks
         ArrayList<String>   explicitlySetColumns = getExplicitlySetColumns();
         List<ValueNode> allValueNodes = collectAllValueNodes();
@@ -463,6 +469,7 @@ public final class UpdateNode extends DM
 			{
 				readColsBitSet = new FormatableBitSet();
 				FromBaseTable fbt = getResultColumnList(resultSet.getResultColumns());
+
 				afterColumns = resultSet.getResultColumns().copyListAndObjects();
 
 				readColsBitSet = getReadMap(dataDictionary, 
@@ -523,7 +530,7 @@ public final class UpdateNode extends DM
                 COLUMNNAME, rowLocationNode, getContextManager());
         rowLocationColumn.markGenerated();
 
-			/* Append to the ResultColumnList */
+        /* Append to the ResultColumnList */
         resultColumnList.addResultColumn(rowLocationColumn);
 
 		/*
@@ -536,6 +543,12 @@ public final class UpdateNode extends DM
 		/* Set the new result column list in the result set */
 		resultSet.setResultColumns(resultColumnList);
 
+        //
+        // Second step in associating added columns with the TARGET table of
+        // a MERGE statement. Here we associate the columns which were not originally tagged.
+        //
+        if ( inMatchingClause() ) { associateAddedColumns(); }
+
 		/* Bind the expressions */
 		super.bindExpressions();
 
@@ -655,6 +668,47 @@ public final class UpdateNode extends DM
     }
 
     /**
+     * Associate all added columns with the TARGET table of the enclosing
+     * MERGE statement.
+     */
+    private void    associateAddedColumns()
+        throws StandardException
+    {
+        for ( ColumnReference cr : collectAllResultSetColumns() )
+        {
+            if ( !cr.taggedWith( TagFilter.ORIG_UPDATE_COL ) )
+            {
+                cr.setMergeTableID( ColumnReference.MERGE_TARGET );
+            }
+        }
+    }
+
+    /**
+     * Tag the original columns mentioned in the result list.
+     */
+    private void    tagOriginalResultSetColumns()
+        throws StandardException
+    {
+        for ( ColumnReference cr : collectAllResultSetColumns() )
+        {
+            cr.addTag( TagFilter.ORIG_UPDATE_COL );
+        }
+    }
+
+    /**
+     * Collect all of the result set columns.
+     */
+    private List<ColumnReference>   collectAllResultSetColumns()
+        throws StandardException
+    {
+        CollectNodesVisitor<ColumnReference> crVisitor =
+            new CollectNodesVisitor<ColumnReference>(ColumnReference.class);
+        resultSet.getResultColumns().accept( crVisitor );
+
+        return crVisitor.getList();
+    }
+
+    /**
      * Collect all of the ValueNodes in the WHERE clause and on the right side
      * of SET operators. Later on, we will need to add permissions for all UDTs
      * mentioned by these nodes.
@@ -1531,12 +1585,8 @@ public final class UpdateNode extends DM
 			 * the cursor, then a match for the ColumnReference would not
 			 * be found if we didn't null out the name.  (Aren't you
 			 * glad you asked?)
-             *
-             * However, we need the table name if this UPDATE is part of a MERGE
-             * statement. If we clear the table name, then we will not be able to
-             * resolve which table (target or source) holds the column.
 			 */
-			if ( !inMatchingClause() ) { column.clearTableName(); }
+			column.clearTableName();
 		}
 	}
 

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java?rev=1571808&r1=1571807&r2=1571808&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java
Tue Feb 25 20:13:00 2014
@@ -5631,7 +5631,7 @@ public class MergeStatementTest extends 
         goodStatement( dboConnection, "drop table t3_041" );
     }
     
-   /**
+    /**
      * <p>
      * Verify that we don't unnecessarily raise missing schema errors.
      * </p>
@@ -5641,7 +5641,7 @@ public class MergeStatementTest extends 
     {
         Connection  dboConnection = openUserConnection( TEST_DBO );
         Connection  ruthConnection = openUserConnection( RUTH );
-
+        
         //
         // create schema
         //
@@ -5676,7 +5676,7 @@ public class MergeStatementTest extends 
              dboConnection,
              "grant delete on deleteTable_042 to ruth"
              );
-
+        
         //
         // Verify that the unqualified reference to publicSelectColumn
         // does not fail because the RUTH schema does not exist.
@@ -5688,13 +5688,319 @@ public class MergeStatementTest extends 
             "when matched then delete\n";
         expectExecutionWarning( ruthConnection, NO_ROWS_AFFECTED, mergeStatement );
         expectExecutionWarning( dboConnection, NO_ROWS_AFFECTED, mergeStatement );
-
+        
         //
         // drop schema
         //
         goodStatement( dboConnection, "drop table deleteTable_042" );
         goodStatement( dboConnection, "drop table selectTable_042" );
     }
+
+    /**
+     * <p>
+     * Verify correlation names with columns added in order to
+     * support triggers.
+     * </p>
+     */
+    public  void    test_043_correlationNamesAddedColumns()
+        throws Exception
+    {
+        Connection  dboConnection = openUserConnection( TEST_DBO );
+
+        //
+        // create schema
+        //
+        goodStatement
+            (
+             dboConnection,
+             "create type BeforeTriggerType_043 external name 'java.util.HashMap' language
java"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create type AfterTriggerType_043 external name 'java.util.HashMap' language
java"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create function beforeTriggerFunction_043( hashMap BeforeTriggerType_043, hashKey
varchar( 32672 ) ) returns int\n" +
+             "language java parameter style java deterministic no sql\n" +
+             "external name 'org.apache.derbyTesting.functionTests.tests.lang.UDTTest.getIntValue'\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create function afterTriggerFunction_043( hashMap AfterTriggerType_043, hashKey
varchar( 32672 ) ) returns int\n" +
+             "language java parameter style java deterministic no sql\n" +
+             "external name 'org.apache.derbyTesting.functionTests.tests.lang.UDTTest.getIntValue'\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create procedure addHistoryRow_043\n" +
+             "(\n" +
+             "    actionString varchar( 20 ),\n" +
+             "    actionValue int\n" +
+             ")\n" +
+             "language java parameter style java reads sql data\n" +
+             "external name 'org.apache.derbyTesting.functionTests.tests.lang.MergeStatementTest.addHistoryRow'\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create table primaryTable_043\n" +
+             "(\n" +
+             "    key1 int primary key\n" +
+             ")\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create table sourceTable_043\n" +
+             "(\n" +
+             "    sourceChange int,\n" +
+             "    sourceOnClauseColumn int,\n" +
+             "    sourceMatchingClauseColumn int\n" +
+             ")\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create table targetTable_043\n" +
+             "(\n" +
+             "    privateForeignColumn int references primaryTable_043( key1 ),\n" +
+             "    privatePrimaryColumn int primary key,\n" +
+             "    privateBeforeTriggerSource BeforeTriggerType_043,\n" +
+             "    privateAfterTriggerSource AfterTriggerType_043,\n" +
+             "    targetOnClauseColumn int,\n" +
+             "    targetMatchingClauseColumn int\n" +
+             ")\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create table foreignTable_043\n" +
+             "(\n" +
+             "    key1 int references targetTable_043( privatePrimaryColumn )\n" +
+             ")\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create trigger beforeDeleteTrigger_043\n" +
+             "no cascade before delete on targetTable_043\n" +
+             "referencing old as old\n" +
+             "for each row\n" +
+             "call addHistoryRow_043( 'before', beforeTriggerFunction_043( old.privateBeforeTriggerSource,
'foo' ) )\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create trigger afterDeleteTrigger_043\n" +
+             "after delete on targetTable_043\n" +
+             "referencing old as old\n" +
+             "for each row\n" +
+             "call addHistoryRow_043( 'after', afterTriggerFunction_043( old.privateAfterTriggerSource,
'foo' ) )\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create trigger beforeUpdateTrigger_043\n" +
+             "no cascade before update on targetTable_043\n" +
+             "referencing old as old\n" +
+             "for each row\n" +
+             "call addHistoryRow_043( 'before', beforeTriggerFunction_043( old.privateBeforeTriggerSource,
'foo' ) )\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create trigger afterUpdateTrigger_043\n" +
+             "after update on targetTable_043\n" +
+             "referencing old as old\n" +
+             "for each row\n" +
+             "call addHistoryRow_043( 'after', afterTriggerFunction_043( old.privateAfterTriggerSource,
'foo' ) )\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create trigger beforeInsertTrigger_043\n" +
+             "no cascade before insert on targetTable_043\n" +
+             "referencing new as new\n" +
+             "for each row\n" +
+             "call addHistoryRow_043( 'before', beforeTriggerFunction_043( new.privateBeforeTriggerSource,
'foo' ) )\n"
+             );
+        goodStatement
+            (
+             dboConnection,
+             "create trigger afterInsertTrigger_043\n" +
+             "after insert on targetTable_043\n" +
+             "referencing new as new\n" +
+             "for each row\n" +
+             "call addHistoryRow_043( 'after', afterTriggerFunction_043( new.privateAfterTriggerSource,
'foo' ) )\n"
+             );
+
+        //
+        // Now verify that column name are correctly resolved, including columns
+        // added to satisfy triggers and constraints.
+        //
+
+        // delete
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043\n" +
+              "using sourceTable_043\n" +
+              "on targetOnClauseColumn = sourceOnClauseColumn\n" +
+              "when matched and targetMatchingClauseColumn = sourceMatchingClauseColumn\n"
+
+              "     then delete\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on targetOnClauseColumn = sourceOnClauseColumn\n" +
+              "when matched and targetMatchingClauseColumn = sourceMatchingClauseColumn\n"
+
+              "     then delete\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on targetOnClauseColumn = s.sourceOnClauseColumn\n" +
+              "when matched and targetMatchingClauseColumn = s.sourceMatchingClauseColumn\n"
+
+              "     then delete\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on t.targetOnClauseColumn = s.sourceOnClauseColumn\n" +
+              "when matched and t.targetMatchingClauseColumn = s.sourceMatchingClauseColumn\n"
+
+              "     then delete\n"
+              );
+
+        // update
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043\n" +
+              "using sourceTable_043\n" +
+              "on targetOnClauseColumn = sourceOnClauseColumn\n" +
+              "when matched and targetMatchingClauseColumn = sourceMatchingClauseColumn\n"
+
+              "     then update set privateForeignColumn = sourceChange\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on targetOnClauseColumn = sourceOnClauseColumn\n" +
+              "when matched and targetMatchingClauseColumn = sourceMatchingClauseColumn\n"
+
+              "     then update set privateForeignColumn = sourceChange\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on targetOnClauseColumn = s.sourceOnClauseColumn\n" +
+              "when matched and targetMatchingClauseColumn = s.sourceMatchingClauseColumn\n"
+
+              "     then update set privateForeignColumn = s.sourceChange\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on t.targetOnClauseColumn = s.sourceOnClauseColumn\n" +
+              "when matched and t.targetMatchingClauseColumn = s.sourceMatchingClauseColumn\n"
+
+              "     then update set t.privateForeignColumn = s.sourceChange\n"
+              );
+
+        // insert
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043\n" +
+              "using sourceTable_043\n" +
+              "on targetOnClauseColumn = sourceOnClauseColumn\n" +
+              "when not matched and 1 = sourceMatchingClauseColumn\n" +
+              "     then insert ( privateForeignColumn ) values ( sourceChange )\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on targetOnClauseColumn = sourceOnClauseColumn\n" +
+              "when not matched and 1 = sourceMatchingClauseColumn\n" +
+              "     then insert ( privateForeignColumn ) values ( sourceChange )\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on targetOnClauseColumn = s.sourceOnClauseColumn\n" +
+              "when not matched and 1 = s.sourceMatchingClauseColumn\n" +
+              "     then insert ( privateForeignColumn ) values ( s.sourceChange )\n"
+              );
+
+        // all clauses together
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043\n" +
+              "using sourceTable_043\n" +
+              "on targetOnClauseColumn = sourceOnClauseColumn\n" +
+              "when matched and targetMatchingClauseColumn = sourceMatchingClauseColumn\n"
+
+              "     then delete\n" +
+              "when matched and targetMatchingClauseColumn = sourceMatchingClauseColumn\n"
+
+              "     then update set privateForeignColumn = sourceChange\n" +
+              "when not matched and 1 = sourceMatchingClauseColumn\n" +
+              "     then insert ( privateForeignColumn ) values ( sourceChange )\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on targetOnClauseColumn = sourceOnClauseColumn\n" +
+              "when matched and targetMatchingClauseColumn = sourceMatchingClauseColumn\n"
+
+              "     then delete\n" +
+              "when matched and targetMatchingClauseColumn = sourceMatchingClauseColumn\n"
+
+              "     then update set privateForeignColumn = sourceChange\n" +
+              "when not matched and 1 = sourceMatchingClauseColumn\n" +
+              "     then insert ( privateForeignColumn ) values ( sourceChange )\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on targetOnClauseColumn = s.sourceOnClauseColumn\n" +
+              "when matched and targetMatchingClauseColumn = s.sourceMatchingClauseColumn\n"
+
+              "     then delete\n" +
+              "when matched and targetMatchingClauseColumn = s.sourceMatchingClauseColumn\n"
+
+              "     then update set privateForeignColumn = s.sourceChange\n" +
+              "when not matched and 1 = s.sourceMatchingClauseColumn\n" +
+              "     then insert ( privateForeignColumn ) values ( s.sourceChange )\n"
+              );
+        expectExecutionWarning
+            ( dboConnection, NO_ROWS_AFFECTED,
+              "merge into targetTable_043 t\n" +
+              "using sourceTable_043 s\n" +
+              "on t.targetOnClauseColumn = s.sourceOnClauseColumn\n" +
+              "when matched and t.targetMatchingClauseColumn = s.sourceMatchingClauseColumn\n"
+
+              "     then delete\n" +
+              "when matched and t.targetMatchingClauseColumn = s.sourceMatchingClauseColumn\n"
+
+              "     then update set t.privateForeignColumn = s.sourceChange\n" +
+              "when not matched and 1 = s.sourceMatchingClauseColumn\n" +
+              "     then insert ( privateForeignColumn ) values ( s.sourceChange )\n"
+              );
+
+        //
+        // drop schema
+        //
+        goodStatement( dboConnection, "drop table foreignTable_043" );
+        goodStatement( dboConnection, "drop table targetTable_043" );
+        goodStatement( dboConnection, "drop table sourceTable_043" );
+        goodStatement( dboConnection, "drop table primaryTable_043" );
+        goodStatement( dboConnection, "drop procedure addHistoryRow_043" );
+        goodStatement( dboConnection, "drop function afterTriggerFunction_043" );
+        goodStatement( dboConnection, "drop function beforeTriggerFunction_043" );
+        goodStatement( dboConnection, "drop type AfterTriggerType_043 restrict" );
+        goodStatement( dboConnection, "drop type BeforeTriggerType_043 restrict" );
+    }
     
     ///////////////////////////////////////////////////////////////////////////////////
     //



Mime
View raw message