db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From d..@apache.org
Subject svn commit: r1545394 [2/3] - in /db/derby/code/trunk/java: engine/org/apache/derby/catalog/ engine/org/apache/derby/catalog/types/ engine/org/apache/derby/iapi/sql/conn/ engine/org/apache/derby/iapi/sql/dictionary/ engine/org/apache/derby/iapi/store/ac...
Date Mon, 25 Nov 2013 20:30:46 GMT
Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicSortObserver.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicSortObserver.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicSortObserver.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/BasicSortObserver.java Mon Nov 25 20:30:45 2013
@@ -30,6 +30,7 @@ import org.apache.derby.iapi.sql.execute
 import org.apache.derby.iapi.types.DataValueDescriptor;
 
 import java.util.Vector;
+import org.apache.derby.shared.common.sanity.SanityManager;
 
 /**
  * This is the most basic sort observer.  It
@@ -172,4 +173,19 @@ public class BasicSortObserver implement
 
 		return newArray;
 	}
+
+    public boolean deferred() {
+        return false;
+    }
+
+    public boolean deferrable() {
+        return false;
+    }
+
+    public void rememberDuplicate(DataValueDescriptor[] row)
+            throws StandardException {
+        if (SanityManager.DEBUG) {
+            SanityManager.NOTREACHED();
+        }
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateConstraintConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateConstraintConstantAction.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateConstraintConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateConstraintConstantAction.java Mon Nov 25 20:30:45 2013
@@ -292,9 +292,12 @@ public class CreateConstraintConstantAct
 
         for (int i=0; i < characteristics.length; i++) {
             if (characteristics[i] != defaults[i]) {
+                dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_11,
+                                "DEFERRED CONSTRAINTS");
+
                 // Remove when feature DERBY-532 is completed
-                if (!PropertyUtil.getSystemProperty("derby.constraintsTesting",
-                        tableName).equals("true")) {
+                if (!PropertyUtil.getSystemProperty(
+                        "derby.constraintsTesting", "false").equals("true")) {
                     throw StandardException.newException(SQLState.NOT_IMPLEMENTED,
                             "non-default constraint characteristics");
                 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateIndexConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateIndexConstantAction.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateIndexConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/CreateIndexConstantAction.java Mon Nov 25 20:30:45 2013
@@ -22,14 +22,12 @@
 package org.apache.derby.impl.sql.execute;
 
 import java.util.Properties;
-
 import org.apache.derby.catalog.UUID;
 import org.apache.derby.catalog.types.StatisticsImpl;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.services.io.FormatableBitSet;
 import org.apache.derby.iapi.services.loader.ClassFactory;
-import org.apache.derby.shared.common.sanity.SanityManager;
 import org.apache.derby.iapi.sql.Activation;
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
 import org.apache.derby.iapi.sql.depend.DependencyManager;
@@ -59,9 +57,8 @@ import org.apache.derby.iapi.types.DataT
 import org.apache.derby.iapi.types.DataValueDescriptor;
 import org.apache.derby.iapi.types.RowLocation;
 import org.apache.derby.iapi.types.TypeId;
-
-// Used only to access a debug flag, will be removed or replaced.
 import org.apache.derby.impl.services.daemon.IndexStatisticsDaemonImpl;
+import org.apache.derby.shared.common.sanity.SanityManager;
 
 /**
  * ConstantAction to create an index either through
@@ -80,6 +77,29 @@ class CreateIndexConstantAction extends 
 
 	private boolean			unique;
 	private boolean			uniqueWithDuplicateNulls;
+
+    /**
+     * The index represents a PRIMARY KEY or a UNIQUE NOT NULL constraint which
+     * is deferrable.
+     * {@code true} implies {@code unique == false} and
+     * {@code uniqueWithDuplicateNulls == false} and
+     * {@code hasDeferrableChecking == true}.
+     */
+    private boolean         uniqueDeferrable;
+
+    /**
+     * The index duplicate checking is deferrable. {@code true} implies {@code
+     * unique == false} and {@code (uniqueDeferrable ||
+     * uniqueWithDuplicateNulls)}.
+     *
+     */
+    private final boolean   hasDeferrableChecking;
+
+    /**
+     * Used to determine sorting behavior for existing rows if any
+     */
+    private final boolean   initiallyDeferred;
+
 	private String			indexType;
 	private String[]		columnNames;
 	private boolean[]		isAscending;
@@ -123,6 +143,12 @@ class CreateIndexConstantAction extends 
      *                                      column in the key has a null value,
      *                                      no checking is done and insert will
      *                                      always succeed.
+     * @param hasDeferrableChecking         True means this index backs a
+     *                                      deferrable constraint. isConstraint
+     *                                      will be true.
+     * @param initiallyDeferred             True means the index represents
+     *                                      a deferred constraint. Implies
+     *                                      hasDeferrableChecking.
      * @param indexType	                    type of index (BTREE, for example)
      * @param schemaName	                schema that table (and index) 
      *                                      lives in.
@@ -143,6 +169,8 @@ class CreateIndexConstantAction extends 
             boolean         forCreateTable,
             boolean			unique,
             boolean			uniqueWithDuplicateNulls,
+            boolean         hasDeferrableChecking,
+            boolean         initiallyDeferred,
             String			indexType,
             String			schemaName,
             String			indexName,
@@ -157,8 +185,11 @@ class CreateIndexConstantAction extends 
 		super(tableId, indexName, tableName, schemaName);
 
         this.forCreateTable             = forCreateTable;
-		this.unique                     = unique;
+        this.unique                     = unique && !hasDeferrableChecking;
 		this.uniqueWithDuplicateNulls   = uniqueWithDuplicateNulls;
+        this.hasDeferrableChecking      = hasDeferrableChecking;
+        this.initiallyDeferred          = initiallyDeferred;
+        this.uniqueDeferrable           = unique && hasDeferrableChecking;
 		this.indexType                  = indexType;
 		this.columnNames                = columnNames;
 		this.isAscending                = isAscending;
@@ -209,6 +240,9 @@ class CreateIndexConstantAction extends 
 		IndexRowGenerator irg = srcCD.getIndexDescriptor();
 		this.unique = irg.isUnique();
 		this.uniqueWithDuplicateNulls = irg.isUniqueWithDuplicateNulls();
+        this.hasDeferrableChecking = false; // N/A such indexes are not shared
+        this.uniqueDeferrable = false;      // N/A
+        this.initiallyDeferred = false;     // N/A
 		this.indexType = irg.indexType();
 		this.columnNames = srcCD.getColumnNames();
 		this.isAscending = irg.isAscending();
@@ -410,6 +444,11 @@ class CreateIndexConstantAction extends 
 		 * If so, we will use a single physical conglomerate--namely, the
 		 * one that already exists--to support both indexes. I.e. we will
 		 * *not* create a new conglomerate as part of this constant action.
+         *
+         * Deferrable constraints are backed by indexes that are *not* shared
+         * since they use physically non-unique indexes and as such are
+         * different from indexes used to represent non-deferrable
+         * constraints.
 		 */ 
 
 		// check if we have similar indices already for this table
@@ -453,9 +492,13 @@ class CreateIndexConstantAction extends 
 			 *       set to TRUE and the index being created is non-unique, OR
 			 *    c) both the existing index and the one being created are
 			 *       non-unique and have uniqueWithDuplicateNulls set to FALSE.
-			 */ 
-			boolean possibleShare = (irg.isUnique() || !unique) &&
-			    (bcps.length == baseColumnPositions.length);
+             *
+             * 4. hasDeferrableChecking is FALSE.
+             */
+            boolean possibleShare =
+                    (irg.isUnique() || !unique) &&
+                    (bcps.length == baseColumnPositions.length) &&
+                    !hasDeferrableChecking;
 
 			//check if existing index is non unique and uniqueWithDuplicateNulls
 			//is set to true (backing index for unique constraint)
@@ -517,6 +560,8 @@ class CreateIndexConstantAction extends 
 				indexRowGenerator =
 					new IndexRowGenerator(
 						indexType, unique, uniqueWithDuplicateNulls,
+                        false, // uniqueDeferrable
+                        false, // deferrable indexes are not shared
 						baseColumnPositions,
 						isAscending,
 						baseColumnPositions.length);
@@ -577,7 +622,7 @@ class CreateIndexConstantAction extends 
 		indexProperties.put("baseConglomerateId",
 							Long.toString(td.getHeapConglomerateId()));
         
