db-derby-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kahat...@apache.org
Subject svn commit: r1592945 - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/compile/ testing/org/apache/derbyTesting/functionTests/tests/lang/
Date Wed, 07 May 2014 07:56:37 GMT
Author: kahatlen
Date: Wed May  7 07:56:37 2014
New Revision: 1592945

URL: http://svn.apache.org/r1592945
Log:
DERBY-6563: NOT elimination for CASE expressions is broken

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

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ConditionalNode.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ConditionalNode.java?rev=1592945&r1=1592944&r2=1592945&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ConditionalNode.java
(original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/ConditionalNode.java
Wed May  7 07:56:37 2014
@@ -660,19 +660,19 @@ class ConditionalNode extends ValueNode
 	ValueNode eliminateNots(boolean underNotNode) 
 					throws StandardException
 	{
-		ValueNode thenExpression;
-		ValueNode elseExpression;
-
-		if (! underNotNode)
-		{
-			return this;
-		}
-
-		/* Simply swap the then and else expressions */
-        thenExpression = thenElseList.elementAt(0);
-        elseExpression = thenElseList.elementAt(1);
-		thenElseList.setElementAt(elseExpression, 0);
-		thenElseList.setElementAt(thenExpression, 1);
+        // NOT CASE WHEN a THEN b ELSE c END is equivalent to
+        // CASE WHEN a THEN NOT b ELSE NOT c END, so just push the
+        // NOT node down to the THEN and ELSE expressions.
+        for (int i = 0; i < thenElseList.size(); i++) {
+            thenElseList.setElementAt(
+                    thenElseList.elementAt(i).eliminateNots(underNotNode),
+                    i);
+        }
+
+        // Eliminate NOTs in the WHEN expression too. The NOT node above us
+        // should not be pushed into the WHEN expression, though, as that
+        // would alter the meaning of the CASE expression.
+        testCondition = testCondition.eliminateNots(false);
 
 		return this;
 	}

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CaseExpressionTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CaseExpressionTest.java?rev=1592945&r1=1592944&r2=1592945&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CaseExpressionTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/CaseExpressionTest.java
Wed May  7 07:56:37 2014
@@ -21,11 +21,13 @@
 
 package org.apache.derbyTesting.functionTests.tests.lang;
 
-import java.sql.Connection;
+import java.sql.PreparedStatement;
 import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.Statement;
 import java.sql.ResultSet;
+import java.util.ArrayList;
+import java.util.Arrays;
 
 import junit.framework.Test;
 import junit.framework.TestSuite;
@@ -378,5 +380,91 @@ public class CaseExpressionTest extends 
         JDBC.assertSingleValueResultSet(rs, "6");
         
     }
