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 rh...@apache.org on 2014/03/20 20:50:05 UTC

svn commit: r1579725 - in /db/derby/code/trunk/java/engine/org/apache/derby/impl/sql: compile/MatchingClauseNode.java compile/MergeNode.java execute/MatchingClauseConstantAction.java

Author: rhillegas
Date: Thu Mar 20 19:50:05 2014
New Revision: 1579725

URL: http://svn.apache.org/r1579725
Log:
DERBY-3155: Cleanup MERGE statement in order to make the code more readable; commit derby-3155-49-aa-cleanup1.diff.

Modified:
    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/execute/MatchingClauseConstantAction.java

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=1579725&r1=1579724&r2=1579725&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 Thu Mar 20 19:50:05 2014
@@ -173,22 +173,19 @@ public class MatchingClauseNode extends 
     /** Return true if this is a WHEN MATCHED ... DELETE clause */
     boolean isDeleteClause()    { return !( isUpdateClause() || isInsertClause() ); }
 
-    /** Return the bound DML statement--returns null if called before binding */
-    DMLModStatementNode getDML()    { return _dml; }
-
     /**
      * Return the list of columns which form the rows of the ResultSet which drive
      * the INSERT/UPDATE/DELETE actions.
      */
-    ResultColumnList    getBufferedColumns() { return _thenColumns; }
+    ResultColumnList    getThenColumns() { return _thenColumns; }
 
     ///////////////////////////////////////////////////////////////////////////////////
     //
-    // bind() BEHAVIOR
+    // bind() BEHAVIOR CALLED BY MergeNode
     //
     ///////////////////////////////////////////////////////////////////////////////////
 
-    /** Bind this WHEN [ NOT ] MATCHED clause against the parent JoinNode */
+    /** Bind this WHEN [ NOT ] MATCHED clause against the parent MergeNode */
     void    bind
         (
          DataDictionary dd,
@@ -280,7 +277,11 @@ public class MatchingClauseNode extends 
         }
     }
     
-    ////////////////////// UPDATE ///////////////////////////////
+    ////////////////
+    //
+    // BIND UPDATE
+    //
+    ////////////////
 
     /** Bind a WHEN MATCHED ... THEN UPDATE clause */
     private void    bindUpdate
@@ -693,7 +694,11 @@ public class MatchingClauseNode extends 
     }
 
 
-    ////////////////////// DELETE ///////////////////////////////
+    ////////////////
+    //
+    // BIND DELETE
+    //
+    ////////////////
 
     /** Bind a WHEN MATCHED ... THEN DELETE clause */
     private void    bindDelete
@@ -772,7 +777,7 @@ public class MatchingClauseNode extends 
 
     /**
      * <p>
-     * Calculate the 1-based offsets which define the rows which will be buffered up
+     * Calculate the 1-based offsets which define the "then" rows which will be buffered up
      * for a DELETE action at run-time. The rows are constructed
      * from the columns in the SELECT list of the driving left joins. This method
      * calculates an array of offsets into the SELECT list. The columns at those
@@ -783,21 +788,25 @@ public class MatchingClauseNode extends 
     private void    bindDeleteThenColumns( ResultColumnList selectList )
         throws StandardException
     {
-        int     bufferedCount = _thenColumns.size();
+        int     thenCount = _thenColumns.size();
         int     selectCount = selectList.size();
         
-        _deleteColumnOffsets = new int[ bufferedCount ];
+        _deleteColumnOffsets = new int[ thenCount ];
 
-        for ( int bidx = 0; bidx < bufferedCount; bidx++ )
+        for ( int bidx = 0; bidx < thenCount; bidx++ )
         {
-            ResultColumn    bufferedRC = _thenColumns.elementAt( bidx );
-            ValueNode       bufferedExpression = bufferedRC.getExpression();
+            ResultColumn    thenRC = _thenColumns.elementAt( bidx );
+            ValueNode       thenExpression = thenRC.getExpression();
 
-            _deleteColumnOffsets[ bidx ] = getSelectListOffset( selectList, bufferedExpression );
+            _deleteColumnOffsets[ bidx ] = getSelectListOffset( selectList, thenExpression );
         }
     }
 
-    ////////////////////// INSERT ///////////////////////////////
+    ////////////////
+    //
+    // BIND INSERT
+    //
+    ////////////////
 
     /** Bind a WHEN NOT MATCHED ... THEN INSERT clause */
     private void    bindInsert
