db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From krist...@apache.org
Subject svn commit: r1174436 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/store/access/btree/ engine/org/apache/derby/impl/store/access/btree/index/ engine/org/apache/derby/impl/store/access/conglomerate/ engine/org/apache/derby/impl/store/acce...
Date Thu, 22 Sep 2011 22:48:59 GMT
Author: kristwaa
Date: Thu Sep 22 22:48:59 2011
New Revision: 1174436

URL: http://svn.apache.org/viewvc?rev=1174436&view=rev
Log:
DERBY-5367: Stale data retrieved when using new collation=TERRITORY_BASED:PRIMARY feature

Deoptimize code path for BTree insert when updating columns with a collation
different from UCS BASIC. Simply undeleting the existing matching row (marked
as deleted) may be incorrect, because the value stored there can be different
from the key value used for lookup due to the collation.

Added code to track whether a conglomerate contains a collated column or not,
such that the right insert code path can be chosen. The array of collation ids
is scanned when a conglomerate is created, and when a conglomerate is
"restored" from disk (i.e. readExternal).

Added a test for the new code path (based on the issue report).

Patch file: derby-5367-4c-fix_with_optimization_improved.diff

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTree.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/OpenBTree.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2I.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/ConglomerateUtil.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/GenericConglomerate.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerate.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerateScratchSpace.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/heap/Heap.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest2.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTree.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTree.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTree.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTree.java Thu
Sep 22 22:48:59 2011
@@ -57,8 +57,6 @@ import java.io.ObjectInput;
 
 import java.util.Properties;
 
-import org.apache.derby.iapi.services.io.ArrayUtil;
-
 /**
 
   A b-tree object corresponds to an instance of a b-tree conglomerate.  It 
@@ -192,6 +190,11 @@ public abstract class BTree extends Gene
     The array of collation id's for each column in the template.
     **/
     protected int[]   collation_ids;
+    /**
+     * Tells if there is at least one column in the conglomerate whose collation
+     * isn't StringDataValue.COLLATION_TYPE_UCS_BASIC.
+     */
+    protected boolean hasCollatedTypes;
 
 
 	/*
@@ -586,7 +589,8 @@ public abstract class BTree extends Gene
     public DynamicCompiledOpenConglomInfo getDynamicCompiledConglomInfo()
 		throws StandardException
     {
-        return(new OpenConglomerateScratchSpace(format_ids, collation_ids));
+        return(new OpenConglomerateScratchSpace(
+                format_ids, collation_ids, hasCollatedTypes));
     }
 
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/BTreeController.java
Thu Sep 22 22:48:59 2011
@@ -51,7 +51,6 @@ import org.apache.derby.iapi.types.RowLo
 
 import org.apache.derby.iapi.services.io.FormatableBitSet;
 import org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil;
-import org.apache.derby.impl.store.access.conglomerate.TemplateRow;
 
 /**
 
@@ -845,17 +844,44 @@ public class BTreeController extends Ope
                             insert_slot, false, this.btree_undo);
 
                         boolean update_succeeded = true;
-
                         try 
                         {
-                            int rowloc_index = 
-                                this.getConglomerate().nKeyFields - 1;
-                            targetleaf.page.updateFieldAtSlot(
-                                insert_slot, rowloc_index, 
-                                (DataValueDescriptor) RowUtil.getColumn(
-                                    rowToInsert, 
-                                    (FormatableBitSet) null, rowloc_index),
-                                this.btree_undo);
+                            if (runtime_mem.hasCollatedTypes())
+                            {
+                                // See DERBY-5367.
+                                // There are types in the BTree with a 
+                                // collation different than UCS BASIC, we
+                                // update all fields to make sure they hold
+                                // the correct values.
+                                // NOTE: We could optimize here by only
+                                // updating the fields that actually hold
+                                // collated types.
+                                int rowsToUpdate = getConglomerate().nKeyFields;
+                                for (int i=0; i < rowsToUpdate; i++) {
+                                targetleaf.page.updateFieldAtSlot(
+                                    insert_slot, i, 
+                                    (DataValueDescriptor) RowUtil.getColumn(
+                                        rowToInsert, 
+                                        (FormatableBitSet) null, i),
+                                    this.btree_undo);
+                                }
+                            }
+                            else
+                            {
+                                // There are no collated types in the BTree,
+                                // which means that the values currently
+                                // stored in the undeleted row are correct.
+                                // We simply update the row location to point
+                                // to the correct row in the heap.
+                                int rowloc_index =
+                                        this.getConglomerate().nKeyFields - 1;
+                                targetleaf.page.updateFieldAtSlot(
+                                    insert_slot, rowloc_index, 
+                                    (DataValueDescriptor) RowUtil.getColumn(
+                                        rowToInsert, 
+                                        (FormatableBitSet) null, rowloc_index),
+                                    this.btree_undo);
+                            }
                         }
                         catch (StandardException se)
                         {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/OpenBTree.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/OpenBTree.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/OpenBTree.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/OpenBTree.java
Thu Sep 22 22:48:59 2011
@@ -34,7 +34,6 @@ import org.apache.derby.iapi.store.acces
 import org.apache.derby.iapi.store.access.SpaceInfo;
 import org.apache.derby.iapi.store.raw.ContainerHandle;
 import org.apache.derby.iapi.store.raw.LockingPolicy;
-import org.apache.derby.iapi.store.raw.RecordHandle;
 import org.apache.derby.iapi.store.raw.Transaction;
 
 import org.apache.derby.iapi.types.DataValueDescriptor;
@@ -91,7 +90,6 @@ public class OpenBTree 
     **/
     protected int                           init_lock_level;
 
