You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by rh...@apache.org on 2010/06/07 17:12:22 UTC

svn commit: r952263 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/compile/ResultColumnList.java testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java

Author: rhillegas
Date: Mon Jun  7 15:12:21 2010
New Revision: 952263

URL: http://svn.apache.org/viewvc?rev=952263&view=rev
Log:
DERBY-4692: Forbid UNIONs between BOOLEAN and non-BOOLEAN types, per the SQL Standard.

Modified:
    db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java?rev=952263&r1=952262&r2=952263&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ResultColumnList.java Mon Jun  7 15:12:21 2010
@@ -2373,14 +2373,10 @@ public class ResultColumnList extends Qu
 				continue;
 
 			/* 
-			** Check type compatability.  We want to make sure that
-			** the types are assignable in either direction
-			** and they are comparable.
+			** Check type compatability.
 			*/
 			ClassFactory cf = getClassFactory();
-			if (
-				!thisExpr.getTypeCompiler().storable(otherTypeId, cf) &&
-				!otherExpr.getTypeCompiler().storable(thisTypeId, cf))
+			if ( !unionCompatible( thisExpr, otherExpr ) )
 			{
 				throw StandardException.newException(SQLState.LANG_NOT_UNION_COMPATIBLE, 
                                                      thisTypeId.getSQLTypeName(),
@@ -2440,6 +2436,35 @@ public class ResultColumnList extends Qu
 		}
 	}
 
+    /**
+     * Return true if the types of two expressions are union compatible. The rules for union
+     * compatibility are found in the SQL Standard, part 2, section 7.3 (<query expression>),
+     * syntax rule 20.b.ii. That in turn, refers you to section 9.3 (Result of data type combinations).
+     * See, for instance, <a href="https://issues.apache.org/jira/browse/DERBY-4692">DERBY-4692</a>.
+     *
+     * This logic may enforce only a weaker set of rules. Here is the original comment
+     * on the original logic: "We want to make sure that the types are assignable in either direction
+     * and they are comparable." We may need to revisit this code to make it conform to the
+     * Standard.
+     */
+    private boolean unionCompatible( ValueNode left, ValueNode right )
+        throws StandardException
+    {
+        TypeId leftTypeId = left.getTypeId();
+        TypeId rightTypeId = right.getTypeId();
+        ClassFactory cf = getClassFactory();
+
+        if (
+            !left.getTypeCompiler().storable(rightTypeId, cf) &&
+            !right.getTypeCompiler().storable(leftTypeId, cf)
+            )
+        { return false; }
+
+        if ( leftTypeId.isBooleanTypeId() != rightTypeId.isBooleanTypeId() ) { return false; }
+
+        return true;
+    }
+
 	/**
 	 * Do the 2 RCLs have the same type & length.
 	 * This is useful for UNIONs when deciding whether a NormalizeResultSet is required.

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java?rev=952263&r1=952262&r2=952263&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java Mon Jun  7 15:12:21 2010
@@ -321,7 +321,7 @@ public class BooleanValuesTest  extends 
      * <ul>
      * <li>Add a new column to ALL_TYPES and corresponding rows (see setUp())</li>
      * <li>Add the new datatype to one of the tests below</li>
-     * <li>Add a new bad implicit cast to test_06_implicitCasts()</li>
+     * <li>Add a new bad union case to test_06_unions()</li>
      * </ul>
      */
     public void test_01_datatypeCount() throws Exception
@@ -495,98 +495,36 @@ public class BooleanValuesTest  extends 
     
     /**
      * <p>
-     * Test that values are implicitly cast to boolean according to the rules in the SQL Standard,
-     * part 2, section 6.12 (<cast specification>), general rule 20. Other than booleans themselves,
-     * the only legal casts are from string types to boolean. The following transformations are applied
-     * to the strings:
-     * </p>
-     *
-     * <ul>
-     * <li>Trim whitespace off the string</li>
-     * <li>Then apply the rules in section 5.3 (<literal>). This means that the trimmed string must be 'TRUE', 'FALSE', or 'UNKNOWN', regardless of case.</li>
-     * <li>Otherwise, raise an exception.</li>
-     * </ul>
-     *
-     * <p>
-     * See <a href="https://issues.apache.org/jira/browse/DERBY-4658">DERBY-4658</a>.
+     * Test that unions fail if one but not both sides of the union is BOOLEAN. The rules for union
+     * compatibility are found in the SQL Standard, part 2, section 7.3 (<query expression>),
+     * syntax rule 20.b.ii. That in turn, refers you to section 9.3 (Result of data type combinations).
+     * See, for instance, <a href="https://issues.apache.org/jira/browse/DERBY-4692">DERBY-4692</a>.This enforces the rules found 
      * </p>
      */
