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 ka...@apache.org on 2013/10/07 11:33:08 UTC

svn commit: r1529805 - in /db/derby/code/branches/10.10: ./ java/engine/org/apache/derby/impl/sql/compile/OrNode.java java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java

Author: kahatlen
Date: Mon Oct  7 09:33:08 2013
New Revision: 1529805

URL: http://svn.apache.org/r1529805
Log:
DERBY-6363: Incorrect evaluation of logical expressions in CASE

Merged revision 1529099 from trunk.

Modified:
    db/derby/code/branches/10.10/   (props changed)
    db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/OrNode.java
    db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java

Propchange: db/derby/code/branches/10.10/
------------------------------------------------------------------------------
  Merged /db/derby/code/trunk:r1529099

Modified: db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/OrNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/OrNode.java?rev=1529805&r1=1529804&r2=1529805&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/OrNode.java (original)
+++ db/derby/code/branches/10.10/java/engine/org/apache/derby/impl/sql/compile/OrNode.java Mon Oct  7 09:33:08 2013
@@ -115,6 +115,25 @@ public class OrNode extends BinaryLogica
 		 *	or:
 		 *		x = ColumnReference
 		 * where all ColumnReferences are from the same table.
+         *
+         * We only convert the OR chain to an IN list if it has been
+         * normalized to conjunctive normal form (CNF) first. That is, the
+         * shape of the chain must be something like this:
+         *
+         *               OR
+         *              /  \
+         *             =    OR
+         *                 /  \
+         *                =   OR
+         *                    / \
+         *                   =   FALSE
+         *
+         * Predicates in WHERE, HAVING and ON clauses will have been
+         * normalized by the time we get here. Boolean expressions other
+         * places in the query are not necessarily normalized, but they
+         * won't benefit from IN list conversion anyway, since they cannot
+         * be used as qualifiers in a multi-probe scan, so simply skip the
+         * conversion in those cases.
 		 */
 		if (firstOr)
 		{
@@ -122,8 +141,11 @@ public class OrNode extends BinaryLogica
 			ColumnReference	cr = null;
 			int				columnNumber = -1;
 			int				tableNumber = -1;
+            ValueNode       vn;
 
-			for (ValueNode vn = this; vn instanceof OrNode; vn = ((OrNode) vn).getRightOperand())
+            for (vn = this;
+                    vn instanceof OrNode;
+                    vn = ((OrNode) vn).getRightOperand())
 			{
 				OrNode on = (OrNode) vn;
 				ValueNode left = on.getLeftOperand();
@@ -210,6 +232,12 @@ public class OrNode extends BinaryLogica
 				}
 			}
 
+            // DERBY-6363: An OR chain on conjunctive normal form should be
+            // terminated by a false BooleanConstantNode. If it is terminated
+            // by some other kind of node, it is not on CNF, and it should
+            // not be converted to an IN list.
+            convert = convert && vn.isBooleanFalse();
+
 			/* So, can we convert the OR chain? */
 			if (convert)
 			{
@@ -217,7 +245,9 @@ public class OrNode extends BinaryLogica
 													C_NodeTypes.VALUE_NODE_LIST,
 													getContextManager());
 				// Build the IN list 
-				for (ValueNode vn = this; vn instanceof OrNode; vn = ((OrNode) vn).getRightOperand())
+                for (vn = this;
+                        vn instanceof OrNode;
+                        vn = ((OrNode) vn).getRightOperand())
 				{
 					OrNode on = (OrNode) vn;
 					BinaryRelationalOperatorNode bron =
@@ -460,7 +490,7 @@ public class OrNode extends BinaryLogica
 			}
 			else
 			{
-				isValid = leftOperand.verifyChangeToCNF();
+				isValid = isValid && leftOperand.verifyChangeToCNF();
 			}
 		}
 

Modified: db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java?rev=1529805&r1=1529804&r2=1529805&view=diff
==============================================================================
--- db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java (original)
+++ db/derby/code/branches/10.10/java/testing/org/apache/derbyTesting/functionTests/tests/lang/BooleanValuesTest.java Mon Oct  7 09:33:08 2013
@@ -2139,6 +2139,50 @@ public class BooleanValuesTest  extends 
                 "values case when 1 or 2 then 1 else 0 end");
     }
     
+    /**
+     * Some BOOLEAN expressions used to be transformed to non-equivalent
+     * IN lists. Verify that they now return the correct results.
+     * Regression test case for DERBY-6363.
+     */
+    public void test_6363() throws SQLException {
+        Statement s = createStatement();
+        s.execute("create table d6363(a int, b char)");
+        s.execute("insert into d6363 values (1, 'a'), (2, 'b'), (3, 'a'), "
+                + "(4, 'b'), (5, 'a'), (6, 'b')");
+
+        JDBC.assertFullResultSet(s.executeQuery(
+            "select a, ((b = 'a' or b = 'b') and a < 4), "
+                    + "((b = 'a' or b = 'c' or b = 'b') and a < 4), "
+                    + "((b = 'a' or (b = 'c' or b = 'b')) and a < 4), "
+                    + "((b = 'a' or b in ('c', 'b')) and a < 4), "
+                    + "(a < 4 and (b = 'a' or b = 'b')) "
+                    + "from d6363 order by a"),
+            new String[][] {
+                { "1", "true", "true", "true", "true", "true" },
+                { "2", "true", "true", "true", "true", "true" },
+                { "3", "true", "true", "true", "true", "true" },
+                { "4", "false", "false", "false", "false", "false" },
+                { "5", "false", "false", "false", "false", "false" },
+                { "6", "false", "false", "false", "false", "false" },
+            });
+
+        JDBC.assertFullResultSet(s.executeQuery(
+            "select a, b, "
+            + "case when ((b = 'a' or b = 'b') and a < 4) "
+            + "then 'x' else '-' end, "
+            + "case when (a < 4 and (b = 'a' or b = 'b')) "
+            + "then 'y' else '-' end "
+            + "from d6363 order by a"),
+            new String[][] {
+                { "1", "a", "x", "y" },
+                { "2", "b", "x", "y" },
+                { "3", "a", "x", "y" },
+                { "4", "b", "-", "-" },
+                { "5", "a", "-", "-" },
+                { "6", "b", "-", "-" },
+            });
+    }
+
     ///////////////////////////////////////////////////////////////////////////////////
     //
     // SQL ROUTINES