This is an automated email from the ASF dual-hosted git repository.

jhyde pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/calcite.git

commit b432756e2be9ad0557a56254550eb4438dd0efcf
Author: Julian Hyde <[email protected]>
AuthorDate: Fri Aug 2 17:59:01 2019 -0700

    Deprecate RexBuilder.constantNull(), because it produces untyped NULL 
literals that make planning difficult
    
    We cannot deprecate RelBuilder.literal(null), but remove all uses of
    in internal code, for similar reasons.
---
 .../org/apache/calcite/rel/core/TableScan.java     |   6 +-
 .../AggregateExpandDistinctAggregatesRule.java     |   3 +-
 .../rel/rules/AggregateReduceFunctionsRule.java    |  65 +++++-------
 .../calcite/rel/rules/AggregateValuesRule.java     |   3 +-
 .../calcite/rel/rules/LoptOptimizeJoinRule.java    |   3 +-
 .../calcite/rel/rules/SubQueryRemoveRule.java      | 115 +++++++++++----------
 .../apache/calcite/rel/rules/ValuesReduceRule.java |  11 +-
 .../java/org/apache/calcite/rex/RexBuilder.java    |   8 +-
 .../sql2rel/NullInitializerExpressionFactory.java  |   8 +-
 .../apache/calcite/sql2rel/RelDecorrelator.java    |  25 ++---
 .../sql2rel/RelStructuredTypeFlattener.java        |   7 +-
 .../calcite/sql2rel/SqlNodeToRexConverterImpl.java |   4 +-
 .../calcite/sql2rel/StandardConvertletTable.java   |  11 +-
 .../java/org/apache/calcite/tools/RelBuilder.java  |   3 +-
 .../org/apache/calcite/test/RexProgramTest.java    |   6 +-
 .../catalog/EmpInitializerExpressionFactory.java   |   2 +-
 .../org/apache/calcite/test/RelOptRulesTest.xml    |  32 +++---
 core/src/test/resources/sql/blank.iq               |   2 +-
 core/src/test/resources/sql/sub-query.iq           |   4 +-
 19 files changed, 148 insertions(+), 170 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/rel/core/TableScan.java 
b/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
index d87715b..07dce01 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/TableScan.java
@@ -152,11 +152,7 @@ public abstract class TableScan extends AbstractRelNode {
     // Project nulls for the extra fields. (Maybe a sub-class table has
     // extra fields, but we don't.)
     for (RelDataTypeField extraField : extraFields) {
-      exprList.add(
-          rexBuilder.ensureType(
-              extraField.getType(),
-              rexBuilder.constantNull(),
-              true));
+      exprList.add(rexBuilder.makeNullLiteral(extraField.getType()));
       nameList.add(extraField.getName());
     }
 
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
index d773d80..1a75136 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateExpandDistinctAggregatesRule.java
@@ -824,8 +824,7 @@ public final class AggregateExpandDistinctAggregatesRule 
extends RelOptRule {
             rexBuilder.makeCall(SqlStdOperatorTable.CASE, filterRef,
                 argRef.left,
                 rexBuilder.ensureType(argRef.left.getType(),
-                    rexBuilder.makeCast(argRef.left.getType(),
-                        rexBuilder.constantNull()),
+                    rexBuilder.makeNullLiteral(argRef.left.getType()),
                     true));
         sourceOf.put(arg, projects.size());
         projects.add(Pair.of(condition, "i$" + argRef.right));
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
 
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
index b97a9bb..80e7ae7 100644
--- 
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
+++ 
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
@@ -475,7 +475,7 @@ public class AggregateReduceFunctionsRule extends 
RelOptRule {
     return rexBuilder.makeCall(SqlStdOperatorTable.CASE,
         rexBuilder.makeCall(SqlStdOperatorTable.EQUALS,
             countRef, rexBuilder.makeExactLiteral(BigDecimal.ZERO)),
-        rexBuilder.makeCast(sumZeroRef.getType(), rexBuilder.constantNull()),
+        rexBuilder.makeNullLiteral(sumZeroRef.getType()),
         sumZeroRef);
   }
 
@@ -572,46 +572,18 @@ public class AggregateReduceFunctionsRule extends 
RelOptRule {
             aggCallMapping,
             ImmutableList.of(argOrdinalType));
 
-    final RexNode avgSumSquaredArg =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.DIVIDE, sumSquaredArg, countArg);
-
-    final RexNode diff =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.MINUS,
-            sumArgSquared, avgSumSquaredArg);
-
-    final RexNode denominator;
-    if (biased) {
-      denominator = countArg;
-    } else {
-      final RexLiteral one =
-          rexBuilder.makeExactLiteral(BigDecimal.ONE);
-      final RexNode nul =
-          rexBuilder.makeCast(countArg.getType(), rexBuilder.constantNull());
-      final RexNode countMinusOne =
-          rexBuilder.makeCall(
-              SqlStdOperatorTable.MINUS, countArg, one);
-      final RexNode countEqOne =
-          rexBuilder.makeCall(
-              SqlStdOperatorTable.EQUALS, countArg, one);
-      denominator =
-          rexBuilder.makeCall(
-              SqlStdOperatorTable.CASE,
-              countEqOne, nul, countMinusOne);
-    }
+    final RexNode div = divide(biased, rexBuilder, sumArgSquared, 
sumSquaredArg,
+        countArg);
 
