db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From rhille...@apache.org
Subject svn commit: r1540713 [1/2] - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/sql/dictionary/ engine/org/apache/derby/iapi/sql/execute/ engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/impl/sql/execute/ testing/org/apache/der...
Date Mon, 11 Nov 2013 13:40:28 GMT
Author: rhillegas
Date: Mon Nov 11 13:40:27 2013
New Revision: 1540713

URL: http://svn.apache.org/r1540713
Log:
DERBY-3155: Add support for INSERT action of MERGE statement; commit derby-3155-07-ad-insertAction.diff.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TableDescriptor.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/NoPutResultSet.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/DeleteNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.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/ResultColumnList.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/UpdateNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLVTIResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteVTIResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericConstantActionFactory.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertVTIResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MatchingClauseConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MergeResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MiscResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/NoRowsResultSetImpl.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdatableVTIConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateVTIResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/WriteCursorConstantAction.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/dictionary/TableDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TableDescriptor.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TableDescriptor.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/dictionary/TableDescriptor.java Mon Nov 11 13:40:27 2013
@@ -1127,7 +1127,7 @@ public class TableDescriptor extends Uni
 	}
 
 	/**
-	 * @param columnNumber	The ordinal position of the column in the table
+	 * @param columnNumber	The ordinal (1-based) position of the column in the table
 	 *
 	 * @return	A ColumnDescriptor describing the column
 	 */

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/NoPutResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/NoPutResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/NoPutResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/sql/execute/NoPutResultSet.java Mon Nov 11 13:40:27 2013
@@ -48,6 +48,9 @@ public interface NoPutResultSet extends 
 	public	static	final	String	LAST			=	"last";
 	public	static	final	String	PREVIOUS		=	"previous";
 
+    // result set number of all temporary result sets
+    public  static  final   int TEMPORARY_RESULT_SET_NUMBER = 0;
+    
 	/**
 	 * Mark the ResultSet as the topmost one in the ResultSet tree.
 	 * Useful for closing down the ResultSet on an error.

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=1540713&r1=1540712&r2=1540713&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 Mon Nov 11 13:40:27 2013
@@ -1607,6 +1607,21 @@ abstract class DMLModStatementNode exten
             userExprFun.dup();       // instance (current row)
             userExprFun.push(i + 1); // arg1
 
+            // poke our result set number into all column references in this generation expression
+            // if we're an action of a MERGE statement. that is because the dummy SELECT was not
+            // actually optimized so column references still need result set numbers
+            if ( inMatchingClause() )
+            {
+                CollectNodesVisitor<ColumnReference> getCRs =
+                    new CollectNodesVisitor<ColumnReference>( ColumnReference.class );
+                rc.accept( getCRs );
+
+                for ( ColumnReference cr : getCRs.getList() )
+                {
+                    cr.getSource().setResultSetNumber( rsNumber );
+                }
+            }
+
             rc.generateExpression(ecb, userExprFun);
             userExprFun.cast(ClassName.DataValueDescriptor);
                 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DeleteNode.java Mon Nov 11 13:40:27 2013
@@ -470,7 +470,8 @@ class DeleteNode extends DMLModStatement
 					  readColsBitSet.getNumBitsSet(),			
 				  (UUID) null,
 				  resultSet.isOneRowResultSet(),
-				  dependentConstantActions);
+				  dependentConstantActions,
+                  inMatchingClause());
 		}
 		else
 		{

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/InsertNode.java Mon Nov 11 13:40:27 2013
@@ -791,7 +791,8 @@ public final class InsertNode extends DM
 				  null,
 				  null,
 				  resultSet.isOneRowResultSet(), 
-				  autoincRowLocation
+				  autoincRowLocation,
+				  inMatchingClause()
 				  );
 		}
 		else
@@ -928,7 +929,14 @@ public final class InsertNode extends DM
 			acb.pushGetResultSetFactoryExpression(mb);
 
 			// arg 1
-			resultSet.generate(acb, mb);
+            if ( inMatchingClause() )
+            {
+                matchingClause.generateResultSetField( acb, mb );
+            }
+            else
+            {
+                resultSet.generate( acb, mb );
+            }
 
 			// arg 2 generate code to evaluate generation clauses
 			generateGenerationClauses( resultColumnList, resultSet.getResultSetNumber(), false, acb, mb );

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=1540713&r1=1540712&r2=1540713&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 Mon Nov 11 13:40:27 2013
@@ -24,18 +24,26 @@ package	org.apache.derby.impl.sql.compil
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.List;
+import org.apache.derby.catalog.types.DefaultInfoImpl;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.ClassName;
 import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.services.classfile.VMOpcode;
 import org.apache.derby.iapi.services.compiler.LocalField;
 import org.apache.derby.iapi.services.compiler.MethodBuilder;
 import org.apache.derby.iapi.services.context.ContextManager;
 import org.apache.derby.iapi.services.io.FormatableBitSet;
 import org.apache.derby.shared.common.sanity.SanityManager;
+import org.apache.derby.iapi.sql.ResultColumnDescriptor;
+import org.apache.derby.iapi.sql.ResultDescription;
 import org.apache.derby.iapi.sql.compile.CompilerContext;
 import org.apache.derby.iapi.sql.compile.Visitor;
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptor;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
 import org.apache.derby.iapi.sql.execute.ConstantAction;
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;
 
 /**
  * Node representing a WHEN MATCHED or WHEN NOT MATCHED clause
@@ -74,12 +82,13 @@ public class MatchingClauseNode extends 
 
     /** the columns in the temporary conglomerate which drives the INSERT/UPDATE/DELETE */
     private ResultColumnList        _thenColumns;
-    private int[]                           _thenColumnOffsets;
+    private int[]                           _deleteColumnOffsets;
 
     // Filled in at generate() time
     private int                             _clauseNumber;
     private String                          _actionMethodName;
     private String                          _resultSetFieldName;
+    private String                          _rowMakingMethodName;
     
     ///////////////////////////////////////////////////////////////////////////////////
     //
@@ -98,6 +107,7 @@ public class MatchingClauseNode extends 
          ResultColumnList   insertValues,
          ContextManager     cm
          )
+        throws StandardException
     {
         super( cm );
         
@@ -114,6 +124,7 @@ public class MatchingClauseNode extends 
          ResultColumnList   updateColumns,
          ContextManager     cm
          )
+        throws StandardException
     {
         return new MatchingClauseNode( matchingRefinement, updateColumns, null, null, cm );
     }
@@ -124,6 +135,7 @@ public class MatchingClauseNode extends 
          ValueNode  matchingRefinement,
          ContextManager     cm
          )
+        throws StandardException
     {
         return new MatchingClauseNode( matchingRefinement, null, null, null, cm );
     }
@@ -136,6 +148,7 @@ public class MatchingClauseNode extends 
          ResultColumnList   insertValues,
          ContextManager     cm
          )
+        throws StandardException
     {
         return new MatchingClauseNode( matchingRefinement, null, insertColumns, insertValues, cm );
     }
@@ -180,13 +193,11 @@ public class MatchingClauseNode extends 
          )
         throws StandardException
     {
-        bindExpressions( mergeNode, fullFromList, targetTable );
-        
+        _thenColumns = new ResultColumnList( getContextManager() );
+
         if ( isDeleteClause() ) { bindDelete( dd, fullFromList, targetTable ); }
         if ( isUpdateClause() ) { bindUpdate( dd, fullFromList, targetTable ); }
         if ( isInsertClause() ) { bindInsert( dd, mergeNode, fullFromList, targetTable ); }
-
-        bindExpressions( _thenColumns, fullFromList );
     }
 
     /** Bind the optional refinement condition in the MATCHED clause */
@@ -198,32 +209,12 @@ public class MatchingClauseNode extends 
         }
     }
 
-    /** Bind the expressions in this MATCHED clause */
-    private void    bindExpressions
-        (
-         MergeNode mergeNode,
-         FromList fullFromList,
-         FromTable targetTable
-         )
-        throws StandardException
+    /** Re-bind various clauses and lists once we have ResultSet numbers for the driving left join */
+    void    bindResultSetNumbers( MergeNode mergeNode, FromList fullFromList ) throws StandardException
     {
-        _thenColumns = new ResultColumnList( getContextManager() );
-
-        if ( isUpdateClause() )
-        {
-            // needed to make the UpdateNode bind
-            _updateColumns.replaceOrForbidDefaults( targetTable.getTableDescriptor(), _updateColumns, true );
-
-            bindExpressions( _updateColumns, fullFromList );
-        }
-        else if ( isInsertClause() )
-        {
-            // needed to make the SelectNode bind
-            _insertValues.replaceOrForbidDefaults( targetTable.getTableDescriptor(), _insertColumns, true );
-            bindExpressions( _insertValues, fullFromList );
-        }
+        bindRefinement( mergeNode, fullFromList );
     }