-    private DynamicCompiledOpenConglomInfo  init_dynamic_info;
     private boolean                         init_hold;
 
     /**
@@ -414,8 +412,6 @@ public class OpenBTree 
         // Isolation level of this btree.
         init_lock_level     = lock_level;
 
-        init_dynamic_info   = dynamic_info;
-
         init_hold           = hold;
 
 
@@ -429,9 +425,8 @@ public class OpenBTree 
         this.runtime_mem    = 
             (dynamic_info != null ? 
              ((OpenConglomerateScratchSpace) dynamic_info) : 
-             new OpenConglomerateScratchSpace(
-                 conglomerate.format_ids, 
-                 conglomerate.collation_ids));
+              (OpenConglomerateScratchSpace)
+                conglomerate.getDynamicCompiledConglomInfo());
 
 	}
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2I.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2I.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2I.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/btree/index/B2I.java
Thu Sep 22 22:48:59 2011
@@ -29,12 +29,9 @@ import java.util.Properties;
 import org.apache.derby.iapi.reference.SQLState;
 
 import org.apache.derby.iapi.services.io.ArrayInputStream;
-import org.apache.derby.iapi.services.io.FormatableBitSet;
 
 import org.apache.derby.iapi.services.sanity.SanityManager;
 import org.apache.derby.iapi.error.StandardException;
-import org.apache.derby.iapi.store.raw.Page;
-import org.apache.derby.impl.store.access.btree.ControlRow;
 
 import org.apache.derby.impl.store.access.conglomerate.ConglomerateUtil;
 import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
@@ -66,7 +63,6 @@ import org.apache.derby.impl.store.acces
 
 import org.apache.derby.iapi.services.cache.ClassSize;
 
-import org.apache.derby.iapi.services.io.CompressedNumber;
 import org.apache.derby.iapi.services.io.FormatableBitSet;
 import org.apache.derby.iapi.services.io.StoredFormatIds;
 
@@ -596,6 +592,7 @@ public class B2I extends BTree
         // conglom state.
         collation_ids = 
             ConglomerateUtil.createCollationIds(template.length, collationIds);
+        hasCollatedTypes = hasCollatedColumns(collation_ids);
 
 		// Do the generic part of creating the b-tree.
 		super.create(
@@ -1156,6 +1153,9 @@ public class B2I extends BTree
         
         // In memory maintain a collation id per column in the template.
         collation_ids = new int[format_ids.length];
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(!hasCollatedTypes);
+        }
 
         // initialize all the entries to COLLATION_TYPE_UCS_BASIC, 
         // and then reset as necessary.  For version ACCESS_B2I_V3_ID,
@@ -1181,7 +1181,8 @@ public class B2I extends BTree
                     "length = " + collation_ids.length);
             }
 
-            ConglomerateUtil.readCollationIdArray(collation_ids, in);
+            hasCollatedTypes =
+                    ConglomerateUtil.readCollationIdArray(collation_ids, in);
         }
         else if (conglom_format_id != StoredFormatIds.ACCESS_B2I_V3_ID)
         {

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/ConglomerateUtil.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/ConglomerateUtil.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/ConglomerateUtil.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/ConglomerateUtil.java
Thu Sep 22 22:48:59 2011
@@ -28,7 +28,6 @@ import org.apache.derby.iapi.services.io
 import org.apache.derby.iapi.services.io.Formatable;
 import org.apache.derby.iapi.services.io.FormatIdUtil;
 
-import org.apache.derby.iapi.store.access.ColumnOrdering;
 import org.apache.derby.iapi.store.access.RowUtil;
 
 import org.apache.derby.iapi.store.raw.FetchDescriptor;
@@ -310,9 +309,11 @@ public final class ConglomerateUtil
      *                           the sparse array from the stream.
      *                           
      * @param in                 The stream to read the collation info from.
+     * @return {@code true} if at least one column has a different collation
+     *      than UCS BASIC, {@code false} otherwise.
      *
      **/
