db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ma...@apache.org
Subject svn commit: r1625884 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/impl/sql/execute/ testing/org/apache/derbyTesting/functionTests/tests/lang/ testing/org/apache/derbyTesting/functionTests/tests/upgra...
Date Thu, 18 Sep 2014 03:52:34 GMT
Author: mamta
Date: Thu Sep 18 03:52:34 2014
New Revision: 1625884

URL: http://svn.apache.org/r1625884
Log:
CERBY-6414(Incorrect handling when using an UPDATE to SET an identity column to DEFAULT)

I have created DERBY-6742 for JDBC part of this feature so we can generate auto generated resultset for an update statement updating generated columns. This implementation is supported through Statement.RETURN_GENERATED_KEYS flag.

Junit tests for this feature are in GeneratedColumnsTest.java. Upgrade tests are in Changes10_12.java. Upgrade test shows that a soft upgrade from pre-10.11 will not support update of generated columns using DEFAULT but 10.11 to trunk soft upgrade will allow it. This is because starting 10.11, we have started using sequence generator to create unique ids. If we want to support updating of idetity columns for pre-10.11 releases, we will need to maintain the code for old way of generating unique ids. In order to avoid that, this feature is available to only 10.11 db during soft upgrade.

For UPDATE of identity column to work in the MERGE sql, we need to make changes to MERGE code(DERBY-6743). MERGE already has required code for insert putting DEFAULT in generated columns. Implementation needs to be added for update putting DEFAULT in generated columns in case of MERGE. In the mean time, I have renamed existing junit test test_015_bug_6414 to atest_015_bug_6414 in MergeStatementTest.java so we do not run into failures.

Some detail about the part of the implementation that was tricky for DERBY-6414.
The existing code was originally written to handle inserting values in identity columns using DEFAULT. In case of insert, InsertResultSet uses ColumnDescriptors in resultDescription to find the type of the generated columns. This data structure holds the column descriptors of all the columns in the table. All the columns are in this data structure because even though INSERT statement may not explicitly assign a value to each and every column in the table, all the columns end up getting some value in them through an INSERT statement. The code in InsertResultSet.initializeAIcache method relies on availability of all the columns type information. But in case of Update, resultDescription does not include all the columns in the table. It only has the columns being touched by the Update statement(the rest of the columns in the table will retain their original values), and for each of those touched columns, it has a duplicate entry in resultDescription in order to have before and after valu
 es for the changed column values. This difference in array content of resultDescription requires us to have separate implementation of initializeAIcache method for insert and update.


Added:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModGeneratedColumnsStatementNode.java   (with props)
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLWriteGeneratedColumnsResultSet.java   (with props)
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/Changes10_12.java   (with props)
Modified:
    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/UpdateNode.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.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/UpdateConstantAction.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UpdateResultSet.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/UpgradeRun.java

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModGeneratedColumnsStatementNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModGeneratedColumnsStatementNode.java?rev=1625884&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModGeneratedColumnsStatementNode.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModGeneratedColumnsStatementNode.java Thu Sep 18 03:52:34 2014
@@ -0,0 +1,84 @@
+/*
+
+   Derby - Class org.apache.derby.impl.sql.compile.DMLModGeneratedColumnsStatementNode
+
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package	org.apache.derby.impl.sql.compile;
+
+import org.apache.derby.iapi.error.StandardException;
+
+import org.apache.derby.iapi.services.context.ContextManager;
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;
+import org.apache.derby.iapi.sql.dictionary.SequenceDescriptor;
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
+import org.apache.derby.iapi.types.RowLocation;
+
+/**
+ * A DMLModGeneratedColumnsStatementNode for a table(with identity columns)
+ *  modification: to wit, INSERT, UPDATE.
+ * The code below used to reside in InsertNode but when we fixed DERBY-6414,
+ *  rather than duplicating the code in UpdateNode, we moved the common code 
+ *  for insert and update of identity columns to this class.
+ *
+ */
+abstract class DMLModGeneratedColumnsStatementNode extends DMLModStatementNode
+{
+
+    protected   RowLocation[] 		autoincRowLocation;
+
+    protected   String              identitySequenceUUIDString;
+
+    DMLModGeneratedColumnsStatementNode
+    (
+     ResultSetNode resultSet,
+     MatchingClauseNode matchingClause,
+     int statementType,
+     ContextManager cm
+    )
+    {
+        super(resultSet, matchingClause, statementType, cm);
+    }
+
+    DMLModGeneratedColumnsStatementNode
+    (
+     ResultSetNode resultSet,
+     MatchingClauseNode matchingClause,
+     ContextManager cm
+    )
+    {
+        super(resultSet, matchingClause, cm);
+    }
+
+    // if this is 10.11 or higher and the table has an identity column,
+    // get the uuid of the sequence generator backing the identity column
+    protected String getUUIDofSequenceGenerator() throws StandardException
+    {
+        DataDictionary dataDictionary = getDataDictionary();
+        if (targetTableDescriptor.tableHasAutoincrement() &&
+            dataDictionary.checkVersion(DataDictionary.DD_VERSION_DERBY_10_11, null))
+        {
+            SequenceDescriptor  seq = dataDictionary.getSequenceDescriptor(
+                dataDictionary.getSystemSchemaDescriptor(),
+                TableDescriptor.makeSequenceName(targetTableDescriptor.getUUID()));
+            return (seq.getUUID().toString());
+        }
+        return null;
+    }
+}
\ No newline at end of file

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/DMLModGeneratedColumnsStatementNode.java
------------------------------------------------------------------------------
    svn:eol-style = native

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=1625884&r1=1625883&r2=1625884&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 Thu Sep 18 03:52:34 2014
@@ -41,13 +41,11 @@ import org.apache.derby.iapi.sql.diction
 import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
 import org.apache.derby.iapi.sql.dictionary.IndexLister;
-import org.apache.derby.iapi.sql.dictionary.SequenceDescriptor;
 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
 import org.apache.derby.iapi.sql.execute.ConstantAction;
 import org.apache.derby.iapi.sql.execute.ExecRowBuilder;
 import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
 import org.apache.derby.iapi.store.access.TransactionController;
-import org.apache.derby.iapi.types.RowLocation;
 import org.apache.derby.iapi.util.StringUtil;
 import org.apache.derby.impl.sql.execute.FKInfo;
 import org.apache.derby.vti.DeferModification;
@@ -74,7 +72,7 @@ import org.apache.derby.vti.DeferModific
  * <p>
  * After optimizing, ...
  */