-    
+
     /** Collect the columns mentioned by expressions in this MATCHED clause */
     void    getColumnsInExpressions
         (
@@ -255,6 +246,8 @@ public class MatchingClauseNode extends 
         }
     }
     
+    ////////////////////// UPDATE ///////////////////////////////
+
     /** Bind a WHEN MATCHED ... THEN UPDATE clause */
     private void    bindUpdate
         (
@@ -264,6 +257,8 @@ public class MatchingClauseNode extends 
          )
         throws StandardException
     {
+        bindSetClauses( fullFromList, targetTable );
+        
         SelectNode  selectNode = new SelectNode
             (
              _updateColumns,
@@ -280,6 +275,22 @@ public class MatchingClauseNode extends 
         _dml.bindStatement();
     }
     
+    /** Bind the SET clauses of an UPDATE action */
+    private void    bindSetClauses
+        (
+         FromList fullFromList,
+         FromTable targetTable
+         )
+        throws StandardException
+    {
+        // needed to make the UpdateNode bind
+        _updateColumns.replaceOrForbidDefaults( targetTable.getTableDescriptor(), _updateColumns, true );
+
+        bindExpressions( _updateColumns, fullFromList );
+    }
+
+    ////////////////////// DELETE ///////////////////////////////
+
     /** Bind a WHEN MATCHED ... THEN DELETE clause */
     private void    bindDelete
         (
@@ -308,10 +319,22 @@ public class MatchingClauseNode extends 
 
         _dml.bindStatement();
 
-        ResultColumnList    deleteSignature = _dml.resultSet.resultColumns;
-        for ( int i = 0; i < deleteSignature.size(); i++ )
+        buildThenColumnsForDelete();
+    }
+
+    /**
+     * <p>
+     * Construct the signature of the temporary table which drives the
+     * INSERT/UPDATE/DELETE action.
+     * </p>
+     */
+    private void    buildThenColumnsForDelete()
+        throws StandardException
+    {
+        ResultColumnList    dmlSignature = _dml.resultSet.resultColumns;
+        for ( int i = 0; i < dmlSignature.size(); i++ )
         {
-            ResultColumn    origRC = deleteSignature.elementAt( i );
+            ResultColumn    origRC = dmlSignature.elementAt( i );
             ResultColumn    newRC;
             ValueNode       expression = origRC.getExpression();
 
@@ -328,6 +351,35 @@ public class MatchingClauseNode extends 
         }
     }
 
+    /**
+     * <p>
+     * Calculate the 1-based offsets which define the 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
+     * offsets will form the row which is buffered up for the DELETE
+     * action.
+     * </p>
+     */
+    void    bindDeleteThenColumns( ResultColumnList selectList )
+        throws StandardException
+    {
+        int     bufferedCount = _thenColumns.size();
+        int     selectCount = selectList.size();
+        
+        _deleteColumnOffsets = new int[ bufferedCount ];
+
+        for ( int bidx = 0; bidx < bufferedCount; bidx++ )
+        {
+            ResultColumn    bufferedRC = _thenColumns.elementAt( bidx );
+            ValueNode       bufferedExpression = bufferedRC.getExpression();
+
+            _deleteColumnOffsets[ bidx ] = getSelectListOffset( selectList, bufferedExpression );
+        }
+    }
+
+    ////////////////////// INSERT ///////////////////////////////
+
     /** Bind a WHEN NOT MATCHED ... THEN INSERT clause */
     private void    bindInsert
         (
@@ -338,6 +390,8 @@ public class MatchingClauseNode extends 
          )
         throws StandardException
     {
+        bindInsertValues( fullFromList, targetTable );
+        
         // the VALUES clause may not mention columns in the target table
         FromList    targetTableFromList = new FromList( getOptimizerFactory().doJoinOrderOptimization(), getContextManager() );
         targetTableFromList.addElement( fullFromList.elementAt( 0 ) );
@@ -373,8 +427,162 @@ public class MatchingClauseNode extends 
              );
 
         _dml.bindStatement();
+
+        buildInsertThenColumns( targetTable );
+    }
+
+    /**  Bind the values in the INSERT list */
+    private void    bindInsertValues
+        (
+         FromList fullFromList,
+         FromTable targetTable
+         )
+        throws StandardException
+    {
+        if ( _insertColumns.size() != _insertValues.size() )
+        {
+            throw StandardException.newException( SQLState.LANG_DB2_INVALID_COLS_SPECIFIED ); 
+        }
+        
+        TableDescriptor td = targetTable.getTableDescriptor();
+
+        // forbid illegal values for identity columns
+        for ( int i = 0; i <_insertValues.size(); i++ )
+        {
+            ResultColumn    rc = _insertValues.elementAt( i );
+            String          columnName = _insertColumns.elementAt( i ).exposedName;
+            ValueNode       expr = rc.getExpression();
+            ColumnDescriptor    cd = td.getColumnDescriptor( columnName );
+
+            // if the column isn't in the table, this will be sorted out when we bind
+            // the InsertNode
+            if ( cd == null ) { continue; }
+
+            // DEFAULT is the only value allowed for a GENERATED ALWAYS AS IDENTITY column
+            if ( cd.isAutoincAlways() && !(expr instanceof DefaultNode) )
+            {
+                throw StandardException.newException( SQLState.LANG_AI_CANNOT_MODIFY_AI, columnName );
+            }
+
+            // NULL is illegal as the value for any identity column
+            if ( cd.isAutoincrement() && (expr instanceof UntypedNullConstantNode) )
+            {
+                throw StandardException.newException( SQLState.LANG_NULL_INTO_NON_NULL, columnName );
+            }
+        }
+        
+        // needed to make the SelectNode bind
+        _insertValues.replaceOrForbidDefaults( targetTable.getTableDescriptor(), _insertColumns, true );
+        bindExpressions( _insertValues, fullFromList );
+    }
+    
+    /** Construct the row in the temporary table which drives an INSERT action */
+    private void    buildInsertThenColumns( FromTable targetTable )
+        throws StandardException
+    {
+        TableDescriptor td = targetTable.getTableDescriptor();
+
+        _thenColumns = _dml.resultSet.resultColumns.copyListAndObjects();
+
+        //
+        // Here we set up for the evaluation of expressions in the temporary table
+        // which drives the INSERT action. If we were actually generating the dummy SELECT
+        // for the DML action, the work would normally be done there. But we don't generate
+        // that SELECT. So we do the following here:
+        //
+        // 1) If a column has a value specified in the WHEN [ NOT ] MATCHED clause, then we use it.
+        //     There is some special handling to make the DEFAULT value work for identity columns.
+        //
+        // 2) Otherwise, if the column has a default, then we plug it in.
+        //
+        for ( int i = 0; i < _thenColumns.size(); i++ )
+        {
+            ColumnDescriptor    cd = td.getColumnDescriptor( i + 1 );
+            ResultColumn    origRC = _thenColumns.elementAt( i );
+            String              columnName = origRC.getName();
+            
+            boolean         changed = false;
+
+            //
+            // VirtualColumnNodes are skipped at code-generation time. This can result in
+            // NPEs when evaluating generation expressions. Replace VirtualColumnNodes with
+            // UntypedNullConstantNodes, except for identity columns, which require special
+            // handling below.
+            //
+            if ( !origRC.isAutoincrement() && (origRC.getExpression() instanceof VirtualColumnNode) )
+            {
+                origRC.setExpression( new UntypedNullConstantNode( getContextManager() ) );
+            }
+
+            for ( int ic = 0; ic < _insertColumns.size(); ic++ )
+            {
+                ResultColumn    icRC = _insertColumns.elementAt( ic );
+
+                if ( columnName.equals( icRC.getName() ) )
+                {
+                    ResultColumn    newRC = null;
+                    
+                    // replace DEFAULT for a generated or identity column
+                    ResultColumn    insertRC =_insertValues.elementAt( ic );
+
+                    if ( insertRC.wasDefaultColumn() || (insertRC.getExpression() instanceof UntypedNullConstantNode ) )
+                    {
+                       if ( !cd.isAutoincrement() )
+                        {
+                            //
+                            // Eliminate column references under identity columns. They
+                            // will mess up the code generation.
+                            //
+                            ValueNode   expr = origRC.getExpression();
+                            if ( expr instanceof ColumnReference )
+                            {
+                                origRC.setExpression( new UntypedNullConstantNode( getContextManager() ) );
+                            }
+                            continue;
+                        }
+
+                        ColumnReference autoGenCR = new ColumnReference( columnName, targetTable.getTableName(), getContextManager() );
+                        ResultColumn    autoGenRC = new ResultColumn( autoGenCR, null, getContextManager() );
+                        VirtualColumnNode autoGenVCN = new VirtualColumnNode( targetTable, autoGenRC, i + 1, getContextManager() );
+
+                        newRC = new ResultColumn( autoGenCR, autoGenVCN, getContextManager() );
+
+                        // set the type so that buildThenColumnSignature() will function correctly
+                        newRC.setType( origRC.getTypeServices() );
+                    }
+                    else
+                    {
+                        newRC = insertRC.cloneMe();
+                        newRC.setType( origRC.getTypeServices() );
+                    }
+
+                    newRC.setVirtualColumnId( origRC.getVirtualColumnId() );
+                    _thenColumns.setElementAt( newRC, i  );
+                    changed = true;
+                    break;
+                }
+            }
+
+            // plug in defaults if we haven't done so already
+            if ( !changed )
+            {
+                DefaultInfoImpl     defaultInfo = (DefaultInfoImpl) cd.getDefaultInfo();
+
+				if ( (defaultInfo != null) && !defaultInfo.isGeneratedColumn() && !cd.isAutoincrement() )
+				{
+                    _thenColumns.setDefault( origRC, cd, defaultInfo );
+                    changed = true;
+				}
+            }
+
+            // set the result column name correctly for buildThenColumnSignature()
+            ResultColumn    finalRC = _thenColumns.elementAt( i );
+            finalRC.setName( cd.getColumnName() );
+        }   // end loop through _thenColumns
     }
 