-		if (uniqueWithDuplicateNulls) 
+        if (uniqueWithDuplicateNulls && !hasDeferrableChecking)
         {
             if (dd.checkVersion(DataDictionary.DD_VERSION_DERBY_10_4, null))
             {
@@ -619,6 +664,8 @@ class CreateIndexConstantAction extends 
                                             indexType, 
                                             unique, 
                                             uniqueWithDuplicateNulls,
+                                            uniqueDeferrable,
+                                            hasDeferrableChecking,
                                             baseColumnPositions,
                                             isAscending,
                                             baseColumnPositions.length);
@@ -628,6 +675,9 @@ class CreateIndexConstantAction extends 
 				indexRowGenerator = new IndexRowGenerator(
                                             indexType, 
                                             unique,
+                                            false,
+                                            false,
+                                            false,
                                             baseColumnPositions,
                                             isAscending,
                                             baseColumnPositions.length);
@@ -753,7 +803,7 @@ class CreateIndexConstantAction extends 
 			int             numColumnOrderings;
             SortObserver    sortObserver;
             Properties      sortProperties = null;
-			if (unique || uniqueWithDuplicateNulls)
+            if (unique || uniqueWithDuplicateNulls || uniqueDeferrable)
 			{
 				// if the index is a constraint, use constraintname in 
                 // possible error message
@@ -771,14 +821,19 @@ class CreateIndexConstantAction extends 
 					}
 				}
 
-				if (unique) 
+                if (unique || uniqueDeferrable)
 				{
-                    numColumnOrderings = baseColumnPositions.length;
+                    numColumnOrderings = unique ? baseColumnPositions.length :
+                            baseColumnPositions.length + 1;
 
 					sortObserver = 
                         new UniqueIndexSortObserver(
+                                tc,
+                                lcc,
+                                DeferredDuplicates.UNDEFINED_CONGLOMERATE,
                                 true, 
-                                isConstraint, 
+                                uniqueDeferrable,
+                                initiallyDeferred,
                                 indexOrConstraintName,
                                 indexTemplateRow,
                                 true,
@@ -799,8 +854,12 @@ class CreateIndexConstantAction extends 
 					//use sort operator which treats nulls unequal
 					sortObserver = 
                         new UniqueWithDuplicateNullsIndexSortObserver(
+                                tc,
+                                lcc,
+                                DeferredDuplicates.UNDEFINED_CONGLOMERATE,
                                 true, 
-                                isConstraint, 
+                                hasDeferrableChecking,
+                                initiallyDeferred,
                                 indexOrConstraintName,
                                 indexTemplateRow,
                                 true,
@@ -854,7 +913,11 @@ class CreateIndexConstantAction extends 
 					TransactionController.IS_DEFAULT, // not temporary
 					rowSource,
 					(long[]) null);
-			
+
+            if (initiallyDeferred) {
+                DeferredDuplicates.associateDuplicatesWithConglomerate(
+                    lcc, conglomId);
+            }
 		}
 		finally
 		{

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLSingleTableConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLSingleTableConstantAction.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLSingleTableConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DDLSingleTableConstantAction.java Mon Nov 25 20:30:45 2013
@@ -306,6 +306,10 @@ abstract class DDLSingleTableConstantAct
                         false,          // not part of create table 
                         false,          // not unique
                         true,           // create as unique when not null index
+                        cd.getIndexDescriptor().hasDeferrableChecking(),
+                        false,          // deferred or not: shouldn't matter
+                                        // since we know we already have a
+                                        // unique index
                         cd.getIndexDescriptor().indexType(), 
                         td.getSchemaName(), 
                         cd.getConglomerateName(), td.getName(), td.getUUID(),

Added: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeferredDuplicates.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeferredDuplicates.java?rev=1545394&view=auto
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeferredDuplicates.java (added)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/DeferredDuplicates.java Mon Nov 25 20:30:45 2013
@@ -0,0 +1,248 @@
+/*
+
+   Derby - Class org.apache.derby.impl.sql.execute.DeferredDuplicates
+
+   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.Enumeration;
+import java.util.HashMap;
+import org.apache.derby.iapi.error.StandardException;
+import org.apache.derby.iapi.services.io.FormatableBitSet;
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
+import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
+import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
+import org.apache.derby.iapi.sql.dictionary.DataDictionary;
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
+import org.apache.derby.iapi.store.access.BackingStoreHashtable;
+import org.apache.derby.iapi.store.access.ScanController;
+import org.apache.derby.iapi.store.access.TransactionController;
+import org.apache.derby.iapi.types.DataValueDescriptor;
+import org.apache.derby.shared.common.reference.SQLState;
+
+public class DeferredDuplicates
+{
+    /**
+     * Sometimes we need to save duplicate rows before we know the id
+     * of the constraint index, so we assign the duplicates row a
+     * temporary constraint id (UNDEFINED_CONGLOMERATE) and fix it up
+     * later, see associateDuplicatesWithConglomerate.
+     */
+    public final static long UNDEFINED_CONGLOMERATE = -1;
+
+    /**
+     * Save the contents of an constraint supporting index row in a
+     * hash table (which may spill to disk) for later checking,
+     * typically on transaction commit, or upon request.
+     *
+     * @param tc        the transaction controller
+     * @param indexCID  the identity of the index conglomerate which supports
+     *                  the deferred constraint
+     * @param deferredRowsHashTable
+     *                  client cached value
+     * @param lcc       the language connection context
+     * @param insertRow the duplicate row to be saved in the hash table
+     *                  for later checking
+     * @return the hash table (for caching by client to minimize lookups)
+     * @throws StandardException standard error policy
+     */
+    public static BackingStoreHashtable rememberDuplicate(
+            TransactionController tc,
+            long indexCID,
+            BackingStoreHashtable deferredRowsHashTable,
+            LanguageConnectionContext lcc,
+            DataValueDescriptor[] insertRow) throws StandardException {
+
+        // Don't copy the RowLocation, we don't need it:
+        final int keyLength = insertRow.length -1 ;
+
+        if (deferredRowsHashTable == null) {
+            // Use the backing hashtable for this index's deferred rows
+            // by checking the transaction's map of such backing hash
+            // tables (one per index conglomerate).  Use it if it
+            // exists, else make a new one.
+
+            final HashMap<Long, BackingStoreHashtable> hashTables =
+                    lcc.getDeferredHashTables();
+            deferredRowsHashTable =
+                    hashTables.get(Long.valueOf(indexCID));
+
+            if (deferredRowsHashTable == null) {
+                deferredRowsHashTable = makeHashTable(tc, keyLength);
+                hashTables.put(
+                        Long.valueOf(indexCID),
+                        deferredRowsHashTable);
+            }
+        }
+
+        DataValueDescriptor[] hashRowArray = new DataValueDescriptor[keyLength];
+        System.arraycopy(insertRow, 0, hashRowArray, 0, keyLength);
+        deferredRowsHashTable.putRow(true, hashRowArray, null);
+
+        return deferredRowsHashTable;
+    }
+
+    /**
+     * See javadoc for {@link #UNDEFINED_CONGLOMERATE}.
+     *
+     * @param lcc language connection context
+     * @param indexCID the id of the index conglomerate supporting the
+     *                 deferred constraint
+     */
+    public static void associateDuplicatesWithConglomerate(
+            LanguageConnectionContext lcc,
+            long indexCID) {
+
+        final HashMap<Long, BackingStoreHashtable> hashTables =
+                    lcc.getDeferredHashTables();
+
+        if (hashTables == null) {
+            return; // no duplicates recorded in this transaction
+        }
+
+        BackingStoreHashtable ht = hashTables.remove(
+                Long.valueOf(UNDEFINED_CONGLOMERATE));
+
+        if (ht != null) {
+            hashTables.put(indexCID, ht);
+        } // else no duplicates recorded for this index
+    }
+
+    /**
+     * The information for deferred rows needs updating if the underlying
+     * index is rebuilt, for example on bulk insert for import.
+     * @param lcc the language connection context needed to find the
+     *            deferred rows information if any
+     * @param oldIndexCID the old id of the supporting index
+     * @param newIndexCID the new id of the supporting index after recreation
+     */
+    public static void updateIndexCID(
+            LanguageConnectionContext lcc,
+            long oldIndexCID,
+            long newIndexCID) {
+        final HashMap<Long, BackingStoreHashtable> hashTables =
+                    lcc.getDeferredHashTables();
+
+        if (hashTables == null) {
+            return; // no duplicates recorded in this transaction
+        }
+
+        BackingStoreHashtable ht = hashTables.remove(
+                Long.valueOf(oldIndexCID));
+
+        if (ht != null) {
+            hashTables.put(Long.valueOf(newIndexCID), ht);
+        }
+    }
+
+    private static BackingStoreHashtable makeHashTable(
+            TransactionController tc,
+            int cols) throws StandardException {
+
+        // key: all columns (these are index rows)
+        int[] keyCols = new int[cols];
+
+        for (int i = 0; i < cols; i++) {
+            keyCols[i] = i;
+        }
+
+        return new BackingStoreHashtable(
+                tc,
+                null,
+                keyCols,
+                true, // remove duplicates: no need for more copies:
+                      // one is enough to know what to look for on commit
+                -1,
+                HashScanResultSet.DEFAULT_MAX_CAPACITY,
+                HashScanResultSet.DEFAULT_INITIAL_CAPACITY,
+                HashScanResultSet.DEFAULT_MAX_CAPACITY,
+                false,
+                false);
+    }
+
+    public static void validate(TransactionController tc,
+                                long indexCID,
+                                LanguageConnectionContext lcc,
+                                BackingStoreHashtable ht,
+                                boolean rollbackOnError)
+            throws StandardException {
+
+        Enumeration e = ht.elements();
+        while (e.hasMoreElements()) {
+            DataValueDescriptor[] key = (DataValueDescriptor[])e.nextElement();
+            // FIXME: This is not very efficient: we could sort the rows in the
+            // hash table, and then check all rows using a single scan.
+            ScanController indexSC = null;
+            boolean sawException = false;
+
+            try {
+                indexSC = tc.openScan(
+                    indexCID,
+                    false,
+                    0, // read only
+                    TransactionController.MODE_RECORD,
+                    TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK,
+                    (FormatableBitSet)null, // retrieve all fields
+                    key,
+                    ScanController.GE, // startSearchOp
+                    null,
+                    key,
+                    ScanController.GT);
+
+                if (indexSC.next()) {
+                    if (indexSC.next()) {
+                        // two matching rows found, constraint violated
+                        final DataDictionary dd = lcc.getDataDictionary();
+                        final ConglomerateDescriptor cd =
+                                dd.getConglomerateDescriptor(indexCID);
+                        final TableDescriptor td =
+                                dd.getTableDescriptor(cd.getTableID());
+                        final ConstraintDescriptor conDesc =
+                                dd.getConstraintDescriptor(td, cd.getUUID());
+
+                        throw StandardException.newException(
+                            rollbackOnError ?
+                                SQLState.LANG_DEFERRED_DUPLICATE_KEY_CONSTRAINT_T :
+                                SQLState.LANG_DEFERRED_DUPLICATE_KEY_CONSTRAINT_S,
+                            conDesc.getConstraintName(),
+                            td.getName());
+                    } // else exactly one row contains key: OK
+                } else {
+                    // No rows contain key: OK, must have been deleted later
+                    // in transaction, or we got here due to pessimistic
+                    // assumption on a timeout while checking on the insert.
+                }
+            } catch (StandardException se) {
+                sawException = true;
+                throw se;
+            } finally {
+                // Clean up resource usage
+                try {
+                    if (indexSC != null) {
+                        indexSC.close();
+                    }
+                } catch (StandardException ie) {
+                    if (!sawException) {
+                        throw ie;
+                    } // else: can't let it shadow preceding exception
+                }
+            }
+        }
+    }
+}

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/ForeignKeyRIChecker.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/ForeignKeyRIChecker.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/ForeignKeyRIChecker.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/ForeignKeyRIChecker.java Mon Nov 25 20:30:45 2013
@@ -116,7 +116,7 @@ public class ForeignKeyRIChecker extends
 	 * the RI check.
 	 *
 	 * NOTE: The level will eventually be instantaneous
-	 * locking once the implemenation changes.
+     * locking once the implementation changes.
 	 *
 	 * @return The isolation level for the scan for
 	 * the RI check.

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=1545394&r1=1545393&r2=1545394&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 25 20:30:45 2013
@@ -226,6 +226,10 @@ public class GenericConstantActionFactor
      *                                  column in the key has a null value,
      *                                  no checking is done and insert will
      *                                  always succeed.
+     * @param hasDeferrableChecking True if the index is used to back a
+     *                              deferrable constraint
+     * @param initiallyDeferred  True means the deferrable constraint has
+     *                           deferred mode initially.
      * @param indexType	The type of index (BTREE, for example)
      * @param schemaName			the schema that table (and index) lives in.
      * @param indexName	Name of the index
@@ -242,6 +246,8 @@ public class GenericConstantActionFactor
         boolean forCreateTable,
 		boolean			unique,
 		boolean			uniqueWithDuplicateNulls,
+        boolean         hasDeferrableChecking,
+        boolean         initiallyDeferred,
 		String			indexType,
 		String			schemaName,
 		String			indexName,
@@ -254,11 +260,22 @@ public class GenericConstantActionFactor
 		Properties		properties
     )
 	{
-		return	new CreateIndexConstantAction
-			( forCreateTable, unique, uniqueWithDuplicateNulls, indexType, 
-				schemaName, indexName, tableName, tableId,
-			  columnNames, isAscending, isConstraint,
-			  conglomerateUUID, properties );
+        return new CreateIndexConstantAction(
+            forCreateTable,
+            unique,
+            uniqueWithDuplicateNulls,
+            hasDeferrableChecking,
+            initiallyDeferred,
+            indexType,
+            schemaName,
+            indexName,
+            tableName,
+            tableId,
+            columnNames,
+            isAscending,
+            isConstraint,
+            conglomerateUUID,
+            properties);
 	}
 
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericRIChecker.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericRIChecker.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericRIChecker.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/GenericRIChecker.java Mon Nov 25 20:30:45 2013
@@ -21,17 +21,10 @@
 
 package org.apache.derby.impl.sql.execute;
 