-public final class InsertNode extends DMLModStatementNode
+public final class InsertNode extends DMLModGeneratedColumnsStatementNode
 {
     private     ResultColumnList    targetColumnList;
     private     boolean             deferred;
@@ -88,10 +86,6 @@ public final class InsertNode extends DM
     private     ValueNode           offset;
     private     ValueNode           fetchFirst;
     private     boolean           hasJDBClimitClause; // true if using JDBC limit/offset escape syntax
-
-	protected   RowLocation[] 		autoincRowLocation;
-
-    private     String              identitySequenceUUIDString;
     
 	/**
      * Constructor for an InsertNode.
@@ -555,20 +549,7 @@ public final class InsertNode extends DM
                                                   resultSet);
 		}
 
-        // if this is 10.11 or higher and the table has an identity column,
-        // get the uuid of the sequence generator backing the identity column
-        if (
-            targetTableDescriptor.tableHasAutoincrement() &&
-            dd.checkVersion( DataDictionary.DD_VERSION_DERBY_10_11, null )
-            )
-        {
-            SequenceDescriptor  seq = dd.getSequenceDescriptor
-                (
-                 dd.getSystemSchemaDescriptor(),
-                 TableDescriptor.makeSequenceName( targetTableDescriptor.getUUID() )
-                 );
-            identitySequenceUUIDString = seq.getUUID().toString();
-        }
+        identitySequenceUUIDString = getUUIDofSequenceGenerator();
         
         getCompilerContext().removePrivilegeFilter( ignorePermissions );
 		getCompilerContext().popCurrentPrivType();

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=1625884&r1=1625883&r2=1625884&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 Thu Sep 18 03:52:34 2014
@@ -68,7 +68,7 @@ import org.apache.derby.vti.DeferModific
  *
  */
 
-public final class UpdateNode extends DMLModStatementNode
+public final class UpdateNode extends DMLModGeneratedColumnsStatementNode
 {
 	//Note: These are public so they will be visible to
 	//the RepUpdateNode.
@@ -371,9 +371,25 @@ public final class UpdateNode extends DM
         forbidGenerationOverrides( resultSet.getResultColumns(),
 								   addedGeneratedColumns );
         
-		LanguageConnectionContext lcc = getLanguageConnectionContext();
-		if (lcc.getAutoincrementUpdate() == false)
-			resultSet.getResultColumns().forbidOverrides(null);
+        //DERBY-6414(Incorrect handling when using an UPDATE to SET an 
+        // identity column to DEFAULT)
+        //The bug is fixed only for Derby 10.11 and higher. Starting 10.11,
+        // we have started using sequence generator to create unique ids
+        //If we fix this jira for prior releases, we will need to maintain
+        // the code for old way of generating unique ids.
+        if (dataDictionary.checkVersion( DataDictionary.DD_VERSION_DERBY_10_11, null )) {
+            //Replace any DEFAULTs with the associated tree for the default if
+            // allowed, otherwise throw an exception
+            resultSet.getResultColumns().replaceOrForbidDefaults(
+            		targetTableDescriptor, 
+            		resultSet.getResultColumns(), true);
+            resultSet.getResultColumns().checkForInvalidDefaults();
+            resultSet.getResultColumns().forbidOverrides(resultSet.getResultColumns());
+        } else {
+    		LanguageConnectionContext lcc = getLanguageConnectionContext();
+    		if (lcc.getAutoincrementUpdate() == false)
+    			resultSet.getResultColumns().forbidOverrides(null);
+        }
 
 		/*
 		** Mark the columns in this UpdateNode's result column list as
@@ -635,8 +651,15 @@ public final class UpdateNode extends DM
             {
                 deferred = true;
             }
+            TransactionController tc = 
+                    getLanguageConnectionContext().getTransactionCompile();
+
+            autoincRowLocation = 
+                    dataDictionary.computeAutoincRowLocations(tc, targetTableDescriptor);
         }
 
+		identitySequenceUUIDString = getUUIDofSequenceGenerator();
+
 		getCompilerContext().popCurrentPrivType();
 
         getCompilerContext().removePrivilegeFilter( tagFilter );
@@ -934,7 +957,9 @@ public final class UpdateNode extends DM
 				  readColsBitSet.getNumBitsSet(),			
 			  positionedUpdate,
 			  resultSet.isOneRowResultSet(),
-			  inMatchingClause()
+			  autoincRowLocation,
+			  inMatchingClause(),
+			  identitySequenceUUIDString
 			  );
 	}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java?rev=1625884&r1=1625883&r2=1625884&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BaseActivation.java Thu Sep 18 03:52:34 2014
@@ -739,7 +739,7 @@ public abstract class BaseActivation imp
 	       throws StandardException
 	{
 		DataValueDescriptor l =
-			((InsertResultSet)resultSet).getSetAutoincrementValue(columnPosition, increment);
+			((DMLWriteGeneratedColumnsResultSet)resultSet).getSetAutoincrementValue(columnPosition, increment);
 		return l;
 
 	}

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLWriteGeneratedColumnsResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLWriteGeneratedColumnsResultSet.java?rev=1625884&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLWriteGeneratedColumnsResultSet.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLWriteGeneratedColumnsResultSet.java Thu Sep 18 03:52:34 2014
@@ -0,0 +1,121 @@
+/*
+
+   Derby - Class org.apache.derby.impl.sql.execute.DMLWriteGeneratedColumnsResultSet
+
+   Licensed to the Apache Software Foundation (ASF) under one or more
+   contributor license agreements.  See the NOTICE file distributed with
+   this work for additional information regarding copyright ownership.
+   The ASF licenses this file to you under the Apache License, Version 2.0
+   (the "License"); you may not use this file except in compliance with
+   the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
+
+ */
+
+package org.apache.derby.impl.sql.execute;
+
+import java.util.HashMap;
+
+
+import org.apache.derby.catalog.UUID;
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.sql.Activation;
+import org.apache.derby.iapi.sql.ResultColumnDescriptor;
+import org.apache.derby.iapi.sql.execute.ConstantAction;
+import org.apache.derby.iapi.sql.execute.NoPutResultSet;
+import org.apache.derby.iapi.types.DataValueDescriptor;
+import org.apache.derby.iapi.types.NumberDataValue;
+import org.apache.derby.iapi.types.RowLocation;
+import org.apache.derby.shared.common.sanity.SanityManager;
+
+/*
+ * This class includes code for auto generated columns that can be shared
+ *  by insert and update statements in the execution phase.
+ */
+abstract public class DMLWriteGeneratedColumnsResultSet extends DMLWriteResultSet
+{    
+	/**
+	 * keeps track of autoincrement values that are generated by 
+	 * getSetAutoincrementValues.
+	 */
+	protected DataValueDescriptor				aiCache[];
+	
+	protected String              identitySequenceUUIDString;
+
+	protected	NoPutResultSet			sourceResultSet;
+
+	/**
+	 * Constructor
+	 *
+ 	 * @param activation		an activation
+	 *
+ 	 * @exception StandardException on error
+	 */
+	DMLWriteGeneratedColumnsResultSet(Activation activation)
+		throws StandardException
+	{
+		this(activation, activation.getConstantAction());
+	}
+
+	DMLWriteGeneratedColumnsResultSet(Activation activation, ConstantAction constantAction)
+		throws StandardException
+	{
+		super(activation, constantAction);
+	}
+	
+    /**
+     * getSetAutoincrementValue will get the autoincrement value of the 
+     * columnPosition specified for the target table. If increment is 
+     * non-zero we will also update the autoincrement value. 
+     *
+     * @param columnPosition	position of the column in the table (1-based)
+     * @param increment			amount of increment. 
+     *
+     * @exception StandardException if anything goes wrong.
+     */
+    public NumberDataValue
+    	getSetAutoincrementValue(int columnPosition, long increment)
+    	throws StandardException {
+        if (SanityManager.DEBUG) {
+            // This method should be overriden by InsertResultSet and
+            // UpdateResultSet, other shouldn't need it.
+            SanityManager.NOTREACHED();
+        }
+		return null; 
+    }
+    
+    public void saveAIcacheInformation(String schemaName,
+    		String tableName, String[] columnNames) 
+    throws StandardException{
+        if (aiCache != null)
+        {
+            HashMap<String,Long> aiHashtable = new HashMap<String,Long>();
+            int numColumns = aiCache.length;
+            // this insert updated ai values, store them in some persistent
+            // place so that I can see these values.
+            for (int i = 0; i < numColumns; i++)
+            {
+                if (aiCache[i] == null)
+                    continue;
+                aiHashtable.put(AutoincrementCounter.makeIdentity(
+                        schemaName,
+                        tableName,
+                        columnNames[i]),
+                        new Long(aiCache[i].getLong()));
+            }
+            InternalTriggerExecutionContext itec =
+                (InternalTriggerExecutionContext)lcc.getTriggerExecutionContext();
+            if (itec == null)
+                lcc.copyHashtableToAIHT(aiHashtable);
+            else
+                itec.copyHashtableToAIHT(aiHashtable);
+        }	
+    }
+}
\ No newline at end of file

Propchange: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DMLWriteGeneratedColumnsResultSet.java
------------------------------------------------------------------------------
    svn:eol-style = native

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=1625884&r1=1625883&r2=1625884&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 Thu Sep 18 03:52:34 2014
@@ -941,7 +941,10 @@ 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 autoincRowLocation array of row locations into syscolumns for
+	                              autoincrement columns
 	 *  @param underMerge   True if this is an action of a MERGE statement.
+	 *  @param identitySequenceUUIDString   For 10.11 and higher, the handle on the sequence for the identity column
      *  @return                     The constant action constructed
 	 *
 	 *  @exception StandardException Thrown on failure
@@ -968,7 +971,9 @@ public class GenericConstantActionFactor
 								int					numColumns,
 								boolean				positionedUpdate,
 								boolean				singleRowSource,
-								boolean				underMerge
+								RowLocation[]		autoincRowLocation,
+								boolean				underMerge,
+								String		identitySequenceUUIDString
 							)
 			throws StandardException
 	{
@@ -991,7 +996,9 @@ public class GenericConstantActionFactor
 										numColumns,
 										positionedUpdate,
 										singleRowSource,
-										underMerge
+										autoincRowLocation,
+										underMerge,
+										identitySequenceUUIDString
 										);
 	}
 

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=1625884&r1=1625883&r2=1625884&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 Thu Sep 18 03:52:34 2014
@@ -282,6 +282,11 @@ public class InsertConstantAction extend
 	 * @param 	i	the column number
 	 */
 	public String getColumnName(int i) { return columnNames[i]; }