+    ////////////////////// bind() MINIONS ///////////////////////////////
+
     /** Boilerplate for binding a list of ResultColumns against a FromList */
     private void bindExpressions( ResultColumnList rcl, FromList fromList )
         throws StandardException
@@ -401,67 +609,68 @@ public class MatchingClauseNode extends 
 
     /**
      * <p>
-     * Calculate the 1-based offsets which define the rows which will be buffered up
-     * for this INSERT/UPDATE/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
-     * offsets will form the row which is buffered up for the INSERT/UPDATE/DELETE
-     * action.
+     * Bind the row which will go into the temporary table at run-time.
      * </p>
      */
     void    bindThenColumns( ResultColumnList selectList )
         throws StandardException
     {
-        int     bufferedCount = _thenColumns.size();
-        int     selectCount = selectList.size();
-        
-        _thenColumnOffsets = new int[ bufferedCount ];
+        if ( isDeleteClause() ) { bindDeleteThenColumns( selectList ); }
+        else if ( isUpdateClause() )
+        {
+            throw StandardException.newException( SQLState.NOT_IMPLEMENTED, "MERGE" );
+        }
+    }
 
-        for ( int bidx = 0; bidx < bufferedCount; bidx++ )
+    /**
+     * <p>
+     * Find a column reference in the SELECT list of the driving left join
+     * and return its 1-based offset into that list.  Returns -1 if the column
+     * can't be found.
+     * </p>
+     */
+    private int getSelectListOffset( ResultColumnList selectList, ValueNode bufferedExpression )
+        throws StandardException
+    {
+        int                 selectCount = selectList.size();
+
+        if ( bufferedExpression instanceof ColumnReference )
         {
-            ResultColumn    bufferedRC = _thenColumns.elementAt( bidx );
-            ValueNode       bufferedExpression = bufferedRC.getExpression();
-            int                     offset = -1;    // start out undefined
+            ColumnReference bufferedCR = (ColumnReference) bufferedExpression;
+            String              tableName = bufferedCR.getTableName();
+            String              columnName = bufferedCR.getColumnName();
 
-            if ( bufferedExpression instanceof ColumnReference )
+            // loop through the SELECT list to find this column reference
+            for ( int sidx = 0; sidx < selectCount; sidx++ )
             {
-                ColumnReference bufferedCR = (ColumnReference) bufferedExpression;
-                String              tableName = bufferedCR.getTableName();
-                String              columnName = bufferedCR.getColumnName();
+                ResultColumn    selectRC = selectList.elementAt( sidx );
+                ValueNode       selectExpression = selectRC.getExpression();
+                ColumnReference selectCR = selectExpression instanceof ColumnReference ?
+                    (ColumnReference) selectExpression : null;
 
-                // loop through the SELECT list to find this column reference
-                for ( int sidx = 0; sidx < selectCount; sidx++ )
+                if ( selectCR != null )
                 {
-                    ResultColumn    selectRC = selectList.elementAt( sidx );
-                    ValueNode       selectExpression = selectRC.getExpression();
-                    ColumnReference selectCR = selectExpression instanceof ColumnReference ?
-                        (ColumnReference) selectExpression : null;
-
-                    if ( selectCR != null )
+                    if (
+                        tableName.equals( selectCR.getTableName() ) &&
+                        columnName.equals( selectCR.getColumnName() )
+                        )
                     {
-                        if (
-                            tableName.equals( selectCR.getTableName() ) &&
-                            columnName.equals( selectCR.getColumnName() )
-                            )
-                        {
-                            offset = sidx + 1;
-                            break;
-                        }
+                        return sidx + 1;
                     }
                 }
             }
-            else if ( bufferedExpression instanceof CurrentRowLocationNode )
-            {
-                //
-                // There is only one RowLocation in the SELECT list, the row location for the
-                // tuple from the target table. The RowLocation is always the last column in
-                // the SELECT list.
-                //
-                offset = selectCount;
-            }
-
-            _thenColumnOffsets[ bidx ] = offset;
         }
+        else if ( bufferedExpression instanceof CurrentRowLocationNode )
+        {
+            //
+            // There is only one RowLocation in the SELECT list, the row location for the
+            // tuple from the target table. The RowLocation is always the last column in
+            // the SELECT list.
+            //
+            return selectCount;
+        }
+
+        return -1;
     }
 
     ///////////////////////////////////////////////////////////////////////////////////