-    
+
+    /**
+     * Verify that NOT elimination produces the correct results.
+     * DERBY-6563.
+     */
+    public void testNotElimination() throws SQLException {
+        setAutoCommit(false);
+
+        Statement s = createStatement();
+        s.execute("create table d6563(b1 boolean, b2 boolean, b3 boolean)");
+
+        // Fill the table with all possible combinations of true/false/null.
+        Boolean[] universe = { true, false, null };
+        PreparedStatement insert = prepareStatement(
+                "insert into d6563 values (?, ?, ?)");
+        for (Boolean v1 : universe) {
+            insert.setObject(1, v1);
+            for (Boolean v2 : universe) {
+                insert.setObject(2, v2);
+                for (Boolean v3 : universe) {
+                    insert.setObject(3, v3);
+                    insert.executeUpdate();
+                }
+            }
+        }
+
+        // Truth table for
+        // B1, B2, B3, WHEN B1 THEN B2 ELSE B3, NOT (WHEN B1 THEN B2 ELSE B3).
+        Object[][] expectedRows = {
+            { false, false, false, false, true  },
+            { false, false, true,  true,  false },
+            { false, false, null,  null,  null  },
+            { false, true,  false, false, true  },
+            { false, true,  true,  true,  false },
+            { false, true,  null,  null,  null  },
+            { false, null,  false, false, true  },
+            { false, null,  true,  true,  false },
+            { false, null,  null,  null,  null  },
+            { true,  false, false, false, true  },
+            { true,  false, true,  false, true  },
+            { true,  false, null,  false, true  },
+            { true,  true,  false, true,  false },
+            { true,  true,  true,  true,  false },
+            { true,  true,  null,  true,  false },
+            { true,  null,  false, null,  null  },
+            { true,  null,  true,  null,  null  },
+            { true,  null,  null,  null,  null  },
+            { null,  false, false, false, true  },
+            { null,  false, true,  true,  false },
+            { null,  false, null,  null,  null  },
+            { null,  true,  false, false, true  },
+            { null,  true,  true,  true,  false },
+            { null,  true,  null,  null,  null  },
+            { null,  null,  false, false, true  },
+            { null,  null,  true,  true,  false },
+            { null,  null,  null,  null,  null  },
+        };
+
+        // Verify the truth table. Since NOT elimination is not performed on
+        // expressions in the SELECT list, this passed even before the fix.
+        JDBC.assertFullResultSet(
+            s.executeQuery(
+                "select b1, b2, b3, case when b1 then b2 else b3 end, "
+                        + "not case when b1 then b2 else b3 end "
+                        + "from d6563 order by b1, b2, b3"),
+            expectedRows, false);
+
+        // Now take only those rows where the NOT CASE expression evaluated
+        // to TRUE, and strip off the expression columns at the end.
+        ArrayList<Object[]> rows = new ArrayList<Object[]>();
+        for (Object[] row : expectedRows) {
+            if (row[4] == Boolean.TRUE) {
+                rows.add(Arrays.copyOf(row, 3));
+            }
+        }
+
+        // Assert that those are the only rows returned if the NOT CASE
+        // expression is used as a predicate. This query used to return a
+        // different set of rows before the fix.
+        expectedRows = rows.toArray(new Object[rows.size()][]);
+        JDBC.assertFullResultSet(
+                s.executeQuery("select * from d6563 where "
+                        + "not case when b1 then b2 else b3 end "
+                        + "order by b1, b2, b3"),
+                expectedRows, false);
+    }
+
 }

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullIfTest.java
URL: http://svn.apache.org/viewvc/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullIfTest.java?rev=1592945&r1=1592944&r2=1592945&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullIfTest.java
(original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/NullIfTest.java
Wed May  7 07:56:37 2014
@@ -305,6 +305,51 @@ public class NullIfTest extends BaseJDBC
     }
 
     /**
+     * Verify that NOT elimination produces the correct results.
+     * DERBY-6563.
+     */
+    public void testNotElimination() throws SQLException {
+        setAutoCommit(false);
+
+        Statement s = createStatement();
+        s.execute("create table d6563(b1 boolean, b2 boolean)");
+        s.execute("insert into d6563 values (true, true), (true, false), "
+                + "(true, null), (false, true), (false, false), "
+                + "(false, null), (null, null), (null, true), (null, false)");
+
+        // Truth table for B1, B2, NULLIF(B1, B2), NOT NULLIF(B1, B2).
+        Object[][] expectedRows = {
+            { false, false, null,  null  },
+            { false, true,  false, true  },
+            { false, null,  false, true  },
+            { true,  false, true,  false },
+            { true,  true,  null,  null  },
+            { true,  null,  true,  false },
+            { null,  false, null,  null  },
+            { null,  true,  null,  null  },
+            { null,  null,  null,  null  },
+        };
+
+        // Verify the truth table. Since NOT elimination is not performed on
+        // expressions in the SELECT list, this passed even before the fix.
+        JDBC.assertFullResultSet(
+            s.executeQuery(
+                "select b1 , b2, nullif(b1, b2), not nullif(b1, b2) "
+                        + "from d6563 order by b1, b2"),
+            expectedRows, false);
+
+        // Only two rows - (false, true) and (false, null) - made
+        // NOT NULLIF(B1, B2) evaluate to TRUE. Verify that it also evaluates
+        // to TRUE for those two rows, and only those two rows, when it is
+        // used as a predicate. The query used to return (true, true).
+        JDBC.assertFullResultSet(
+            s.executeQuery(
+                "select * from d6563 where not nullif(b1, b2) order by b1, b2"),
+            new Object[][] { { false, true }, { false, null } },
+            false);
+    }
+
+    /**
      * Runs the test fixtures in embedded and client.
      * 
      * @return test suite



Mime
View raw message