PHOENIX-2141 ComparisonExpression should return Boolean null if either operand 
is null


Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/bbed18fd
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/bbed18fd
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/bbed18fd

Branch: refs/heads/4.5-HBase-1.0
Commit: bbed18fdb53d214f7927c1881f1b12306d3932d9
Parents: 9227b32
Author: maryannxue <wei....@intel.com>
Authored: Mon Jul 27 14:50:16 2015 -0400
Committer: James Taylor <jtay...@salesforce.com>
Committed: Tue Aug 11 18:42:11 2015 -0700

----------------------------------------------------------------------
 .../phoenix/compile/ExpressionCompiler.java     |  3 +
 .../apache/phoenix/compile/HavingCompiler.java  |  2 +-
 .../apache/phoenix/compile/WhereCompiler.java   |  2 +-
 .../apache/phoenix/compile/WhereOptimizer.java  |  2 +-
 .../phoenix/expression/AndExpression.java       |  3 +
 .../expression/ComparisonExpression.java        |  4 +-
 .../phoenix/expression/LiteralExpression.java   | 23 ++++++--
 .../phoenix/expression/NullValueTest.java       | 59 ++++++++++++++++++++
 8 files changed, 89 insertions(+), 9 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/bbed18fd/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
index 1278494..1523dce 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
@@ -251,6 +251,9 @@ public class ExpressionCompiler extends 
UnsupportedAllParseNodeVisitor<Expressio
             if (child.getDataType() != PBoolean.INSTANCE) {
                 throw TypeMismatchException.newException(PBoolean.INSTANCE, 
child.getDataType(), child.toString());
             }
+            if (LiteralExpression.isBooleanNull(child)) {
+                return child;
+            }
             if (LiteralExpression.isFalse(child)) {
                 iterator.remove();
             }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bbed18fd/phoenix-core/src/main/java/org/apache/phoenix/compile/HavingCompiler.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/HavingCompiler.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/HavingCompiler.java