-import org.apache.derby.shared.common.sanity.SanityManager;
 import org.apache.derby.iapi.error.StandardException;
 
 import org.apache.derby.iapi.types.DataValueDescriptor;
-import org.apache.derby.iapi.types.RowLocation;
-import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
-import org.apache.derby.iapi.sql.dictionary.ConglomerateDescriptor;
 import org.apache.derby.iapi.sql.execute.ExecRow;
-import org.apache.derby.iapi.sql.execute.ExecIndexRow;
-
-import org.apache.derby.iapi.store.access.ConglomerateController;
 import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
 import org.apache.derby.iapi.store.access.ScanController;
 import org.apache.derby.iapi.store.access.StaticCompiledOpenConglomInfo;
@@ -105,7 +98,7 @@ public abstract class GenericRIChecker
 	 * The scan is set up to return no columns.
 	 * NOTE: We only need an instantaneous lock on the
 	 * table that we are probing as we are just checking
-	 * for the existance of a row.  All updaters, whether
+     * for the existence of a row.  All updaters, whether
 	 * to the primary or foreign key tables, will hold an
 	 * X lock on the table that they are updating and will
 	 * be probing the other table, so instantaneous locks
@@ -118,7 +111,10 @@ public abstract class GenericRIChecker
 	 *
 	 * @param conglomNumber		the particular conglomerate we 
 	 *							are interested in
+     * @param scoci
+     * @param dcoci
 	 * @param searchRow			the row to match
+     * @return                  scan controller
 	 *
 	 * @exception StandardException on error
 	 */
@@ -236,7 +232,7 @@ public abstract class GenericRIChecker
 	 * the RI check.
 	 *
 	 * NOTE: The level will eventually be instantaneous
-	 * locking once the implemenation changes.
+     * locking once the implementation changes.
 	 *
 	 * @return The isolation level for the scan for
 	 * the RI check.

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/IndexChanger.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/IndexChanger.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/IndexChanger.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/IndexChanger.java Mon Nov 25 20:30:45 2013
@@ -21,15 +21,14 @@
 
 package org.apache.derby.impl.sql.execute;
 
+import java.sql.SQLException;
 import java.util.Properties;
-
 import org.apache.derby.catalog.UUID;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
 import org.apache.derby.iapi.services.i18n.MessageService;
 import org.apache.derby.iapi.services.io.FormatableBitSet;
 import org.apache.derby.iapi.services.monitor.Monitor;