@@ -508,7 +717,9 @@ public class MatchingClauseNode extends 
             (
              getClauseType(),
              refinementName,
-             _thenColumnOffsets,
+             buildThenColumnSignature(),
+             _rowMakingMethodName,
+             _deleteColumnOffsets,
              _resultSetFieldName,
              _actionMethodName,
              _dml.makeConstantAction()
@@ -523,14 +734,36 @@ public class MatchingClauseNode extends 
 
     /**
      * <p>
+     * Build the signature of the row which will go into the temporary table.
+     * </p>
+     */
+    private ResultDescription    buildThenColumnSignature()
+        throws StandardException
+    {
+        ResultColumnDescriptor[]  cells = _thenColumns.makeResultDescriptors();
+
+        return getLanguageConnectionContext().getLanguageFactory().getResultDescription( cells, "MERGE" );
+    }
+
+    /**
+     * <p>
      * Generate a method to invoke the INSERT/UPDATE/DELETE action. This method
      * will be called at runtime by MatchingClauseConstantAction.executeConstantAction().
      * </p>
      */
-    void    generate( ActivationClassBuilder acb, int clauseNumber )
+    void    generate
+        (
+         ActivationClassBuilder acb,
+         ResultColumnList selectList,
+         HalfOuterJoinNode  hojn,
+         int    clauseNumber
+         )
         throws StandardException
     {
         _clauseNumber = clauseNumber;
+
+        if ( isInsertClause() ) { generateInsertRow( acb, selectList, hojn ); }
+        
         _actionMethodName = "mergeActionMethod_" + _clauseNumber;
         
         MethodBuilder mb = acb.getClassBuilder().newMethodBuilder
@@ -541,6 +774,8 @@ public class MatchingClauseNode extends 
              );
         mb.addThrownException(ClassName.StandardException);
 
+        remapConstraints();
+
         // now generate the action into this method
         _dml.generate( acb, mb );
         
@@ -550,6 +785,36 @@ public class MatchingClauseNode extends 
 
     /**
      * <p>
+     * Re-map ColumnReferences in constraints to point into the row from the
+     * temporary table. This is where the row will be stored when constraints
+     * are being evaluated.
+     * </p>
+     */
+    private void    remapConstraints()
+        throws StandardException
+    {
+        if( !isInsertClause() ) { return; }
+        else
+        {
+            CollectNodesVisitor<ColumnReference> getCRs =
+                new CollectNodesVisitor<ColumnReference>(ColumnReference.class);
+
+            ValueNode   checkConstraints = ((InsertNode) _dml).checkConstraints;
+
+            if ( checkConstraints != null )
+            {
+                checkConstraints.accept(getCRs);
+                List<ColumnReference> colRefs = getCRs.getList();
+                for ( ColumnReference cr : colRefs )
+                {
+                    cr.getSource().setResultSetNumber( NoPutResultSet.TEMPORARY_RESULT_SET_NUMBER );
+                }
+            }            
+        }
+    }
+
+    /**
+     * <p>
      * Adds a field to the generated class to hold the ResultSet of buffered rows
      * which drive the INSERT/UPDATE/DELETE action. Generates code to push
      * the contents of that field onto the stack.
@@ -573,6 +838,64 @@ public class MatchingClauseNode extends 
         mb.getField( resultSetField );
     }
     
+    /**
+     * <p>
+     * Generate a method to build a row for the temporary table for INSERT actions.
+     * The method stuffs each column in the row with the result of the corresponding
+     * expression built out of columns in the current row of the driving left join.
+     * The method returns the stuffed row.
+     * </p>
+     */
+    void    generateInsertRow
+        (
+         ActivationClassBuilder acb,
+         ResultColumnList selectList,
+         HalfOuterJoinNode  hojn
+         )
+        throws StandardException
+    {
+        // point expressions in the temporary row at the columns in the
+        // result column list of the driving left join.
+        adjustThenColumns( selectList, hojn );
+        
+        _rowMakingMethodName = "mergeRowMakingMethod_" + _clauseNumber;
+        
+        MethodBuilder mb = acb.getClassBuilder().newMethodBuilder
+            (
+             Modifier.PUBLIC,
+             ClassName.ExecRow,
+             _rowMakingMethodName
+             );
+        mb.addThrownException(ClassName.StandardException);
+
+        _thenColumns.generateEvaluatedRow( acb, mb, false, true );
+    }
+
+    /**
+     * <p>
+     * Point the column references in the temporary row at corresponding
+     * columns returned by the driving left join.
+     * </p>
+     */
+    void    adjustThenColumns
+        (
+         ResultColumnList selectList,
+         HalfOuterJoinNode  hojn
+         )
+        throws StandardException
+    {
+        ResultColumnList    leftJoinResult = hojn.resultColumns;
+        CollectNodesVisitor<ColumnReference> getCRs =
+            new CollectNodesVisitor<ColumnReference>( ColumnReference.class );
+        _thenColumns.accept( getCRs );
+
+        for ( ColumnReference cr : getCRs.getList() )
+        {
+            ResultColumn    leftJoinRC = leftJoinResult.elementAt( getSelectListOffset( selectList, cr ) - 1 );
+            cr.setSource( leftJoinRC );
+        }
+    }
+    
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // Visitable BEHAVIOR

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=1540713&r1=1540712&r2=1540713&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 Mon Nov 11 13:40:27 2013
@@ -148,7 +148,9 @@ public final class MergeNode extends DML
     private ArrayList<MatchingClauseNode>   _matchingClauses;
 
     // filled in at bind() time
+    private ResultColumnList    _selectList;
     private FromList                _leftJoinFromList;
+    private HalfOuterJoinNode   _hojn;
 
     // filled in at generate() time
     private ConstantAction      _constantAction;
@@ -230,12 +232,12 @@ public final class MergeNode extends DML
         // from the driving left join.
         for ( MatchingClauseNode mcn : _matchingClauses )
         {
-            mcn.bindRefinement( this, _leftJoinFromList );
+            mcn.bindResultSetNumbers( this, _leftJoinFromList );
         }
         
         for ( MatchingClauseNode mcn : _matchingClauses )
         {
-            if ( mcn.isUpdateClause() || mcn.isInsertClause() )
+            if ( mcn.isUpdateClause() )
             {
                 throw StandardException.newException( SQLState.NOT_IMPLEMENTED, "MERGE" );
             }
@@ -260,7 +262,7 @@ public final class MergeNode extends DML
         try {
             cc.setReliability( previousReliability | CompilerContext.SQL_IN_ROUTINES_ILLEGAL );
             
-            HalfOuterJoinNode   hojn = new HalfOuterJoinNode
+            _hojn = new HalfOuterJoinNode
                 (
                  _sourceTable,
                  _targetTable,
@@ -271,7 +273,7 @@ public final class MergeNode extends DML
                  getContextManager()
                  );
 
-            _leftJoinFromList = hojn.makeFromList( true, true );
+            _leftJoinFromList = _hojn.makeFromList( true, true );
             _leftJoinFromList.bindTables( dd, new FromList( getOptimizerFactory().doJoinOrderOptimization(), getContextManager() ) );
 
             if ( !sourceIsBase_View_or_VTI() )
@@ -280,10 +282,10 @@ public final class MergeNode extends DML
             }
 
             FromList    topFromList = new FromList( getOptimizerFactory().doJoinOrderOptimization(), getContextManager() );
-            topFromList.addFromTable( hojn );
+            topFromList.addFromTable( _hojn );
 
             // preliminary binding of the matching clauses to resolve column
-            // referneces. this ensures that we can add all of the columns from
+            // references. this ensures that we can add all of the columns from
             // the matching refinements to the SELECT list of the left join.
             // we re-bind the matching clauses when we're done binding the left join
             // because, at that time, we have result set numbers needed for
@@ -295,11 +297,14 @@ public final class MergeNode extends DML
         
             ResultColumnList    selectList = buildSelectList();
 
+            // save a copy so that we can remap column references when generating the temporary rows
+            _selectList = selectList.copyListAndObjects();
+
             // calculate the offsets into the SELECT list which define the rows for
             // the WHEN [ NOT ] MATCHED  actions
             for ( MatchingClauseNode mcn : _matchingClauses )
             {
-                mcn.bindThenColumns( selectList );
+                mcn.bindThenColumns( _selectList );
             }            
             
             resultSet = new SelectNode
@@ -610,6 +615,14 @@ public final class MergeNode extends DML
     void generate( ActivationClassBuilder acb, MethodBuilder mb )
 							throws StandardException
 	{
+        for ( MatchingClauseNode mcn : _matchingClauses )
+        {
+            if ( mcn.isUpdateClause() )
+            {
+                throw StandardException.newException( SQLState.NOT_IMPLEMENTED, "MERGE" );
+            }
+        }
+
         int     clauseCount = _matchingClauses.size();
 
 		/* generate the parameters */
@@ -625,7 +638,7 @@ public final class MergeNode extends DML
         {
             MatchingClauseNode  mcn = _matchingClauses.get( i );
 
-            mcn.generate( acb, i );
+            mcn.generate( acb, _selectList, _hojn, i );
             clauseActions[ i ] = mcn.makeConstantAction( acb );
         }
         _constantAction = getGenericConstantActionFactory().getMergeConstantAction( clauseActions );

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java Mon Nov 11 13:40:27 2013
@@ -1186,6 +1186,43 @@ class ResultColumnList extends QueryTree
    		// this sets up the method and the static field.
    		MethodBuilder userExprFun = acb.newUserExprFun();
 
+        generateEvaluatedRow( acb, userExprFun, genNulls, false );
+
+        // what we return is the access of the field, i.e. the pointer to the method.
+   	    acb.pushMethodReference(mb, userExprFun);
+	}
+
+	/**
+     * <p>
+	 * Generate the code for a method (userExprFun) which creates a row
+     * and, column by column, stuffs it with the evaluated
+     * expressions of our ResultColumns. The method returns the
+     * stuffed row.
+     * </p>
+	 *
+	 * This is the method that does the work.
+	 */
+	void generateEvaluatedRow
+        (
+         ExpressionClassBuilder acb,
+         MethodBuilder userExprFun,
+         boolean genNulls,
+         boolean forMatchingClause
+         ) 
+			throws StandardException
+	{
+   		// generate the function and initializer:
+		// private ExecRow fieldX;
+		// In the constructor:
+		//	 fieldX = getExecutionFactory().getValueRow(# cols);
+   		// private ExecRow exprN()
+   		// { 
+   		//   fieldX.setColumn(1, col(1).generateColumn(ps)));
+   		//   ... and so on for each column ...
+   		//   return fieldX;
+   		// }
+   		// static Method exprN = method pointer to exprN;
+
 		/* Declare the field */
 		LocalField field = acb.newFieldDeclaration(Modifier.PRIVATE, ClassName.ExecRow);
 
@@ -1211,7 +1248,7 @@ class ResultColumnList extends QueryTree
 			{
 				ValueNode sourceExpr = rc.getExpression();
 
-				if (sourceExpr instanceof VirtualColumnNode && ! ( ((VirtualColumnNode) sourceExpr).getCorrelated()))
+				if ( sourceExpr instanceof VirtualColumnNode && ! ( ((VirtualColumnNode) sourceExpr).getCorrelated()) )
 				{
 					continue;
 				}
@@ -1300,10 +1337,13 @@ class ResultColumnList extends QueryTree
 					continue;
 				}
 
-				if (sourceExpr instanceof ColumnReference && ! ( ((ColumnReference) sourceExpr).getCorrelated()))
-				{
-					continue;
-				}
+                if ( !forMatchingClause )
+                {
+                    if (sourceExpr instanceof ColumnReference && ! ( ((ColumnReference) sourceExpr).getCorrelated()))
+                    {
+                        continue;
+                    }
+                }
 			}
 
 
@@ -1422,9 +1462,6 @@ class ResultColumnList extends QueryTree
 
 		// we are now done modifying userExprFun
 		userExprFun.complete();
-
-        // what we return is the access of the field, i.e. the pointer to the method.
-   	    acb.pushMethodReference(mb, userExprFun);
 	}
 
 	/**
@@ -3919,15 +3956,7 @@ class ResultColumnList extends QueryTree
                 //
 				if ( (defaultInfo != null) && !defaultInfo.isGeneratedColumn() )
 				{
-					/* Query is dependent on the DefaultDescriptor */
-					DefaultDescriptor defaultDescriptor = cd.getDefaultDescriptor(getDataDictionary());
-					getCompilerContext().createDependency(defaultDescriptor);
-
-					rc.setExpression(
-						DefaultNode.parseDefault(
-							defaultInfo.getDefaultText(),
-							getLanguageConnectionContext(),
-							getCompilerContext()));
+                    setDefault( rc, cd, defaultInfo );
 				}
 				else
 				{
@@ -3940,6 +3969,25 @@ class ResultColumnList extends QueryTree
 		}
 	}
 