@@ -1087,33 +1096,11 @@ public class MatchingClauseNode extends 
     }
 
 
-    ////////////////////// bind() MINIONS ///////////////////////////////
-
-    /** Boilerplate for binding a list of ResultColumns against a FromList */
-    private void bindExpressions( ResultColumnList rcl, FromList fromList )
-        throws StandardException
-    {
-        CompilerContext cc = getCompilerContext();
-        final int previousReliability = cc.getReliability();
-
-        boolean wasSkippingTypePrivileges = cc.skipTypePrivileges( true );
-        cc.setReliability( previousReliability | CompilerContext.SQL_IN_ROUTINES_ILLEGAL );
-        
-        try {
-            rcl.bindExpressions
-                (
-                 fromList,
-                 new SubqueryList( getContextManager() ),
-                 new ArrayList<AggregateNode>()
-                 );
-        }
-        finally
-        {
-            // Restore previous compiler state
-            cc.setReliability( previousReliability );
-            cc.skipTypePrivileges( wasSkippingTypePrivileges );
-        }
-    }
+    ////////////////////////
+    //
+    // BIND THE THEN ROW
+    //
+    ////////////////////////
 
     /**
      * <p>
@@ -1133,16 +1120,16 @@ public class MatchingClauseNode extends 
      * can't be found.
      * </p>
      */