-import org.apache.derby.shared.common.sanity.SanityManager;
 import org.apache.derby.iapi.sql.Activation;
 import org.apache.derby.iapi.sql.ResultDescription;
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
@@ -41,6 +40,7 @@ import org.apache.derby.iapi.sql.diction
 import org.apache.derby.iapi.sql.execute.CursorResultSet;
 import org.apache.derby.iapi.sql.execute.ExecIndexRow;
 import org.apache.derby.iapi.sql.execute.ExecRow;
+import org.apache.derby.iapi.store.access.BackingStoreHashtable;
 import org.apache.derby.iapi.store.access.ConglomerateController;
 import org.apache.derby.iapi.store.access.DynamicCompiledOpenConglomInfo;
 import org.apache.derby.iapi.store.access.ScanController;
@@ -48,22 +48,23 @@ import org.apache.derby.iapi.store.acces
 import org.apache.derby.iapi.store.access.TransactionController;
 import org.apache.derby.iapi.types.DataValueDescriptor;
 import org.apache.derby.iapi.types.RowLocation;
+import org.apache.derby.shared.common.sanity.SanityManager;
 
 /**
   Perform Index maintenance associated with DML operations for a single index.
   */
 class IndexChanger
 {
-	private IndexRowGenerator irg;
+    final private IndexRowGenerator irg;
 	//Index Conglomerate ID
-	private long indexCID;
-	private DynamicCompiledOpenConglomInfo indexDCOCI;
-	private StaticCompiledOpenConglomInfo indexSCOCI;
-	private String indexName;
+    final private long indexCID;
+    final private DynamicCompiledOpenConglomInfo indexDCOCI;
+    final private StaticCompiledOpenConglomInfo indexSCOCI;
+    final private String indexName;
 	private ConglomerateController baseCC;
-	private TransactionController tc;
-	private int lockMode;
-	private FormatableBitSet baseRowReadMap;
+    final private TransactionController tc;
+    final private int lockMode;
+    final private FormatableBitSet baseRowReadMap;
 
 	private ConglomerateController indexCC = null;
 	private ScanController indexSC = null;
@@ -79,7 +80,11 @@ class IndexChanger
 	private final Activation				activation;
 	private boolean					ownIndexSC = true;
 
-	/**
+    private final boolean deferrable; // supports a deferrable constraint
+    private final LanguageConnectionContext lcc;
+    private BackingStoreHashtable deferredRowsHashTable; // cached for speed
+
+    /**
 	  Create an IndexChanger
 
 	  @param irg the IndexRowGenerator for the index.
@@ -112,6 +117,8 @@ class IndexChanger
 		 throws StandardException
 	{
 		this.irg = irg;
+        this.deferrable = irg.hasDeferrableChecking(); // cache value
+                                                       // for speed..
 		this.indexCID = indexCID;
 		this.indexSCOCI = indexSCOCI;
 		this.indexDCOCI = indexDCOCI;
@@ -124,8 +131,11 @@ class IndexChanger
 		this.activation = activation;
 		this.indexName = indexName;
 
-		// activation will be null when called from DataDictionary
-		if (activation != null && activation.getIndexConglomerateNumber() == indexCID)
+        this.lcc = (activation != null) ?
+                activation.getLanguageConnectionContext() : null;
+        // activation will be null when called from DataDictionary
+        if (activation != null &&
+                activation.getIndexConglomerateNumber() == indexCID)
 		{
 			ownIndexSC = false;
 		}
@@ -134,10 +144,9 @@ class IndexChanger
 		{
 			SanityManager.ASSERT(tc != null, 
 				"TransactionController argument to constructor is null");
-			SanityManager.ASSERT(irg != null, 
-				"IndexRowGenerator argument to constructor is null");
 		}
-	}
+
+    }
 
 	/**
 	 * Set the row holder for this changer to use.
@@ -430,16 +439,101 @@ class IndexChanger
 	 *
 	 * @param row	The row to insert
 	 *
-	 * @exception StandardException		Thrown on duplicate key error
+     * @exception StandardException     Thrown on duplicate key error unless
+     *                                  we have a deferred constraint. In that
+     *                                  index rows are saved for checking
+     *                                  on commit.
 	 */
 	private void insertAndCheckDups(ExecIndexRow row)
 				throws StandardException
 	{
 		openIndexCC();
 
-		int insertStatus = indexCC.insert(row.getRowArray());
+        int insertStatus;
+
+        final DataValueDescriptor[] rowArray = row.getRowArray();
+
+        if (deferrable) {
+            insertStatus = indexCC.insert(row.getRowArray());
+
+            if (SanityManager.DEBUG) { // deferrable: we use a non-unique index
+                SanityManager.ASSERT(
+                        insertStatus != ConglomerateController.ROWISDUPLICATE);
+            }
+
+            final DataValueDescriptor [] key =
+                    new DataValueDescriptor[rowArray.length - 1];
+            System.arraycopy(rowArray, 0, key, 0, key.length);
+            ScanController idxScan = tc.openScan(
+                    indexCID,
+                    false,
+                    0, // FIXME: want NO_WAIT but not yet implemented
+                       // for row locks in BTRee scan
+                    TransactionController.MODE_RECORD,
+                    TransactionController.ISOLATION_READ_COMMITTED_NOHOLDLOCK,
+                    (FormatableBitSet)null, // retrieve all fields
+                    key,
+                    ScanController.GE, // startSearchOp
+                    null,
+                    key,
+                    ScanController.GT);
+
+            boolean duplicate = false;
+
+            try {
+                final boolean foundOne = idxScan.next();
+
+                if (SanityManager.DEBUG) {
+                    SanityManager.ASSERT(
+                            foundOne, "IndexChanger: inserted row gone?");
+                }
+
+                duplicate = foundOne && idxScan.next();
+
+            } catch (StandardException e) {
+                if (e.getSQLState().equals(SQLState.LOCK_TIMEOUT) ||
+                    e.getSQLState().equals(SQLState.DEADLOCK)) {
+                    // Assume there is a duplicate, so we'll check again at
+                    // commit time.
+                    duplicate = true;
+                } else {
+                    throw e;
+                }
+            }
+
+            if (duplicate && irg.isUniqueWithDuplicateNulls()) {
+                int keyParts = rowArray.length - 1;
 
-		if (insertStatus == ConglomerateController.ROWISDUPLICATE)
+                for (int i = 0; i < keyParts; i++) {
+                    // Keys with null in it are always unique
+                    if (rowArray[i].isNull()) {
+                        duplicate = false;
+                        break;
+                    }
+                }
+            }
+
+            if (duplicate) {
+                if (lcc.isEffectivelyDeferred(activation, indexCID)) {
+                    // Save duplicate row so we can check at commit time there is
+                    // no longer any duplicate.
+
+                    deferredRowsHashTable = DeferredDuplicates.rememberDuplicate(
+                            tc,
+                            indexCID,
+                            deferredRowsHashTable,
+                            lcc,
+                            row.getRowArray());
+                } else { // the constraint is not deferred, so throw
+                    insertStatus = ConglomerateController.ROWISDUPLICATE;
+                }
+            }
+
+        } else { // not a deferred constraint
+            insertStatus = indexCC.insert(row.getRowArray());
+        }
+
+        if (insertStatus == ConglomerateController.ROWISDUPLICATE)
 		{
 			/*
 			** We have a duplicate key error. 
@@ -467,16 +561,14 @@ class IndexChanger
 				StandardException.newException(
 				SQLState.LANG_DUPLICATE_KEY_CONSTRAINT, indexOrConstraintName, tableName);
 			throw se;
-		}
-		if (SanityManager.DEBUG)
-		{
-			if (insertStatus != 0)
-			{
-				SanityManager.THROWASSERT("Unknown insert status " + insertStatus);
-			}
-		}
-	}
-
+        } else {
+            if (SanityManager.DEBUG) {
+                if (insertStatus != 0) {
+                    SanityManager.THROWASSERT("Unknown insert status " + insertStatus);
+                }
+            }
+        }
+    }
 
 	/**
 	 * Open the ConglomerateController for this index if it isn't open yet.
@@ -607,7 +699,9 @@ class IndexChanger
 	{
 		setOurIndexRow(newRow, baseRowLocation);
 		//defer inserts if its on unique or UniqueWhereNotNull index
-		if (irg.isUnique() || irg.isUniqueWithDuplicateNulls())
+        if (irg.isUnique() ||
+            irg.isUniqueWithDuplicateNulls() ||
+            irg.hasDeferrableChecking())
 		{
 			doDeferredInsert();
 		}

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=1545394&r1=1545393&r2=1545394&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 25 20:30:45 2013
@@ -50,6 +50,7 @@ import org.apache.derby.iapi.sql.diction
 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
 import org.apache.derby.iapi.sql.dictionary.DataDescriptorGenerator;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
+import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
 import org.apache.derby.iapi.sql.dictionary.StatisticsDescriptor;
 import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
 import org.apache.derby.iapi.sql.dictionary.TriggerDescriptor;
@@ -60,6 +61,7 @@ import org.apache.derby.iapi.sql.execute
 import org.apache.derby.iapi.sql.execute.NoPutResultSet;
 import org.apache.derby.iapi.sql.execute.RowChanger;
 import org.apache.derby.iapi.sql.execute.TargetResultSet;
+import org.apache.derby.iapi.store.access.AccessFactoryGlobals;
 import org.apache.derby.iapi.store.access.ColumnOrdering;
 import org.apache.derby.iapi.store.access.ConglomerateController;
 import org.apache.derby.iapi.store.access.GroupFetchScanController;
@@ -1447,6 +1449,9 @@ class InsertResultSet extends DMLWriteRe
 		// Update all indexes
 		if (constants.irgs.length > 0)
 		{
+//            MEN VI HAR MANGE SORTS, EN PR INDEX: alle blir droppet, hvordan
+//                    assossiere alle med nye indekser som tildeles inni her???
+//                            FIXME!!
 			updateAllIndexes(newHeapConglom, constants, td, dd, fullTemplate);
 		}
 
@@ -1815,30 +1820,70 @@ class InsertResultSet extends DMLWriteRe
 			 * wrapper that is still in use in another sort.
 			 */
 			boolean reuseWrappers = (numIndexes == 1);
-			if (cd.getIndexDescriptor().isUnique())
-			{
-				numColumnOrderings = baseColumnPositions.length;
-				String[] columnNames = getColumnNames(baseColumnPositions);
+            final IndexRowGenerator indDes = cd.getIndexDescriptor();
+            Properties sortProperties = null;
+            String indexOrConstraintName = cd.getConglomerateName();
+            boolean deferred = false;
+            boolean deferrable = false;
 
-				String indexOrConstraintName = cd.getConglomerateName();
-				if (cd.isConstraint()) 
-				{
-                    // so, the index is backing up a constraint
+            if (cd.isConstraint())
+            {
+                // so, the index is backing up a constraint
 
-					ConstraintDescriptor conDesc = 
+                ConstraintDescriptor conDesc =
                         dd.getConstraintDescriptor(td, cd.getUUID());
 
-					indexOrConstraintName = conDesc.getConstraintName();
-				}
+                indexOrConstraintName = conDesc.getConstraintName();
+                deferred = lcc.isEffectivelyDeferred(
+                        activation, cd.getConglomerateNumber());
+                deferrable = conDesc.deferrable();
+            }
+
+            if (indDes.isUnique() || indDes.isUniqueDeferrable())
+            {
+                numColumnOrderings =
+                        indDes.isUnique() ? baseColumnPositions.length :
+                        baseColumnPositions.length + 1;
+
+                String[] columnNames = getColumnNames(baseColumnPositions);
+
 				sortObserver = 
                     new UniqueIndexSortObserver(
+                            tc,
+                            lcc,
+                            cd.getConglomerateNumber(),
                             false, // don't clone rows
-                            cd.isConstraint(), 
+                            deferrable,
+                            deferred,
                             indexOrConstraintName,
                             indexRows[index],
                             reuseWrappers,
                             td.getName());
-			}
+            } else if (indDes.isUniqueWithDuplicateNulls())
+            {
+                numColumnOrderings = baseColumnPositions.length + 1;
+
+                // tell transaction controller to use the unique with
+                // duplicate nulls sorter, when making createSort() call.
+                sortProperties = new Properties();
+                sortProperties.put(
+                   AccessFactoryGlobals.IMPL_TYPE,
+                   AccessFactoryGlobals.SORT_UNIQUEWITHDUPLICATENULLS_EXTERNAL);
+                //use sort operator which treats nulls unequal
+                sortObserver =
+                        new UniqueWithDuplicateNullsIndexSortObserver(
+                        tc,
+                        lcc,
+                        cd.getConglomerateNumber(),
+                        true,
+                        deferrable,
+                        deferred,
+                        indexOrConstraintName,
+                        indexRows[index],
+                        true,
+                        td.getName());
+
+            }
 			else
 			{
 				numColumnOrderings = baseColumnPositions.length + 1;
@@ -1866,7 +1911,7 @@ class InsertResultSet extends DMLWriteRe
 			// create the sorters
 			sortIds[index] = 
                 tc.createSort(
-                    (Properties)null, 
+                    sortProperties,
                     indexRows[index].getRowArrayClone(),
                     ordering[index],
                     sortObserver,
@@ -1961,8 +2006,14 @@ class InsertResultSet extends DMLWriteRe
 			if(cd.getIndexDescriptor().isUniqueWithDuplicateNulls())
 			{
 				properties.put(
-	                    "uniqueWithDuplicateNulls", Boolean.toString(true));
+                    "uniqueWithDuplicateNulls", Boolean.toString(true));
 			}
+
+            if (cd.getIndexDescriptor().hasDeferrableChecking()) {
+                properties.put(
+                    "hasDeferrableChecking", Boolean.toString(true));
+            }
+
 			properties.put("rowLocationColumn", 
 							Integer.toString(indexRowLength - 1));
 			properties.put("nKeyFields", Integer.toString(indexRowLength));
@@ -2025,6 +2076,12 @@ class InsertResultSet extends DMLWriteRe
 			// Drop the old conglomerate
 			tc.dropConglomerate(constants.indexCIDS[index]);
 
+            // We recreated the index, so any old deferred constraints
+            // information supported by the dropped index needs to be updated
+            // with the new index.
+            DeferredDuplicates.updateIndexCID(
+                    lcc, constants.indexCIDS[index], newIndexCongloms[index]);
+
 			indexConversionTable.put(new Long(constants.indexCIDS[index]),
 									new Long(newIndexCongloms[index]));
 		}
@@ -2329,23 +2386,38 @@ class InsertResultSet extends DMLWriteRe
 			boolean[] isAscending = constants.irgs[index].isAscending();
 			int numColumnOrderings;
 			SortObserver sortObserver = null;
-			if (cd.getIndexDescriptor().isUnique())
+            final IndexRowGenerator indDes = cd.getIndexDescriptor();
+
+            if (indDes.isUnique() || indDes.isUniqueDeferrable())
 			{
-				numColumnOrderings = baseColumnPositions.length;
+                numColumnOrderings =
+                        indDes.isUnique() ? baseColumnPositions.length :
+                        baseColumnPositions.length + 1;
+
 				String[] columnNames = getColumnNames(baseColumnPositions);
 
 				String indexOrConstraintName = cd.getConglomerateName();
+                boolean deferred = false;
+                boolean uniqueDeferrable = false;
+
 				if (cd.isConstraint()) 
 				{
                     // so, the index is backing up a constraint
 					ConstraintDescriptor conDesc = 
                         dd.getConstraintDescriptor(td, cd.getUUID());
 					indexOrConstraintName = conDesc.getConstraintName();
+                    deferred = lcc.isEffectivelyDeferred(activation,
+                            cd.getConglomerateNumber());
+                    uniqueDeferrable = conDesc.deferrable();
 				}
 				sortObserver = 
                     new UniqueIndexSortObserver(
+                            tc,
+                            lcc,
+                            cd.getConglomerateNumber(),
                             false, // don't clone rows
-                            cd.isConstraint(), 
+                            uniqueDeferrable,
+                            deferred,
                             indexOrConstraintName,
                             indexRows[index],
                             true,
@@ -2439,9 +2511,15 @@ class InsertResultSet extends DMLWriteRe
 			if(cd.getIndexDescriptor().isUniqueWithDuplicateNulls())
 			{
 				properties.put(
-	                    "uniqueWithDuplicateNulls", Boolean.toString(true));
+                    "uniqueWithDuplicateNulls", Boolean.toString(true));
 			}
-			properties.put("rowLocationColumn", 
+
+            if (cd.getIndexDescriptor().hasDeferrableChecking()) {
+                properties.put(
+                    "hasDeferrableChecking", Boolean.toString(true));
+            }
+
+            properties.put("rowLocationColumn",
 							Integer.toString(indexRowLength - 1));
 			properties.put("nKeyFields", Integer.toString(indexRowLength));
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MaterializedResultSet.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MaterializedResultSet.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MaterializedResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/MaterializedResultSet.java Mon Nov 25 20:30:45 2013
@@ -253,7 +253,7 @@ class MaterializedResultSet extends NoPu
                         TransactionController.MODE_TABLE,
                         TransactionController.ISOLATION_SERIALIZABLE);
 			}
-			materializedCC.insert(sourceRow.getRowArray());
+            materializedCC.insert(sourceRow.getRowArray());
 
 			createTCTime += getElapsedMillis(beginTCTime);
 		}

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RIBulkChecker.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RIBulkChecker.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RIBulkChecker.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RIBulkChecker.java Mon Nov 25 20:30:45 2013
@@ -271,7 +271,7 @@ public class RIBulkChecker 
 		failedCounter++;
 		if (unreferencedCC != null)
 		{
-			unreferencedCC.insert(foreignKeyRow);
+            unreferencedCC.insert(foreignKeyRow);
 		}
 	}	
 	/*

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RowChangerImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RowChangerImpl.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RowChangerImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/RowChangerImpl.java Mon Nov 25 20:30:45 2013
@@ -454,7 +454,7 @@ class RowChangerImpl	implements	RowChang
 			}
 			else
 			{
-				baseCC.insert(baseRow.getRowArray());
+                baseCC.insert(baseRow.getRowArray());
 			}
 		}
 	}

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetConstraintsConstantAction.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetConstraintsConstantAction.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetConstraintsConstantAction.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/SetConstraintsConstantAction.java Mon Nov 25 20:30:45 2013
@@ -21,39 +21,23 @@
 
 package org.apache.derby.impl.sql.execute;
 
-import java.util.Enumeration;
-import java.util.Hashtable;
 import java.util.List;
 
-import org.apache.derby.catalog.UUID;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
-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.services.property.PropertyUtil;
 import org.apache.derby.iapi.sql.Activation;
 import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
-import org.apache.derby.iapi.sql.depend.DependencyManager;
-import org.apache.derby.iapi.sql.dictionary.CheckConstraintDescriptor;
 import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptor;
-import org.apache.derby.iapi.sql.dictionary.ConstraintDescriptorList;
 import org.apache.derby.iapi.sql.dictionary.DataDictionary;
-import org.apache.derby.iapi.sql.dictionary.ForeignKeyConstraintDescriptor;
-import org.apache.derby.iapi.sql.dictionary.IndexRowGenerator;
-import org.apache.derby.iapi.sql.dictionary.ReferencedKeyConstraintDescriptor;
+import org.apache.derby.iapi.sql.dictionary.KeyConstraintDescriptor;
 import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
-import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
 import org.apache.derby.iapi.sql.execute.ConstantAction;
-import org.apache.derby.iapi.sql.execute.ExecIndexRow;
-import org.apache.derby.iapi.sql.execute.ExecRow;
-import org.apache.derby.iapi.store.access.ConglomerateController;
-import org.apache.derby.iapi.store.access.TransactionController;
-import org.apache.derby.iapi.types.RowLocation;
 import org.apache.derby.impl.sql.compile.TableName;
 
 /**
  * This class describes actions that are performed for a
- * set constraint at Execution time.  
+ * set constraint at execution time.
  * <p>
  * Note that the dependency action we send is SET_CONSTRAINTS
  * rather than ALTER_TABLE.  We do this because we want
@@ -64,20 +48,20 @@ import org.apache.derby.impl.sql.compile
 class SetConstraintsConstantAction extends DDLConstantAction
 {
 
-    final private boolean   initiallyDeferred;
-    private List<TableName> constraints;
+    final private boolean   deferred;
+    final private List<TableName> constraints;
 
 
 	// CONSTRUCTORS
     /**
-     * @param constraints               List of constraints to set; null if all.
-     * @param initiallyDeferred         Encodes IMMEDIATE (false), DEFERRED (true)
+     * @param constraints      List of constraints to set; null if all.
+     * @param deferred         Encodes IMMEDIATE (false), DEFERRED (true)
      */
     SetConstraintsConstantAction(
             List<TableName>             constraints,
-            boolean                     initiallyDeferred) {
+            boolean                     deferred) {
         this.constraints = constraints;
-        this.initiallyDeferred = initiallyDeferred;
+        this.deferred = deferred;
 	}
 
     @Override
@@ -89,7 +73,7 @@ class SetConstraintsConstantAction exten
 	}
 
 	/**
-	 *	This is the guts of the Execution-time logic for DROP CONSTRAINT.
+     *  This is the guts of the Execution-time logic for SET CONSTRAINT.
 	 *
 	 *	@see ConstantAction#executeConstantAction
 	 *
@@ -102,7 +86,6 @@ class SetConstraintsConstantAction exten
                 activation.getLanguageConnectionContext();
 
         final DataDictionary dd = lcc.getDataDictionary();
-        ConstraintDescriptorList cl = new ConstraintDescriptorList();
 
         if (constraints != null) {
             for (TableName c : constraints) {
@@ -121,13 +104,44 @@ class SetConstraintsConstantAction exten
                             c.getFullSQLName());
                 }
 
-                cl.add(cd);
+                // Remove when feature DERBY-532 is completed
+                if (!PropertyUtil.getSystemProperty(
+                        "derby.constraintsTesting", "false").equals("true")) {
+                    throw StandardException.newException(
+                        SQLState.NOT_IMPLEMENTED, "SET CONSTRAINT");
+                }
+
+                if (deferred && !cd.deferrable()) {
+                    throw StandardException.newException(
+                            SQLState.LANG_SET_CONSTRAINT_NOT_DEFERRABLE,
+                            cd.getConstraintName());
+                }
+
+                if (cd instanceof KeyConstraintDescriptor) {
+                    // Unique, primary key and foreign key
+
+                    lcc.setDeferred(activation,
+                                    ((KeyConstraintDescriptor)cd).
+                                        getIndexConglomerateDescriptor(dd).
+                                        getConglomerateNumber(),
+                                    deferred);
+                } else {
+                    // Check constraints
+                    throw StandardException.newException(
+                            SQLState.NOT_IMPLEMENTED, "SET CONSTRAINT");
+                }
             }
         } else {
-            cl = dd.getConstraintDescriptors(null); // all
+            // Remove when feature DERBY-532 is completed
+            if (!PropertyUtil.getSystemProperty(
+                    "derby.constraintsTesting", "false").equals("true")) {
+                throw StandardException.newException(SQLState.NOT_IMPLEMENTED,
+                        "SET CONSTRAINT");
+            }
+
+            lcc.setDeferredAll(activation, deferred);
         }
 
-        throw StandardException.newException(SQLState.NOT_IMPLEMENTED,
-                       "SET CONSTRAINT");
+
     }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderImpl.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderImpl.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderImpl.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/TemporaryRowHolderImpl.java Mon Nov 25 20:30:45 2013
@@ -332,7 +332,7 @@ class TemporaryRowHolderImpl implements 
 
 		}else
 		{
-			status = cc.insert(inputRow.getRowArray());
+            status = cc.insert(inputRow.getRowArray());
 			if (isVirtualMemHeap)
 				state = STATE_INSERT;
 		}
@@ -400,7 +400,7 @@ class TemporaryRowHolderImpl implements 
 			uniqueIndexRow[1] = baseRowLocation;
 			// Insert the row into the secondary index.
 			int status;
-			if ((status = uniqueIndex_cc.insert(uniqueIndexRow))!= 0)
+            if ((status = uniqueIndex_cc.insert(uniqueIndexRow))!= 0)
 			{
 				if(status == ConglomerateController.ROWISDUPLICATE)
 				{
@@ -468,7 +468,7 @@ class TemporaryRowHolderImpl implements 
 		positionIndexRow[0] = position_sqllong;
 		positionIndexRow[1] = rl;
 		//insert the row location to position index
-		positionIndex_cc.insert(positionIndexRow);
+        positionIndex_cc.insert(positionIndexRow);
 	}
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UniqueIndexSortObserver.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UniqueIndexSortObserver.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UniqueIndexSortObserver.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UniqueIndexSortObserver.java Mon Nov 25 20:30:45 2013
@@ -21,16 +21,12 @@
 
 package org.apache.derby.impl.sql.execute;
 
-import org.apache.derby.iapi.reference.SQLState;
-
-import org.apache.derby.iapi.services.io.Storable;
-
 import org.apache.derby.iapi.error.StandardException;
-
-import org.apache.derby.iapi.store.access.SortObserver;
-
+import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
 import org.apache.derby.iapi.sql.execute.ExecRow;
-
+import org.apache.derby.iapi.store.access.BackingStoreHashtable;
+import org.apache.derby.iapi.store.access.TransactionController;
 import org.apache.derby.iapi.types.DataValueDescriptor;
 
 /**
@@ -40,29 +36,38 @@ import org.apache.derby.iapi.types.DataV
  */
 class UniqueIndexSortObserver extends BasicSortObserver 
 {
-	private boolean		isConstraint;
-	private String		indexOrConstraintName;
-	private String 		tableName;
-
-	public UniqueIndexSortObserver(boolean doClone, boolean isConstraint, 
-				String indexOrConstraintName, ExecRow execRow, 
-				boolean reuseWrappers, String tableName)
+    private final boolean                   deferrable;
+    private final boolean                   deferred;
+    private final String                    indexOrConstraintName;
+    private final String                    tableName;
+    private final TransactionController     tc;
+    private final LanguageConnectionContext lcc;
+    private final long                      indexCID;
+    private BackingStoreHashtable           deferredRowsHashTable;
+
+    public UniqueIndexSortObserver(
+            TransactionController tc,
+            LanguageConnectionContext lcc,
+            long indexCID,
+            boolean doClone,
+            boolean deferrable,
+            boolean deferred,
+            String indexOrConstraintName,
+            ExecRow execRow,
+            boolean reuseWrappers,
+            String tableName)
 	{
-		super(doClone, true, execRow, reuseWrappers);
-		this.isConstraint = isConstraint;
+        super(doClone, !deferred, execRow, reuseWrappers);
+        this.tc = tc;
+        this.lcc = lcc;
+        this.indexCID = indexCID;
+        this.deferrable = deferrable;
+        this.deferred = deferred;
 		this.indexOrConstraintName = indexOrConstraintName;
 		this.tableName = tableName;
 	}
 
-	/*
-	 * Overridden from BasicSortObserver
-	 */
-
-	/**
-	 * @see AggregateSortObserver#insertDuplicateKey
-	 *
-	 * @exception StandardException		Thrown on failure
-	 */
+    @Override
 	public DataValueDescriptor[] insertDuplicateKey(
     DataValueDescriptor[]   in, 
     DataValueDescriptor[]   dup)
@@ -74,4 +79,25 @@ class UniqueIndexSortObserver extends Ba
 		throw se;
 	}
 