+    /** Set the default in a ResultColumn */
+    void    setDefault( ResultColumn rc, ColumnDescriptor cd, DefaultInfoImpl defaultInfo )
+        throws StandardException
+    {
+        /* Query is dependent on the DefaultDescriptor */
+        DefaultDescriptor defaultDescriptor = cd.getDefaultDescriptor(getDataDictionary());
+        getCompilerContext().createDependency(defaultDescriptor);
+
+        rc.setExpression
+            (
+             DefaultNode.parseDefault
+             (
+              defaultInfo.getDefaultText(),
+              getLanguageConnectionContext(),
+              getCompilerContext()
+              )
+             );
+    }
+
 	/**
 	 * Walk the RCL and check for DEFAULTs.  DEFAULTs
 	 * are invalid at the time that this method is called,

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultSetNode.java Mon Nov 11 13:40:27 2013
@@ -1088,10 +1088,17 @@ public abstract class ResultSetNode exte
                 newColumnReference = new ColumnReference(
                         oldResultColumn.getName(), null, getContextManager());
 
+                DataTypeDescriptor  dtd = oldResultColumn.getType();
+                if ( dtd == null )
+                {
+                    ColumnDescriptor    cd = target.targetTableDescriptor.getColumnDescriptor( index + 1 );
+                    dtd = cd.getType();
+                }
+
 				/* The ColumnReference points to the source of the value */
 				newColumnReference.setSource(oldResultColumn);
 				// colMap entry is 0-based, columnId is 1-based.
-				newColumnReference.setType(oldResultColumn.getType());
+				newColumnReference.setType( dtd );
 
 				// Source of an insert, so nesting levels must be 0
 				newColumnReference.setNestingLevel(0);
@@ -1102,7 +1109,7 @@ public abstract class ResultSetNode exte
 				// alternatively, we could do what the else clause does,
 				// and look it up in the DD again.
                newResultColumn = new ResultColumn(
-						oldResultColumn.getType(),
+						dtd,
 						newColumnReference,
 						getContextManager());
 			}

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=1540713&r1=1540712&r2=1540713&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 Mon Nov 11 13:40:27 2013
@@ -710,7 +710,8 @@ public final class UpdateNode extends DM
 				  targetTableDescriptor.getNumberOfColumns() :
 				  readColsBitSet.getNumBitsSet(),			
 			  positionedUpdate,
-			  resultSet.isOneRowResultSet()
+			  resultSet.isOneRowResultSet(),
+			  inMatchingClause()
 			  );
 	}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CallStatementResultSet.java Mon Nov 11 13:40:27 2013
@@ -106,7 +106,7 @@ class CallStatementResultSet extends NoR
      */
     public void close() throws StandardException
     {
-        super.close();
+        close( false );
         
         
         

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLVTIResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLVTIResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLVTIResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLVTIResultSet.java Mon Nov 11 13:40:27 2013
@@ -128,7 +128,7 @@ abstract class DMLVTIResultSet extends D
         if( null != sourceResultSet)
             sourceResultSet.close();
 		numOpens = 0;
-		super.close();
+		close( false );
 	} // end of cleanUp
 
 	public void finish() throws StandardException

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteConstantAction.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteConstantAction.java Mon Nov 11 13:40:27 2013
@@ -90,6 +90,7 @@ public class DeleteConstantAction extend
      *  @param streamStorableHeapColIds Null for non rep. (0 based)
 	 *  @param numColumns	Number of columns to read.
 	 *  @param singleRowSource		Whether or not source is a single row source
+	 *  @param underMerge   True if this is an action of a MERGE statement.
 	 */
     DeleteConstantAction(
 								long				conglomId,
@@ -108,7 +109,8 @@ public class DeleteConstantAction extend
 								int					numColumns,
 								boolean				singleRowSource,
 								ResultDescription   resultDescription,
-								ConstantAction[] dependentCActions)
+								ConstantAction[] dependentCActions,
+								boolean underMerge)
 	{
 		super( conglomId, 
 			   heapSCOCI,
@@ -123,7 +125,8 @@ public class DeleteConstantAction extend
 			   baseRowReadList,
 			   baseRowReadMap,
 			   streamStorableHeapColIds,
-			   singleRowSource
+			   singleRowSource,
+			   underMerge
 			   );
 
 		this.numColumns = numColumns;

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteResultSet.java Mon Nov 11 13:40:27 2013
@@ -630,10 +630,16 @@ class DeleteResultSet extends DMLWriteRe
 		if (rc != null) {
 			rc.close();
 		}
-		super.close();
+		close();
 	}
 
     @Override
+    public void close() throws StandardException
+    {
+        close( constants.underMerge() );
+    }
+                               
+    @Override
 	public void finish() throws StandardException {
 		if (source != null)
 			source.finish();

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteVTIResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteVTIResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteVTIResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeleteVTIResultSet.java Mon Nov 11 13:40:27 2013
@@ -171,4 +171,10 @@ class DeleteVTIResultSet extends DMLVTIR
 			// rowHolder kept across opens
 		}
     } // end of openCore
+    
+    @Override
+    public void close() throws StandardException
+    {
+        close( false );
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericConstantActionFactory.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericConstantActionFactory.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericConstantActionFactory.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericConstantActionFactory.java Mon Nov 11 13:40:27 2013
@@ -464,6 +464,7 @@ public class GenericConstantActionFactor
 	 *	@param baseRowReadMap		BaseRowReadMap[heapColId]->ReadRowColumnId.
      *  @param streamStorableHeapColIds Null for non rep. (0 based)
 	 *  @param singleRowSource		Whether or not source is a single row source
+	 *  @param underMerge   True if this is an action of a MERGE statement.
 	 *
 	 *  @exception StandardException		Thrown on failure
 	 */
@@ -494,7 +495,8 @@ public class GenericConstantActionFactor
 								int					numColumns,
 								UUID				dependencyId,
 								boolean				singleRowSource,
-								ConstantAction[]	dependentConstantActions
+								ConstantAction[]	dependentConstantActions,
+								boolean				underMerge
 	)
 			throws StandardException
 	{
@@ -516,7 +518,8 @@ public class GenericConstantActionFactor
 										numColumns,
 										singleRowSource,
 										resultDescription,
-										dependentConstantActions
+										dependentConstantActions,
+										underMerge
 										);
 	}
 
@@ -759,6 +762,7 @@ public class GenericConstantActionFactor
 	 *  @param singleRowSource	Whether or not source is a single row source
 	 *  @param autoincRowLocation array of row locations into syscolumns for
 	                              autoincrement columns
+	 *  @param underMerge   True if this is an INSERT action of a MERGE statement.
 	 *
 	 * @exception StandardException		Thrown on failure
 	 */
@@ -785,7 +789,8 @@ public class GenericConstantActionFactor
 								Object[]			stageControl,
 								Object[]			ddlList,
 								boolean				singleRowSource,
-								RowLocation[]		autoincRowLocation
+								RowLocation[]		autoincRowLocation,
+								boolean		underMerge
 							)
 			throws StandardException
 	{
@@ -805,7 +810,8 @@ public class GenericConstantActionFactor
 										streamStorableHeapColIds,
 										indexedCols,
 										singleRowSource,
-										autoincRowLocation
+										autoincRowLocation,
+										underMerge
 										);
 	}
 
@@ -906,6 +912,7 @@ public class GenericConstantActionFactor
 	 *  @param numColumns			The number of columns being read.
 	 *	@param positionedUpdate		is this a positioned update
 	 *  @param singleRowSource		Whether or not source is a single row source