-    final RexNode div =
-        rexBuilder.makeCall(
-            SqlStdOperatorTable.DIVIDE, diff, denominator);
-
-    RexNode result = div;
+    final RexNode result;
     if (sqrt) {
       final RexNode half =
           rexBuilder.makeExactLiteral(new BigDecimal("0.5"));
       result =
           rexBuilder.makeCall(
               SqlStdOperatorTable.POWER, div, half);
+    } else {
+      result = div;
     }
 
     return rexBuilder.makeCast(
@@ -750,7 +722,7 @@ public class AggregateReduceFunctionsRule extends 
RelOptRule {
         ImmutableIntList.of(xIndex), ImmutableList.of(argXType), 
argXAndYNotNullFilterOrdinal);
 
     RexLiteral zero = rexBuilder.makeExactLiteral(BigDecimal.ZERO);
-    RexNode nul = rexBuilder.constantNull();
+    RexNode nul = rexBuilder.makeNullLiteral(zero.getType());
     final RexNode avgSumXSumY = rexBuilder.makeCall(SqlStdOperatorTable.CASE,
         rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, countArg, zero), nul,
             rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, sumXSumY, 
countArg));
@@ -803,21 +775,30 @@ public class AggregateReduceFunctionsRule extends 
RelOptRule {
         ImmutableIntList.of(argXOrdinal, argYOrdinal),
         ImmutableList.of(argXOrdinalType, argYOrdinalType),
         argXAndYNotNullFilterOrdinal);
+    final RexNode result = divide(biased, rexBuilder, sumXY, sumXSumY, 
countArg);
+    return rexBuilder.makeCast(oldCall.getType(), result);
+  }
+
+  private RexNode divide(boolean biased, RexBuilder rexBuilder, RexNode sumXY,
+      RexNode sumXSumY, RexNode countArg) {
     final RexNode avgSumSquaredArg =
          rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, sumXSumY, countArg);
-    final RexNode diff = rexBuilder.makeCall(SqlStdOperatorTable.MINUS, sumXY, 
avgSumSquaredArg);
+    final RexNode diff =
+        rexBuilder.makeCall(SqlStdOperatorTable.MINUS, sumXY, 
avgSumSquaredArg);
     final RexNode denominator;
     if (biased) {
       denominator = countArg;
     } else {
       final RexLiteral one = rexBuilder.makeExactLiteral(BigDecimal.ONE);
-      final RexNode nul = rexBuilder.makeCast(countArg.getType(), 
rexBuilder.constantNull());
-      final RexNode countMinusOne = 
rexBuilder.makeCall(SqlStdOperatorTable.MINUS, countArg, one);
-      final RexNode countEqOne = 
rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, countArg, one);
-      denominator = rexBuilder.makeCall(SqlStdOperatorTable.CASE, countEqOne, 
nul, countMinusOne);
+      final RexNode nul = rexBuilder.makeNullLiteral(countArg.getType());
+      final RexNode countMinusOne =
+          rexBuilder.makeCall(SqlStdOperatorTable.MINUS, countArg, one);
+      final RexNode countEqOne =
+          rexBuilder.makeCall(SqlStdOperatorTable.EQUALS, countArg, one);
+      denominator = rexBuilder.makeCall(SqlStdOperatorTable.CASE, countEqOne,
+          nul, countMinusOne);
     }