+    @Override
+    public boolean deferred() {
+        return deferred;
+    }
+
+    @Override
+    public boolean deferrable() {
+        return deferrable;
+    }
+
+    @Override
+    public void rememberDuplicate(DataValueDescriptor[] row)
+            throws StandardException {
+        deferredRowsHashTable = DeferredDuplicates.rememberDuplicate(
+                    tc,
+                    indexCID,
+                    deferredRowsHashTable,
+                    lcc,
+                    row);
+    }
+
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UniqueWithDuplicateNullsIndexSortObserver.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UniqueWithDuplicateNullsIndexSortObserver.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UniqueWithDuplicateNullsIndexSortObserver.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/execute/UniqueWithDuplicateNullsIndexSortObserver.java Mon Nov 25 20:30:45 2013
@@ -22,7 +22,10 @@ package org.apache.derby.impl.sql.execut
 
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
+import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
 import org.apache.derby.iapi.sql.execute.ExecRow;
+import org.apache.derby.iapi.store.access.BackingStoreHashtable;
+import org.apache.derby.iapi.store.access.TransactionController;
 import org.apache.derby.iapi.types.DataValueDescriptor;
 
 /**
@@ -33,33 +36,47 @@ import org.apache.derby.iapi.types.DataV
  */
 public class UniqueWithDuplicateNullsIndexSortObserver extends BasicSortObserver {
     
-    private boolean		isConstraint;
-    private String		indexOrConstraintName;
-    private String 		tableName;
-    
+    private final String                    indexOrConstraintName;
+    private final String                    tableName;
+    private final boolean                   deferrable;
+    private final boolean                   deferred;
+    private final TransactionController     tc;
+    private final LanguageConnectionContext lcc;
+    private final long                      indexCID;
+    private BackingStoreHashtable           deferredRowsHashTable;
     /**
      * Constructs an object of UniqueWithDuplicateNullsIndexSortObserver
      * 
-     * 
-     * 
+     * @param tc      Transaction controller
+     * @param lcc     Language Connection context
+     * @param indexCID Conglomerate id if the index
      * @param doClone If true, then rows that are retained
      * 		by the sorter will be cloned.  This is needed
      * 		if language is reusing row wrappers.
-     * @param isConstraint is this part of a constraint
+     * @param deferrable deferrable constraint
+     * @param deferred constraint mode is deferred
      * @param indexOrConstraintName name of index of constraint
      * @param execRow	ExecRow to use as source of clone for store.
      * @param reuseWrappers	Whether or not we can reuse the wrappers
      * @param tableName name of the table
      */
     public UniqueWithDuplicateNullsIndexSortObserver(
-    boolean doClone, 
-    boolean isConstraint,
-    String  indexOrConstraintName, 
-    ExecRow execRow,
-    boolean reuseWrappers, 
-    String  tableName) {
+            TransactionController tc,
+            LanguageConnectionContext lcc,
+            long indexCID,
+            boolean doClone,
+            boolean deferrable,
+            boolean deferred,
+            String  indexOrConstraintName,
+            ExecRow execRow,
+            boolean reuseWrappers,
+            String  tableName) {
         super(doClone, false, execRow, reuseWrappers);
-        this.isConstraint = isConstraint;
+        this.tc = tc;
+        this.lcc = lcc;
+        this.indexCID = indexCID;
+        this.deferrable = deferrable;
+        this.deferred = deferred;
         this.indexOrConstraintName = indexOrConstraintName;
         this.tableName = tableName;
     }
@@ -70,9 +87,10 @@ public class UniqueWithDuplicateNullsInd
      * @param in new key
      * @param dup the new key is duplicate of this key
      * @return DVD [] if there is at least one null in
-     * the key else thorws StandardException
+     * the key else throws StandardException
      * @throws StandardException is the duplicate key has all non null parts
      */
+    @Override
     public DataValueDescriptor[] insertDuplicateKey(DataValueDescriptor[] in,
             DataValueDescriptor[] dup) throws StandardException {
         for (int i = 0; i < in.length; i++) {
@@ -86,4 +104,26 @@ public class UniqueWithDuplicateNullsInd
                 indexOrConstraintName, tableName);
         throw se;
     }
+
+    @Override
+    public boolean deferred() {
+        return deferred;
+    }
+
+    @Override
+    public boolean deferrable() {
+        return deferrable;
+    }
+
+    @Override
+    public void rememberDuplicate(DataValueDescriptor[] row)
+            throws StandardException {
+        deferredRowsHashTable = DeferredDuplicates.rememberDuplicate(
+                    tc,
+                    indexCID,
+                    deferredRowsHashTable,
+                    lcc,
+                    row);
+    }
+
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/sort/MergeSort.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/sort/MergeSort.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/sort/MergeSort.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/sort/MergeSort.java Mon Nov 25 20:30:45 2013
@@ -21,34 +21,26 @@
 
 package org.apache.derby.impl.store.access.sort;
 
+import java.util.Enumeration;
+import java.util.Properties;
+import java.util.Vector;
+import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.reference.SQLState;
-
 import org.apache.derby.iapi.services.io.FormatableBitSet;
-
-import org.apache.derby.shared.common.sanity.SanityManager;
-import org.apache.derby.iapi.error.StandardException;
-import org.apache.derby.iapi.store.access.conglomerate.ScanControllerRowSource;
-import org.apache.derby.iapi.store.access.conglomerate.ScanManager;
-import org.apache.derby.iapi.store.access.conglomerate.Sort;
-import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
 import org.apache.derby.iapi.store.access.ColumnOrdering;
 import org.apache.derby.iapi.store.access.RowUtil;
-import org.apache.derby.iapi.store.access.ScanController;
-import org.apache.derby.iapi.store.access.SortObserver;
 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.store.raw.StreamContainerHandle;
+import org.apache.derby.iapi.store.access.conglomerate.ScanControllerRowSource;
+import org.apache.derby.iapi.store.access.conglomerate.ScanManager;
+import org.apache.derby.iapi.store.access.conglomerate.Sort;
+import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
 import org.apache.derby.iapi.store.raw.RawStoreFactory;
+import org.apache.derby.iapi.store.raw.StreamContainerHandle;
 import org.apache.derby.iapi.store.raw.Transaction;
-
 import org.apache.derby.iapi.types.DataValueDescriptor;
-
-import org.apache.derby.iapi.types.Orderable;
-
-import java.util.Enumeration;
-import java.util.Properties;
-import java.util.Vector;
+import org.apache.derby.shared.common.sanity.SanityManager;
 
 /**
 
@@ -487,6 +479,19 @@ class MergeSort implements Sort
 		// ordering array.
         for (int i = 0; i < colsToCompare; i++)
         {
+            if (i == colsToCompare - 1 && sortObserver.deferrable()) {
+                if (sortObserver.deferred()) {
+                    // Last column, which is RowLocation. We compared equal
+                    // this far so duplicate: remember till end of
+                    // transaction, but continue sorting on RowLocation, since
+                    // the index needs to be sorted on the column, too, for
+                    // the Btree to load.
+                    sortObserver.rememberDuplicate(r1);
+                } else {
+                    // report the duplicate
+                    break;
+                }
+            }
 			// Get columns to compare.
             int colid = this.columnOrderingMap[i];
             boolean nullsLow = this.columnOrderingNullsLowMap[i];

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/sort/UniqueWithDuplicateNullsMergeSort.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/sort/UniqueWithDuplicateNullsMergeSort.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/sort/UniqueWithDuplicateNullsMergeSort.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/sort/UniqueWithDuplicateNullsMergeSort.java Mon Nov 25 20:30:45 2013
@@ -36,7 +36,7 @@ final class UniqueWithDuplicateNullsMerg
      * Compares two keys. 
      *
      * If all the parts of the keys are not null then the leading 
-     * (keys.length - 1) parts are compared, else if no part of the key
+     * (keys.length - 1) parts are compared, else if a part of the key
      * is null then all parts of the key are compared (keys.length).
      *
      * This behavior is useful for implementing unique constraints where
@@ -50,6 +50,7 @@ final class UniqueWithDuplicateNullsMerg
      *
      * @return 0 for duplicates non zero for distinct keys 
      */
+    @Override
     protected int compare(DataValueDescriptor[] r1, DataValueDescriptor[] r2)
     throws StandardException {
         // Get the number of columns we have to compare.
@@ -71,8 +72,13 @@ final class UniqueWithDuplicateNullsMerg
             //location too.  This is used to provide proper sorting of
             //duplicate keys with nulls, they must be ordered properly 
             //according to the last field also.
-            if (i == colsToCompare - 1 && nonull)
-                return 0;
+            if (i == colsToCompare - 1 && nonull) {
+                if (sortObserver.deferred()) {
+                    sortObserver.rememberDuplicate(r1);
+                } else {
+                    return 0;
+                }
+            }
 
             // Get columns to compare.
             int colid = columnOrderingMap[i];

Modified: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/jdbc/EmbedXAResource.java Mon Nov 25 20:30:45 2013
@@ -30,6 +30,7 @@ import javax.transaction.xa.Xid;
 import javax.transaction.xa.XAException;
 
 import org.apache.derby.iapi.error.ExceptionSeverity;
+import org.apache.derby.iapi.error.ExceptionUtil;
 import org.apache.derby.iapi.error.StandardException;
 import org.apache.derby.iapi.jdbc.BrokeredConnection;
 import org.apache.derby.iapi.jdbc.ResourceAdapter;
@@ -304,7 +305,16 @@ class EmbedXAResource implements XAResou
                     return XAResource.XA_RDONLY;
                 }
             } catch (SQLException sqle) {
-                throw wrapInXAException(sqle);
+                XAException xe = wrapInXAException(sqle);
+
+                if (sqle.getSQLState().equals(
+                      ExceptionUtil.getSQLStateFromIdentifier(
+                        SQLState.LANG_DEFERRED_DUPLICATE_KEY_CONSTRAINT_T))) {
+                    // We are rolling back
+                    returnConnectionToResource(tranState, xid_im);
+                }
+
+                throw xe;
             }
         }
         