-    private int getSelectListOffset( ResultColumnList selectList, ValueNode bufferedExpression )
+    private int getSelectListOffset( ResultColumnList selectList, ValueNode thenExpression )
         throws StandardException
     {
         int                 selectCount = selectList.size();
 
-        if ( bufferedExpression instanceof ColumnReference )
+        if ( thenExpression instanceof ColumnReference )
         {
-            ColumnReference bufferedCR = (ColumnReference) bufferedExpression;
-            String              bufferedCRName = bufferedCR.getColumnName();
-            int                 bufferedCRMergeTableID = getMergeTableID( bufferedCR );
+            ColumnReference thenCR = (ColumnReference) thenExpression;
+            String              thenCRName = thenCR.getColumnName();
+            int                 thenCRMergeTableID = getMergeTableID( thenCR );
 
             // loop through the SELECT list to find this column reference
             for ( int sidx = 0; sidx < selectCount; sidx++ )
@@ -1155,8 +1142,8 @@ public class MatchingClauseNode extends 
                 if ( selectCR != null )
                 {
                     if (
-                        ( getMergeTableID( selectCR ) == bufferedCRMergeTableID) &&
-                        bufferedCRName.equals( selectCR.getColumnName() )
+                        ( getMergeTableID( selectCR ) == thenCRMergeTableID) &&
+                        thenCRName.equals( selectCR.getColumnName() )
                         )
                     {
                         return sidx + 1;
@@ -1168,12 +1155,12 @@ public class MatchingClauseNode extends 
             {
                 SanityManager.THROWASSERT
                     (
-                     "Can't find select list column corresponding to " + bufferedCR.getSQLColumnName() +
-                     " with merge table id = " + bufferedCRMergeTableID
+                     "Can't find select list column corresponding to " + thenCR.getSQLColumnName() +
+                     " with merge table id = " + thenCRMergeTableID
                      );
             }
         }
-        else if ( bufferedExpression instanceof CurrentRowLocationNode )
+        else if ( thenExpression instanceof CurrentRowLocationNode )
         {
             //
             // There is only one RowLocation in the SELECT list, the row location for the
@@ -1203,6 +1190,38 @@ public class MatchingClauseNode extends 
         return mergeTableID;
     }
 
+    /////////////////
+    //
+    // BIND MINIONS
+    //
+    /////////////////
+
+    /** Boilerplate for binding a list of ResultColumns against a FromList */
+    private void bindExpressions( ResultColumnList rcl, FromList fromList )
+        throws StandardException
+    {
+        CompilerContext cc = getCompilerContext();
+        final int previousReliability = cc.getReliability();
+
+        boolean wasSkippingTypePrivileges = cc.skipTypePrivileges( true );
+        cc.setReliability( previousReliability | CompilerContext.SQL_IN_ROUTINES_ILLEGAL );
+        
+        try {
+            rcl.bindExpressions
+                (
+                 fromList,
+                 new SubqueryList( getContextManager() ),
+                 new ArrayList<AggregateNode>()
+                 );
+        }
+        finally
+        {
+            // Restore previous compiler state
+            cc.setReliability( previousReliability );
+            cc.skipTypePrivileges( wasSkippingTypePrivileges );
+        }
+    }
+
     /**
      * <p>
      * Forbid subqueries in WHEN [ NOT ] MATCHED clauses.
@@ -1385,7 +1404,7 @@ public class MatchingClauseNode extends 
 
     /**
      * <p>
-     * Adds a field to the generated class to hold the ResultSet of buffered rows
+     * Adds a field to the generated class to hold the ResultSet of "then" rows
      * which drive the INSERT/UPDATE/DELETE action. Generates code to push
      * the contents of that field onto the stack.
      * </p>
@@ -1525,17 +1544,6 @@ public class MatchingClauseNode extends 
         }
     }
     
-    /** Return true if the ResultColumn represents a RowLocation */
-    private boolean isRowLocation( ResultColumn rc ) throws StandardException
-    {
-        if ( rc.getExpression() instanceof CurrentRowLocationNode ) { return true; }
-
-        DataTypeDescriptor  dtd = rc.getTypeServices();
-        if ( (dtd != null) && (dtd.getTypeId().isRefTypeId()) ) { return true; }
-
-        return false;
-    }
-    
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // Visitable BEHAVIOR
@@ -1634,4 +1642,15 @@ public class MatchingClauseNode extends 
         return getCRs.getList();
     }
 
+    /** Return true if the ResultColumn represents a RowLocation */
+    private boolean isRowLocation( ResultColumn rc ) throws StandardException
+    {
+        if ( rc.getExpression() instanceof CurrentRowLocationNode ) { return true; }
+
+        DataTypeDescriptor  dtd = rc.getTypeServices();
+        if ( (dtd != null) && (dtd.getTypeId().isRefTypeId()) ) { return true; }
+
+        return false;
+    }
+    
 }

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=1579725&r1=1579724&r2=1579725&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 Thu Mar 20 19:50:05 2014
@@ -119,7 +119,7 @@ import org.apache.derby.shared.common.sa
  * whether a given driving row matches. The row matches iff targetTable.RowLocation is not null.
  * The driving row is then assigned to the
  * first DELETE/UPDATE/INSERT action to which it applies. The relevant columns from
- * the driving row are extracted and buffered in a temporary table specific to that
+ * the driving row are extracted and buffered in a temporary table (the "then" rows) specific to that
  * DELETE/UPDATE/INSERT action. After the driving left join has been processed,
  * the DELETE/UPDATE/INSERT actions are run in order, each taking its corresponding
  * temporary table as its source ResultSet.
@@ -193,6 +193,90 @@ public final class MergeNode extends DML
 
     ///////////////////////////////////////////////////////////////////////////////////
     //
+    // BIND-TIME ENTRY POINTS CALLED BY MatchingClauseNode
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /** Get the target table for the MERGE statement */
+    FromBaseTable   getTargetTable() { return _targetTable; }
+
+    /** Associate a column with the SOURCE or TARGET table */
+    void    associateColumn( FromList fromList, 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) fromList.elementAt( SOURCE_TABLE_INDEX )).getMatchingColumn( cr ) != null )
+            {
+                cr.setMergeTableID( ColumnReference.MERGE_SOURCE );
+            }
+            else if ( ((FromTable) fromList.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().
+    }
+
+    /** Boilerplate for binding an expression against a FromList */
+    void bindExpression( ValueNode value, FromList fromList )
+        throws StandardException
+    {
+        CompilerContext cc = getCompilerContext();
+        final int previousReliability = cc.getReliability();
+
+        cc.setReliability( previousReliability | CompilerContext.SQL_IN_ROUTINES_ILLEGAL );
+        cc.pushCurrentPrivType( Authorizer.SELECT_PRIV );
+            
+        try {
+            // this adds SELECT priv on referenced columns and EXECUTE privs on referenced routines
+            value.bindExpression
+                (
+                 fromList,
+                 new SubqueryList( getContextManager() ),
+                 new ArrayList<AggregateNode>()
+                 );
+        }
+        finally
+        {
+            // Restore previous compiler state
+            cc.popCurrentPrivType();
+            cc.setReliability( previousReliability );
+        }
+    }
+
+    /** Add the columns in the matchingRefinement clause to the evolving map */
+    void    getColumnsInExpression
+        ( HashMap<String,ColumnReference> map, ValueNode expression, int mergeTableID )
+        throws StandardException
+    {
+        if ( expression == null ) { return; }
+
+        List<ColumnReference> colRefs = getColumnReferences( expression );
+
+        getColumnsFromList( map, colRefs, mergeTableID );
+    }
+
+    /** Add a list of columns to the the evolving map */
+    void    getColumnsFromList
+        ( HashMap<String,ColumnReference> map, ResultColumnList rcl, int mergeTableID )
+        throws StandardException
+    {
+        List<ColumnReference> colRefs = getColumnReferences( rcl );
+
+        getColumnsFromList( map, colRefs, mergeTableID );
+    }
+    
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
     // bind() BEHAVIOR
     //
     ///////////////////////////////////////////////////////////////////////////////////
@@ -252,40 +336,11 @@ public final class MergeNode extends DML
         bindLeftJoin( dd );
 	}
 
