db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kahat...@apache.org
Subject svn commit: r728822 - in /db/derby/code/trunk/java: engine/org/apache/derby/iapi/types/ testing/org/apache/derbyTesting/functionTests/tests/lang/
Date Mon, 22 Dec 2008 23:22:12 GMT
Author: kahatlen
Date: Mon Dec 22 15:22:11 2008
New Revision: 728822

URL: http://svn.apache.org/viewvc?rev=728822&view=rev
Log:
DERBY-3975: SELECT DISTINCT may return duplicates with territory-based collation

Made the implementation of hashCode() in the collation-sensitive
subclasses of SQLChar consistent with the collation-sensitive
implementations of equals(), compareTo() and stringCompare().

Also extended CollationTest with tests for SELECT DISTINCT on strings
that contain different characters but are considered equal in French
locale.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLChar.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLClob.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLLongvarchar.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLVarchar.java
    db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLChar.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLChar.java?rev=728822&r1=728821&r2=728822&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLChar.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLChar.java Mon Dec
22 15:22:11 2008
@@ -163,6 +163,16 @@
 		 return holderForCollationSensitiveInfo.stringCompare(char1, char2);
 	 }
 
+     /**
+      * Return a hash code that is consistent with
+      * {@link #stringCompare(SQLChar, SQLChar)}.
+      *
+      * @return hash code
+      */
+     public int hashCode() {
+         return hashCodeForCollation();
+     }
+
 	/**
 	 * This method implements the like function for char (with no escape value).
 	 * The difference in this method and the same method in superclass is that

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLClob.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLClob.java?rev=728822&r1=728821&r2=728822&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLClob.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLClob.java Mon Dec
22 15:22:11 2008
@@ -164,6 +164,16 @@
 		 return holderForCollationSensitiveInfo.stringCompare(char1, char2);
 	 }
 
+     /**
+      * Return a hash code that is consistent with
+      * {@link #stringCompare(SQLChar, SQLChar)}.
+      *
+      * @return hash code
+      */
+     public int hashCode() {
+         return hashCodeForCollation();
+     }
+
 	/**
 	 * This method implements the like function for char (with no escape value).
 	 * The difference in this method and the same method in superclass is that

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLLongvarchar.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLLongvarchar.java?rev=728822&r1=728821&r2=728822&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLLongvarchar.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLLongvarchar.java
Mon Dec 22 15:22:11 2008
@@ -165,6 +165,16 @@
 		 return holderForCollationSensitiveInfo.stringCompare(char1, char2);
 	 }
 
+    /**
+      * Return a hash code that is consistent with
+      * {@link #stringCompare(SQLChar, SQLChar)}.
+      *
+      * @return hash code
+      */
+     public int hashCode() {
+         return hashCodeForCollation();
+     }
+
 	/**
 	 * This method implements the like function for char (with no escape value).
 	 * The difference in this method and the same method in superclass is that

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLVarchar.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLVarchar.java?rev=728822&r1=728821&r2=728822&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLVarchar.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/CollatorSQLVarchar.java Mon
Dec 22 15:22:11 2008
@@ -171,6 +171,16 @@
 		 return holderForCollationSensitiveInfo.stringCompare(char1, char2);
 	 }
 
+     /**
+      * Return a hash code that is consistent with
+      * {@link #stringCompare(SQLChar, SQLChar)}.
+      *
+      * @return hash code
+      */
+     public int hashCode() {
+         return hashCodeForCollation();
+     }
+
 	/**
 	 * This method implements the like function for char (with no escape value).
 	 * The difference in this method and the same method in superclass is that

Modified: db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java?rev=728822&r1=728821&r2=728822&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLChar.java Mon Dec 22 15:22:11
2008
@@ -2655,6 +2655,11 @@
      */
     public int hashCode()
     {
+        if (SanityManager.DEBUG) {
+            SanityManager.ASSERT(!(this instanceof CollationElementsInterface),
+                    "SQLChar.hashCode() does not work with collation");
+        }
+
         try {
             if (getString() == null)
             {
@@ -2703,6 +2708,24 @@
     }
 
     /**
+     * Hash code implementation for collator sensitive subclasses.
+     */
+    int hashCodeForCollation() {
+        CollationKey key = null;
+
+        try {
+            key = getCollationKey();
+        } catch (StandardException se) {
+            // ignore exceptions, like we do in hashCode()
+            if (SanityManager.DEBUG) {
+                SanityManager.THROWASSERT("Unexpected exception", se);
+            }
+        }
+
+        return key == null ? 0 : key.hashCode();
+    }
+
+    /**
      * Get a SQLVarchar for a built-in string function.  
      *
      * @return a SQLVarchar.

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest.java?rev=728822&r1=728821&r2=728822&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CollationTest.java
Mon Dec 22 15:22:11 2008
@@ -257,39 +257,58 @@
       //End of parameter testing
       
       s.close();
-      compareAgrave(1,1);
+      compareAgrave(1, 1, 2);
       }
       
 
 public void testFrenchCollation() throws SQLException {
-    compareAgrave(2,1);    
+    compareAgrave(2, 1, 1);
 }
 
 
 
- /**
- * For a TERRITORY_BASED collation french database, differences between pre-composed accents
such 
- * as "\u00C0" (A-grave) and combining accents such as "A\u0300" (A, combining-grave) should
match
- * for = and like. But they do not match for UCS_BASIC. We insert both into a table and search
- * based on equal and like. 
+/**
+ * For a TERRITORY_BASED collation french database, differences between
+ * pre-composed accents such as "\u00C0" (A-grave) and combining accents
+ * such as "A\u0300" (A, combining-grave) should match for {@code =}, but
+ * not for {@code LIKE}. They should never match for UCS_BASIC. We insert
+ * both into a table and search based on {@code =} and {@code LIKE}.
  *  
  * @param expectedMatchCountForEqual  number of rows we expect back for =. 
  * 	2 for French, 1 for English 
  * @param expectedMatchCountForLike  number of rows we expect back for LIKE. 
  * 	1 for French and English 
+ * @param expectedDistinctRows number of rows expected from SELECT DISTINCT
  * @throws SQLException
  */
 private void compareAgrave(int expectedMatchCountForEqual,
-		int expectedMatchCountForLike) throws SQLException {
-      
+        int expectedMatchCountForLike, int expectedDistinctRows)
+            throws SQLException {
+    String[] dataTypes = {"VARCHAR(5)", "CHAR(5)"};
+    for (int i = 0; i < dataTypes.length; i++) {
+        compareAgrave(dataTypes[i], expectedMatchCountForEqual,
+                expectedMatchCountForLike, expectedDistinctRows);
+    }
+}
+
+/**
+ * Helper for {@link #compareAgrave(int, int, int)} which performs the test
+ * for one data type.
+ */
+private void compareAgrave(String dataType, int expectedMatchCountForEqual,
+		int expectedMatchCountForLike, int expectedDistinctRows)
+            throws SQLException {
+
+      // Create the two strings that are supposed to be equal in French locale.
       String agrave = "\u00C0";
       String agraveCombined ="A\u0300";
+
       Statement s = createStatement();
       
       try {
           s.executeUpdate("DROP TABLE T");
       }catch (SQLException se) {}
-      s.executeUpdate("CREATE TABLE T (vc varchar(30))");
+      s.executeUpdate("CREATE TABLE T (vc " + dataType + ")");
       PreparedStatement ps = prepareStatement("INSERT INTO T VALUES (?)");
       ps.setString(1,agrave);
       ps.executeUpdate();
@@ -300,12 +319,18 @@
       ps.setString(1, agrave);
       ResultSet rs = ps.executeQuery();
       JDBC.assertSingleValueResultSet(rs, Integer.toString(expectedMatchCountForEqual));
-      ps = prepareStatement("SELECT COUNT(*) FROM T WHERE VC LIKE ?");
+      // Use '%' at the end of the pattern so that we also match the trailing
+      // blanks if the data type is CHAR instead of VARCHAR.
+      ps = prepareStatement("SELECT COUNT(*) FROM T WHERE VC LIKE ? || '%'");
       ps.setString(1, agrave);
       rs = ps.executeQuery();
       JDBC.assertSingleValueResultSet(rs, Integer.toString(expectedMatchCountForLike));
 
-
+      // DERBY-3975: They should match for distinct, the same way as for =
+      int distinctRows = JDBC.assertDrainResults(
+              s.executeQuery("SELECT DISTINCT VC FROM T"));
+      assertEquals("Unexpected number of distinct rows",
+              expectedDistinctRows, distinctRows);
   }
 
 



Mime
View raw message