@@ -820,7 +830,9 @@ class EmbedXAResource implements XAResou
         else if (sqlstate.equals(SQLState.LOCK_TIMEOUT))
             xaErrorCode = XAException.XA_RBTIMEOUT;
         else if (seErrorCode >=  ExceptionSeverity.SESSION_SEVERITY)
-            xaErrorCode = XAException.XAER_RMFAIL;            
+            xaErrorCode = XAException.XAER_RMFAIL;
+        else if (sqlstate.equals(StandardException.getSQLStateFromIdentifier(SQLState.LANG_DEFERRED_DUPLICATE_KEY_CONSTRAINT_T)))
+            xaErrorCode = XAException.XA_RBINTEGRITY;
         else
             xaErrorCode = XAException.XAER_RMERR;
         

Modified: db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/jdbc/XATransactionState.java Mon Nov 25 20:30:45 2013
@@ -37,6 +37,7 @@ import org.apache.derby.iapi.store.acces
 import org.apache.derby.iapi.reference.SQLState;
 import java.util.HashMap;
 import javax.transaction.xa.XAException;
+import org.apache.derby.iapi.error.ExceptionUtil;
 import org.apache.derby.shared.common.reference.MessageId;
 
 /** 
@@ -359,7 +360,20 @@ final class XATransactionState extends C
      * Prepare the global transaction for commit.
      */
     synchronized int xa_prepare() throws SQLException {
-        int retVal = conn.xa_prepare();
+        int retVal;
+
+        try {
+            retVal = conn.xa_prepare();
+        } catch (SQLException e) {
+            if (e.getSQLState().equals(
+                  ExceptionUtil.getSQLStateFromIdentifier(
+                    SQLState.LANG_DEFERRED_DUPLICATE_KEY_CONSTRAINT_T))) {
+                // we are rolling back
+                xa_finalize();
+            }
+
+            throw e;
+        }
 
         if (retVal == XATransactionController.XA_RDONLY) {
             // Read-only transactions are implicitly committed when they are

Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages.xml Mon Nov 25 20:30:45 2013
@@ -873,6 +873,20 @@ Guide.
             </msg>
 
             <msg>
+                <name>23506.T.1</name>
+                <text>The transaction was aborted because of a deferred constraint violation: Duplicate in unique or primary key constraint identified by '{0}' defined on '{1}'.</text>
+                <arg>indexOrConstraintName</arg>
+                <arg>tableName</arg>
+            </msg>
+
+            <msg>
+                <name>23507.S.1</name>
+                <text>Deferred constraint violation: Duplicate in unique or primary key constraint identified by '{0}' defined on '{1}'.</text>
+                <arg>indexOrConstraintName</arg>
+                <arg>tableName</arg>
+            </msg>
+
+            <msg>
                 <name>23513</name>
                 <text>The check constraint '{1}' was violated while performing an INSERT or UPDATE on table '{0}'.</text>
                 <arg>tableName</arg>
@@ -3683,6 +3697,12 @@ Guide.
                 <arg>className</arg>
             </msg>
 
+            <msg>
+                <name>X0Y91.S</name>
+                <text>Cannot change constraint mode of {0}. It is not a deferrable constraint.</text>
+                <arg>constraintName</arg>
+            </msg>
+X0Y91
         </family>
 
 

Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java?rev=1545394&r1=1545393&r2=1545394&view=diff
==============================================================================
--- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java (original)
+++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java Mon Nov 25 20:30:45 2013
@@ -739,6 +739,8 @@ public interface SQLState {
 	
 	String LANG_NULL_INTO_NON_NULL                                     = "23502";
 	String LANG_DUPLICATE_KEY_CONSTRAINT                               = "23505";
+    String LANG_DEFERRED_DUPLICATE_KEY_CONSTRAINT_T                    = "23506.T.1";
+    String LANG_DEFERRED_DUPLICATE_KEY_CONSTRAINT_S                    = "23507.S.1";
 	String LANG_FK_VIOLATION                                           = "23503";
 	String LANG_CHECK_CONSTRAINT_VIOLATED                              = "23513";
 
@@ -1400,7 +1402,7 @@ public interface SQLState {
 	String LANG_UNKNOWN_TOOL_NAME                                = "X0Y88.S";
 	String LANG_BAD_OPTIONAL_TOOL_ARGS                                = "X0Y89.S";
 	String LANG_CANT_INSTANTIATE_CLASS                                = "X0Y90.S";
-
+    String LANG_SET_CONSTRAINT_NOT_DEFERRABLE                         = "X0Y91.S";
 
 	// TEMPORARY EXECUTION RESTRICTIONS
 



Mime
View raw message