+	 *  @param underMerge   True if this is an action of a MERGE statement.
 	 *
 	 *  @exception StandardException Thrown on failure
 	 */
@@ -931,7 +938,8 @@ public class GenericConstantActionFactor
 								int[]				streamStorableHeapColIds,
 								int					numColumns,
 								boolean				positionedUpdate,
-								boolean				singleRowSource
+								boolean				singleRowSource,
+								boolean				underMerge
 							)
 			throws StandardException
 	{
@@ -953,7 +961,8 @@ public class GenericConstantActionFactor
 										streamStorableHeapColIds,
 										numColumns,
 										positionedUpdate,
-										singleRowSource
+										singleRowSource,
+										underMerge
 										);
 	}
 
@@ -1121,6 +1130,8 @@ public class GenericConstantActionFactor
 	(
          int    clauseType,
          String matchRefinementName,
+         ResultDescription  thenColumnSignature,
+         String rowMakingMethodName,
          int[]  thenColumns,
          String resultSetFieldName,
          String actionMethodName,
@@ -1128,7 +1139,16 @@ public class GenericConstantActionFactor
      )
 	{
 		return new MatchingClauseConstantAction
-            ( clauseType, matchRefinementName, thenColumns, resultSetFieldName, actionMethodName, thenAction );
+            (
+             clauseType,
+             matchRefinementName,
+             thenColumnSignature,
+             rowMakingMethodName,
+             thenColumns,
+             resultSetFieldName,
+             actionMethodName,
+             thenAction
+             );
 	}
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertConstantAction.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertConstantAction.java Mon Nov 11 13:40:27 2013
@@ -88,6 +88,9 @@ public class InsertConstantAction extend
 	 */
     RowLocation[] autoincRowLocation;
 	private long[] autoincIncrement;
+
+    /** Position of autogenerated column */
+    private transient   int firstAutoGenColumn = -1;
 	
 	// CONSTRUCTORS
 
@@ -119,6 +122,7 @@ public class InsertConstantAction extend
 	 *  @param singleRowSource		Whether or not source is a single row source
 	 *  @param autoincRowLocation Array of rowlocations of autoincrement values
 	 * 							  in SYSCOLUMNS for each ai column.
+	 *  @param underMerge   True if this is an action of a MERGE statement.
 	 */
     InsertConstantAction(TableDescriptor tableDescriptor,
 								long				conglomId,
@@ -136,7 +140,8 @@ public class InsertConstantAction extend
 								int[]               streamStorableHeapColIds,
 								boolean[]			indexedCols,
 								boolean				singleRowSource,
-								RowLocation[]		autoincRowLocation)
+                                RowLocation[]		autoincRowLocation,
+								boolean		underMerge)
 	{
 		super(conglomId, 
 			  heapSCOCI,
@@ -153,7 +158,8 @@ public class InsertConstantAction extend
 			  null,
 			  null,
 			  streamStorableHeapColIds,
-			  singleRowSource
+			  singleRowSource,
+			  underMerge
 			  );
 		this.indexedCols = indexedCols;
 		this.autoincRowLocation = autoincRowLocation;
@@ -220,6 +226,25 @@ public class InsertConstantAction extend
 		ArrayUtil.writeLongArray(out, autoincIncrement);
 	}
 
+    /** Get the 0-based position of the autogenerated column */
+    public  int     getAutoGenColumn()
+    {
+        if ( !hasAutoincrement() ) { return -1; }
+        if ( firstAutoGenColumn < 0 )
+        {
+            for ( int i = 0; i < autoincIncrement.length; i++ )
+            {
+                if ( autoincIncrement[ i ] > 0 )
+                {
+                    firstAutoGenColumn = i;
+                    break;
+                }
+            }
+        }
+
+        return firstAutoGenColumn;
+    }
+
 	/**
 	  *	Gets the name of the schema that the table is in
 	  *

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertResultSet.java Mon Nov 11 13:40:27 2013
@@ -69,6 +69,7 @@ import org.apache.derby.iapi.store.acces
 import org.apache.derby.iapi.store.access.SortController;
 import org.apache.derby.iapi.store.access.SortObserver;
 import org.apache.derby.iapi.store.access.TransactionController;
+import org.apache.derby.iapi.types.DataTypeDescriptor;
 import org.apache.derby.iapi.types.DataValueDescriptor;
 import org.apache.derby.iapi.types.NumberDataValue;
 import org.apache.derby.iapi.types.RowLocation;
@@ -170,6 +171,12 @@ class InsertResultSet extends DMLWriteRe
 	private long					identityVal;  //support of IDENTITY_LOCAL_VAL function
 	private boolean					setIdentity;
 	
+    /**
+     * This array contains data value descriptors that can be used (and reused)
+     * to hold the normalized column values.
+     */
+    private DataValueDescriptor[] cachedDestinations;
+
 
 	/**
      * Returns the description of the inserted rows.
@@ -351,7 +358,7 @@ class InsertResultSet extends DMLWriteRe
 				false;
 
         resultDescription = sourceResultSet.getResultDescription();
-
+        
 		// Is this a bulkInsert or regular insert?
 		String insertMode = constants.getProperty("insertMode");
 
@@ -394,8 +401,6 @@ class InsertResultSet extends DMLWriteRe
 				}
 			}
 		}
-
-		//System.out.println("new InsertResultSet " + sourceResultSet.getClass());
 	}
 	
 	/**
@@ -570,7 +575,7 @@ class InsertResultSet extends DMLWriteRe
 	 * Clean up resources and call close on data members.
 	 */
 	public void close() throws StandardException {
-		super.close();
+		close( constants.underMerge() );
 		if (autoGeneratedKeysRowsHolder != null) {
 			autoGeneratedKeysRowsHolder.close();
 		}
@@ -1237,6 +1242,103 @@ class InsertResultSet extends DMLWriteRe
                 } 
  }
 