-    /** Create a FromList for binding a WHEN [ NOT ] MATCHED clause */
-    private FromList    cloneFromList( DataDictionary dd, FromBaseTable targetTable )
-        throws StandardException
-    {
-        FromList    dummyFromList = new FromList( getContextManager() );
-        FromBaseTable   dummyTargetTable = new FromBaseTable
-            (
-             targetTable.getTableNameField(),
-             targetTable.correlationName,
-             null,
-             null,
-             getContextManager()
-             );
-        FromTable       dummySourceTable = cloneFromTable( _sourceTable );
-
-        dummyTargetTable.setMergeTableID( ColumnReference.MERGE_TARGET );
-        dummySourceTable.setMergeTableID ( ColumnReference.MERGE_SOURCE );
-        
-        dummyFromList.addFromTable( dummySourceTable );
-        dummyFromList.addFromTable( dummyTargetTable );
-        
-        //
-        // Don't add any privileges while binding the tables.
-        //
-        IgnoreFilter    ignorePermissions = new IgnoreFilter();
-        getCompilerContext().addPrivilegeFilter( ignorePermissions );
-             
-        dummyFromList.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(), getContextManager() ) );
-
-        // ready to add permissions
-        getCompilerContext().removePrivilegeFilter( ignorePermissions );
-        
-        return dummyFromList;
-    }
+    /////////////////////////////////////
+    //
+    // TABLE AND CORRELATION CHECKS
+    //
+    /////////////////////////////////////
 
     /** Get the exposed name of a FromTable */
     private String  getExposedName( FromTable ft ) throws StandardException
@@ -337,6 +392,59 @@ public final class MergeNode extends DML
         }
     }
 