-    final RexNode result = rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, 
diff, denominator);
-    return rexBuilder.makeCast(oldCall.getType(), result);
+    return rexBuilder.makeCall(SqlStdOperatorTable.DIVIDE, diff, denominator);
   }
 
   /**
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/AggregateValuesRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/AggregateValuesRule.java
index d61cb95..67e474a 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateValuesRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateValuesRule.java
@@ -89,8 +89,7 @@ public class AggregateValuesRule extends RelOptRule {
       case MIN:
       case MAX:
       case SUM:
-        literals.add((RexLiteral) rexBuilder.makeCast(
-            aggregateCall.getType(), rexBuilder.constantNull()));
+        literals.add(rexBuilder.makeNullLiteral(aggregateCall.getType()));
         break;
 
       default:
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
index 57a108c..a8cbc93 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/LoptOptimizeJoinRule.java
@@ -1651,8 +1651,7 @@ public class LoptOptimizeJoinRule extends RelOptRule {
           newType =
               typeFactory.createTypeWithNullability(newType, true);
         }
-        projExpr =
-            rexBuilder.makeCast(newType, rexBuilder.constantNull());
+        projExpr = rexBuilder.makeNullLiteral(newType);
       } else {
         RelDataTypeField mappedField = currFields.get(replacementKeys[i]);
         RexNode mappedInput =
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
index eb1ae08..39b257a 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/SubQueryRemoveRule.java
@@ -32,14 +32,15 @@ import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rex.LogicVisitor;
 import org.apache.calcite.rex.RexCorrelVariable;
 import org.apache.calcite.rex.RexInputRef;
+import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexShuttle;
 import org.apache.calcite.rex.RexSubQuery;
 import org.apache.calcite.rex.RexUtil;
+import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.fun.SqlQuantifyOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
-import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql2rel.RelDecorrelator;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
@@ -167,9 +168,15 @@ public abstract class SubQueryRemoveRule extends 
RelOptRule {
     assert op == SqlStdOperatorTable.SOME_GE || op == 
SqlStdOperatorTable.SOME_LE
         || op == SqlStdOperatorTable.SOME_LT || op == 
SqlStdOperatorTable.SOME_GT;
 
-    RexNode caseRexNode = null;
-    boolean useMin = op.comparisonKind == SqlKind.GREATER_THAN
-        || op.comparisonKind == SqlKind.GREATER_THAN_OR_EQUAL;
+    final RexNode caseRexNode;
+    final RexNode literalFalse = builder.literal(false);
+    final RexNode literalTrue = builder.literal(true);
+    final RexLiteral literalUnknown =
+        builder.getRexBuilder().makeNullLiteral(literalFalse.getType());
+    final SqlAggFunction minMax = op.comparisonKind == SqlKind.GREATER_THAN
+        || op.comparisonKind == SqlKind.GREATER_THAN_OR_EQUAL
+        ? SqlStdOperatorTable.MIN
+        : SqlStdOperatorTable.MAX;
 
     if (variablesSet.isEmpty()) {
       // for non-correlated case queries such as
@@ -191,8 +198,7 @@ public abstract class SubQueryRemoveRule extends RelOptRule 
{
       //   from emp) as q
       builder.push(e.rel).
           aggregate(builder.groupKey(),
-              useMin ? builder.min("m", builder.field(0))
-                  : builder.max("m", builder.field(0)),
+              builder.aggregateCall(minMax, builder.field(0)).as("m"),
               builder.count(false, "c"),
               builder.count(false, "d", builder.field(0)))
           .as("q")
@@ -200,20 +206,21 @@ public abstract class SubQueryRemoveRule extends 
RelOptRule {
       caseRexNode = builder.call(SqlStdOperatorTable.CASE,
           builder.call(SqlStdOperatorTable.EQUALS, builder.field("q", "c"),
               builder.literal(0)),
-          builder.literal(false),
+          literalFalse,
           builder.call(SqlStdOperatorTable.IS_TRUE,
-              builder.call(RelOptUtil.op(op.comparisonKind, null), 
e.operands.get(0),
-                  builder.field("q", "m"))),
-          builder.literal(true),
-          builder.call(SqlStdOperatorTable.GREATER_THAN, builder.field("q", 
"c"),
-                  builder.field("q", "d")),
-          e.rel.getCluster().getRexBuilder().makeNullLiteral(
-              builder.getTypeFactory().createSqlType(SqlTypeName.BOOLEAN)),
-          builder.call(RelOptUtil.op(op.comparisonKind, null), 
e.operands.get(0),
-                  builder.field("q", "m")));
+              builder.call(RelOptUtil.op(op.comparisonKind, null),
+                  e.operands.get(0), builder.field("q", "m"))),
+          literalTrue,
+          builder.call(SqlStdOperatorTable.GREATER_THAN,
+              builder.field("q", "c"), builder.field("q", "d")),
+          literalUnknown,
+          builder.call(RelOptUtil.op(op.comparisonKind, null),
+              e.operands.get(0), builder.field("q", "m")));
     } else {
       // for correlated case queries such as
-      // select e.deptno, e.deptno < some (select deptno from emp where 
emp.name = e.name) as v
+      //
+      // select e.deptno, e.deptno < some (
+      //   select deptno from emp where emp.name = e.name) as v
       // from emp as e
       //
       // becomes
@@ -228,44 +235,44 @@ public abstract class SubQueryRemoveRule extends 
RelOptRule {
       //   end as v
       // from emp as e
       // left outer join (
-      //   select max(deptno) as m, count(*) as c, count(deptno) as d, 
"alwaysTrue" as indicator
+      //   select max(deptno) as m, count(*) as c, count(deptno) as d,
+      //       "alwaysTrue" as indicator
       //   group by name from emp) as q on e.name = q.name
       builder.push(e.rel)
           .aggregate(builder.groupKey(),
-              useMin ? builder.min("m", builder.field(0))
-                  : builder.max("m", builder.field(0)),
+              builder.aggregateCall(minMax, builder.field(0)).as("m"),
               builder.count(false, "c"),
               builder.count(false, "d", builder.field(0)));
 
       final List<RexNode> parentQueryFields = new ArrayList<>();
       parentQueryFields.addAll(builder.fields());
       String indicator = "trueLiteral";
-      parentQueryFields.add(builder.alias(builder.literal(true), indicator));
+      parentQueryFields.add(builder.alias(literalTrue, indicator));
       builder.project(parentQueryFields).as("q");
-      builder.join(JoinRelType.LEFT, builder.literal(true), variablesSet);
+      builder.join(JoinRelType.LEFT, literalTrue, variablesSet);
       caseRexNode = builder.call(SqlStdOperatorTable.CASE,
-          builder.call(SqlStdOperatorTable.IS_NULL, builder.field("q", 
indicator)),
-          builder.literal(false),
+          builder.call(SqlStdOperatorTable.IS_NULL,
+              builder.field("q", indicator)),
+          literalFalse,
           builder.call(SqlStdOperatorTable.EQUALS, builder.field("q", "c"),
               builder.literal(0)),
-          builder.literal(false),
+          literalFalse,
           builder.call(SqlStdOperatorTable.IS_TRUE,
-              builder.call(RelOptUtil.op(op.comparisonKind, null), 
e.operands.get(0),
-                  builder.field("q", "m"))),
-          builder.literal(true),
-          builder.call(SqlStdOperatorTable.GREATER_THAN, builder.field("q", 
"c"),
-                  builder.field("q", "d")),
-          e.rel.getCluster().getRexBuilder().makeNullLiteral(
-              builder.getTypeFactory().createSqlType(SqlTypeName.BOOLEAN)),
-          builder.call(RelOptUtil.op(op.comparisonKind, null), 
e.operands.get(0),
-                  builder.field("q", "m")));
+              builder.call(RelOptUtil.op(op.comparisonKind, null),
+                  e.operands.get(0), builder.field("q", "m"))),
+          literalTrue,
+          builder.call(SqlStdOperatorTable.GREATER_THAN,
+              builder.field("q", "c"), builder.field("q", "d")),
+          literalUnknown,
+          builder.call(RelOptUtil.op(op.comparisonKind, null),
+              e.operands.get(0), builder.field("q", "m")));
     }
 
     // CASE statement above is created with nullable boolean type, but it might
     // not be correct.  If the original sub-query node's type is not nullable 
it
-    // is guranteed for case statement to not produce NULLs. Therefore to avoid
+    // is guaranteed for case statement to not produce NULLs. Therefore to 
avoid
     // planner complaining we need to add cast.  Note that nullable type is
-    // created due to MIN aggcall, since there is no groupby.
+    // created due to the MIN aggregate call, since there is no GROUP BY.
     if (!e.getType().isNullable()) {
       return builder.cast(caseRexNode, e.getType().getSqlTypeName());
     }
@@ -411,6 +418,10 @@ public abstract class SubQueryRemoveRule extends 
RelOptRule {
         .map(builder::isNull)
         .collect(Collectors.toList());
 
+    final RexLiteral trueLiteral = (RexLiteral) builder.literal(true);
+    final RexLiteral falseLiteral = (RexLiteral) builder.literal(false);
+    final RexLiteral unknownLiteral =
+        builder.getRexBuilder().makeNullLiteral(trueLiteral.getType());
     if (allLiterals) {
       final List<RexNode> conditions =
           Pair.zip(expressionOperands, fields).stream()
@@ -420,7 +431,7 @@ public abstract class SubQueryRemoveRule extends RelOptRule 
{
       case TRUE:
       case TRUE_FALSE:
         builder.filter(conditions);
-        builder.project(builder.alias(builder.literal(true), "cs"));
+        builder.project(builder.alias(trueLiteral, "cs"));
         builder.distinct();
         break;
       default:
@@ -472,15 +483,15 @@ public abstract class SubQueryRemoveRule extends 
RelOptRule {
             builder.count(builder.fields()).as("ck"));
         builder.as("ct");
         if (!variablesSet.isEmpty()) {
-          builder.join(JoinRelType.LEFT, builder.literal(true), variablesSet);
+          builder.join(JoinRelType.LEFT, trueLiteral, variablesSet);
         } else {
-          builder.join(JoinRelType.INNER, builder.literal(true), variablesSet);
+          builder.join(JoinRelType.INNER, trueLiteral, variablesSet);
         }
         offset += 2;
         builder.push(e.rel);
         // fall through
       default:
-        fields.add(builder.alias(builder.literal(true), "i"));
+        fields.add(builder.alias(trueLiteral, "i"));
         builder.project(fields);
         builder.distinct();
       }
@@ -495,16 +506,16 @@ public abstract class SubQueryRemoveRule extends 
RelOptRule {
     switch (logic) {
     case TRUE:
       builder.join(JoinRelType.INNER, builder.and(conditions), variablesSet);
-      return builder.literal(true);
+      return trueLiteral;
     }
     // Now the left join
     builder.join(JoinRelType.LEFT, builder.and(conditions), variablesSet);
 
     final ImmutableList.Builder<RexNode> operands = ImmutableList.builder();
-    Boolean b = true;
+    RexLiteral b = trueLiteral;
     switch (logic) {
     case TRUE_FALSE_UNKNOWN:
-      b = null;
+      b = unknownLiteral;
       // fall through
     case UNKNOWN_AS_TRUE:
       if (allLiterals) {
@@ -513,29 +524,29 @@ public abstract class SubQueryRemoveRule extends 
RelOptRule {
         if (variablesSet.isEmpty()) {
           operands.add(
               builder.isNull(builder.field("c")),
-              builder.literal(false));
+              falseLiteral);
         }
         operands.add(
-            builder.equals(builder.field("cs"), builder.literal(false)),
-            builder.literal(b));
+            builder.equals(builder.field("cs"), falseLiteral),
+            b);
       } else {
         operands.add(
             builder.equals(builder.field("ct", "c"), builder.literal(0)),
-            builder.literal(false));
+            falseLiteral);
       }
       break;
     }
 
     if (!keyIsNulls.isEmpty()) {
-      operands.add(builder.or(keyIsNulls), builder.literal(null));
+      operands.add(builder.or(keyIsNulls), unknownLiteral);
     }
 
     if (allLiterals) {
       operands.add(builder.isNotNull(builder.field("cs")),
-          builder.literal(true));
+          trueLiteral);
     } else {
       operands.add(builder.isNotNull(Util.last(builder.fields())),
-          builder.literal(true));
+          trueLiteral);
     }
 
     if (!allLiterals) {
@@ -545,10 +556,10 @@ public abstract class SubQueryRemoveRule extends 
RelOptRule {
         operands.add(
             builder.call(SqlStdOperatorTable.LESS_THAN,
                 builder.field("ct", "ck"), builder.field("ct", "c")),
-            builder.literal(b));
+            b);
       }
     }
-    operands.add(builder.literal(false));
+    operands.add(falseLiteral);
     return builder.call(SqlStdOperatorTable.CASE, operands.build());
   }
 
diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
index 3774430..3434079 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ValuesReduceRule.java
@@ -196,9 +196,9 @@ public abstract class ValuesReduceRule extends RelOptRule {
         ImmutableList.builder();
     for (int row = 0; row < values.getTuples().size(); ++row) {
       int i = 0;
-      RexNode reducedValue;
       if (conditionExpr != null) {
-        reducedValue = reducibleExps.get((row * fieldsPerRow) + i);
+        final RexNode reducedValue =
+            reducibleExps.get((row * fieldsPerRow) + i);
         ++i;
         if (!reducedValue.isAlwaysTrue()) {
           ++changeCount;
@@ -206,17 +206,18 @@ public abstract class ValuesReduceRule extends RelOptRule 
{
         }
       }
 
-      ImmutableList<RexLiteral> valuesList;
+      final ImmutableList<RexLiteral> valuesList;
       if (projectExprs != null) {
         ++changeCount;
         final ImmutableList.Builder<RexLiteral> tupleBuilder =
             ImmutableList.builder();
         for (; i < fieldsPerRow; ++i) {
-          reducedValue = reducibleExps.get((row * fieldsPerRow) + i);
+          final RexNode reducedValue =
+              reducibleExps.get((row * fieldsPerRow) + i);
           if (reducedValue instanceof RexLiteral) {
             tupleBuilder.add((RexLiteral) reducedValue);
           } else if (RexUtil.isNullLiteral(reducedValue, true)) {
-            tupleBuilder.add(rexBuilder.constantNull());
+            
tupleBuilder.add(rexBuilder.makeNullLiteral(reducedValue.getType()));
           } else {
             return;
           }
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java 
b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index cdb1008..3a8c650 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -407,7 +407,7 @@ public class RexBuilder {
               new RexOver(typeFactory.createTypeWithNullability(type, false),
                   operator, exprs, window, distinct, ignoreNulls),
               false),
-          makeCast(type, constantNull()));
+          makeNullLiteral(type));
     }
     if (!allowPartial) {
       Preconditions.checkArgument(physical, "DISALLOW PARTIAL over RANGE");
@@ -463,7 +463,11 @@ public class RexBuilder {
 
   /**
    * Creates a constant for the SQL <code>NULL</code> value.
+   *
+   * @deprecated Use {@link #makeNullLiteral(RelDataType)}, which produces a
+   * NULL of the correct type
    */