index 224a9b4..9ccd2f0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/HavingCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/HavingCompiler.java
@@ -54,7 +54,7 @@ public class HavingCompiler {
         if (expression.getDataType() != PBoolean.INSTANCE) {
             throw TypeMismatchException.newException(PBoolean.INSTANCE, 
expression.getDataType(), expression.toString());
         }
-        if (LiteralExpression.isFalse(expression)) {
+        if (LiteralExpression.isBooleanFalseOrNull(expression)) {
             context.setScanRanges(ScanRanges.NOTHING);
             return null;
         } else if (LiteralExpression.isTrue(expression)) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bbed18fd/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
index 9631850..13963d7 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
@@ -235,7 +235,7 @@ public class WhereCompiler {
     private static void setScanFilter(StatementContext context, 
FilterableStatement statement, Expression whereClause, boolean 
disambiguateWithFamily, boolean hashJoinOptimization) {
         Scan scan = context.getScan();
 
-        if (LiteralExpression.isFalse(whereClause)) {
+        if (LiteralExpression.isBooleanFalseOrNull(whereClause)) {
             context.setScanRanges(ScanRanges.NOTHING);
         } else if (whereClause != null && 
!LiteralExpression.isTrue(whereClause) && !hashJoinOptimization) {
             Filter filter = null;

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bbed18fd/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java 
b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java
index 6dfae7e..601eee1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereOptimizer.java
@@ -120,7 +120,7 @@ public class WhereOptimizer {
             context.setScanRanges(ScanRanges.EVERYTHING);
             return whereClause;
         }
-        if (LiteralExpression.isFalse(whereClause)) {
+        if (LiteralExpression.isBooleanFalseOrNull(whereClause)) {
             context.setScanRanges(ScanRanges.NOTHING);
             return null;
         }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bbed18fd/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
index 70e94ca..29b024d 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/AndExpression.java
@@ -44,6 +44,9 @@ public class AndExpression extends AndOrExpression {
             if (child.getDataType() != PBoolean.INSTANCE) {
                 throw TypeMismatchException.newException(PBoolean.INSTANCE, 
child.getDataType(), child.toString());
             }
+            if (LiteralExpression.isBooleanNull(child)) {
+                return child;
+            }
             if (LiteralExpression.isFalse(child)) {
                 return child;
             }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bbed18fd/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java
index 1c8df20..074ac0a 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/ComparisonExpression.java
@@ -142,7 +142,7 @@ public class ComparisonExpression extends 
BaseCompoundExpression {
         if (lhsExpr instanceof LiteralExpression) {
             lhsValue = ((LiteralExpression)lhsExpr).getValue();
             if (lhsValue == null) {
-                return LiteralExpression.newConstant(false, PBoolean.INSTANCE, 
lhsExpr.getDeterminism());
+                return LiteralExpression.newConstant(null, PBoolean.INSTANCE, 
lhsExpr.getDeterminism());
             }
         }
         Object rhsValue = null;
@@ -150,7 +150,7 @@ public class ComparisonExpression extends 
BaseCompoundExpression {
         if (rhsExpr instanceof LiteralExpression) {
             rhsValue = ((LiteralExpression)rhsExpr).getValue();
             if (rhsValue == null) {
-                return LiteralExpression.newConstant(false, PBoolean.INSTANCE, 
rhsExpr.getDeterminism());
+                return LiteralExpression.newConstant(null, PBoolean.INSTANCE, 
rhsExpr.getDeterminism());
             }
         }
         if (lhsValue != null && rhsValue != null) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bbed18fd/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
index 05bd9b3..e911aae 100644
--- 
a/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
+++ 
b/phoenix-core/src/main/java/org/apache/phoenix/expression/LiteralExpression.java
@@ -89,10 +89,10 @@ public class LiteralExpression extends 
BaseTerminalExpression {
     }
 
     public static boolean isFalse(Expression child) {
-       if (child!=null) {
-               return child == 
BOOLEAN_EXPRESSIONS[child.getDeterminism().ordinal()];
-       }
-       return false;
+        if (child!=null) {
+            return child == 
BOOLEAN_EXPRESSIONS[child.getDeterminism().ordinal()];
+        }
+        return false;
     }
     
     public static boolean isTrue(Expression child) {
@@ -101,6 +101,21 @@ public class LiteralExpression extends 
BaseTerminalExpression {
        }
        return false;
     }
+
+    public static boolean isBooleanNull(Expression child) {
+       if (child!=null) {
+               return child == 
TYPED_NULL_EXPRESSIONS[PBoolean.INSTANCE.ordinal()+PDataType.values().length*child.getDeterminism().ordinal()];
+       }
+       return false;
+    }
+
+    public static boolean isBooleanFalseOrNull(Expression child) {
+        if (child!=null) {
+            return child == 
BOOLEAN_EXPRESSIONS[child.getDeterminism().ordinal()]
+                    || child == 
TYPED_NULL_EXPRESSIONS[PBoolean.INSTANCE.ordinal()+PDataType.values().length*child.getDeterminism().ordinal()];
+        }
+        return false;
+    }
     
     public static LiteralExpression newConstant(Object value) {
         return newConstant(value, Determinism.ALWAYS);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/bbed18fd/phoenix-core/src/test/java/org/apache/phoenix/expression/NullValueTest.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/test/java/org/apache/phoenix/expression/NullValueTest.java 
b/phoenix-core/src/test/java/org/apache/phoenix/expression/NullValueTest.java
new file mode 100644
index 0000000..d5addf0
--- /dev/null
+++ 
b/phoenix-core/src/test/java/org/apache/phoenix/expression/NullValueTest.java
@@ -0,0 +1,59 @@
+package org.apache.phoenix.expression;
+
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.util.Properties;
+
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.util.PropertiesUtil;
+import org.junit.Test;
+
+public class NullValueTest extends BaseConnectionlessQueryTest {
+    
+    @Test
+    public void testComparisonExpressionWithNullOperands() throws Exception {
+        String[] query = {"SELECT 'a' >= ''", 
+                          "SELECT '' < 'a'", 
+                          "SELECT '' = ''"};
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            for (String q : query) {
+                ResultSet rs = conn.createStatement().executeQuery(q);
+                assertTrue(rs.next());
+                assertNull(rs.getObject(1));
+                assertEquals(false, rs.getBoolean(1));
+                assertFalse(rs.next());
+            }
+        } finally {
+            conn.close();
+        }       
+    }
+    
+    @Test
+    public void testAndOrExpressionWithNullOperands() throws Exception {
+        String[] query = {"SELECT 'a' >= '' or '' < 'a'", 
+                          "SELECT 'a' >= '' and '' < 'a'"};
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        Connection conn = DriverManager.getConnection(getUrl(), props);
+        try {
+            for (String q : query) {
+                ResultSet rs = conn.createStatement().executeQuery(q);
+                assertTrue(rs.next());
+                assertNull(rs.getObject(1));
+                assertEquals(false, rs.getBoolean(1));
+                assertFalse(rs.next());
+            }
+        } finally {
+            conn.close();
+        }       
+    }
+
+}

Reply via email to