+    /** Throw a "not base table" exception */
+    private void    notBaseTable()  throws StandardException
+    {
+        throw StandardException.newException( SQLState.LANG_TARGET_NOT_BASE_TABLE );
+    }
+
+    /** Return true if the target table is a base table */
+    private boolean targetIsBaseTable( FromBaseTable targetTable ) throws StandardException
+    {
+        FromBaseTable   fbt = targetTable;
+        TableDescriptor desc = fbt.getTableDescriptor();
+        if ( desc == null ) { return false; }
+
+        switch( desc.getTableType() )
+        {
+        case TableDescriptor.BASE_TABLE_TYPE:
+        case TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE:
+            return true;
+
+        default:
+            return false;
+        }
+    }
+
+    /** Return true if the source table is a base table, view, or table function */
+    private boolean sourceIsBase_View_or_VTI() throws StandardException
+    {
+        if ( _sourceTable instanceof FromVTI ) { return true; }
+        if ( !( _sourceTable instanceof FromBaseTable) ) { return false; }
+
+        FromBaseTable   fbt = (FromBaseTable) _sourceTable;
+        TableDescriptor desc = fbt.getTableDescriptor();
+        if ( desc == null ) { return false; }
+
+        switch( desc.getTableType() )
+        {
+        case TableDescriptor.BASE_TABLE_TYPE:
+        case TableDescriptor.SYSTEM_TABLE_TYPE:
+        case TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE:
+        case TableDescriptor.VIEW_TYPE:
+            return true;
+
+        default:
+            return false;
+        }
+    }
+
+    ///////////////////////////
+    //
+    // BINDING THE LEFT JOIN
+    //
+    ///////////////////////////
+
     /**
      * Bind the driving left join select.
      * Stuffs the left join SelectNode into the resultSet variable.
@@ -453,109 +561,45 @@ public final class MergeNode extends DML
         }
     }
 
-    /** Get the target table for the MERGE statement */
-    FromBaseTable   getTargetTable() { return _targetTable; }
-
-    /** Throw a "not base table" exception */
-    private void    notBaseTable()  throws StandardException
-    {
-        throw StandardException.newException( SQLState.LANG_TARGET_NOT_BASE_TABLE );
-    }
+    ////////////////////////////
+    //
+    // CLONING THE FROM LIST
+    //
+    ////////////////////////////
 