+	
+	/**
+	 * get the array of column names in the target table.
+	 */
+	public String[] getColumnNames() { return columnNames; }
 
 	/**
 	 * gets the increment value for a column.

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=1625884&r1=1625883&r2=1625884&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 Thu Sep 18 03:52:34 2014
@@ -89,14 +89,13 @@ import org.apache.derby.shared.common.sa
  * and triggers to be executed based on the c's and t's
  * compiled into the insert plan.
  */
-class InsertResultSet extends DMLWriteResultSet implements TargetResultSet
+class InsertResultSet extends DMLWriteGeneratedColumnsResultSet implements TargetResultSet
 {
 	// RESOLVE. Embarassingly large public state. If we could move the Replication
 	// code into the same package, then these variables could be protected.
 
 	// passed in at construction time
                                                  
-	private	NoPutResultSet			sourceResultSet;
 	NoPutResultSet			savedSource;
 	InsertConstantAction	constants;
     private GeneratedMethod         generationClauses;
@@ -163,11 +162,6 @@ class InsertResultSet extends DMLWriteRe
 	private	TriggerInfo				triggerInfo;
 	private RISetChecker 			fkChecker;
 	private TriggerEventActivator	triggerActivator;
-	/**
-	 * keeps track of autoincrement values that are generated by 
-	 * getSetAutoincrementValues.
-	 */
-	private DataValueDescriptor				aiCache[];
     private BulkInsertCounter[]                 bulkInsertCounters;
     private BackingStoreHashtable   deferredChecks; // cached ref.
     private List<UUID>              violatingCheckConstraints;
@@ -181,8 +175,6 @@ class InsertResultSet extends DMLWriteRe
 	private long					identityVal;  //support of IDENTITY_LOCAL_VAL function
 	private boolean					setIdentity;
 	
-    private String              identitySequenceUUIDString;
-
 	// TargetResultSet interface
 
 	/**
@@ -375,21 +367,7 @@ class InsertResultSet extends DMLWriteRe
 		// Is this a bulkInsert or regular insert?
 		String insertMode = constants.getProperty("insertMode");
 
-                RowLocation[] rla;
-
-		if ((rla = constants.getAutoincRowLocation()) != null)
-		{
-			aiCache = new DataValueDescriptor[ rla.length ];
-			bulkInsertCounters = new BulkInsertCounter[ rla.length ];
-			for (int i = 0; i < resultDescription.getColumnCount(); i++)
-			{
-				if (rla[i] == null)
-					continue;
-				ResultColumnDescriptor rcd = 
-					resultDescription.getColumnDescriptor(i + 1);
-				aiCache[i] = rcd.getType().getNull();
-			}
-		}
+		initializeAIcache(constants.getAutoincRowLocation());
 
 		if (insertMode != null)
 		{
@@ -522,29 +500,8 @@ class InsertResultSet extends DMLWriteRe
 
 		cleanUp();
 
-		if (aiCache != null)
-		{
-			HashMap<String,Long> aiHashtable = new HashMap<String,Long>();
-			int numColumns = aiCache.length;
-			// this insert updated ai values, store them in some persistent
-			// place so that I can see these values.
-			for (int i = 0; i < numColumns; i++)
-			{
-				if (aiCache[i] == null)
-					continue;
-				aiHashtable.put(AutoincrementCounter.makeIdentity(
-								  constants.getSchemaName(),
-								  constants.getTableName(),
-								  constants.getColumnName(i)),
-								new Long(aiCache[i].getLong()));
-			}
-			InternalTriggerExecutionContext itec =
-				(InternalTriggerExecutionContext)lcc.getTriggerExecutionContext();
-			if (itec == null)
-				lcc.copyHashtableToAIHT(aiHashtable);
-			else
-				itec.copyHashtableToAIHT(aiHashtable);
-		}	
+		saveAIcacheInformation(constants.getSchemaName(), 
+			constants.getTableName(), constants.getColumnNames());
 
 		endTime = getCurrentTimeMillis();
 	}
@@ -2722,4 +2679,44 @@ class InsertResultSet extends DMLWriteRe
             violatingCheckConstraints.add(cid);
         }
     }
+    
+    /*
+     * The implementation of this method is slightly different than the one
+     *  in UpdateResultSet. This code was originally written for insert but
+     *  with DERBY-6414, we have started supporting update of auto generated
+     *  column with keyword DEFAULT. The reason of different implementation is
+     *  that the array used in the following method, namely, 
+     *  ColumnDescriptors in resultDescription hold different entries for
+     *  insert and update case. For insert case, the array holds the column
+     *  descriptors of all the columns in the table. This is because all the
+     *  columns in the table are going to get some value into them whether
+     *  or not they were included directly in the actual INSERT statement.
+     *  The 2nd array, rla has a spot for each of the columns in the table, 
+     *  with non null value for auto generated column. But in case of Update,
+     *  resultDescription does not include all the columns in the table. It
+     *  only has the columns being touched by the Update statement(the rest of
+     *  the columns in the table will retain their original values), and for 
+     *  each of those touched columns, it has a duplicate entry in 
+     *  resultDescription in order to have before and after values for the 
+     *  changed column values. Lastly, it has a row location information for 
+     *  the row being updated. This difference in array content of 
+     *  resultDescription requires us to have separate implementation of this
+     *  method for insert and update.
+     */
+    protected void  initializeAIcache(RowLocation[] rla) 
+    		throws StandardException{
+    	if ((rla = constants.getAutoincRowLocation()) != null)
+    	{
+    		aiCache = new DataValueDescriptor[ rla.length ];
+    		bulkInsertCounters = new BulkInsertCounter[ rla.length ];
+    		for (int i = 0; i < resultDescription.getColumnCount(); i++)
+    		{
+    			if (rla[i] == null)
+    				continue;
+    			ResultColumnDescriptor rcd = 
+    				resultDescription.getColumnDescriptor(i + 1);
+    			aiCache[i] = rcd.getType().getNull();
+    		}
+    	}
+    }
 }

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=1625884&r1=1625883&r2=1625884&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 Thu Sep 18 03:52:34 2014
@@ -39,6 +39,7 @@ import java.io.IOException;
 import java.util.Properties;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
