db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
Subject svn commit: r1564874 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/compile/ testing/org/apache/derbyTesting/functionTests/tests/lang/
Date Wed, 05 Feb 2014 18:44:06 GMT
Author: rhillegas
Date: Wed Feb  5 18:44:05 2014
New Revision: 1564874

URL: http://svn.apache.org/r1564874
Log:
DERBY-3155: Revamp how columns referenced by WHEN [ NOT ] MATCHED clauses are linked to the
columns coming back from the driving left join of a MERGE statement; commit derby-3155-20-aa-reworkColumnMatching.diff.

Modified:
    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/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/ResultColumn.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/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=1564874&r1=1564873&r2=1564874&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
Wed Feb  5 18:44:05 2014
@@ -42,6 +42,11 @@ import org.apache.derby.iapi.util.JBitSe
 
 public class ColumnReference extends ValueNode
 {
+    // For associating columns with the SOURCE and TARGET tables of MERGE statements.
+    public  static  final   int MERGE_UNKNOWN = 0;
+    public  static  final   int MERGE_SOURCE = MERGE_UNKNOWN + 1;
+    public  static  final   int MERGE_TARGET = MERGE_SOURCE + 1;
+    
 	private String	_columnName;
 
 	/*
@@ -104,6 +109,10 @@ public class ColumnReference extends Val
 	 */
 	private java.util.ArrayList<RemapInfo> remaps;
 
+    /** Columns mentioned by MERGE statements need to be associated
+     * the SOURCE or TARGET table */
+    private int _mergeTableID = MERGE_UNKNOWN;
+
 	/**
      * Constructor.
 	 * This one is called by the parser where we could
@@ -354,6 +363,10 @@ public class ColumnReference extends Val
 			oldCR.getGeneratedToReplaceWindowFunctionCall();
 		scoped = oldCR.isScoped();
         copyTagsFrom( oldCR );
+        if ( oldCR._mergeTableID != MERGE_UNKNOWN )
+        {
+            setMergeTableID( oldCR.getMergeTableID() );
+        }
 	}
 
 	/**
@@ -391,7 +404,7 @@ public class ColumnReference extends Val
 			throw StandardException.newException(SQLState.LANG_ILLEGAL_COLUMN_REFERENCE, _columnName);
 		}
 
-		matchingRC = fromList.bindColumnReference(this);
+        matchingRC = fromList.bindColumnReference(this);
 
 		/* Error if no match found in fromList */
 		if (matchingRC == null)
@@ -1224,6 +1237,38 @@ public class ColumnReference extends Val
 		return scoped;
 	}
 