-    public void test_06_implicitCasts() throws Exception
+    public void test_06_unions() throws Exception
     {
         Connection conn = getConnection();
 
-        vetGoodImplicitCastFromString( conn, "'true'", Boolean.TRUE );
-        vetGoodImplicitCastFromString( conn, "'false'", Boolean.FALSE );
-        vetGoodImplicitCastFromString( conn, "'TRUE'", Boolean.TRUE );
-        vetGoodImplicitCastFromString( conn, "'FALSE'", Boolean.FALSE );
-        vetGoodImplicitCastFromString( conn, "' true '", Boolean.TRUE );
-        vetGoodImplicitCastFromString( conn, "' false '", Boolean.FALSE );
-
-        vetGoodImplicitCastFromString( conn, "cast (null as char( 10 ) )", null );
-        vetGoodImplicitCastFromString( conn, "cast (null as clob )", null );
-        vetGoodImplicitCastFromString( conn, "cast (null as long varchar )", null );
-        vetGoodImplicitCastFromString( conn, "cast (null as varchar( 10 ) )", null );
-
-        vetGoodImplicitCastFromString( conn, "cast ('true' as char( 10 ) )", Boolean.TRUE );
-        vetGoodImplicitCastFromString( conn, "cast ('true' as clob )", Boolean.TRUE );
-        vetGoodImplicitCastFromString( conn, "cast ('true' as long varchar)", Boolean.TRUE );
-        vetGoodImplicitCastFromString( conn, "cast ('true' as varchar( 10 ) )", Boolean.TRUE );
-
-        vetGoodImplicitCastFromString( conn, "cast ('false' as char( 10 ) )", Boolean.FALSE );
-        vetGoodImplicitCastFromString( conn, "cast ('false' as clob )", Boolean.FALSE );
-        vetGoodImplicitCastFromString( conn, "cast ('false' as long varchar)", Boolean.FALSE );
-        vetGoodImplicitCastFromString( conn, "cast ('false' as varchar( 10 ) )", Boolean.FALSE );
-        
-        expectExecutionError( conn, BAD_CAST, makeImplicitCast( "'neither'" ) );
-
-        expectExecutionError( conn, BAD_CAST, makeImplicitCast( "cast ('neither' as char(10))" ) );
-        expectExecutionError( conn, BAD_CAST, makeImplicitCast( "cast ('neither' as clob)" ) );
-        expectExecutionError( conn, BAD_CAST, makeImplicitCast( "cast ('neither' as long varchar)" ) );
-        expectExecutionError( conn, BAD_CAST, makeImplicitCast( "cast ('neither' as varchar(10))" ) );
-
         vetBadImplicitCasts( conn, "bigint_col" );
         vetBadImplicitCasts( conn, "blob_col" );
-        // char type ok
+        vetBadImplicitCasts( conn, "char_col" );
         vetBadImplicitCasts( conn, "char_for_bit_data_col" );
-        // clob type ok
+        vetBadImplicitCasts( conn, "clob_col" );
         vetBadImplicitCasts( conn, "date_col" );
         vetBadImplicitCasts( conn, "decimal_col" );
         vetBadImplicitCasts( conn, "real_col" );
         vetBadImplicitCasts( conn, "double_col" );
         vetBadImplicitCasts( conn, "int_col" );
-        // long varchar type ok
+        vetBadImplicitCasts( conn, "long_varchar_col" );
         vetBadImplicitCasts( conn, "long_varchar_for_bit_data_col" );
         vetBadImplicitCasts( conn, "numeric_col" );
         vetBadImplicitCasts( conn, "smallint_col" );
         vetBadImplicitCasts( conn, "time_col" );
         vetBadImplicitCasts( conn, "timestamp_col" );
-        // varchar type ok
+        vetBadImplicitCasts( conn, "varchar_col" );
         vetBadImplicitCasts( conn, "varchar_for_bit_data_col" );
         if ( _supportsXML ) { vetBadImplicitCasts( conn, "xml_col" ); }
     }
-    private void vetGoodImplicitCastFromString( Connection conn, String text, Boolean booleanValue ) throws Exception
-    {
-        String expectedValue = null;
-        if ( booleanValue != null ) { expectedValue = booleanValue.toString(); }
-
-        assertResults
-            (
-             conn,
-             makeImplicitCast( text ),
-             new String[][]
-             {
-                 { expectedValue },
-             },
-             false
-             );
-    }
-    private String makeImplicitCast( String text )
-    {
-        return
-            "select isindex from sys.sysconglomerates where conglomeratename = 'foo'\n" +
-            "union\n" +
-            "values ( " + text + " )\n";
-    }
     private void vetBadImplicitCasts( Connection conn, String columnName ) throws Exception
     {
         vetBadImplicitCastToBoolean( conn, columnName );