+import org.apache.derby.iapi.types.RowLocation;
 
 /**
  *	This class  describes compiled constants that are passed into
@@ -69,6 +70,19 @@ public class UpdateConstantAction extend
 
     private String schemaName;
     private String tableName;
+    private String columnNames[];
+
+    String  identitySequenceUUIDString;
+
+    /**
+     * An array of row location objects (0 based), one for each
+     * column in the table. If the column is an 
+     * autoincrement table then the array points to
+     * the row location of the column in SYSCOLUMNS.
+     * if not, then it contains null.
+     */
+    RowLocation[] autoincRowLocation;
+    private long[] autoincIncrement;
 
 	// CONSTRUCTORS
 
@@ -102,28 +116,33 @@ 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 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.
+	 *  @param identitySequenceUUIDString   For 10.11 and higher, the handle on the sequence for the identity column
 	 */
     UpdateConstantAction(
                                 TableDescriptor     targetTableDesc,
-								StaticCompiledOpenConglomInfo heapSCOCI,
-								IndexRowGenerator[]	irgs,
-								long[]				indexCIDS,
-								StaticCompiledOpenConglomInfo[] indexSCOCIs,
-								String[]			indexNames,
-								boolean				deferred,
-								UUID				targetUUID,
-								int					lockMode,
-								int[]				changedColumnIds,
-								FKInfo[]			fkInfo,
-								TriggerInfo			triggerInfo,
-								FormatableBitSet				baseRowReadList,
-								int[]				baseRowReadMap,
-								int[]               streamStorableHeapColIds,
-								int					numColumns,
-								boolean				positionedUpdate,
-								boolean				singleRowSource,
-                                boolean             underMerge)
+                                StaticCompiledOpenConglomInfo heapSCOCI,
+                                IndexRowGenerator[]	irgs,
+                                long[]				indexCIDS,
+                                StaticCompiledOpenConglomInfo[] indexSCOCIs,
+                                String[]			indexNames,
+                                boolean				deferred,
+                                UUID				targetUUID,
+                                int					lockMode,
+                                int[]				changedColumnIds,
+                                FKInfo[]			fkInfo,
+                                TriggerInfo			triggerInfo,
+                                FormatableBitSet				baseRowReadList,
+                                int[]				baseRowReadMap,
+                                int[]               streamStorableHeapColIds,
+                                int					numColumns,
+                                boolean				positionedUpdate,
+                                boolean				singleRowSource,
+                                RowLocation[]		autoincRowLocation,
+                                boolean             underMerge,
+                                String		identitySequenceUUIDString)
             throws StandardException
 	{
 		super(
@@ -151,6 +170,28 @@ public class UpdateConstantAction extend
 		this.numColumns = numColumns;
         this.schemaName = targetTableDesc.getSchemaName();
         this.tableName = targetTableDesc.getName();
+        this.columnNames = targetTableDesc.getColumnNamesArray();
+        this.autoincIncrement = targetTableDesc.getAutoincIncrementArray();
+        this.identitySequenceUUIDString = identitySequenceUUIDString;
+        this.autoincRowLocation = autoincRowLocation;
+	}
+
+	/**
+	 * Does the target table has autoincrement columns.
+	 *
+	 * @return 	True if the table has ai columns
+	 */
+	public boolean hasAutoincrement()
+	{
+		return (autoincRowLocation != null);
+	}
+
+	/**
+	 * gets the row location 
+	 */
+	RowLocation[] getAutoincRowLocation()
+	{
+		return autoincRowLocation;
 	}
 
 	// INTERFACE METHODS
@@ -170,6 +211,8 @@ public class UpdateConstantAction extend
 		changedColumnIds = ArrayUtil.readIntArray(in);
 		positionedUpdate = in.readBoolean();
 		numColumns = in.readInt();
+		autoincIncrement = ArrayUtil.readLongArray(in);
+		identitySequenceUUIDString = (String) in.readObject();
 	}
 
 	/**
@@ -184,6 +227,8 @@ public class UpdateConstantAction extend
 		ArrayUtil.writeIntArray(out,changedColumnIds);
 		out.writeBoolean(positionedUpdate);
 		out.writeInt(numColumns);
+		ArrayUtil.writeLongArray(out, autoincIncrement);
+		out.writeObject( identitySequenceUUIDString );
 	}
 
 	/**
@@ -201,4 +246,23 @@ public class UpdateConstantAction extend
     public String getTableName() {
         return tableName;
     }
+
+    /**
+     * gets the name of the desired column in the taget table.
+     * 
+     * @param 	i	the column number
+     */
+    public String getColumnName(int i) { return columnNames[i]; }
+
+    /**
+     * get the array of column names in the target table.
+     */
+    public String[] getColumnNames() { return columnNames; }
+
+    /**
+     * gets the increment value for a column.
+     *
+     * @param 	i 	the column number
+     */
+    public long   getAutoincIncrement(int i) { return autoincIncrement[i]; }
 }

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=1625884&r1=1625883&r2=1625884&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 Thu Sep 18 03:52:34 2014
@@ -24,6 +24,8 @@ package org.apache.derby.impl.sql.execut
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Properties;
+import java.util.Vector;
+
 import org.apache.derby.catalog.UUID;
 import org.apache.derby.iapi.db.TriggerExecutionContext;
 import org.apache.derby.iapi.error.StandardException;
@@ -42,16 +44,16 @@ import org.apache.derby.iapi.sql.execute
 import org.apache.derby.iapi.store.access.BackingStoreHashtable;
 import org.apache.derby.iapi.store.access.ConglomerateController;
 import org.apache.derby.iapi.store.access.ScanController;