-    public static void readCollationIdArray(
+    public static boolean readCollationIdArray(
     int[]           collation_id_array,
     ObjectInput     in)
         throws IOException
@@ -332,6 +333,7 @@ public final class ConglomerateUtil
             int array_index = CompressedNumber.readInt(in);
             collation_id_array[array_index] = CompressedNumber.readInt(in);
         }
+        return num_compressed_entries > 0;
 	}
 
 	/**

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/GenericConglomerate.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/GenericConglomerate.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/GenericConglomerate.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/GenericConglomerate.java
Thu Sep 22 22:48:59 2011
@@ -30,8 +30,8 @@ import org.apache.derby.iapi.error.Stand
 import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;
 
 import org.apache.derby.iapi.types.DataValueDescriptor;
-
 import org.apache.derby.iapi.types.DataType;
+import org.apache.derby.iapi.types.StringDataValue;
 
 import java.sql.ResultSet;
 import java.sql.SQLException;
@@ -210,4 +210,20 @@ public abstract class GenericConglomerat
         throw(StandardException.newException(
                 SQLState.HEAP_UNIMPLEMENTED_FEATURE));
 	}
+
+    /**
+     * Tells if there are columns with collations (other than UCS BASIC) in the
+     * given list of collation ids.
+     *
+     * @param collationIds collation ids for the conglomerate columns
+     * @return {@code true} if a collation other than UCS BASIC was found.
+     */
+    public static boolean hasCollatedColumns(int[] collationIds) {
+        for (int i=0; i < collationIds.length; i++) {
+            if (collationIds[i] != StringDataValue.COLLATION_TYPE_UCS_BASIC) {
+                return true;
+            }
+        }
+        return false;
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerate.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerate.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerate.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerate.java
Thu Sep 22 22:48:59 2011
@@ -876,7 +876,8 @@ public abstract class OpenConglomerate
         this.runtime_mem    = 
             (dynamic_info != null ? 
              ((OpenConglomerateScratchSpace) dynamic_info) : 
-             new OpenConglomerateScratchSpace(format_ids, collation_ids));
+             ((OpenConglomerateScratchSpace)
+                conglomerate.getDynamicCompiledConglomInfo()));
 
         // Is this an open for update or read?  This will
 		// be passed down to the raw store fetch methods, which allows

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerateScratchSpace.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerateScratchSpace.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerateScratchSpace.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/conglomerate/OpenConglomerateScratchSpace.java
Thu Sep 22 22:48:59 2011
@@ -32,6 +32,8 @@ import org.apache.derby.iapi.types.DataV
 
 import org.apache.derby.iapi.services.io.FormatableBitSet;
 
+import org.apache.derby.iapi.services.sanity.SanityManager;
+
 /**
 
 A utility class to store and use temporary scratch space associated with
@@ -74,8 +76,15 @@ public class OpenConglomerateScratchSpac
     /**
      * A complete array of format id's and collation_ids for this conglomerate.
      **/
