You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@storm.apache.org by sr...@apache.org on 2015/11/10 19:39:51 UTC

[2/3] storm git commit: Implement nullable semantics for AND, OR and NOT operators.

Implement nullable semantics for AND, OR and NOT operators.


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

Branch: refs/heads/STORM-1040
Commit: 8890de3e098b759d0a2938e06b4841d371066b7e
Parents: 183b5ac
Author: Haohui Mai <wh...@apache.org>
Authored: Wed Nov 4 09:24:32 2015 -0800
Committer: Haohui Mai <wh...@apache.org>
Committed: Wed Nov 4 09:24:32 2015 -0800

----------------------------------------------------------------------
 .../apache/storm/sql/compiler/ExprCompiler.java | 101 +++++++++++++++----
 .../storm/sql/compiler/TestExprSemantic.java    |  49 ++++++---
 2 files changed, 119 insertions(+), 31 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/storm/blob/8890de3e/external/sql/storm-sql-core/src/jvm/org/apache/storm/sql/compiler/ExprCompiler.java
----------------------------------------------------------------------
diff --git a/external/sql/storm-sql-core/src/jvm/org/apache/storm/sql/compiler/ExprCompiler.java b/external/sql/storm-sql-core/src/jvm/org/apache/storm/sql/compiler/ExprCompiler.java
index fd3a614..db97d43 100644
--- a/external/sql/storm-sql-core/src/jvm/org/apache/storm/sql/compiler/ExprCompiler.java
+++ b/external/sql/storm-sql-core/src/jvm/org/apache/storm/sql/compiler/ExprCompiler.java
@@ -17,7 +17,9 @@
  */
 package org.apache.storm.sql.compiler;
 
+import com.google.common.base.Joiner;
 import com.google.common.collect.ImmutableMap;
+import org.apache.calcite.adapter.enumerable.CallImplementor;
 import org.apache.calcite.adapter.enumerable.RexImpTable;
 import org.apache.calcite.adapter.java.JavaTypeFactory;
 import org.apache.calcite.rel.type.RelDataType;
