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 km...@apache.org on 2013/08/05 19:05:13 UTC

svn commit: r1510609 - in /db/derby/code/branches/10.9: ./ java/engine/org/apache/derby/iapi/types/ java/engine/org/apache/derby/impl/sql/compile/ java/testing/org/apache/derbyTesting/functionTests/tests/lang/

Author: kmarsden
Date: Mon Aug  5 17:05:13 2013
New Revision: 1510609

URL: http://svn.apache.org/r1510609
Log:
DERBY-6017 IN lists with mixed types may return wrong results

merge from trunk revisions 1424889, 1448025, 1450695
Contributed by Knut Anders Hatlen


Added:
    db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InPredicateTest.java
      - copied, changed from r1424889, db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InPredicateTest.java
Modified:
    db/derby/code/branches/10.9/   (props changed)
    db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataType.java
    db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java
    db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/InListOperatorNode.java
    db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/ValueNodeList.java
    db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java

Propchange: db/derby/code/branches/10.9/
------------------------------------------------------------------------------
  Merged /db/derby/code/trunk:r1424889,1448025,1450695

Modified: db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataType.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataType.java?rev=1510609&r1=1510608&r2=1510609&view=diff
==============================================================================
--- db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataType.java (original)
+++ db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataType.java Mon Aug  5 17:05:13 2013
@@ -1126,6 +1126,13 @@ public abstract class DataType
 		 * compare using the dominant type of the two values being compared.
 		 * Otherwise we can end up with wrong results when doing the binary
 		 * search (ex. as caused by incorrect truncation).  DERBY-2256.
+         *
+         * DERBY-6017: Actually, it's not good enough to compare using the
+         * dominant type of the two values being compared. It has to be the
+         * dominant type of *all* the values in the left operand and the right
+         * operand. Therefore, InListOperatorNode.preprocess() inserts a
+         * cast if necessary to ensure that either the left side or the right
+         * side of each comparison is of the overall dominating type.
 		 */
 		int leftPrecedence = left.typePrecedence();
 		DataValueDescriptor comparator = null;

Modified: db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java?rev=1510609&r1=1510608&r2=1510609&view=diff
==============================================================================
--- db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java (original)
+++ db/derby/code/branches/10.9/java/engine/org/apache/derby/iapi/types/DataTypeDescriptor.java Mon Aug  5 17:05:13 2013
@@ -700,11 +700,8 @@ public final class DataTypeDescriptor im
 	 * @param cf		A ClassFactory
 	 *
 	 * @return DataTypeDescriptor  DTS for dominant type
-	 *
-	 * @exception StandardException		Thrown on error
 	 */
 	public DataTypeDescriptor getDominantType(DataTypeDescriptor otherDTS, ClassFactory cf)
-			throws StandardException
 	{
 		boolean				nullable;
 		TypeId				thisType;

Modified: db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/InListOperatorNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/InListOperatorNode.java?rev=1510609&r1=1510608&r2=1510609&view=diff
==============================================================================
--- db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/InListOperatorNode.java (original)
+++ db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/InListOperatorNode.java Mon Aug  5 17:05:13 2013
@@ -151,7 +151,29 @@ public final class InListOperatorNode ex
 			equal.bindComparisonOperator();
 			return equal;
 		}
-		else if ((leftOperand instanceof ColumnReference) &&
+
+        // DERBY-6017: All comparisons have to be performed using the dominant
+        // type of *all* the values in the left operand and the right operand.
+        // If either the left operand is of the dominant type, or all of the
+        // values in the right operand are of the dominant type, we know that
+        // each comparison will be performed using the dominant type.
+        // Otherwise, cast the left operand to the dominant type to ensure
+        // that each comparison operation will use the dominant type.
+        DataTypeDescriptor targetType = getDominantType();
+        int targetTypePrecedence = targetType.getTypeId().typePrecedence();
+        if ((leftOperand.getTypeServices().getTypeId().typePrecedence() !=
+                    targetTypePrecedence) &&
+                !rightOperandList.allSamePrecendence(targetTypePrecedence)) {
+            CastNode cn = (CastNode) getNodeFactory().getNode(
+                    C_NodeTypes.CAST_NODE,
+                    leftOperand,
+                    targetType,
+                    getContextManager());
+            cn.bindCastNodeOnly();
+            leftOperand = cn;
+        }
+
+        if ((leftOperand instanceof ColumnReference) &&
 				 rightOperandList.containsOnlyConstantAndParamNodes())
 		{
 			/* At this point we have an IN-list made up of constant and/or
@@ -236,27 +258,8 @@ public final class InListOperatorNode ex
 				 * would lead to comparisons with truncated values and could
 				 * therefore lead to an incorrect sort order. DERBY-2256.
 				 */
-				DataTypeDescriptor targetType = leftOperand.getTypeServices();
-				TypeId judgeTypeId = targetType.getTypeId();
-
-				if (!rightOperandList.allSamePrecendence(
-					judgeTypeId.typePrecedence()))
-				{
-					/* Iterate through the entire list of values to find out
-					 * what the dominant type is.
-					 */
-					ClassFactory cf = getClassFactory();
-					int sz = rightOperandList.size();
-					for (int i = 0; i < sz; i++)
-					{
-						ValueNode vn = (ValueNode)rightOperandList.elementAt(i);
-						targetType =
-							targetType.getDominantType(
-								vn.getTypeServices(), cf);
-					}
-				}
  
-				/* Now wort the list in ascending order using the dominant
+				/* Now sort the list in ascending order using the dominant
 				 * type found above.
 				 */
 				DataValueDescriptor judgeODV = targetType.getNull();
@@ -369,6 +372,31 @@ public final class InListOperatorNode ex
 	}
 
 	/**
+     * Get the dominant type of all the operands in this IN list.
+     * @return the type descriptor for the dominant type
+     * @see DataTypeDescriptor#getDominantType(DataTypeDescriptor, ClassFactory)
+     */
+    private DataTypeDescriptor getDominantType() {
+        DataTypeDescriptor targetType = leftOperand.getTypeServices();
+        TypeId judgeTypeId = targetType.getTypeId();
+
+        if (!rightOperandList.allSamePrecendence(
+                judgeTypeId.typePrecedence())) {
+            // Iterate through the entire list of values to find out
+            // what the dominant type is.
+            ClassFactory cf = getClassFactory();
+            int sz = rightOperandList.size();
+            for (int i = 0; i < sz; i++) {
+                ValueNode vn = (ValueNode) rightOperandList.elementAt(i);
+                targetType = targetType.getDominantType(
+                        vn.getTypeServices(), cf);
+            }
+        }
+
+        return targetType;
+    }
+
+	/**
 	 * Eliminate NotNodes in the current query block.  We traverse the tree, 
 	 * inverting ANDs and ORs and eliminating NOTs as we go.  We stop at 
 	 * ComparisonOperators and boolean expressions.  We invert 

Modified: db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/ValueNodeList.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/ValueNodeList.java?rev=1510609&r1=1510608&r2=1510609&view=diff
==============================================================================
--- db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/ValueNodeList.java (original)
+++ db/derby/code/branches/10.9/java/engine/org/apache/derby/impl/sql/compile/ValueNodeList.java Mon Aug  5 17:05:13 2013
@@ -260,7 +260,6 @@ public class ValueNodeList extends Query
 	 *			type precendence as the specified value.
 	 */
 	boolean allSamePrecendence(int precedence)
-	throws StandardException
 	{
 		boolean allSame = true;
 		int size = size();

Copied: db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InPredicateTest.java (from r1424889, db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InPredicateTest.java)
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InPredicateTest.java?p2=db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InPredicateTest.java&p1=db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InPredicateTest.java&r1=1424889&r2=1510609&rev=1510609&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InPredicateTest.java (original)
+++ db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/InPredicateTest.java Mon Aug  5 17:05:13 2013
@@ -118,4 +118,72 @@ public class InPredicateTest extends Bas
                 " 9223372036854775807, 9.223372036854776E18)"),
                 allRows);
     }