+    /** Associate this column with a SOURCE or TARGET table of a MERGE statement */
+    void    setMergeTableID( int mergeTableID )
+    {
+        // Changing the association of a column means we are confused. Shouldn't happen.
+        if ( _mergeTableID != MERGE_UNKNOWN )
+        {
+            if (SanityManager.DEBUG)
+            {
+                SanityManager.ASSERT
+                    (
+                     (_mergeTableID == mergeTableID),
+                     "MERGE statement can't re-associate column " + debugName()
+                     );
+            }
+        }
+
+        _mergeTableID = mergeTableID;
+    }
+
+    /** Get the MERGE table (SOURCE or TARGET) associated with this column */
+    int getMergeTableID()
+    {
+        return _mergeTableID;
+    }
+
+    /** Get the name of this column (for debugging printout) */
+    String  debugName()
+    {
+        if ( _qualifiedTableName == null ) { return _columnName; }
+        else { return _qualifiedTableName + "." + _columnName; }
+    }
+
 	/**
 	 * Helper class to keep track of remap data when a ColumnReference
 	 * is remapped multiple times.  This allows the CR to be UN-

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=1564874&r1=1564873&r2=1564874&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 Wed Feb
 5 18:44:05 2014
@@ -1154,6 +1154,17 @@ abstract class FromTable extends ResultS
 		 */
         for (ResultColumn rc : inputRcl)
 		{
+            ColumnReference oldCR = rc.getReference();
+            if ( oldCR != null )
+            {
+                // for UPDATE actions of MERGE statement, preserve the original table name.
+                // this is necessary in order to correctly bind the column list of the dummy
SELECT.
+                if ( oldCR.getMergeTableID() != ColumnReference.MERGE_UNKNOWN )
+                {
+                    exposedName = oldCR.getQualifiedTableName();
+                }
+            }
+            
             ResultColumn newRc = new ResultColumn(
                     rc.getName(),
                     new ColumnReference(rc.getName(), exposedName, cm),

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=1564874&r1=1564873&r2=1564874&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
Wed Feb  5 18:44:05 2014
@@ -187,57 +187,6 @@ public class MatchingClauseNode extends 
     //
     ///////////////////////////////////////////////////////////////////////////////////
 
-    /**
-     * <p>
-     * Replace references to the correlation name with the underlying table name
-     * in all ColumnReferences under all expressions. This replacement is
-     * done before the ColumnReferences are bound.
-     * </p>
-     */
-    public  void    replaceCorrelationName
-        (
-         MergeNode  parent,
-         String correlationName,
-         TableName  newTableName
-         )
-        throws StandardException
-    {
-        parent.replaceCorrelationName( correlationName, newTableName, _matchingRefinement
);
-        replaceCorrelationNameInSetClauses( parent, correlationName, newTableName );
-        parent.replaceCorrelationName( correlationName, newTableName, _insertColumns );
-        parent.replaceCorrelationName( correlationName, newTableName, _insertValues );
-    }
-    
-    /**
-     * <p>
-     * Replace references to the correlation name with the underlying table name
-     * in the SET clauses of WHEN MATCHED ... THEN UPDATE clauses. This replacement is
-     * done before the ColumnReferences are bound.
-     * </p>
-     */
-    public  void    replaceCorrelationNameInSetClauses
-        (
-         MergeNode  parent,
-         String correlationName,
-         TableName  newTableName
-         )
-        throws StandardException
-    {
-        if ( _updateColumns == null ) { return; }
-        
-        // this handles the right side of the SET clauses
-        parent.replaceCorrelationName( correlationName, newTableName, _updateColumns );
-
-        // we have to hand-process the left side because the Visitor
-        // logic for ResultColumns does not process the ColumnReference
-        for ( int i = 0; i < _updateColumns.size(); i++ )
-        {
-            ResultColumn    rc = _updateColumns.elementAt( i );
-
-            parent.replaceCorrelationName( correlationName, newTableName, rc.getReference()
);
-        }
-    }
-    
     /** Bind this WHEN [ NOT ] MATCHED clause against the parent JoinNode */
     void    bind
         (
@@ -301,7 +250,7 @@ public class MatchingClauseNode extends 
     {
         if ( _matchingRefinement != null )
         {
-            mergeNode.getColumnsInExpression( drivingColumnMap, _matchingRefinement );
+            mergeNode.getColumnsInExpression( drivingColumnMap, _matchingRefinement, ColumnReference.MERGE_UNKNOWN
);
         }
 
         if ( isUpdateClause() )
@@ -315,10 +264,10 @@ public class MatchingClauseNode extends 
             //
             for ( ResultColumn rc : _updateColumns )
             {
-                mergeNode.getColumnsInExpression( drivingColumnMap, rc.getExpression() );
+                mergeNode.getColumnsInExpression( drivingColumnMap, rc.getExpression(), ColumnReference.MERGE_UNKNOWN
);
 
                 ColumnReference leftCR = new ColumnReference( rc.getName(), targetTableName,
getContextManager() );
-                mergeNode.addColumn( drivingColumnMap, leftCR );
+                mergeNode.addColumn( drivingColumnMap, leftCR, ColumnReference.MERGE_TARGET
);
             }
         }
         else if ( isInsertClause() )
@@ -326,7 +275,7 @@ public class MatchingClauseNode extends 
             // get all columns mentioned in the VALUES subclauses of WHEN NOT MATCHED ...
THEN INSERT clauses
             for ( ResultColumn rc : _insertValues )
             {
-                mergeNode.getColumnsInExpression( drivingColumnMap, rc.getExpression() );
+                mergeNode.getColumnsInExpression( drivingColumnMap, rc.getExpression(), ColumnReference.MERGE_UNKNOWN
);
             }
         }
     }
@@ -338,15 +287,17 @@ public class MatchingClauseNode extends 
         (
          DataDictionary dd,
          FromList fullFromList,
-         FromTable targetTable
+         FromBaseTable targetTable
          )
         throws StandardException
     {
-        bindSetClauses( fullFromList, targetTable );
-        
+        ResultColumnList    setClauses = realiasSetClauses( targetTable );
+        bindSetClauses( fullFromList, targetTable, setClauses );
+
         SelectNode  selectNode = new SelectNode
             (
-             _updateColumns,
+             //             _updateColumns,
+             setClauses,
              fullFromList,
              null,      // where clause
              null,      // group by list
@@ -355,7 +306,7 @@ public class MatchingClauseNode extends 
              null,      // optimizer plan override
              getContextManager()
              );
-        _dml = new UpdateNode( targetTable.getTableName(), selectNode, this, getContextManager()
);
+        _dml = new UpdateNode( targetTable.getTableNameField(), selectNode, this, getContextManager()
);
 
         _dml.bindStatement();
 
@@ -385,6 +336,42 @@ public class MatchingClauseNode extends 
 
     /**
      * <p>
+     * Due to discrepancies on how names are resolved in SELECT and UPDATE,
+     * we have to force the left side of SET clauses to use the same table identifiers
+     * as the right sides of the SET clauses.
+     * </p>
+     */
+    private ResultColumnList    realiasSetClauses
+        (
+         FromBaseTable targetTable
+         )
+        throws StandardException
+    {
+        ResultColumnList    rcl = new ResultColumnList( getContextManager() );
+        for ( int i = 0; i < _updateColumns.size(); i++ )
+        {
+            ResultColumn    setRC = _updateColumns.elementAt( i );
+            ColumnReference newTargetColumn = new ColumnReference
+                (
+                 setRC.getReference().getColumnName(),
+                 targetTable.getTableName(),
+                 getContextManager()
+                 );
+            newTargetColumn.setMergeTableID( ColumnReference.MERGE_TARGET );
+            ResultColumn    newRC = new ResultColumn
+                (
+                 newTargetColumn,
+                 setRC.getExpression(),
+                 getContextManager()
+                 );
+            rcl.addResultColumn( newRC );
+        }
+
+        return rcl;
+    }
+    
+    /**
+     * <p>
      * Get the bound SELECT node under the dummy UPDATE node.
      * This may not be the source result set of the UPDATE node. That is because a ProjectRestrictResultSet
      * may have been inserted on top of it by DEFAULT handling. This method
@@ -417,14 +404,15 @@ public class MatchingClauseNode extends 
     private void    bindSetClauses
         (
          FromList fullFromList,
-         FromTable targetTable
+         FromTable targetTable,
+         ResultColumnList   setClauses
          )
         throws StandardException
     {
         // needed to make the UpdateNode bind
-        _updateColumns.replaceOrForbidDefaults( targetTable.getTableDescriptor(), _updateColumns,
true );
+        setClauses.replaceOrForbidDefaults( targetTable.getTableDescriptor(), _updateColumns,
true );
 
-        bindExpressions( _updateColumns, fullFromList );
+        bindExpressions( setClauses, fullFromList );
     }
 
     /**
@@ -685,8 +673,14 @@ public class MatchingClauseNode extends 
          )
         throws StandardException
     {
+        FromBaseTable   deleteTarget = new FromBaseTable
+            ( targetTable.getTableNameField(), null, null, null, getContextManager() );
+        FromList    dummyFromList = new FromList( getContextManager() );
+        dummyFromList.addFromTable( deleteTarget );
+        dummyFromList.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(),
getContextManager() ) );
+ 
         CurrentOfNode   currentOfNode = CurrentOfNode.makeForMerge
-            ( CURRENT_OF_NODE_NAME, targetTable, getContextManager() );
+            ( CURRENT_OF_NODE_NAME, deleteTarget, getContextManager() );
         FromList        fromList = new FromList( getContextManager() );
         fromList.addFromTable( currentOfNode );
         SelectNode      selectNode = new SelectNode
@@ -700,7 +694,7 @@ public class MatchingClauseNode extends 
              null, /* optimizer plan override */
              getContextManager()
              );
-        _dml = new DeleteNode( targetTable.getTableName(), selectNode, this, getContextManager()
);
+        _dml = new DeleteNode( targetTable.getTableNameField(), selectNode, this, getContextManager()
);
 
         _dml.bindStatement();
 
@@ -771,7 +765,7 @@ public class MatchingClauseNode extends 
          DataDictionary dd,
          MergeNode  mergeNode,
          FromList fullFromList,
-         FromTable targetTable
+         FromBaseTable targetTable
          )
         throws StandardException
     {
@@ -795,7 +789,7 @@ public class MatchingClauseNode extends 
              );
         _dml = new InsertNode
             (
-             targetTable.getTableName(),
+             targetTable.getTableNameField(),
              _insertColumns,
              selectNode,
              this,      // in NOT MATCHED clause
@@ -1089,8 +1083,8 @@ public class MatchingClauseNode extends 
         if ( bufferedExpression instanceof ColumnReference )
         {
             ColumnReference bufferedCR = (ColumnReference) bufferedExpression;
-            String              tableName = bufferedCR.getTableName();
-            String              columnName = bufferedCR.getColumnName();
+            String              bufferedCRName = bufferedCR.getColumnName();
+            int                 bufferedCRMergeTableID = getMergeTableID( bufferedCR );
 
             // loop through the SELECT list to find this column reference
             for ( int sidx = 0; sidx < selectCount; sidx++ )
@@ -1103,14 +1097,19 @@ public class MatchingClauseNode extends 
                 if ( selectCR != null )
                 {
                     if (
-                        tableName.equals( selectCR.getTableName() ) &&
-                        columnName.equals( selectCR.getColumnName() )
+                        ( getMergeTableID( selectCR ) == bufferedCRMergeTableID) &&
+                        bufferedCRName.equals( selectCR.getColumnName() )
                         )
                     {
                         return sidx + 1;
                     }
                 }
             }
+            
+            if (SanityManager.DEBUG)
+            {
+                SanityManager.THROWASSERT( "Can't find select list column corresponding to
" + bufferedCR.debugName() );
+            }
         }
         else if ( bufferedExpression instanceof CurrentRowLocationNode )
         {
@@ -1125,6 +1124,23 @@ public class MatchingClauseNode extends 
         return -1;
     }
 
+    /** Find the MERGE table id of the indicated column */
+    private int getMergeTableID( ColumnReference cr )
+    {
+        int                 mergeTableID = cr.getMergeTableID();
+
+        if (SanityManager.DEBUG)
+        {
+            SanityManager.ASSERT
+                (
+                 ( (mergeTableID == ColumnReference.MERGE_SOURCE) || (mergeTableID == ColumnReference.MERGE_TARGET)
),
+                 "Column " + cr.debugName() + " has illegal MERGE table id: " + mergeTableID
+                 );
+        }
+
+        return mergeTableID;
+    }
+
     /**
      * <p>
      * Forbid subqueries in WHEN [ NOT ] MATCHED clauses.

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=1564874&r1=1564873&r2=1564874&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 Wed Feb
 5 18:44:05 2014
@@ -40,6 +40,7 @@ import org.apache.derby.iapi.sql.diction
 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
 import org.apache.derby.iapi.sql.execute.ConstantAction;
 import org.apache.derby.iapi.util.IdUtil;
+import org.apache.derby.shared.common.sanity.SanityManager;
 
 /**
  * <p>
@@ -213,24 +214,10 @@ public final class MergeNode extends DML
             throw StandardException.newException( SQLState.LANG_SAME_EXPOSED_NAME );
         }
 
-        //
-        // Replace all references to correlation names with the actual
-        // resolved table name.
-        //
         FromList    dfl = new FromList( getContextManager() );
         dfl.addFromTable( _sourceTable );
         dfl.addFromTable( _targetTable );
         dfl.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(),
getContextManager() ) );
-        
-        replaceCorrelationName( _targetTable.correlationName, _targetTable.tableName );
-        _targetTable.correlationName = null;
-
-        if ( _sourceTable instanceof FromBaseTable )
-        {
-            TableName   sourceTableName = ((FromBaseTable) _sourceTable).tableName;
-            replaceCorrelationName( _sourceTable.correlationName, sourceTableName );
-            _sourceTable.correlationName = null;
-        }
 
         //
         // Bind the WHEN [ NOT ] MATCHED clauses.
@@ -238,7 +225,7 @@ public final class MergeNode extends DML
         FromList    dummyFromList = new FromList( getContextManager() );
         FromBaseTable   dummyTargetTable = new FromBaseTable
             (
-             _targetTable.tableName,
+             _targetTable.getTableNameField(),
              _targetTable.correlationName,
              null,
              null,
@@ -249,7 +236,7 @@ public final class MergeNode extends DML
         dummyFromList.addFromTable( dummySourceTable );
         dummyFromList.addFromTable( dummyTargetTable );
         dummyFromList.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(),
getContextManager() ) );
-        
+
         // target table must be a base table
         if ( !targetIsBaseTable( _targetTable ) ) { notBaseTable(); }
 
@@ -268,104 +255,6 @@ public final class MergeNode extends DML
         }
 	}
 
-    /**
-     * <p>
-     * Replace references to the correlation name with the underlying table name
-     * in all ColumnReferences under all expressions. If the correlation name is null,
-     * then replace all references to the unqualified table name with the fully
-     * qualified table name. This replacement is
-     * done before the ColumnReferences are bound.
-     * </p>
-     */
-    private void    replaceCorrelationName
-        (
-         String correlationName,
-         TableName  newTableName
-         )
-        throws StandardException
-    {
-        if ( correlationName == null ) { correlationName = newTableName.getTableName(); }
-
-        replaceCorrelationName
-            (
-             correlationName,
-             newTableName,
-             _searchCondition
-             );
-            
-        for ( MatchingClauseNode mcn : _matchingClauses )
-        {
-            mcn.replaceCorrelationName
-                (
-                 this,
-                 correlationName,
-                 newTableName
-                 );
-        }
-    }
-    
-    /**
-     * <p>
-     * Replace references to the correlation name with the underlying table name
-     * in all ColumnReferences under the indicated list of ResultColumns. This replacement
is
-     * done before the ColumnReferences are bound.
-     * </p>
-     */
-    public  void    replaceCorrelationName
-        (
-         String correlationName,
-         TableName  newTableName,
-         ResultColumnList   rcl
-         )
-        throws StandardException
-    {
-        if ( rcl == null ) { return; }
-        
-        for ( int i = 0; i < rcl.size(); i++ )
-        {
-            replaceCorrelationName( correlationName, newTableName, rcl.elementAt( i ) );
-        }
-    }
-    
-    /**
-     * <p>
-     * Replace references to the correlation name with the underlying table name
-     * in all ColumnReferences in the indicated expression. This replacement is
-     * done before the ColumnReferences are bound.
-     * </p>
-     */
-    public  void    replaceCorrelationName
-        (
-         String correlationName,
-         TableName  newTableName,
-         ValueNode  expression
-         )
-        throws StandardException
-    {
-        if ( expression == null ) { return; }
-        
-        CollectNodesVisitor<ColumnReference> getCRs =
-            new CollectNodesVisitor<ColumnReference>(ColumnReference.class);
-
-        expression.accept(getCRs);
-        List<ColumnReference> colRefs = getCRs.getList();
-
-        for ( ColumnReference cr : colRefs )
-        {
-            TableName   origTableName = cr.getQualifiedTableName();
-            if ( origTableName != null )
-            {
-                if (
-                    (origTableName.getSchemaName() == null) &&
-                    correlationName.equals( origTableName.getTableName() )
-                    )
-                {
-                    cr.setQualifiedTableName( newTableName );
-                }
-            }
-        }
-    }
-
     /** Get the exposed name of a FromTable */
     private String  getExposedName( FromTable ft ) throws StandardException
     {
@@ -477,20 +366,34 @@ public final class MergeNode extends DML
     private ResultColumnList    buildSelectList() throws StandardException
     {
         HashMap<String,ColumnReference> drivingColumnMap = new HashMap<String,ColumnReference>();
-        getColumnsInExpression( drivingColumnMap, _searchCondition );
+        getColumnsInExpression( drivingColumnMap, _searchCondition, ColumnReference.MERGE_UNKNOWN
);
         
         for ( MatchingClauseNode mcn : _matchingClauses )
         {
             mcn.getColumnsInExpressions( this, drivingColumnMap );
-            getColumnsFromList( drivingColumnMap, mcn.getBufferedColumns() );
+
+            int mergeTableID = mcn.isDeleteClause() ? ColumnReference.MERGE_TARGET : ColumnReference.MERGE_UNKNOWN;
+            getColumnsFromList( drivingColumnMap, mcn.getBufferedColumns(), mergeTableID
);
         }
 
         ResultColumnList    selectList = new ResultColumnList( getContextManager() );
 
         // add all of the columns from the source table which are mentioned
-        addColumns( (FromTable) _leftJoinFromList.elementAt( SOURCE_TABLE_INDEX ), drivingColumnMap,
selectList );
+        addColumns
+            (
+             (FromTable) _leftJoinFromList.elementAt( SOURCE_TABLE_INDEX ),
+             drivingColumnMap,
+             selectList,
+             ColumnReference.MERGE_SOURCE
+             );
         // add all of the columns from the target table which are mentioned
-        addColumns( (FromTable) _leftJoinFromList.elementAt( TARGET_TABLE_INDEX ), drivingColumnMap,
selectList );
+        addColumns
+            (
+             (FromTable) _leftJoinFromList.elementAt( TARGET_TABLE_INDEX ),
+             drivingColumnMap,
+             selectList,
+             ColumnReference.MERGE_TARGET
+             );
 
         addTargetRowLocation( selectList );
 
@@ -507,6 +410,7 @@ public final class MergeNode extends DML
         TableName   fromTableName = _targetTable.getTableName();
         ColumnReference cr = new ColumnReference
                 ( TARGET_ROW_LOCATION_NAME, fromTableName, getContextManager() );
+        cr.setMergeTableID( ColumnReference.MERGE_TARGET );
         ResultColumn    rowLocationColumn = new ResultColumn( (String) null, cr, getContextManager()
);
         rowLocationColumn.markGenerated();
 
@@ -598,7 +502,8 @@ public final class MergeNode extends DML
         (
          FromTable  fromTable,
          HashMap<String,ColumnReference> drivingColumnMap,
-         ResultColumnList   selectList
+         ResultColumnList   selectList,
+         int    mergeTableID
          )
         throws StandardException
     {
@@ -608,6 +513,7 @@ public final class MergeNode extends DML
         {
             ColumnReference cr = new ColumnReference
                 ( columnNames[ i ], fromTable.getTableName(), getContextManager() );
+            cr.setMergeTableID( mergeTableID );
             ResultColumn    rc = new ResultColumn( (String) null, cr, getContextManager()
);
             selectList.addResultColumn( rc );
         }
@@ -632,7 +538,7 @@ public final class MergeNode extends DML
     
     /** Add the columns in the matchingRefinement clause to the evolving map */
     void    getColumnsInExpression
-        ( HashMap<String,ColumnReference> map, ValueNode expression )
+        ( HashMap<String,ColumnReference> map, ValueNode expression, int mergeTableID
)
         throws StandardException
     {
         if ( expression == null ) { return; }
@@ -643,12 +549,12 @@ public final class MergeNode extends DML
         expression.accept(getCRs);
         List<ColumnReference> colRefs = getCRs.getList();
 
-        getColumnsFromList( map, colRefs );
+        getColumnsFromList( map, colRefs, mergeTableID );
     }
 
     /** Add a list of columns to the the evolving map */
     private void    getColumnsFromList
-        ( HashMap<String,ColumnReference> map, ResultColumnList rcl )
+        ( HashMap<String,ColumnReference> map, ResultColumnList rcl, int mergeTableID
)
         throws StandardException
     {
         CollectNodesVisitor<ColumnReference> getCRs =
@@ -657,17 +563,17 @@ public final class MergeNode extends DML
         rcl.accept( getCRs );
         List<ColumnReference> colRefs = getCRs.getList();
 
-        getColumnsFromList( map, colRefs );
+        getColumnsFromList( map, colRefs, mergeTableID );
     }
     
     /** Add a list of columns to the the evolving map */
     private void    getColumnsFromList
-        ( HashMap<String,ColumnReference> map, List<ColumnReference> colRefs
)
+        ( HashMap<String,ColumnReference> map, List<ColumnReference> colRefs,
int mergeTableID )
         throws StandardException
     {
         for ( ColumnReference cr : colRefs )
         {
-            addColumn( map, cr );
+            addColumn( map, cr, mergeTableID );
         }
     }
 
@@ -675,10 +581,13 @@ public final class MergeNode extends DML
     void    addColumn
         (
          HashMap<String,ColumnReference> map,
-         ColumnReference    cr
+         ColumnReference    originalCR,
+         int    mergeTableID
          )
         throws StandardException
     {
+        ColumnReference cr = originalCR;
+        
         if ( cr.getTableName() == null )
         {
             ResultColumn    rc = _leftJoinFromList.bindColumnReference( cr );
@@ -686,6 +595,9 @@ public final class MergeNode extends DML
             cr = new ColumnReference( cr.getColumnName(), tableName, getContextManager()
);
         }
 
+        associateColumn( cr, mergeTableID );
+        originalCR.setMergeTableID( cr.getMergeTableID() );
+
         String  key = makeDCMKey( cr.getTableName(), cr.getColumnName() );
         if ( map.get( key ) == null )
         {
@@ -693,6 +605,32 @@ public final class MergeNode extends DML
         }
     }
 
+    /** Associate a column with the SOURCE or TARGET table */
+    private void    associateColumn( ColumnReference cr, int mergeTableID )
+        throws StandardException
+    {
+        if ( mergeTableID != ColumnReference.MERGE_UNKNOWN )    { cr.setMergeTableID( mergeTableID
); }
+        else
+        {
+            // 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 )
+            {
+                cr.setMergeTableID( ColumnReference.MERGE_SOURCE );
+            }
+            else if ( ((FromTable)_leftJoinFromList.elementAt( TARGET_TABLE_INDEX )).getMatchingColumn(
cr ) != null )
+            {
+                cr.setMergeTableID( ColumnReference.MERGE_TARGET );
+            }
+        }
+
+        // Don't raise an error if a column in another table is referenced and we
+        // don't know how to handle it here. If the column is not in the SOURCE or TARGET
+        // table, then it will be caught by other bind-time logic. Columns which ought
+        // to be associated, but aren't, will be caught later on by MatchingClauseNode.getMergeTableID().
+    }
+
     /** Make a HashMap key for a column in the driving column map of the LEFT JOIN */
     private String  makeDCMKey( String tableName, String columnName )
     {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumn.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumn.java?rev=1564874&r1=1564873&r2=1564874&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumn.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumn.java Wed
Feb  5 18:44:05 2014
@@ -900,7 +900,11 @@ class ResultColumn extends ValueNode
 			If the node was created using a reference, the table name
 			of the reference must agree with that of the tabledescriptor.
 		 */
-		if (_reference != null && _reference.getTableName() != null) 
+		if (
+            _reference != null &&
+            _reference.getTableName() != null &&
+            (_reference.getMergeTableID() == ColumnReference.MERGE_UNKNOWN)
+            ) 
 		{
 			if ( (tableDescriptor != null) && ! tableDescriptor.getName().equals(
 					_reference.getTableName()) ) 

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=1564874&r1=1564873&r2=1564874&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
Wed Feb  5 18:44:05 2014
@@ -4898,6 +4898,73 @@ public class MergeStatementTest extends 
         goodStatement( dboConnection, "drop table t1_032" );
     }
     
+    /**
+     * <p>
+     * Correctly resolve column references using a source and target
+     * whose table and column names are identical but which live in different
+     * schemas.
+     * </p>
+     */
+    public  void    test_033_identicalNames()
+        throws Exception
+    {
+        Connection  dboConnection = openUserConnection( TEST_DBO );
+        Connection  ruthConnection = openUserConnection( RUTH );
+        Connection  aliceConnection = openUserConnection( ALICE );
+
+        //
+        // create schema
+        //
+        goodStatement
+            (
+             ruthConnection,
+             "create table t1_033( x int, y int )"
+             );
+        goodStatement
+            (
+             aliceConnection,
+             "create table t1_033( x int, y int )"
+             );
+        goodStatement
+            (
+             ruthConnection,
+             "insert into t1_033 values ( 1, 100 ), ( 2, 200 ), ( 3, 300 )"
+             );
+        goodStatement
+            (
+             aliceConnection,
+             "insert into t1_033 values ( 1, 1000 ), ( 3, 3000 ), ( 4, 4000 )"
+             );
+
+        // verify the behavior
+        goodUpdate
+            (
+             dboConnection,
+             "merge into ruth.t1_033 r\n" +
+             "using alice.t1_033 a on r.x = a.x\n" +
+             "when matched then update set x = a.x * 10\n",
+             2
+             );
+        assertResults
+            (
+             dboConnection,
+             "select * from ruth.t1_033 order by x",
+             new String[][]
+             {
+                 { "2", "200" },
+                 { "10", "100" },
+                 { "30", "300" },
+             },
+             false
+             );
+        
+        //
+        // drop schema
+        //
+        goodStatement( ruthConnection, "drop table t1_033" );
+        goodStatement( aliceConnection, "drop table t1_033" );
+    }
+    
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // ROUTINES



Mime
View raw message