@@ -67,9 +69,9 @@ import static org.apache.calcite.sql.fun.SqlStdOperatorTable.PLUS;
  */
 class ExprCompiler implements RexVisitor<String> {
   private final PrintWriter pw;
-  private final Map<RexNode, String> expr = new IdentityHashMap<>();
   private final JavaTypeFactory typeFactory;
   private static final ImpTable IMP_TABLE = new ImpTable();
+  private int nameCount;
 
   ExprCompiler(PrintWriter pw, JavaTypeFactory typeFactory) {
     this.pw = pw;
@@ -78,14 +80,10 @@ class ExprCompiler implements RexVisitor<String> {
 
   @Override
   public String visitInputRef(RexInputRef rexInputRef) {
-    if (expr.containsKey(rexInputRef)) {
-      return expr.get(rexInputRef);
-    }
     String name = reserveName(rexInputRef);
     String typeName = javaTypeName(rexInputRef);
     pw.print(String.format("%s %s = (%s)(_data.get(%d));\n", typeName, name,
                            typeName, rexInputRef.getIndex()));
-    expr.put(rexInputRef, name);
     return name;
   }
 
@@ -167,8 +165,7 @@ class ExprCompiler implements RexVisitor<String> {
   }
 
   private String reserveName(RexNode node) {
-    String name = "t" + expr.size();
-    expr.put(node, name);
+    String name = "t" + ++nameCount;
     return name;
   }
 
@@ -285,6 +282,9 @@ class ExprCompiler implements RexVisitor<String> {
     }
 
 
+    // If any of the arguments are false, result is false;
+    // else if any arguments are null, result is null;
+    // else true.
     private static final CallExprPrinter AND_EXPR = new CallExprPrinter() {
       @Override
       public String translate(
@@ -293,15 +293,40 @@ class ExprCompiler implements RexVisitor<String> {
         PrintWriter pw = compiler.pw;
         pw.print(String.format("final %s %s;\n", compiler.javaTypeName(call),
                                val));
-        String lhs = call.getOperands().get(0).accept(compiler);
-        pw.print(String.format("if (!(%2$s)) { %1$s = false; }\n", val, lhs));
-        pw.print("else {\n");
-        String rhs = call.getOperands().get(1).accept(compiler);
-        pw.print(String.format("  %1$s = %2$s;\n}\n", val, rhs));
+        RexNode op0 = call.getOperands().get(0);
+        RexNode op1 = call.getOperands().get(1);
+        boolean lhsNullable = op0.getType().isNullable();
+        boolean rhsNullable = op1.getType().isNullable();
+        String lhs = op0.accept(compiler);
+        if (!lhsNullable) {
+          pw.print(String.format("if (!(%2$s)) { %1$s = false; }\n", val, lhs));
+          pw.print("else {\n");
+          String rhs = op1.accept(compiler);
+          pw.print(String.format("  %1$s = %2$s;\n}\n", val, rhs));
+        } else {
+          String foldedLHS = foldNullExpr(
+              String.format("%1$s == null || %1$s", lhs), "true", lhs);
+          pw.print(String.format("if (%s) {\n", foldedLHS));
+          String rhs = op1.accept(compiler);
+          String s;
+          if (rhsNullable) {
+            s = foldNullExpr(
+                String.format("(%2$s != null && !(%2$s)) ? false : %1$s", lhs,
+                              rhs),
+                "null", rhs);
+          } else {
+            s = String.format("!(%2$s) ? false : %1$s", lhs, rhs);
+          }
+          pw.print(String.format("  %1$s = %2$s;\n", val, s));
+          pw.print(String.format("} else { %1$s = false; }\n", val));
+        }
         return val;
       }
     };
 
+    // If any of the arguments are true, result is true;
+    // else if any arguments are null, result is null;
+    // else false.
     private static final CallExprPrinter OR_EXPR = new CallExprPrinter() {
       @Override
       public String translate(
@@ -310,11 +335,32 @@ class ExprCompiler implements RexVisitor<String> {
         PrintWriter pw = compiler.pw;
         pw.print(String.format("final %s %s;\n", compiler.javaTypeName(call),
                                val));
-        String lhs = call.getOperands().get(0).accept(compiler);
-        pw.print(String.format("if (%2$s) { %1$s = true; }\n", val, lhs));
-        pw.print("else {\n");
-        String rhs = call.getOperands().get(1).accept(compiler);
-        pw.print(String.format("  %1$s = %2$s;\n}\n", val, rhs));
+        RexNode op0 = call.getOperands().get(0);
+        RexNode op1 = call.getOperands().get(1);
+        boolean lhsNullable = op0.getType().isNullable();
+        boolean rhsNullable = op1.getType().isNullable();
+        String lhs = op0.accept(compiler);
+        if (!lhsNullable) {
+          pw.print(String.format("if (%2$s) { %1$s = true; }\n", val, lhs));
+          pw.print("else {\n");
+          String rhs = op1.accept(compiler);
+          pw.print(String.format("  %1$s = %2$s;\n}\n", val, rhs));
+        } else {
+          String foldedLHS = foldNullExpr(
+              String.format("%1$s == null || !(%1$s)", lhs), "true", lhs);
+          pw.print(String.format("if (%s) {\n", foldedLHS));
+          String rhs = op1.accept(compiler);
+          String s;
+          if (rhsNullable) {
+            s = foldNullExpr(
+                String.format("(%2$s != null && %2$s) ? true : %1$s", lhs, rhs),
+                "null", rhs);
+          } else {
+            s = String.format("%2$s ? %2$s : %1$s", lhs, rhs);
+          }
+          pw.print(String.format("  %1$s = %2$s;\n", val, s));
+          pw.print(String.format("} else { %1$s = true; }\n", val));
+        }
         return val;
       }
     };
@@ -325,13 +371,30 @@ class ExprCompiler implements RexVisitor<String> {
           ExprCompiler compiler, RexCall call) {
         String val = compiler.reserveName(call);
         PrintWriter pw = compiler.pw;
-        String lhs = call.getOperands().get(0).accept(compiler);
+        RexNode op = call.getOperands().get(0);
+        String lhs = op.accept(compiler);
+        boolean nullable = call.getType().isNullable();
         pw.print(String.format("final %s %s;\n", compiler.javaTypeName(call),
                                val));
-        pw.print(String.format("%1$s = !(%2$s);\n", val, lhs));
+        if (!nullable) {
+          pw.print(String.format("%1$s = !(%2$s);\n", val, lhs));
+        } else {
+          String s = foldNullExpr(
+              String.format("%1$s == null ? null : !(%1$s)", lhs), "null", lhs);
+          pw.print(String.format("%1$s = %2$s;\n", val, s));
+        }
         return val;
       }
     };
+
+    private static String foldNullExpr(String notNullExpr, String
+        nullExpr, String op) {
+      if (op.equals("null")) {
+        return nullExpr;
+      } else {
+        return notNullExpr;
+      }
+    }
   }
 
 }

http://git-wip-us.apache.org/repos/asf/storm/blob/8890de3e/external/sql/storm-sql-core/src/test/org/apache/storm/sql/compiler/TestExprSemantic.java
----------------------------------------------------------------------
diff --git a/external/sql/storm-sql-core/src/test/org/apache/storm/sql/compiler/TestExprSemantic.java b/external/sql/storm-sql-core/src/test/org/apache/storm/sql/compiler/TestExprSemantic.java
index bda9e00..7bde092 100644
--- a/external/sql/storm-sql-core/src/test/org/apache/storm/sql/compiler/TestExprSemantic.java
+++ b/external/sql/storm-sql-core/src/test/org/apache/storm/sql/compiler/TestExprSemantic.java
@@ -43,8 +43,7 @@ public class TestExprSemantic {
   public void testLogicalExpr() throws Exception {
     Values v = testExpr(
         Lists.newArrayList("ID > 0 OR ID < 1", "ID > 0 AND ID < 1",
-                           "NOT (ID > 0 AND ID < 1)"),
-        "WHERE ID > 0 AND ID < 2");
+                           "NOT (ID > 0 AND ID < 1)"));
     assertEquals(new Values(true, false, true), v);
   }
 
@@ -58,12 +57,42 @@ public class TestExprSemantic {
     assertEquals(new Values(true, false, false, true, false, true, false), v);
   }
 
-  private Values testExpr(List<String> exprs, String additionalCaluse)
-      throws Exception {
-    String sql = "SELECT " + Joiner.on(',').join(exprs) + " FROM FOO";
-    if (additionalCaluse != null) {
-      sql += " " + additionalCaluse;
-    }
+  @Test
+  public void testNotWithNull() throws Exception {
+    Values v = testExpr(
+        Lists.newArrayList(
+            "NOT TRUE", "NOT FALSE", "NOT UNKNOWN"
+        ));
+    assertEquals(new Values(false, true, null), v);
+  }
+
+  @Test
+  public void testAndWithNull() throws Exception {
+    Values v = testExpr(
+        Lists.newArrayList(
+            "UNKNOWN AND TRUE", "UNKNOWN AND FALSE", "UNKNOWN AND UNKNOWN",
+            "TRUE AND TRUE", "TRUE AND FALSE", "TRUE AND UNKNOWN",
+            "FALSE AND TRUE", "FALSE AND FALSE", "FALSE AND UNKNOWN"
+        ));
+    assertEquals(new Values(null, false, null, true, false, null, false,
+                            false, false), v);
+  }
+
+  @Test
+  public void testOrWithNull() throws Exception {
+    Values v = testExpr(
+        Lists.newArrayList(
+            "UNKNOWN OR TRUE", "UNKNOWN OR FALSE", "UNKNOWN OR UNKNOWN",
+            "TRUE OR TRUE", "TRUE OR FALSE", "TRUE OR UNKNOWN",
+            "FALSE OR TRUE", "FALSE OR FALSE", "FALSE OR UNKNOWN"
+            ));
+    assertEquals(new Values(true, null, null, true, true, true, true,
+                            false, null), v);
+  }
+
+  private Values testExpr(List<String> exprs) throws Exception {
+    String sql = "SELECT " + Joiner.on(',').join(exprs) + " FROM FOO" +
+        " WHERE ID > 0 AND ID < 2";
     TestUtils.CalciteState state = TestUtils.sqlOverDummyTable(sql);
     PlanCompiler compiler = new PlanCompiler(typeFactory);
     AbstractValuesProcessor proc = compiler.compile(state.tree);
@@ -75,8 +104,4 @@ public class TestExprSemantic {
     return values.get(0);
   }
 
-  private Values testExpr(List<String> exprs) throws Exception {
-    return testExpr(exprs, null);
-  }
-
 }