+  @Deprecated // to be removed before 2.0
   public RexLiteral constantNull() {
     return constantNull;
   }
@@ -1252,7 +1256,7 @@ public class RexBuilder {
     if (!type.isNullable()) {
       type = typeFactory.createTypeWithNullability(type, true);
     }
-    return (RexLiteral) makeCast(type, constantNull());
+    return (RexLiteral) makeCast(type, constantNull);
   }
 
   /** @deprecated Use {@link #makeNullLiteral(RelDataType)} */
diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java
 
b/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java
index 1959790..bc3064c 100644
--- 
a/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java
+++ 
b/core/src/main/java/org/apache/calcite/sql2rel/NullInitializerExpressionFactory.java
@@ -54,13 +54,17 @@ public class NullInitializerExpressionFactory implements 
InitializerExpressionFa
 
   public RexNode newColumnDefaultValue(RelOptTable table, int iColumn,
       InitializerContext context) {
-    return context.getRexBuilder().constantNull();
+    final RelDataType fieldType =
+        table.getRowType().getFieldList().get(iColumn).getType();
+    return context.getRexBuilder().makeNullLiteral(fieldType);
   }
 
   public RexNode newAttributeInitializer(RelDataType type,
       SqlFunction constructor, int iAttribute, List<RexNode> constructorArgs,
       InitializerContext context) {
-    return context.getRexBuilder().constantNull();
+    final RelDataType fieldType =
+        type.getFieldList().get(iAttribute).getType();
+    return context.getRexBuilder().makeNullLiteral(fieldType);
   }
 }
 
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java 
b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index cac5ca7..4facf48 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -1626,7 +1626,7 @@ public class RelDecorrelator implements ReflectiveVisitor 
{
       // nulls on the LHS, the projection now need to make a nullable LHS
       // reference using a nullability indicator. If this this indicator
       // is null, it means the sub-query does not produce any value. As a
-      // result, any RHS ref by this usbquery needs to produce null value.
+      // result, any RHS ref by this sub-query needs to produce null value.
 
       // WHEN indicator IS NULL
       caseOperands[0] =
@@ -1640,11 +1640,9 @@ public class RelDecorrelator implements 
ReflectiveVisitor {
 
       // THEN CAST(NULL AS newInputTypeNullable)
       caseOperands[1] =
-          rexBuilder.makeCast(
-              typeFactory.createTypeWithNullability(
-                  rexNode.getType(),
-                  true),
-              lit);
+          lit == null
+              ? rexBuilder.makeNullLiteral(rexNode.getType())
+              : rexBuilder.makeCast(rexNode.getType(), lit);
 
       // ELSE cast (newInput AS newInputTypeNullable) END
       caseOperands[2] =
@@ -1674,10 +1672,7 @@ public class RelDecorrelator implements 
ReflectiveVisitor {
           // need to enforce nullability by applying an additional
           // cast operator over the transformed expression.
           newRexNode =
-              createCaseExpression(
-                  nullIndicator,
-                  rexBuilder.constantNull(),
-                  newRexNode);
+              createCaseExpression(nullIndicator, null, newRexNode);
         }
         return newRexNode;
       }
@@ -1723,10 +1718,7 @@ public class RelDecorrelator implements 
ReflectiveVisitor {
       if (!RexUtil.isNull(literal)
           && projectPulledAboveLeftCorrelator
           && (nullIndicator != null)) {
-        return createCaseExpression(
-            nullIndicator,
-            rexBuilder.constantNull(),
-            literal);
+        return createCaseExpression(nullIndicator, null, literal);
       }
       return literal;
     }
@@ -1779,10 +1771,7 @@ public class RelDecorrelator implements 
ReflectiveVisitor {
       }
 
       if (projectPulledAboveLeftCorrelator && (nullIndicator != null)) {
-        return createCaseExpression(
-            nullIndicator,
-            rexBuilder.constantNull(),
-            newCall);
+        return createCaseExpression(nullIndicator, null, newCall);
       }
       return newCall;
     }
diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java 
b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
index fdf1762..ea84e82 100644
--- 
a/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
+++ 
b/core/src/main/java/org/apache/calcite/sql2rel/RelStructuredTypeFlattener.java
@@ -266,10 +266,7 @@ public class RelStructuredTypeFlattener implements 
ReflectiveVisitor {
             nullIndicator);
 
     // THEN CAST(NULL AS StructuredType)
-    caseOperands[1] =
-        rexBuilder.makeCast(
-            structuredType,
-            rexBuilder.constantNull());
+    caseOperands[1] = rexBuilder.makeNullLiteral(structuredType);
 
     // ELSE NEW StructuredType(inputs...) END
     caseOperands[2] = newInvocation;
@@ -688,7 +685,7 @@ public class RelStructuredTypeFlattener implements 
ReflectiveVisitor {
     for (RelDataTypeField field : flattenedType.getFieldList()) {
       flattenedExps.add(
           Pair.of(
-              rexBuilder.makeCast(field.getType(), rexBuilder.constantNull()),
+              rexBuilder.makeNullLiteral(field.getType()),
               field.getName()));
     }
   }
diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java 
b/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
index 9f398d6..ea2eaf1 100644
--- 
a/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
+++ 
b/core/src/main/java/org/apache/calcite/sql2rel/SqlNodeToRexConverterImpl.java
@@ -92,9 +92,7 @@ public class SqlNodeToRexConverterImpl implements 
SqlNodeToRexConverter {
       } else {
         type = validator.getValidatedNodeType(literal);
       }