-    /** Build the select list for the left join */
-    private ResultColumnList    buildSelectList() throws StandardException
+    /** Create a FromList for binding a WHEN [ NOT ] MATCHED clause */
+    private FromList    cloneFromList( DataDictionary dd, FromBaseTable targetTable )
+        throws StandardException
     {
-        HashMap<String,ColumnReference> drivingColumnMap = new HashMap<String,ColumnReference>();
-        getColumnsInExpression( drivingColumnMap, _searchCondition, ColumnReference.MERGE_UNKNOWN );
-        
-        for ( MatchingClauseNode mcn : _matchingClauses )
-        {
-            mcn.getColumnsInExpressions( this, drivingColumnMap );
-
-            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,
-             ColumnReference.MERGE_SOURCE
-             );
-        // add all of the columns from the target table which are mentioned
-        addColumns
+        FromList    dummyFromList = new FromList( getContextManager() );
+        FromBaseTable   dummyTargetTable = new FromBaseTable
             (
-             (FromTable) _leftJoinFromList.elementAt( TARGET_TABLE_INDEX ),
-             drivingColumnMap,
-             selectList,
-             ColumnReference.MERGE_TARGET
+             targetTable.getTableNameField(),
+             targetTable.correlationName,
+             null,
+             null,
+             getContextManager()
              );
+        FromTable       dummySourceTable = cloneFromTable( _sourceTable );
 
-        addTargetRowLocation( selectList );
-
-        return selectList;
-    }
-
-    /** Add the target table's row location to the left join's select list */
-    private void    addTargetRowLocation( ResultColumnList selectList )
-        throws StandardException
-    {
-        // tell the target table to generate a row location column
-        _targetTable.setRowLocationColumnName( TARGET_ROW_LOCATION_NAME );
-
-        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();
-
-        selectList.addResultColumn( rowLocationColumn );
-    }
-
-    /** Return true if the target table is a base table */
-    private boolean targetIsBaseTable( FromBaseTable targetTable ) throws StandardException
-    {
-        FromBaseTable   fbt = targetTable;
-        TableDescriptor desc = fbt.getTableDescriptor();
-        if ( desc == null ) { return false; }
-
-        switch( desc.getTableType() )
-        {
-        case TableDescriptor.BASE_TABLE_TYPE:
-        case TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE:
-            return true;
-
-        default:
-            return false;
-        }
-    }
-
-    /** Return true if the source table is a base table, view, or table function */
-    private boolean sourceIsBase_View_or_VTI() throws StandardException
-    {
-        if ( _sourceTable instanceof FromVTI ) { return true; }
-        if ( !( _sourceTable instanceof FromBaseTable) ) { return false; }
-
-        FromBaseTable   fbt = (FromBaseTable) _sourceTable;
-        TableDescriptor desc = fbt.getTableDescriptor();
-        if ( desc == null ) { return false; }
-
-        switch( desc.getTableType() )
-        {
-        case TableDescriptor.BASE_TABLE_TYPE:
-        case TableDescriptor.SYSTEM_TABLE_TYPE:
-        case TableDescriptor.GLOBAL_TEMPORARY_TABLE_TYPE:
-        case TableDescriptor.VIEW_TYPE:
-            return true;
+        dummyTargetTable.setMergeTableID( ColumnReference.MERGE_TARGET );
+        dummySourceTable.setMergeTableID ( ColumnReference.MERGE_SOURCE );
+        
+        dummyFromList.addFromTable( dummySourceTable );
+        dummyFromList.addFromTable( dummyTargetTable );
+        
+        //
+        // Don't add any privileges while binding the tables.
+        //
+        IgnoreFilter    ignorePermissions = new IgnoreFilter();
+        getCompilerContext().addPrivilegeFilter( ignorePermissions );
+             
+        dummyFromList.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(), getContextManager() ) );
 
-        default:
-            return false;
-        }
+        // ready to add permissions
+        getCompilerContext().removePrivilegeFilter( ignorePermissions );
+        
+        return dummyFromList;
     }
 
     /** Clone a FromTable to avoid binding the original */
@@ -593,6 +637,12 @@ public final class MergeNode extends DML
         }
     }
 