-import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
 import org.apache.derby.iapi.store.access.TransactionController;
 import org.apache.derby.iapi.types.BooleanDataValue;
 import org.apache.derby.iapi.types.DataValueDescriptor;
+import org.apache.derby.iapi.types.NumberDataValue;
 import org.apache.derby.iapi.types.RowLocation;
 import org.apache.derby.iapi.types.SQLBoolean;
 import org.apache.derby.iapi.types.SQLRef;
 import org.apache.derby.impl.sql.execute.DeferredConstraintsMemory.CheckInfo;
 import org.apache.derby.shared.common.sanity.SanityManager;
-
+import org.apache.derby.iapi.sql.dictionary.ColumnDescriptorList;
 /**
  * Update the rows from the specified
  * base table. This will cause constraints to be checked
@@ -59,7 +61,7 @@ import org.apache.derby.shared.common.sa
  * compiled into the update plan.
  *
  */
-class UpdateResultSet extends DMLWriteResultSet
+class UpdateResultSet extends DMLWriteGeneratedColumnsResultSet
 {
 	private TransactionController 	tc;
 	private ExecRow					newBaseRow;
@@ -67,7 +69,6 @@ class UpdateResultSet extends DMLWriteRe
 	private ExecRow 					deferredSparseRow;
 	UpdateConstantAction		constants;
 	
-	private NoPutResultSet			source;
 	NoPutResultSet			savedSource;
 	private RowChanger				rowChanger;
 
@@ -181,7 +182,7 @@ class UpdateResultSet extends DMLWriteRe
 
 		// Get the current transaction controller
         tc = activation.getTransactionController();
-		this.source = source;
+        this.sourceResultSet = source;
         this.generationClauses = generationClauses;
 		this.checkGM = checkGM;
 
@@ -253,6 +254,8 @@ class UpdateResultSet extends DMLWriteRe
 			beforeUpdateCopyRequired = true;
 		}
 		
+        identitySequenceUUIDString = constants.identitySequenceUUIDString;
+        initializeAIcache(constants.getAutoincRowLocation());
 	}
 	/**
 		@exception StandardException Standard Derby error policy
@@ -287,6 +290,8 @@ class UpdateResultSet extends DMLWriteRe
 		rowChanger.finish();
 		}
 
+		saveAIcacheInformation(constants.getSchemaName(), 
+			constants.getTableName(), constants.getColumnNames());
 		cleanUp();
     }
 
@@ -310,7 +315,7 @@ class UpdateResultSet extends DMLWriteRe
 		if (lcc.getRunTimeStatisticsMode())
 		{
 			/* savedSource nulled after run time statistics generation */
-			savedSource = source;
+			savedSource = sourceResultSet;
 		}
 
 		/* Get or re-use the row changer.
@@ -344,11 +349,11 @@ class UpdateResultSet extends DMLWriteRe
 
 		if (numOpens++ == 0)
 		{
-			source.openCore();
+			sourceResultSet.openCore();
 		}
 		else
 		{
-			source.reopenCore();
+			sourceResultSet.reopenCore();
 		}
 
 		/* The source does not know whether or not we are doing a
@@ -465,7 +470,7 @@ class UpdateResultSet extends DMLWriteRe
 	{
 
 		boolean rowsFound = false;
-		row = getNextRowCore(source);
+		row = getNextRowCore(sourceResultSet);
 
 		if (row!=null)
 			rowsFound = true;
@@ -485,7 +490,7 @@ class UpdateResultSet extends DMLWriteRe
 
         while ( row != null )
         {
-            evaluateGenerationClauses( generationClauses, activation, source, row, true );
+            evaluateGenerationClauses( generationClauses, activation, sourceResultSet, row, true );
 
 			/* By convention, the last column in the result set for an
 			 * update contains a SQLRef containing the RowLocation of
@@ -624,7 +629,7 @@ class UpdateResultSet extends DMLWriteRe
                     riChecker.doFKCheck(activation, newBaseRow);
 				}
 
-				source.updateRow(newBaseRow, rowChanger);
+				sourceResultSet.updateRow(newBaseRow, rowChanger);
 				rowChanger.updateRow(row,newBaseRow,baseRowLocation);
 
 				//beetle 3865, update cursor use index.
@@ -642,7 +647,7 @@ class UpdateResultSet extends DMLWriteRe
 			}
 			else
 			{
-				row = getNextRowCore(source);
+				row = getNextRowCore(sourceResultSet);
 			}
 		}
 
@@ -799,13 +804,38 @@ class UpdateResultSet extends DMLWriteRe
 		{
 			if (triggerInfo != null)
 			{
+				Vector<AutoincrementCounter> v = null;
+				if (aiCache != null)
+				{
+					v = new Vector<AutoincrementCounter>();
+					for (int i = 0; i < aiCache.length; i++)
+					{
+						String s, t, c;
+						if (aiCache[i] == null)
+							continue;
+					
+						Long initialValue = 
+							lcc.lastAutoincrementValue(
+								(s = constants.getSchemaName()),
+								(t = constants.getTableName()),
+								(c = constants.getColumnName(i)));
+
+						AutoincrementCounter aic = 
+							new AutoincrementCounter(
+								 initialValue,
+								 constants.getAutoincIncrement(i),
+								 aiCache[i].getLong(),
+								 s, t, c, i + 1);
+						v.addElement(aic);
+					}
+				}
 				if (triggerActivator == null)
 				{
 				triggerActivator = new TriggerEventActivator(lcc, 
 											constants.targetUUID,
 											triggerInfo,
 											TriggerExecutionContext.UPDATE_EVENT,
-											activation, null);
+											activation, v);
 				}
 				else
 				{
@@ -877,7 +907,7 @@ class UpdateResultSet extends DMLWriteRe
 
 					if (triggerInfo != null)
 					{
-						source.setCurrentRow(deferredTempRow);
+						sourceResultSet.setCurrentRow(deferredTempRow);
                         allOk = evaluateCheckConstraints();
 					}
 
@@ -928,7 +958,7 @@ class UpdateResultSet extends DMLWriteRe
 				}
 			} finally
 			{
-				source.clearCurrentRow();
+				sourceResultSet.clearCurrentRow();
 				rs.close();
 			}
 		}
@@ -1116,9 +1146,9 @@ class UpdateResultSet extends DMLWriteRe
 		numOpens = 0;
 
 		/* Close down the source ResultSet tree */
-		if (source != null)
+		if (sourceResultSet != null)
 		{
-			source.close();
+			sourceResultSet.close();
 			// cache source across open()s
 		}
 
@@ -1175,4 +1205,64 @@ class UpdateResultSet extends DMLWriteRe
 
         violatingCheckConstraints.add(cid);
     }