-    private int[]                   format_ids;
-    private int[]                   collation_ids;
+    private final int[] format_ids;
+    private final int[] collation_ids;
+    /**
+     * Tells if there is at least one type in the conglomerate whose collation
+     * isn't StringDataValue.COLLATION_TYPE_UCS_BASIC. This can be determined
+     * by looking at the collation ids, but now the caller is passing in the
+     * value to avoid having to look at all the collation ids multiple times.
+     */
+    private final boolean hasCollatedTypes;
 
 
     /**
@@ -96,13 +105,21 @@ public class OpenConglomerateScratchSpac
      *
      * @param format_ids format identifiers for columns in the row
      * @param collation_ids collation identifiers for the columns in the row
+     * @param hasCollatedTypes whether there is at least one collated type with
+     *      a collation other than UCS BASIC in the conglomerate
      */
     public OpenConglomerateScratchSpace(
     int[]   format_ids,
-    int[]   collation_ids)
+    int[]   collation_ids,
+    boolean hasCollatedTypes)
     {
         this.format_ids     = format_ids;
         this.collation_ids  = collation_ids;
+        this.hasCollatedTypes = hasCollatedTypes;
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(GenericConglomerate.hasCollatedColumns(
+                        collation_ids) == hasCollatedTypes);
+        }
     }
 
     /**************************************************************************
@@ -220,4 +237,15 @@ public class OpenConglomerateScratchSpac
 
         return(scratch_row_position);
     }
+    
+    /**
+     * Tells if there is at least one column with a collation different
+     * than UCS BASIC in the conglomerate.
+     *
+     * @return {@code true} if there is at least one column with a collation
+     *      different than UCS BASIC.
+     */
+    public boolean hasCollatedTypes() {
+        return hasCollatedTypes;
+    }
 }

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/heap/Heap.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/heap/Heap.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/heap/Heap.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/store/access/heap/Heap.java Thu
Sep 22 22:48:59 2011
@@ -42,7 +42,6 @@ import org.apache.derby.iapi.error.Stand
 
 import org.apache.derby.iapi.store.access.conglomerate.Conglomerate;
 import org.apache.derby.iapi.store.access.conglomerate.LogicalUndo;
-import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
 import org.apache.derby.iapi.store.access.conglomerate.ScanManager;
 import org.apache.derby.iapi.store.access.conglomerate.TransactionManager;
 
@@ -190,6 +189,11 @@ public class Heap 
     The array of collation id's for each column in the template.
     **/
     protected int[]   collation_ids;
+    /**
+     * Tells if there is at least one column in the conglomerate whose collation
+     * isn't StringDataValue.COLLATION_TYPE_UCS_BASIC.
+     */
+    private boolean hasCollatedTypes;
 
     private static final int BASE_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( Heap.class);
     private static final int CONTAINER_KEY_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog(
ContainerKey.class);
@@ -305,6 +309,7 @@ public class Heap 
         collation_ids = 
             ConglomerateUtil.createCollationIds(
                 format_ids.length, collationIds);
+        hasCollatedTypes = hasCollatedColumns(collation_ids);
 
         // need to open the container and insert the row.  Since we are
         // creating it no need to bother with locking since no one can get
@@ -580,7 +585,8 @@ public class Heap 
     public DynamicCompiledOpenConglomInfo getDynamicCompiledConglomInfo()
 		throws StandardException
     {
-        return(new OpenConglomerateScratchSpace(format_ids, collation_ids));
+        return(new OpenConglomerateScratchSpace(
+                format_ids, collation_ids, hasCollatedTypes));
     }
 
     /**
@@ -1202,6 +1208,9 @@ public class Heap 
 
         // In memory maintain a collation id per column in the template.
         collation_ids = new int[format_ids.length];
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(!hasCollatedTypes);
+        }
 
         // initialize all the entries to COLLATION_TYPE_UCS_BASIC, 
         // and then reset as necessary.  For version ACCESS_HEAP_V2_ID,
@@ -1213,7 +1222,8 @@ public class Heap 
         {
             // current format id, read collation info from disk
 
-            ConglomerateUtil.readCollationIdArray(collation_ids, in);
+            hasCollatedTypes =
+                    ConglomerateUtil.readCollationIdArray(collation_ids, in);
         }
         else if (conglom_format_id != StoredFormatIds.ACCESS_HEAP_V2_ID)
         {

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest2.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest2.java?rev=1174436&r1=1174435&r2=1174436&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest2.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest2.java
Thu Sep 22 22:48:59 2011
@@ -34,25 +34,17 @@ import java.text.RuleBasedCollator;
 import java.util.Locale;
 import java.util.Properties; 
 
-import javax.sql.DataSource;
-
 import junit.framework.Assert;
 import junit.framework.Test;
 import junit.framework.TestSuite;
 
 import org.apache.derbyTesting.junit.BaseJDBCTestCase;
-import org.apache.derbyTesting.junit.DatabasePropertyTestSetup;
 import org.apache.derbyTesting.junit.Decorator;
 import org.apache.derbyTesting.junit.JDBC;
-import org.apache.derbyTesting.junit.JDBCDataSource;
 import org.apache.derbyTesting.junit.SystemPropertyTestSetup;
 import org.apache.derbyTesting.junit.SupportFilesSetup;
-import org.apache.derbyTesting.junit.SQLUtilities;
 import org.apache.derbyTesting.junit.TestConfiguration;
 
-import org.apache.derby.iapi.services.sanity.SanityManager;
-
-
 /**
 Junit test targeted at testing language based Collation.
 
@@ -94,6 +86,10 @@ T24: (DONE) DERBY-2669 If no territory a
             of Database.
 
 
+<p>
+NOTE: The prefix "ci_test" is used for tests that require a case insensitive
+      collation order.
+
 **/
 
 public class CollationTest2 extends BaseJDBCTestCase 