+    ///////////////////////////
+    //
+    // PRIVILEGE MANAGEMENT
+    //
+    ///////////////////////////
+
     /**
      * <p>
      * Add the privileges required by the ON clause.
@@ -658,6 +708,92 @@ public final class MergeNode extends DML
         cc.popCurrentPrivType();
     }
 
+    /** Get a list of CastNodes in an expression */
+    private List<CastNode>   getCastNodes( QueryTreeNode expression )
+        throws StandardException
+    {
+        CollectNodesVisitor<CastNode> getCNs =
+            new CollectNodesVisitor<CastNode>(CastNode.class);
+
+        expression.accept(getCNs);
+        
+        return getCNs.getList();
+    }
+
+    /** Get a list of routines in an expression */
+    private List<StaticMethodCallNode>   getRoutineReferences( QueryTreeNode expression )
+        throws StandardException
+    {
+        CollectNodesVisitor<StaticMethodCallNode> getSMCNs =
+            new CollectNodesVisitor<StaticMethodCallNode>(StaticMethodCallNode.class);
+
+        expression.accept(getSMCNs);
+        
+        return getSMCNs.getList();
+    }
+
+    ///////////////////////////////
+    //
+    // BUILD THE SELECT LIST
+    // FOR THE DRIVING LEFT JOIN
+    //
+    ///////////////////////////////
+
+    /** Build the select list for the left join */
+    private ResultColumnList    buildSelectList() throws StandardException
+    {
+        HashMap<String,ColumnReference> drivingColumnMap = new HashMap<String,ColumnReference>();
+        getColumnsInExpression( drivingColumnMap, _searchCondition, ColumnReference.MERGE_UNKNOWN );
+        
+        for ( MatchingClauseNode mcn : _matchingClauses )
+        {
+            mcn.getColumnsInExpressions( this, drivingColumnMap );
+
+            int mergeTableID = mcn.isDeleteClause() ? ColumnReference.MERGE_TARGET : ColumnReference.MERGE_UNKNOWN;
+            getColumnsFromList( drivingColumnMap, mcn.getThenColumns(), 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,
+             ColumnReference.MERGE_SOURCE
+             );
+        // add all of the columns from the target table which are mentioned
+        addColumns
+            (
+             (FromTable) _leftJoinFromList.elementAt( TARGET_TABLE_INDEX ),
+             drivingColumnMap,
+             selectList,
+             ColumnReference.MERGE_TARGET
+             );
+
+        addTargetRowLocation( selectList );
+
+        return selectList;
+    }
+
+    /** Add the target table's row location to the left join's select list */
+    private void    addTargetRowLocation( ResultColumnList selectList )
+        throws StandardException
+    {
+        // tell the target table to generate a row location column
+        _targetTable.setRowLocationColumnName( TARGET_ROW_LOCATION_NAME );
+
+        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();
+
+        selectList.addResultColumn( rowLocationColumn );
+    }
+
     /**
      * <p>
      * Add to an evolving select list the columns from the indicated table.
@@ -702,42 +838,6 @@ public final class MergeNode extends DML
         return retval;
     }
     
-    /** Add the columns in the matchingRefinement clause to the evolving map */
-    void    getColumnsInExpression
-        ( HashMap<String,ColumnReference> map, ValueNode expression, int mergeTableID )
-        throws StandardException
-    {
-        if ( expression == null ) { return; }
-
-        List<ColumnReference> colRefs = getColumnReferences( expression );
-
-        getColumnsFromList( map, colRefs, mergeTableID );
-    }
-
-    /** Get a list of CastNodes in an expression */
-    private List<CastNode>   getCastNodes( QueryTreeNode expression )
-        throws StandardException
-    {
-        CollectNodesVisitor<CastNode> getCNs =
-            new CollectNodesVisitor<CastNode>(CastNode.class);
-
-        expression.accept(getCNs);
-        
-        return getCNs.getList();
-    }
-
-    /** Get a list of routines in an expression */
-    private List<StaticMethodCallNode>   getRoutineReferences( QueryTreeNode expression )
-        throws StandardException
-    {
-        CollectNodesVisitor<StaticMethodCallNode> getSMCNs =
-            new CollectNodesVisitor<StaticMethodCallNode>(StaticMethodCallNode.class);
-
-        expression.accept(getSMCNs);
-        
-        return getSMCNs.getList();
-    }
-
     /** Get a list of column references in an expression */
     private List<ColumnReference>   getColumnReferences( QueryTreeNode expression )
         throws StandardException
@@ -751,16 +851,6 @@ public final class MergeNode extends DML
     }
 
     /** Add a list of columns to the the evolving map */
-    void    getColumnsFromList
-        ( HashMap<String,ColumnReference> map, ResultColumnList rcl, int mergeTableID )
-        throws StandardException
-    {
-        List<ColumnReference> colRefs = getColumnReferences( rcl );
-
-        getColumnsFromList( map, colRefs, mergeTableID );
-    }
-    
-    /** Add a list of columns to the the evolving map */
     private void    getColumnsFromList
         ( HashMap<String,ColumnReference> map, List<ColumnReference> colRefs, int mergeTableID )
         throws StandardException
@@ -803,65 +893,12 @@ public final class MergeNode extends DML
         }
     }
 