+    @Override
+	protected ExecRow getNextRowCore( NoPutResultSet source )
+		throws StandardException
+	{
+		ExecRow row = super.getNextRowCore( source );
+
+        if ( (row != null) && constants.underMerge() ) { row = processMergeRow( row ); }
+
+        return row;
+	}
+
+    /**
+     * <p>
+     * Special handling if this is an INSERT action of a MERGE statement.
+     * </p>
+     */
+	private ExecRow processMergeRow( ExecRow row )
+		throws StandardException
+	{
+        //
+        // The normal processing of autogenerated columns happens in
+        // the evaluation of the driving ResultSet. That processing assumes
+        // that the distinguished ResultSet in the Activation is an InsertResultSet.
+        // This is not true if we are running under a MERGE statement. In that
+        // case, the distinguished ResultSet in the Activation is a MergeResultSet.
+        // We have to wait until we have an InsertResultSet before we can generate
+        // new identity values.
+        //
+        //
+        if ( constants.hasAutoincrement() )
+        {
+            int     columnPosition = constants.getAutoGenColumn();
+            long    increment = constants.getAutoincIncrement( columnPosition );
+            DataValueDescriptor dvd = row.getColumn( columnPosition + 1 );
+            
+            //
+            // If the identity column was declared BY DEFAULT, then it could be
+            // overridden by the WHEN NOT MATCHED clause. In that case, the
+            // row will contain a non-null value which we do not want to clobber.
+            //
+            //boolean needToGenerateValue = ( dvd == null ) || ( dvd.isNullOp().getBoolean() );
+            boolean needToGenerateValue = ( dvd == null );
+
+            if ( needToGenerateValue )
+            {
+                NumberDataValue newIdentityValue = getSetAutoincrementValue( columnPosition + 1, increment );
+
+                row.setColumn( columnPosition + 1, newIdentityValue );
+            }
+        }
+
+        //
+        // Make sure that the evaluated expressions fit in the base table row.
+        //
+        int count = resultDescription.getColumnCount();
+        if ( cachedDestinations == null )
+        {
+            cachedDestinations = new DataValueDescriptor[ count ];
+            for ( int i = 0; i < count; i++)
+            {
+                int         position = i + 1;
+                ResultColumnDescriptor  colDesc = resultDescription.getColumnDescriptor( position );
+                cachedDestinations[ i ] = colDesc.getType().getNull();
+            }
+        }
+
+        for ( int i = 0; i < count; i++ )
+        {
+            int         position = i + 1;
+            DataTypeDescriptor  dtd = resultDescription.getColumnDescriptor( position ).getType();
+
+            if ( row.getColumn( position ) == null )
+            {
+                row.setColumn( position, dtd.getNull() );
+            }
+
+            row.setColumn
+                (
+                 position,
+                 NormalizeResultSet.normalizeColumn
+                 (
+                  dtd,
+                  row,
+                  position,
+                  cachedDestinations[ i ],
+                  resultDescription
+                  )
+                 );
+        }
+
+        // put the row where expressions in constraints can access it
+        activation.setCurrentRow( row, sourceResultSet.resultSetNumber() );
+
+        return row;
+	}
+
+
 	/**
 	 * Take the input row and return a new compact ExecRow
 	 * using the column positions provided in columnIndexes.
@@ -2079,7 +2181,7 @@ class InsertResultSet extends DMLWriteRe
 				}
 			}
 		}
-		super.close();
+		close( constants.underMerge() );
 	}
 
 	// Class implementation

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertVTIResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertVTIResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertVTIResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/InsertVTIResultSet.java Mon Nov 11 13:40:27 2013
@@ -260,6 +260,12 @@ class InsertVTIResultSet extends DMLVTIR
 		super.cleanUp();
 	} // end of cleanUp
 
+    @Override
+    public void close() throws StandardException
+    {
+        close( false );
+    }
+                               
 	// Class implementation
 
 	public void finish() throws StandardException {

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=1540713&r1=1540712&r2=1540713&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 Mon Nov 11 13:40:27 2013
@@ -72,14 +72,16 @@ public class MatchingClauseConstantActio
     // constructor args
     private int _clauseType;
     private String  _matchRefinementName;
-    private int[]   _thenColumnOffsets;
+    private ResultDescription   _thenColumnSignature;
+    private String  _rowMakingMethodName;
+    private int[]   _deleteColumnOffsets;
     private String  _resultSetFieldName;
     private String  _actionMethodName;
     private ConstantAction  _thenAction;
 
     // faulted in or built at run-time
     private transient   GeneratedMethod _matchRefinementMethod;
-	private transient   TemporaryRowHolderImpl	_thenRows;
+    private transient   GeneratedMethod _rowMakingMethod;
     private transient   ResultSet           _actionRS;
 
 
@@ -97,6 +99,7 @@ public class MatchingClauseConstantActio
      *
      * @param   clauseType  WHEN_NOT_MATCHED_THEN_INSERT, WHEN_MATCHED_THEN_UPDATE, WHEN_MATCHED_THEN_DELETE
      * @param   matchRefinementName Name of the method which evaluates the boolean expression in the WHEN clause.
+     * @param   thenColumnSignature The shape of the row which goes into the temporary table.
      * @param   thenColumns Column positions (1-based) from the driving left join which are needed to execute the THEN clause.
      * @param   resultSetFieldName  Name of the field which will be stuffed at runtime with the temporary table of relevant rows.
      * @param   actionMethodName    Name of the method which invokes the INSERT/UPDATE/DELETE action.
@@ -106,6 +109,8 @@ public class MatchingClauseConstantActio
         (
          int    clauseType,
          String matchRefinementName,
+         ResultDescription  thenColumnSignature,
+         String rowMakingMethodName,
          int[]  thenColumns,
          String resultSetFieldName,
          String actionMethodName,
@@ -114,7 +119,9 @@ public class MatchingClauseConstantActio
     {
         _clauseType = clauseType;
         _matchRefinementName = matchRefinementName;
-        _thenColumnOffsets = ArrayUtil.copy( thenColumns );
+        _thenColumnSignature = thenColumnSignature;
+        _rowMakingMethodName = rowMakingMethodName;
+        _deleteColumnOffsets = ArrayUtil.copy( thenColumns );
         _resultSetFieldName = resultSetFieldName;
         _actionMethodName = actionMethodName;
         _thenAction = thenAction;
@@ -137,11 +144,15 @@ public class MatchingClauseConstantActio
 
 	public void	executeConstantAction( Activation activation )
         throws StandardException
+    {}
+    
+	public void	executeConstantAction( Activation activation, TemporaryRowHolderImpl thenRows )
+        throws StandardException
     {
         // nothing to do if no rows qualified
-        if ( _thenRows == null ) { return; }
+        if ( thenRows == null ) { return; }
 
-        CursorResultSet sourceRS = _thenRows.getResultSet();
+        CursorResultSet sourceRS = thenRows.getResultSet();
         GeneratedMethod actionGM = ((BaseActivation) activation).getMethod( _actionMethodName );
 
         //
@@ -160,6 +171,8 @@ public class MatchingClauseConstantActio
                 Field   resultSetField = activation.getClass().getField( _resultSetFieldName );
                 resultSetField.set( activation, sourceRS );
 
+                Activation  cursorActivation = sourceRS.getActivation();
+
                 //
                 // Now execute the generated method which creates an InsertResultSet,
                 // UpdateResultSet, or DeleteResultSet.
@@ -186,6 +199,17 @@ public class MatchingClauseConstantActio
 
     /**
      * <p>
+     * Initialize this constant action, nulling out any transient state left over from
+     * a previous use.
+     * </p>
+     */
+    void    init()  throws StandardException
+    {
+        _actionRS = null;
+    }
+    
+    /**
+     * <p>
      * Run the matching refinement clause associated with this WHEN [ NOT ] MATCHED clause.
      * The refinement is a boolean expression. Return the boolean value it resolves to.
      * A boolean NULL is treated as false. If there is no refinement clause, then this method
@@ -215,33 +239,93 @@ public class MatchingClauseConstantActio
      * of the MERGE statement's driving left join.
      * </p>
      */
-    void    bufferThenRow
+    TemporaryRowHolderImpl  bufferThenRow
         (
          Activation activation,
-         ResultDescription selectDescription,
+         TemporaryRowHolderImpl thenRows,
          ExecRow selectRow
          ) throws StandardException
     {
-        int             thenRowLength = _thenColumnOffsets.length;
+        if ( thenRows == null ) { thenRows = createThenRows( activation ); }
+
+        ExecRow thenRow;
+
+        switch( _clauseType )
+        {
+        case WHEN_MATCHED_THEN_DELETE:
+            thenRow = bufferThenRowForDelete( activation, selectRow );
+            break;
+
+        default:
+            thenRow = bufferThenRow( activation );
+            break;
+        }
+
+        thenRows.insert( thenRow );
+
+        return thenRows;
+    }
+    
+    /**
+     * <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
+        (
+         Activation activation,
+         ExecRow selectRow
+         )
+        throws StandardException
+    {
+        int             thenRowLength = _thenColumnSignature.getColumnCount();
         ValueRow    thenRow = new ValueRow( thenRowLength );
         for ( int i = 0; i < thenRowLength; i++ )
         {
-            thenRow.setColumn( i + 1, selectRow.getColumn( _thenColumnOffsets[ i ] ) );
+            thenRow.setColumn( i + 1, selectRow.getColumn( _deleteColumnOffsets[ i ] ) );
         }
 
-        if ( _thenRows == null ) { createThenRows( activation, selectDescription ); }
-        _thenRows.insert( thenRow );
+        return thenRow;
     }
 
     /**
      * <p>
+     * Construct and buffer a row for the INSERT/UPDATE/DELETE
+     * action corresponding to this [ NOT ] MATCHED clause.
+     * </p>
+     */
+    ExecRow    bufferThenRow
+        (
+         Activation activation
+         )
+        throws StandardException
+    {
+        if ( _rowMakingMethod == null )
+        {
+            _rowMakingMethod = ((BaseActivation) activation).getMethod( _rowMakingMethodName );
+        }
+
+        return (ExecRow) _rowMakingMethod.invoke( activation );
+    }
+    
+    /**
+     * <p>
      * Release resources at the end.
      * </p>
      */
     void    cleanUp()   throws StandardException
     {
-        if ( _actionRS != null ) { _actionRS.close(); }
-        if ( _thenRows != null ) { _thenRows.close(); }
+        if ( _actionRS != null )
+        {
+            _actionRS.close();
+            _actionRS = null;
+        }
+
+        _matchRefinementMethod = null;
+        _rowMakingMethod = null;
     }
 
     /**
@@ -250,13 +334,10 @@ public class MatchingClauseConstantActio
      * for bulk-processing after the driving left join completes.
      * </p>
      */
-    private void    createThenRows( Activation activation, ResultDescription selectDescription )
+    private TemporaryRowHolderImpl  createThenRows( Activation activation )
         throws StandardException
     {
-        ResultDescription   thenDescription = activation.getLanguageConnectionContext().getLanguageFactory().getResultDescription
-            ( selectDescription, _thenColumnOffsets );
-
-        _thenRows = new TemporaryRowHolderImpl( activation, new Properties(), thenDescription );
+        return new TemporaryRowHolderImpl( activation, new Properties(), _thenColumnSignature );
     }
 
     ///////////////////////////////////////////////////////////////////////////////////
@@ -281,10 +362,12 @@ public class MatchingClauseConstantActio
 
         _clauseType = in.readInt();
         _matchRefinementName = (String) in.readObject();