@@ -902,6 +898,55 @@ public class CollationTest2 extends Base
         dropTable();
     }
 
+    /**
+     * Tests that DERBY-5367 is fixed, a bug where updating the index in a
+     * database with a case insensitive collation resulted in data corruption.
+     * <p>
+     * The bug tested is where a deleted row with an incorrect key value in
+     * the index is undeleted as an optimized insert. In this case it was
+     * caused by the a case insensitive collation order, but other collation
+     * rules could cause this to happen as well.
+     */
+    public void ci_testDerby5367()
+            throws SQLException {
+        assertFalse(isDatabaseBasicCollation());
+        setAutoCommit(true);
+        String TABLE = "DERBY_5367";
+        Statement stmt = createStatement();
+        stmt.executeUpdate("create table " + TABLE + "(" +
+                "VAL varchar(10) not null unique)");
+        
+        // Run first time when the congloms were newly created.
+        runDerby5367TestCode(TABLE);
+
+        // Shut down the database, reboot. This will trigger the code to
+        // read the congloms from disk.
+        TestConfiguration.getCurrent().shutdownDatabase();
+        getConnection();
+
+        // Run second time, read congloms from disk.
+        runDerby5367TestCode(TABLE);
+        dropTable(TABLE);
+    }
+
+    /** Runs the core code for the DERBY-5367 test. */
+    private void runDerby5367TestCode(String table)
+            throws SQLException {
+        PreparedStatement sel = prepareStatement("select val from " + table +
+                " where val = 'Test'");
+        PreparedStatement ins = prepareStatement("insert into " + table +
+                " values ?");
+        ins.setString(1, "Test");
+        ins.executeUpdate();
+        JDBC.assertFullResultSet(sel.executeQuery(), new String[][] {{"Test"}});
+        Statement stmt = createStatement();
+        stmt.executeUpdate("delete from " + table + " where val = 'Test'");
+        ins.setString(1, "test");
+        ins.executeUpdate();
+        JDBC.assertFullResultSet(sel.executeQuery(), new String[][] {{"test"}});
+        stmt.executeUpdate("delete from " + table);
+    }
+
     /**************************************************************************
      * Private/Protected tests of This class:
      **************************************************************************
@@ -1920,6 +1965,7 @@ public class CollationTest2 extends Base
         TestSuite suite = new TestSuite("CollationTest2");
         suite.addTest(new CollationTest2("testDefaultCollation"));
         suite.addTest(collatedTest("en", "testEnglishCollation"));
+        suite.addTest(caseInsensitiveCollationSuite());
         
         // Only add tests for other locales if they are in fact supported 
         // by the jvm.
@@ -1961,4 +2007,17 @@ public class CollationTest2 extends Base
         return Decorator.territoryCollatedDatabase(
                 new CollationTest2(fixture), locale);
     }
+
+    /**
+     * Returns a suite of tests running with a collation strength resulting
+     * in case insensitivity.
+     *
+     * @return A suite of tests.
+     */
+    private static Test caseInsensitiveCollationSuite() {
+        TestSuite suite = new TestSuite("Case insensitive specific tests");
+        suite.addTest(new CollationTest2("ci_testDerby5367")); 
+        return Decorator.territoryCollatedCaseInsensitiveDatabase(
+                suite, "en_US");
+    }
 }



Mime
View raw message