-    /** Associate a column with the SOURCE or TARGET table */
-    void    associateColumn( FromList fromList, 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) fromList.elementAt( SOURCE_TABLE_INDEX )).getMatchingColumn( cr ) != null )
-            {
-                cr.setMergeTableID( ColumnReference.MERGE_SOURCE );
-            }
-            else if ( ((FromTable) fromList.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 )
     {
         return IdUtil.mkQualifiedName( tableName, columnName );
     }
 
-    /** Boilerplate for binding an expression against a FromList */
-    void bindExpression( ValueNode value, FromList fromList )
-        throws StandardException
-    {
-        CompilerContext cc = getCompilerContext();
-        final int previousReliability = cc.getReliability();
-
-        cc.setReliability( previousReliability | CompilerContext.SQL_IN_ROUTINES_ILLEGAL );
-        cc.pushCurrentPrivType( Authorizer.SELECT_PRIV );
-            
-        try {
-            // this adds SELECT priv on referenced columns and EXECUTE privs on referenced routines
-            value.bindExpression
-                (
-                 fromList,
-                 new SubqueryList( getContextManager() ),
-                 new ArrayList<AggregateNode>()
-                 );
-        }
-        finally
-        {
-            // Restore previous compiler state
-            cc.popCurrentPrivType();
-            cc.setReliability( previousReliability );
-        }
-    }
-
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // optimize() BEHAVIOR
@@ -894,6 +931,7 @@ public final class MergeNode extends DML
         // ready to add permissions again
         getCompilerContext().removePrivilegeFilter( ignorePermissions );
 	}
+    
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // generate() BEHAVIOR

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MatchingClauseConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MatchingClauseConstantAction.java?rev=1579725&r1=1579724&r2=1579725&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MatchingClauseConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MatchingClauseConstantAction.java Thu Mar 20 19:50:05 2014
@@ -193,7 +193,7 @@ public class MatchingClauseConstantActio
     
     ///////////////////////////////////////////////////////////////////////////////////
     //
-    // OTHER PUBLIC BEHAVIOR
+    // OTHER PACKAGE VISIBLE BEHAVIOR, CALLED BY MergeResultSet
     //
     ///////////////////////////////////////////////////////////////////////////////////
 
@@ -268,13 +268,36 @@ public class MatchingClauseConstantActio
     
     /**
      * <p>
+     * Release resources at the end.
+     * </p>
+     */
+    void    cleanUp()   throws StandardException
+    {
+        if ( _actionRS != null )
+        {
+            _actionRS.close();
+            _actionRS = null;
+        }
+
+        _matchRefinementMethod = null;
+        _rowMakingMethod = null;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////////////
+    //
+    // MINIONS
+    //
+    ///////////////////////////////////////////////////////////////////////////////////
+
+    /**
+     * <p>
      * Construct and buffer a row for the DELETE
      * action corresponding to this MATCHED clause. The buffered row
      * is built from columns in the passed-in row. The passed-in row is the SELECT list
      * of the MERGE statement's driving left join.
      * </p>
      */
-    ExecRow    bufferThenRowForDelete
+    private ExecRow    bufferThenRowForDelete
         (
          Activation activation,
          ExecRow selectRow
@@ -297,7 +320,7 @@ public class MatchingClauseConstantActio
      * action corresponding to this [ NOT ] MATCHED clause.
      * </p>
      */
-    ExecRow    bufferThenRow
+    private ExecRow    bufferThenRow
         (
          Activation activation
          )
@@ -313,23 +336,6 @@ public class MatchingClauseConstantActio
     
     /**
      * <p>
-     * Release resources at the end.
-     * </p>
-     */
-    void    cleanUp()   throws StandardException
-    {
-        if ( _actionRS != null )
-        {
-            _actionRS.close();
-            _actionRS = null;
-        }
-
-        _matchRefinementMethod = null;
-        _rowMakingMethod = null;
-    }
-
-    /**
-     * <p>
      * Create the temporary table for holding the rows which are buffered up
      * for bulk-processing after the driving left join completes.
      * </p>