-        _thenColumnOffsets = ArrayUtil.readIntArray( in );
-        _resultSetFieldName = (String) in.readObject();
+        _thenColumnSignature = (ResultDescription) in.readObject();
+        _rowMakingMethodName = (String) in.readObject();
+        _deleteColumnOffsets = ArrayUtil.readIntArray( in );
+        _resultSetFieldName = (String) in.readObject(); 
         _actionMethodName = (String) in.readObject();
-        _thenAction = (ConstantAction) in.readObject();
+       _thenAction = (ConstantAction) in.readObject();
 	}
 
 	/**
@@ -301,7 +384,9 @@ public class MatchingClauseConstantActio
 
         out.writeInt( _clauseType );
         out.writeObject( _matchRefinementName );
-        ArrayUtil.writeIntArray( out, _thenColumnOffsets );
+        out.writeObject( _thenColumnSignature );
+        out.writeObject( _rowMakingMethodName );
+        ArrayUtil.writeIntArray( out, _deleteColumnOffsets );
         out.writeObject( _resultSetFieldName );
         out.writeObject( _actionMethodName );
         out.writeObject( _thenAction );

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MergeResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MergeResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MergeResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MergeResultSet.java Mon Nov 11 13:40:27 2013
@@ -58,6 +58,7 @@ class MergeResultSet extends NoRowsResul
 
     private ExecRow                 _row;
     private long                        _rowCount;
+    private TemporaryRowHolderImpl[]    _thenRows;
 
     ///////////////////////////////////////////////////////////////////////////////////
     //
@@ -78,6 +79,7 @@ class MergeResultSet extends NoRowsResul
         super( activation );
         _drivingLeftJoin = drivingLeftJoin;
         _constants = (MergeConstantAction) activation.getConstantAction();
+        _thenRows = new TemporaryRowHolderImpl[ _constants.matchingClauseCount() ];
     }
 
     ///////////////////////////////////////////////////////////////////////////////////
@@ -103,7 +105,7 @@ class MergeResultSet extends NoRowsResul
         int         clauseCount = _constants.matchingClauseCount();
         for ( int i = 0; i < clauseCount; i++ )
         {
-            _constants.getMatchingClause( i ).executeConstantAction( activation );
+            _constants.getMatchingClause( i ).executeConstantAction( activation, _thenRows[ i ] );
         }
 
         cleanUp();
@@ -115,6 +117,12 @@ class MergeResultSet extends NoRowsResul
     {
         super.setup();
 
+        int         clauseCount = _constants.matchingClauseCount();
+        for ( int i = 0; i < clauseCount; i++ )
+        {
+            _constants.getMatchingClause( i ).init();
+        }
+
         _rowCount = 0L;
         _drivingLeftJoin.openCore();
     }
@@ -124,7 +132,7 @@ class MergeResultSet extends NoRowsResul
      */
     public void close() throws StandardException
     {
-        super.close();
+        close( false );
     }
 
     public void cleanUp() throws StandardException
@@ -132,6 +140,13 @@ class MergeResultSet extends NoRowsResul
         int         clauseCount = _constants.matchingClauseCount();
         for ( int i = 0; i < clauseCount; i++ )
         {
+            TemporaryRowHolderImpl  thenRows = _thenRows[ i ];
+            if ( thenRows != null )
+            {
+                thenRows.close();
+                _thenRows[ i ] = null;
+            }
+            
             _constants.getMatchingClause( i ).cleanUp();
         }
     }
@@ -182,9 +197,10 @@ class MergeResultSet extends NoRowsResul
             // find the first clause which applies to this row
             MatchingClauseConstantAction    matchingClause = null;
             int         clauseCount = _constants.matchingClauseCount();
-            for ( int i = 0; i < clauseCount; i++ )
+            int         clauseIdx = 0;
+            for ( ; clauseIdx < clauseCount; clauseIdx++ )
             {
-                MatchingClauseConstantAction    candidate = _constants.getMatchingClause( i );
+                MatchingClauseConstantAction    candidate = _constants.getMatchingClause( clauseIdx );
                 boolean isWhenMatchedClause = false;
                 
                 switch ( candidate.clauseType() )
@@ -209,7 +225,7 @@ class MergeResultSet extends NoRowsResul
 
             if ( matchingClause != null )
             {
-                matchingClause.bufferThenRow( activation, _drivingLeftJoin.getResultDescription(), _row );
+                _thenRows[ clauseIdx ] = matchingClause.bufferThenRow( activation, _thenRows[ clauseIdx ], _row );
                 _rowCount++;
             }
         }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MiscResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MiscResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MiscResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MiscResultSet.java Mon Nov 11 13:40:27 2013
@@ -62,7 +62,8 @@ class MiscResultSet extends NoRowsResult
 		close();
 	}
 
-	// Does not override close() (no action required)
+	public  void    close() throws StandardException    { close( false ); }
+    
 	// Does not override finish() (no action required)
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/NoRowsResultSetImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/NoRowsResultSetImpl.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/NoRowsResultSetImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/NoRowsResultSetImpl.java Mon Nov 11 13:40:27 2013
@@ -344,9 +344,11 @@ abstract class NoRowsResultSetImpl imple
 	/**
      * Dump the stat if not already done so. Close all of the open subqueries.
 	 *
+	 * @param underMerge    True if this is part of an action of a MERGE statement.
+	 *
 	 * @exception StandardException thrown on error
 	 */
-	public void	close() throws StandardException
+	public void	close( boolean underMerge ) throws StandardException
 	{ 
 		if (!isOpen)
 			return;
@@ -412,7 +414,7 @@ abstract class NoRowsResultSetImpl imple
 
 		isOpen = false;
 
-		if (activation.isSingleExecution())
+		if (activation.isSingleExecution() && !underMerge)
 			activation.close();
 	}
 
@@ -635,6 +637,7 @@ abstract class NoRowsResultSetImpl imple
             //
             try {
                 source.setCurrentRow( newRow );
+                activation.setCurrentRow( newRow, source.resultSetNumber() );
                 generationClauses.invoke(activation);
 
                 //

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderResultSet.java Mon Nov 11 13:40:27 2013
@@ -675,7 +675,7 @@ class TemporaryRowHolderResultSet implem
 	 */
 	public int resultSetNumber()
 	{
-		return 0;
+		return TEMPORARY_RESULT_SET_NUMBER;
 	}
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdatableVTIConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdatableVTIConstantAction.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdatableVTIConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdatableVTIConstantAction.java Mon Nov 11 13:40:27 2013
@@ -83,7 +83,8 @@ public class UpdatableVTIConstantAction 
 			  null,
 			  null,
 			  // singleRowSource, irrelevant
-			  false
+			  false,
+			  false // not under a MERGE statement
 			  );
         this.statementType = statementType;
         this.changedColumnIds = changedColumnIds;

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateConstantAction.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateConstantAction.java Mon Nov 11 13:40:27 2013
@@ -97,6 +97,7 @@ public class UpdateConstantAction extend
 	 *  @param numColumns	Number of columns being read.
 	 *  @param positionedUpdate	is this a positioned update
 	 *  @param singleRowSource		Whether or not source is a single row source
+	 *  @param underMerge   True if this is an action of a MERGE statement.
 	 */
     UpdateConstantAction(
 								long				conglomId,
@@ -116,7 +117,8 @@ public class UpdateConstantAction extend
 								int[]               streamStorableHeapColIds,
 								int					numColumns,
 								boolean				positionedUpdate,
-								boolean				singleRowSource)
+								boolean				singleRowSource,
+								boolean				underMerge)
 	{
 		super(
 			conglomId,
@@ -134,7 +136,8 @@ public class UpdateConstantAction extend
 			baseRowReadList,
 			baseRowReadMap,
 			streamStorableHeapColIds,
-			singleRowSource
+			singleRowSource,
+			underMerge
 			);
 
 		this.changedColumnIds = changedColumnIds;

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java Mon Nov 11 13:40:27 2013
@@ -1022,11 +1022,17 @@ class UpdateResultSet extends DMLWriteRe
 			// cache riChecker across open()s
 		}
 
-		super.close();
+		close();
 
 		endTime = getCurrentTimeMillis();
 	}
 
+    @Override
+    public void close() throws StandardException
+    {
+        close( constants.underMerge() );
+    }
+                               
 	void rowChangerFinish() throws StandardException
 	{
 		rowChanger.finish();

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateVTIResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateVTIResultSet.java?rev=1540713&r1=1540712&r2=1540713&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateVTIResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateVTIResultSet.java Mon Nov 11 13:40:27 2013
@@ -179,6 +179,12 @@ class UpdateVTIResultSet extends DMLVTIR
 		}
 	} // end of openCore
 
+    @Override
+    public void close() throws StandardException
+    {
+        close( false );
+    }
+
 	private void updateVTI(ResultSet target, ExecRow row)
 		throws StandardException
 	{



Mime
View raw message