+
+    /**
+     * getSetAutoincrementValue will get the autoincrement value of the 
+     * columnPosition specified for the target table. If increment is 
+     * non-zero we will also update the autoincrement value. 
+     *
+     * @param columnPosition	position of the column in the table (1-based)
+     * @param increment			amount of increment. 
+     *
+     * @exception StandardException if anything goes wrong.
+     */
+    public NumberDataValue
+    	getSetAutoincrementValue(int columnPosition, long increment)
+    	throws StandardException
+    {
+        int index = columnPosition - 1;	// all our indices are 0 based.
+        NumberDataValue newValue;
+        newValue = activation.getCurrentValueAndAdvance
+                ( identitySequenceUUIDString, aiCache[ index ].getTypeFormatId() );
+        aiCache[index] = newValue;
+        return (NumberDataValue) aiCache[index];
+    }
+	
+    /*
+     * The implementation of this method is slightly different than the one
+     *  in InsertResultSet. This code was originally written for insert but
+     *  with DERBY-6414, we have started supporting update of auto generated
+     *  column with keyword DEFAULT. The reason of different implementation is
+     *  that the array used in InsertResultSet's implementation of this method,  
+     *  ColumnDescriptors in resultDescription hold different entries for
+     *  insert and update case. For insert case, the array holds the column
+     *  descriptors of all the columns in the table. This is because all the
+     *  columns in the table are going to get some value into them whether
+     *  or not they were included directly in the actual INSERT statement.
+     *  The 2nd array, rla has a spot for each of the columns in the table, 
+     *  with non null value for auto generated column. But in case of Update,
+     *  resultDescription does not include all the columns in the table. It
+     *  only has the columns being touched by the Update statement(the rest of
+     *  the columns in the table will retain their original values), and for 
+     *  each of those touched columns, it has a duplicate entry in 
+     *  resultDescription in order to have before and after values for the 
+     *  changed column values. Lastly, it has a row location information for 
+     *  the row being updated. This difference in array content of 
+     *  resultDescription requires us to have separate implementation of this
+     *  method for insert and update.
+     */
+	protected void  initializeAIcache(RowLocation[] rla) 
+			throws StandardException{
+        if (rla != null)
+        {
+        	aiCache = new DataValueDescriptor[ rla.length ];
+        	ColumnDescriptorList columns = lcc.getDataDictionary().getTableDescriptor(constants.targetUUID).getColumnDescriptorList();
+       		for (int i = 0; i < columns.size(); i++)
+        	{
+        		if (rla[i] == null)
+        			continue;        		
+        		aiCache[i] = columns.elementAt(i).getType().getNull();
+    		}
+        }
+	}
 }

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java?rev=1625884&r1=1625883&r2=1625884&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/GeneratedColumnsTest.java Thu Sep 18 03:52:34 2014
@@ -116,6 +116,283 @@ public class GeneratedColumnsTest extend
     ///////////////////////////////////////////////////////////////////////////////////
 
     /**
+     * DERBY-6414 - support updating identity columns with DEFAULT keyword.
+     */
+    public void testDerby_6414() throws SQLException {
+        Statement s = createStatement();
+        ResultSet rs = null;
+        setAutoCommit(false);
+    	
+        //Try update of generated always as identity column
+        s.execute("create table t1_6414(a int, "+
+        "b generated always as (-a),"+
+        "c int generated always as identity," +
+        "d char(3)," +
+        "e char(5)" +
+        ")");
+        s.execute("create table t1_after_update_changes_6414(abc int, "+
+        "bbc int,"+
+        "cbc int," +
+        "dbc char(3)," +
+        "ebc char(5)," +
+        "aac int, " +
+        "bac int,"+
+        "cac int," +
+        "dac char(3)," +
+        "eac char(5)" +
+        ")");
+        s.execute("create trigger tr1_t1_6414_after_update_row "+
+                "after update on t1_6414\n" +
+                "referencing old as br new as ar\n" +
+                "for each row\n" +
+                "insert into t1_after_update_changes_6414 values "+
+                "(br.a, br.b, br.c, br.d, br.e, ar.a, ar.b, ar.c, ar.d, ar.e)"
+                );
+
+        goodStatement
+        (
+                getConnection(),
+                "insert into t1_6414(b,a) values (default,1), (default, 2)"
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t1_6414",
+         new String[][]
+         {
+             { "1", "-1", "1", null, null },
+             { "2", "-2", "2", null, null },
+         },
+         false
+         );
+        goodStatement
+        (
+                getConnection(),
+                "update t1_6414 set e='ccccc', a=-a, c=default"
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t1_6414",
+         new String[][]
+         {
+             { "-1", "1", "3", null, "ccccc" },
+             { "-2", "2", "4", null, "ccccc" },
+         },
+         false
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t1_after_update_changes_6414",
+         new String[][]
+         {
+             { "1", "-1", "1", null, null, "-1", "1", "3", null, "ccccc" },
+             { "2", "-2", "2", null, null, "-2", "2", "4", null, "ccccc" },
+         },
+         false
+        );
+        goodStatement
+        (
+                getConnection(),
+                "delete from t1_after_update_changes_6414"
+        );
+
+        goodStatement
+        (
+                getConnection(),
+                "update t1_6414 set c=default, b=default"
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t1_6414",
+         new String[][]
+         {
+             { "-1", "1", "5", null, "ccccc" },
+             { "-2", "2", "6", null, "ccccc" },
+         },
+         false
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t1_after_update_changes_6414",
+         new String[][]
+         {
+             { "-1", "1", "3", null, "ccccc", "-1", "1", "5", null, "ccccc" },
+             { "-2", "2", "4", null, "ccccc", "-2", "2", "6", null, "ccccc" },
+         },
+         false
+        );
+        goodStatement
+        (
+                getConnection(),
+                "delete from t1_after_update_changes_6414"
+        );
+
+        goodStatement
+        (
+                getConnection(),
+                "update t1_6414 set d='ccc'"
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t1_6414",
+         new String[][]
+         {
+             { "-1", "1", "5", "ccc", "ccccc" },
+             { "-2", "2", "6", "ccc", "ccccc" },
+         },
+         false
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t1_after_update_changes_6414",
+         new String[][]
+         {
+             { "-1", "1", "5", null, "ccccc", "-1", "1", "5", "ccc", "ccccc" },
+             { "-2", "2", "6", null, "ccccc", "-2", "2", "6", "ccc", "ccccc" },
+         },
+         false
+        );
+        goodStatement
+        (
+                getConnection(),
+                "delete from t1_after_update_changes_6414"
+        );
+
+        PreparedStatement select = prepareStatement("select a, c from t1_6414 where d='ccc' for update");
+        ResultSet cursor;
+        Statement update = createStatement();
+        String cursorName;
+        cursor = select.executeQuery(); // cursor is now open
+        cursorName = cursor.getCursorName();
+        assertEquals(cursor.next(), true);
+        update.execute("update t1_6414 set a = a+3, c=default  where current of " + cursorName);
+        assertEquals(cursor.next(), true);
+        update.execute("update t1_6414 set a = a+300, c=default  where current of " + cursorName);
+        cursor.close();
+        update.close();
+        assertResults
+        (
+         getConnection(),
+         "select * from t1_6414",
+         new String[][]
+         {
+             { "2", "-2", "7", "ccc", "ccccc" },
+             { "298", "-298", "8", "ccc", "ccccc" },
+         },
+         false
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t1_after_update_changes_6414",
+         new String[][]
+         {
+             { "-1", "1", "5", "ccc", "ccccc", "2", "-2", "7", "ccc", "ccccc" },
+             { "-2", "2", "6", "ccc", "ccccc", "298", "-298", "8", "ccc", "ccccc" },
+         },
+         false
+        );
+
+        //Test update of generated by default identity column
+        s.execute("create table t2_6414(a int, "+
+        "b generated always as (-a),"+
+        "c int generated by default as identity," +
+        "d char(3)," +
+        "e char(5)" +
+        ")");
+        goodStatement
+        (
+                getConnection(),
+                "insert into t2_6414(b,a,d,e,c) "+
+                "values (default,1,'aaa','aaaaa',1), " +
+        		"(default,2,'bbb','bbbbb',default)"
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t2_6414",
+         new String[][]
+         {
+             { "1", "-1", "1", "aaa", "aaaaa" },
+             { "2", "-2", "1", "bbb", "bbbbb" },
+         },
+         false
+        );
+        goodStatement
+        (
+                getConnection(),
+                "update t2_6414 set e='ccccc', a=-a, c=default, d='ccc'"
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t2_6414",
+         new String[][]
+         {
+             { "-1", "1", "2", "ccc", "ccccc" },
+             { "-2", "2", "3", "ccc", "ccccc" },
+         },
+         false
+        );
+        goodStatement
+        (
+                getConnection(),
+                "update t2_6414 set c=default, b=default"
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t2_6414",
+         new String[][]
+         {
+             { "-1", "1", "4", "ccc", "ccccc" },
+             { "-2", "2", "5", "ccc", "ccccc" },
+         },
+         false
+        );
+        goodStatement
+        (
+                getConnection(),
+                "update t2_6414 set d=null"
+        );
+        assertResults
+        (
+         getConnection(),
+         "select * from t2_6414",
+         new String[][]
+         {
+             { "-1", "1", "4", null, "ccccc" },
+             { "-2", "2", "5", null, "ccccc" },
+         },
+         false
+        );
+        select = prepareStatement("select a, c from t2_6414 where b=2 for update");
+        update = createStatement();
+        cursor = select.executeQuery(); // cursor is now open
+        cursorName = cursor.getCursorName();
+        assertEquals(cursor.next(), true);
+        update.execute("update t2_6414 set a = a+3, c=default  where current of " + cursorName);
+        cursor.close();
+        update.close();
+        assertResults
+        (
+         getConnection(),
+         "select * from t2_6414",
+         new String[][]
+         {
+             { "-1", "1", "4", null, "ccccc" },
+             { "1", "-1", "6", null, "ccccc" },
+         },
+         false
+        );
+    }
+    /**
      * Test for DERBY-4448 and DERBY-4451: removal of explicitly given values
      * for generated column failed if there is more than one row in the VALUES
      * clause.

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java?rev=1625884&r1=1625883&r2=1625884&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/MergeStatementTest.java Thu Sep 18 03:52:34 2014
@@ -429,15 +429,6 @@ public class MergeStatementTest extends 
               "when matched and t1.c2 != t2.c2 then update set c3 = t2.c2\n"
               );
 
-        // and you can't update an identity column at all
-        expectCompilationError
-            ( dboConnection, CANT_MODIFY_IDENTITY,
-              "merge into t1\n" +
-              "using t2\n" +
-              "on t1.c1 = t2.c1\n" +
-              "when matched and t1.c2 != t2.c2 then update set c1 = default, c2 = t2.c2\n"
-              );
-
         // Column may not appear twice in INSERT list.
         expectCompilationError
             ( dboConnection, DUPLICATE_COLUMNS,
@@ -1730,6 +1721,16 @@ public class MergeStatementTest extends 
              false
              );
 
+        /* update an identity column with default should work once we change 
+         * MergeStatement implementation to handle auto generated keys
+        goodStatement
+            ( dboConnection, 
+              "merge into t1_007\n" +
+              "using t2_007\n" +
+              "on t1_007.c1 = t2_007.c1\n" +
+              "when matched and t1_007.c2 != t2_007.c2 then update set c1 = default, c2 = t2_007.c2\n"
+              );*/
+
         //
         // drop schema
         //