-      return rexBuilder.makeCast(
-          type,
-          rexBuilder.constantNull());
+      return rexBuilder.makeNullLiteral(type);
     }
 
     BitString bitString;
diff --git 
a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java 
b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
index c5b0b7d..23c52b9 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -368,20 +368,25 @@ public class StandardConvertletTable extends 
ReflectiveConvertletTable {
 
     RexBuilder rexBuilder = cx.getRexBuilder();
     final List<RexNode> exprList = new ArrayList<>();
+    final RelDataTypeFactory typeFactory = rexBuilder.getTypeFactory();
+    final RexLiteral unknownLiteral = rexBuilder.makeNullLiteral(
+        typeFactory.createSqlType(SqlTypeName.BOOLEAN));
+    final RexLiteral nullLiteral = rexBuilder.makeNullLiteral(
+        typeFactory.createSqlType(SqlTypeName.NULL));
     for (int i = 0; i < whenList.size(); i++) {
       if (SqlUtil.isNullLiteral(whenList.get(i), false)) {
-        exprList.add(rexBuilder.constantNull());
+        exprList.add(unknownLiteral);
       } else {
         exprList.add(cx.convertExpression(whenList.get(i)));
       }
       if (SqlUtil.isNullLiteral(thenList.get(i), false)) {
-        exprList.add(rexBuilder.constantNull());
+        exprList.add(nullLiteral);
       } else {
         exprList.add(cx.convertExpression(thenList.get(i)));
       }
     }
     if (SqlUtil.isNullLiteral(call.getElseOperand(), false)) {
-      exprList.add(rexBuilder.constantNull());
+      exprList.add(nullLiteral);
     } else {
       exprList.add(cx.convertExpression(call.getElseOperand()));
     }
diff --git a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java 
b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
index 0ff0c75..239d58a 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -360,7 +360,8 @@ public class RelBuilder {
   public RexNode literal(Object value) {
     final RexBuilder rexBuilder = cluster.getRexBuilder();
     if (value == null) {
-      return rexBuilder.constantNull();
+      final RelDataType type = 
getTypeFactory().createSqlType(SqlTypeName.NULL);
+      return rexBuilder.makeNullLiteral(type);
     } else if (value instanceof Boolean) {
       return rexBuilder.makeLiteral((Boolean) value);
     } else if (value instanceof BigDecimal) {
diff --git a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java 
b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
index 2be216d..736cfbd 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -2729,11 +2729,9 @@ public class RexProgramTest extends 
RexProgramBuilderBase {
   @Test public void testIsNullSimplificationWithIsDistinctFrom() {
     RexNode expr =
         isNotNull(
-            case_(
-                vBool(),
+            case_(vBool(),
                 isDistinctFrom(falseLiteral, vBoolNotNull(0)),
-                vBoolNotNull(2))
-            );
+                vBoolNotNull(2)));
     RexNode s = simplify.simplifyUnknownAs(expr, RexUnknownAs.UNKNOWN);
 
     assertThat(expr.isAlwaysTrue(), is(true));
diff --git 
a/core/src/test/java/org/apache/calcite/test/catalog/EmpInitializerExpressionFactory.java
 
b/core/src/test/java/org/apache/calcite/test/catalog/EmpInitializerExpressionFactory.java
index 4d26cba..7e5048b 100644
--- 
a/core/src/test/java/org/apache/calcite/test/catalog/EmpInitializerExpressionFactory.java
+++ 
b/core/src/test/java/org/apache/calcite/test/catalog/EmpInitializerExpressionFactory.java
@@ -56,7 +56,7 @@ class EmpInitializerExpressionFactory
       return rexBuilder.makeExactLiteral(new BigDecimal(555),
           typeFactory.createSqlType(SqlTypeName.INTEGER));
     default:
-      return rexBuilder.constantNull();
+      return super.newColumnDefaultValue(table, iColumn, context);
     }
   }
 }
diff --git 
a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml 
b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index cb07e35..4142664 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -6683,8 +6683,7 @@ LogicalProject(NAME=[$1])
             <![CDATA[select *
 from dept a
 left join (select name, 1 from dept) as b
-on a.name = b.name
-]]>
+on a.name = b.name]]>
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
@@ -6710,8 +6709,7 @@ LogicalProject(DEPTNO=[$0], NAME=[$1], NAME0=[$2], 
EXPR$1=[$3])
             <![CDATA[select *
 from (select name, 1 from dept) as a
 right join dept b
-on a.name = b.name
-]]>
+on a.name = b.name]]>
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
@@ -6735,10 +6733,10 @@ LogicalProject(NAME=[$0], EXPR$1=[$1], DEPTNO=[$2], 
NAME0=[$3])
     <TestCase name="testJoinProjectTranspose4">
         <Resource name="sql">
             <![CDATA[select *
+from dept a
 left join (select x name, y is not null from
 (values (2, cast(null as integer)), (2, 1)) as t(x, y)) b
-on a.name = b.name
-]]>
+on a.name = b.name]]>
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
@@ -6770,10 +6768,9 @@ LogicalProject(DEPTNO=[$0], NAME=[$1], NAME0=[$2], 
EXPR$1=[$3])
     <TestCase name="testJoinProjectTranspose5">
         <Resource name="sql">
             <![CDATA[select *
-left join (select x name, y is not null from
-(values (2, cast(null as integer)), (2, 1)) as t(x, y)) b
-on a.name = b.name
-]]>
+from dept a
+left join (select name, 1 + 1 from dept) as b
+on a.name = b.name]]>
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
@@ -6799,8 +6796,7 @@ LogicalProject(DEPTNO=[$0], NAME=[$1], NAME0=[$2], 
EXPR$1=[$3])
             <![CDATA[select *
 from (select name, 1 from dept) a
 full join (select name, 1 from dept) as b
-on a.name = b.name
-]]>
+on a.name = b.name]]>
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
@@ -6828,8 +6824,7 @@ LogicalProject(NAME=[$0], EXPR$1=[$1], NAME0=[$2], 
EXPR$10=[$3])
             <![CDATA[select *
 from dept a
 left join (select name from dept) as b
-on a.name = b.name
-]]>
+ on a.name = b.name]]>
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
@@ -6854,9 +6849,10 @@ LogicalProject(DEPTNO=[$0], NAME=[$1], NAME0=[$2])
         <Resource name="sql">
             <![CDATA[select *
 from dept a
-left join (select name, deptno > 10 and cast(null as boolean) from dept b) as b
-on a.name = b.name
-]]>
+left join (
+  select name, deptno > 10 and cast(null as boolean)
+  from dept) as b
+on a.name = b.name]]>
         </Resource>
         <Resource name="planBefore">
             <![CDATA[
@@ -10146,7 +10142,7 @@ LogicalProject(DEPTNO=[$1])
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalProject(EMPNO=[$0], D=[CASE(=($9, 0), false, IS NULL(CASE(true, 
CAST($7):INTEGER, null:INTEGER)), null:NULL, IS NOT NULL($12), true, <($10, 
$9), null:NULL, false)])
+LogicalProject(EMPNO=[$0], D=[CASE(=($9, 0), false, IS NULL(CASE(true, 
CAST($7):INTEGER, null:INTEGER)), null:BOOLEAN, IS NOT NULL($12), true, <($10, 
$9), null:BOOLEAN, false)])
   LogicalJoin(condition=[=(CASE(true, CAST($7):INTEGER, null:INTEGER), $11)], 
joinType=[left])
     LogicalJoin(condition=[true], joinType=[inner])
       LogicalTableScan(table=[[CATALOG, SALES, EMP]])
diff --git a/core/src/test/resources/sql/blank.iq 
b/core/src/test/resources/sql/blank.iq
index 93484e5..763d58b 100644
--- a/core/src/test/resources/sql/blank.iq
+++ b/core/src/test/resources/sql/blank.iq
@@ -73,7 +73,7 @@ insert into table2 values (NULL, 1), (2, 1);
 # Checked on Oracle
 !set lateDecorrelate true
 select i, j from table1 where table1.j NOT IN (select i from table2 where 
table1.i=table2.j);
-EnumerableCalc(expr#0..7=[{inputs}], expr#8=[0], expr#9=[=($t3, $t8)], 
expr#10=[IS NOT TRUE($t9)], expr#11=[IS NOT NULL($t7)], expr#12=[<($t4, $t3)], 
expr#13=[OR($t11, $t12)], expr#14=[IS NOT TRUE($t13)], expr#15=[IS NOT 
NULL($t1)], expr#16=[AND($t10, $t14, $t15)], expr#17=[OR($t9, $t16)], 
proj#0..1=[{exprs}], $condition=[$t17])
+EnumerableCalc(expr#0..7=[{inputs}], expr#8=[0], expr#9=[=($t3, $t8)], 
expr#10=[IS NULL($t1)], expr#11=[IS NOT NULL($t7)], expr#12=[<($t4, $t3)], 
expr#13=[OR($t10, $t11, $t12)], expr#14=[IS NOT TRUE($t13)], expr#15=[OR($t9, 
$t14)], proj#0..1=[{exprs}], $condition=[$t15])
   EnumerableHashJoin(condition=[AND(=($0, $6), =($1, $5))], joinType=[left])
     EnumerableHashJoin(condition=[=($0, $2)], joinType=[left])
       EnumerableTableScan(table=[[BLANK, TABLE1]])
diff --git a/core/src/test/resources/sql/sub-query.iq 
b/core/src/test/resources/sql/sub-query.iq
index 3629fb5..595ca2b 100644
--- a/core/src/test/resources/sql/sub-query.iq
+++ b/core/src/test/resources/sql/sub-query.iq
@@ -32,7 +32,7 @@ where t1.x not in (select t2.x from t2);
 (0 rows)
 
 !ok
-EnumerableCalc(expr#0..4=[{inputs}], expr#5=[0], expr#6=[=($t1, $t5)], 
expr#7=[<>($t1, $t5)], expr#8=[IS NULL($t4)], expr#9=[>=($t2, $t1)], 
expr#10=[IS NOT NULL($t0)], expr#11=[AND($t7, $t8, $t9, $t10)], 
expr#12=[OR($t6, $t11)], X=[$t0], $condition=[$t12])
+EnumerableCalc(expr#0..4=[{inputs}], expr#5=[0], expr#6=[=($t1, $t5)], 
expr#7=[IS NULL($t4)], expr#8=[>=($t2, $t1)], expr#9=[IS NOT NULL($t0)], 
expr#10=[AND($t7, $t8, $t9)], expr#11=[OR($t6, $t10)], X=[$t0], 
$condition=[$t11])
   EnumerableHashJoin(condition=[=($0, $3)], joinType=[left])
     EnumerableHashJoin(condition=[true], joinType=[inner])
       EnumerableUnion(all=[true])
@@ -2047,7 +2047,7 @@ where sal + 100 not in (
 
 !ok
 EnumerableAggregate(group=[{}], C=[COUNT()])
-  EnumerableCalc(expr#0..9=[{inputs}], expr#10=[0], expr#11=[=($t4, $t10)], 
expr#12=[IS NOT TRUE($t11)], expr#13=[IS NOT NULL($t7)], expr#14=[<($t5, $t4)], 
expr#15=[OR($t13, $t14)], expr#16=[IS NOT TRUE($t15)], expr#17=[IS NOT 
NULL($t2)], expr#18=[AND($t12, $t16, $t17)], expr#19=[OR($t11, $t18)], 
proj#0..9=[{exprs}], $condition=[$t19])
+  EnumerableCalc(expr#0..9=[{inputs}], expr#10=[0], expr#11=[=($t4, $t10)], 
expr#12=[IS NULL($t2)], expr#13=[IS NOT NULL($t7)], expr#14=[<($t5, $t4)], 
expr#15=[OR($t12, $t13, $t14)], expr#16=[IS NOT TRUE($t15)], expr#17=[OR($t11, 
$t16)], proj#0..9=[{exprs}], $condition=[$t17])
     EnumerableHashJoin(condition=[AND(=($1, $8), =($2, $9))], joinType=[left])
       EnumerableHashJoin(condition=[=($1, $3)], joinType=[left])
         EnumerableCalc(expr#0..7=[{inputs}], proj#0..1=[{exprs}], SAL=[$t5])

Reply via email to