+
+    /**
+     * Another test case for DERBY-6017. Derby used to evaluate IN lists by
+     * using the semantics of the dominant type of the two values being
+     * compared. It should use the dominant type of all the values in the
+     * left operand and in the IN list. Verify that it works as expected now.
+     */
+    public void testMixedTypes() throws SQLException {
+        setAutoCommit(false);
+
+        // Test an IN predicate that mixes BIGINT and DOUBLE.
+
+        Statement s = createStatement();
+        s.executeUpdate("create table t2(b1 bigint, b2 bigint, d double)");
+        s.executeUpdate("insert into t2 values " +
+                        "(9223372036854775805, 9223372036854775806, 1)");
+
+        // The first query used to return zero rows. However, the next two
+        // queries used to return one row, and SQL:2003, 8.4 <in predicate>
+        // says that the three queries are equivalent. Now, they all return
+        // one row.
+
+        JDBC.assertSingleValueResultSet(
+            s.executeQuery("select true from t2 where b1 in (b2, d)"),
+            "true");
+
+        JDBC.assertSingleValueResultSet(
+            s.executeQuery("select true from t2 where b1 in (values b2, d)"),
+            "true");
+
+        JDBC.assertSingleValueResultSet(
+            s.executeQuery("select true from t2 where b1 = any (values b2, d)"),
+            "true");
+
+        // Test an IN predicate that mixes INT and REAL. They are supposed
+        // to be compared using DOUBLE semantics, but used to be compared as
+        // REALs.
+
+        s.executeUpdate("create table t3 (i1 int, r1 real, r2 real)");
+        s.executeUpdate("insert into t3 values " +
+                        "(2147483645, 2147483645, 2147483645), " +
+                        "(2147483645, 2147483645, 0)");
+
+        Object[][] expectedRows = {
+            {
+                new Integer(2147483645),
+                new Float(2.14748365E9f),
+                new Float(2.14748365E9f),
+            }
+        };
+
+        // The first query used to return two rows. However, the next two
+        // queries used to return one row, and SQL:2003, 8.4 <in predicate>
+        // says that the three queries are equivalent. Now, they all return
+        // one row.
+
+        JDBC.assertFullResultSet(
+            s.executeQuery("select * from t3 where r1 in (i1, r2)"),
+            expectedRows, false);
+
+        JDBC.assertFullResultSet(
+            s.executeQuery("select * from t3 where r1 in (values i1, r2)"),
+            expectedRows, false);
+
+        JDBC.assertFullResultSet(
+            s.executeQuery("select * from t3 where r1 = any (values i1, r2)"),
+            expectedRows, false);
+    }
 }

Modified: db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java?rev=1510609&r1=1510608&r2=1510609&view=diff
==============================================================================
--- db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java (original)
+++ db/derby/code/branches/10.9/java/testing/org/apache/derbyTesting/functionTests/tests/lang/_Suite.java Mon Aug  5 17:05:13 2013
@@ -106,6 +106,7 @@ public class _Suite extends BaseTestCase
         suite.addTest(ScrollCursors2Test.suite());
         suite.addTest(NullIfTest.suite());
         suite.addTest(InListMultiProbeTest.suite());
+        suite.addTest(InPredicateTest.suite());
         suite.addTest(SecurityPolicyReloadingTest.suite());
         suite.addTest(CurrentOfTest.suite());
         suite.addTest(UnaryArithmeticParameterTest.suite());