@@ -2581,16 +2582,15 @@ public class MergeStatementTest extends 
              );
 
         //
-        // The following statement fails because of derby-6414. Revisit this
-        // case when that bug is fixed.
-        //
+        /*update an identity column with default should work once we change
+        // MergeStatement implementation to handle auto generated keys
         expectCompilationError
             ( dboConnection, CANT_MODIFY_IDENTITY,
               "merge into t1_014\n" +
               "using t2_014\n" +
               "on t1_014.c2 = t2_014.c2\n" +
               "when matched then update set c1 = default, c3 = default, c2 = 2 * t2_014.c2, c5 = default\n"
-              );
+              );*/
 
         //
         // drop schema
@@ -2607,7 +2607,7 @@ public class MergeStatementTest extends 
      * the behavior for standalone UPDATE statements.
      * </p>
      */
-    public  void    test_015_bug_6414()
+    public  void    atest_015_bug_6414()
         throws Exception
     {
         Connection  dboConnection = openUserConnection( TEST_DBO );
@@ -2651,8 +2651,8 @@ public class MergeStatementTest extends 
         // column to the next DEFAULT value, i.e., the next value from the
         // sequence generator.
         //
-        expectCompilationError
-            ( dboConnection, CANT_MODIFY_IDENTITY,
+        goodStatement
+            ( dboConnection, 
               "update t1_bug_6414 set a = default, b = -b"
               );
         expectCompilationError

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/Changes10_12.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/Changes10_12.java?rev=1625884&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/Changes10_12.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/Changes10_12.java Thu Sep 18 03:52:34 2014
@@ -0,0 +1,225 @@
+/*
+
+Derby - Class org.apache.derbyTesting.functionTests.tests.upgradeTests.Changes10_12
+
+Licensed to the Apache Software Foundation (ASF) under one or more
+contributor license agreements.  See the NOTICE file distributed with
+this work for additional information regarding copyright ownership.
+The ASF licenses this file to You under the Apache License, Version 2.0
+(the "License"); you may not use this file except in compliance with
+the License.  You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+
+*/
+package org.apache.derbyTesting.functionTests.tests.upgradeTests;
+
+import java.sql.SQLException;
+import java.sql.Statement;
+import junit.framework.Test;
+import org.apache.derbyTesting.junit.BaseTestSuite;
+import org.apache.derbyTesting.junit.JDBC;
+
+
+/**
+ * Upgrade test cases for 10.12.
+ */
+public class Changes10_12 extends UpgradeChange
+{
+
+    //////////////////////////////////////////////////////////////////
+    //
+    // CONSTANTS
+    //
+    //////////////////////////////////////////////////////////////////
+
+    private static  final   String  LANG_AI_CANNOT_MODIFY_AI = "42Z23";
+    private static  final   String  LANG_NULL_INTO_NON_NULL = "23502";
+
+    //////////////////////////////////////////////////////////////////
+    //
+    // CONSTRUCTOR
+    //
+    //////////////////////////////////////////////////////////////////
+
+    public Changes10_12(String name) {
+        super(name);
+    }
+
+    //////////////////////////////////////////////////////////////////
+    //
+    // JUnit BEHAVIOR
+    //
+    //////////////////////////////////////////////////////////////////
+
+    /**
+     * Return the suite of tests to test the changes made in 10.12.
+     *
+     * @param phase an integer that indicates the current phase in
+     *              the upgrade test.
+     * @return the test suite created.
+     */
+    public static Test suite(int phase) {
+        return new BaseTestSuite(Changes10_12.class, "Upgrade test for 10.12");
+    }
+
+    //////////////////////////////////////////////////////////////////
+    //
+    // TESTS
+    //
+    //////////////////////////////////////////////////////////////////
+
+    /**
+     * DERBY-6414(Incorrect handling when using an UPDATE to SET an 
+     *  identity column to DEFAULT)
+     * Starting Derby 10.12, we support updating an identity column using
+     *  the keyword DEFAULT on 10.11 and higher dbs. A 10.11 database in 
+     *  soft upgrade mode can use this feature to update identity columns. 
+     *  Database versions earlier than that will not be able to use this 
+     *  feature. The reason for restricting the functionality to 10.11 and 
+     *  higher dbs is that starting 10.11, we started using sequence generator 
+     *  to create unique values for identity columns. Prior to that, we had 
+     *  really old code to generate unique values. In order to keep the code 
+     *  clean in 10.12, DERBY-6414 is fixed only for identity columns using 
+     *  sequence generator to create the new ids.
+     * @throws SQLException
+     */
+    public void testDerby6414UpdateIdentityColumn() throws SQLException {
+        //10.0 release does not support "generated by default as 
+        // identity" columns. 
+        if (!oldAtLeast(10, 1)) return;
+        
+        Statement s = createStatement();
+        switch (getPhase()) {
+            case PH_CREATE:
+            	//Create the necessary tables and show that update of
+            	// identity columns is not supported in these older
+            	// releases
+                s.execute("create table t1_6414(a int, "+
+                        "c int generated always as identity," +
+                        "d char(3)," +
+                        "e char(5)" +
+                        ")");
+                s.execute("insert into t1_6414(a) values "+
+                        "(1), (2)");
+                //Update of identity columns using DEFAULT keyword is not 
+                // supported in pre-10.12 releases
+                assertCompileError(LANG_AI_CANNOT_MODIFY_AI,
+                        "update t1_6414 set e='ccccc', a=-a, c=default");
+
+                s.execute("create table t2_6414(a int, "+
+                        "c int generated by default as identity," +
+                        "d char(3)," +
+                        "e char(5)" +
+                        ")");
+                s.execute("insert into t2_6414(a,d,e,c) values "+
+                        "(1,'aaa','aaaaa',1)");
+                s.execute("insert into t2_6414(a,d,e,c) values "+
+                		"(2,'bbb','bbbbb',default)");
+                //Update of identity columns using DEFAULT keyword is not 
+                // supported in pre-10.12 releases
+                assertStatementError(LANG_NULL_INTO_NON_NULL,
+                		s,
+                        "update t2_6414 set e='ccccc', a=-a, c=default, d='ccc'");
+                break;
+
+            case PH_SOFT_UPGRADE:
+            	if (!oldAtLeast(10, 11)) {
+                	//If the soft upgrade is on a pre10.11 db, then update of
+                	// identity column will still not be supported. This is
+                	// because those releases do not use sequence generator
+                	// to generate a new value for identity columns
+                    assertCompileError(LANG_AI_CANNOT_MODIFY_AI,
+                            "update t1_6414 set e='ccccc', a=-a, c=default");
+                    assertStatementError(LANG_NULL_INTO_NON_NULL,
+                    		s,
+	                        "update t2_6414 set e='ccccc', a=-a, c=default, d='ccc'");
+                } else {
+                	//We are dealing with 10.11 and higher dbs. These dbs use 
+                	// sequence generator to create the new identity value. On 
+                	// such dbs, on soft upgrade, we allow update of identity
+                	// column using DEFAULT keyword
+                	s.execute("update t1_6414 set e='ccccc', a=-a, c=default");
+                	JDBC.assertFullResultSet(
+                			s.executeQuery("select * from t1_6414"),
+                            new String[][]
+                            {
+                                { "-1", "3", null, "ccccc" },
+                                { "-2", "4", null, "ccccc" },
+                            }
+                    );
+
+                	s.execute(
+                            "update t2_6414 set e='ccccc', a=-a, c=default, d='ccc'");
+                	JDBC.assertFullResultSet(
+                			s.executeQuery("select * from t2_6414"),
+                            new String[][]
+                            {
+                                { "-1", "2", "ccc", "ccccc" },
+                                { "-2", "3", "ccc", "ccccc" },
+                            }
+                    );
+                }
+                break;
+            case PH_POST_SOFT_UPGRADE:
+            	//We are back to the release where the db was created. Those 
+            	// releases do not have fix for DERBY-6414 and hence the
+            	// following UPDATE of identity columns using DEFAULT 
+            	// keyword will fail.
+                assertCompileError(LANG_AI_CANNOT_MODIFY_AI,
+                        "update t1_6414 set e='ccccc', a=-a, c=default");
+                assertStatementError(LANG_NULL_INTO_NON_NULL,
+                		s,
+                        "update t2_6414 set e='ccccc', a=-a, c=default, d='ccc'");
+                break;
+            case PH_HARD_UPGRADE:
+            	s.execute("update t1_6414 set e='ccccc', a=-a, c=default");
+                if (!oldAtLeast(10, 11)) 
+                	JDBC.assertFullResultSet(
+                			s.executeQuery("select * from t1_6414"),
+                            new String[][]
+                            {
+                                { "-1", "3", null, "ccccc" },
+                                { "-2", "4", null, "ccccc" },
+                            }
+                    );
+                else
+                	JDBC.assertFullResultSet(
+                			s.executeQuery("select * from t1_6414"),
+                            new String[][]
+                            {
+                	             { "1", "5", null, "ccccc" },
+                	             { "2", "6", null, "ccccc" },
+                            }
+                    );
+
+            	s.execute(
+                        "update t2_6414 set e='ccccc', a=-a, c=default, d='ccc'");
+                if (!oldAtLeast(10, 11)) 
+                	JDBC.assertFullResultSet(
+                			s.executeQuery("select * from t2_6414"),
+                            new String[][]
+                            {
+                                { "-1", "2", "ccc", "ccccc" },
+                                { "-2", "3", "ccc", "ccccc" },
+                            }
+                    );
+                else
+                	JDBC.assertFullResultSet(
+                			s.executeQuery("select * from t2_6414"),
+                            new String[][]
+                            {
+                                { "1", "4", "ccc", "ccccc" },
+                                { "2", "5", "ccc", "ccccc" },
+                            }
+                    );                	
+                break;
+        }
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/Changes10_12.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/UpgradeRun.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/UpgradeRun.java?rev=1625884&r1=1625883&r2=1625884&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/UpgradeRun.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/upgradeTests/UpgradeRun.java Thu Sep 18 03:52:34 2014
@@ -193,6 +193,8 @@ class UpgradeRun extends UpgradeClassLoa
                 	suite.addTest(Changes10_10.suite(phase));
                 if (oldMinor < 11)
                     suite.addTest(Changes10_11.suite(phase));
+                if (oldMinor < 12)
+                    suite.addTest(Changes10_12.suite(phase));
             }
             
             // Add DatabaseMetaData tests. Since metadata



Mime
View raw message