http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java 
b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index 2352809..f174f41 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -16,10 +16,8 @@
  */
 package org.apache.calcite.rex;
 
-import org.apache.calcite.linq4j.Ord;
 import org.apache.calcite.linq4j.function.Predicate1;
 import org.apache.calcite.plan.RelOptUtil;
-import org.apache.calcite.plan.Strong;
 import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelFieldCollation;
@@ -48,26 +46,23 @@ import org.apache.calcite.util.mapping.Mappings;
 import com.google.common.base.Function;
 import com.google.common.base.Preconditions;
 import com.google.common.base.Predicate;
-import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
-import com.google.common.collect.Multimap;
 import com.google.common.collect.Sets;
 
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
-import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
-import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import javax.annotation.Nonnull;
 
 /**
  * Utility methods concerning row-expressions.
@@ -1038,6 +1033,16 @@ public class RexUtil {
    * Removes expressions that always evaluate to FALSE.
    * Flattens expressions that are ORs.
    */
+  @Nonnull public static RexNode composeDisjunction(RexBuilder rexBuilder,
+      Iterable<? extends RexNode> nodes) {
+    final RexNode e = composeDisjunction(rexBuilder, nodes, false);
+    return Preconditions.checkNotNull(e);
+  }
+
+  /**
+   * Converts a collection of expressions into an OR,
+   * optionally returning null if the list is empty.
+   */
   public static RexNode composeDisjunction(RexBuilder rexBuilder,
       Iterable<? extends RexNode> nodes, boolean nullOnEmpty) {
     ImmutableList<RexNode> list = flattenOr(nodes);
@@ -1565,39 +1570,33 @@ public class RexUtil {
    * nullability.
    *
    * <p>This is useful if you are simplifying expressions in a
-   * {@link Project}. */
+   * {@link Project}.
+   *
+   * @deprecated Use {@link RexSimplify#simplifyPreservingType(RexNode)},
+   * which allows you to specify an {@link RexExecutor}. */
+  @Deprecated // to be removed before 2.0
   public static RexNode simplifyPreservingType(RexBuilder rexBuilder,
-      RexNode e, RexExecutor executor) {
-    final RexNode e2 = simplify(rexBuilder, e, false, executor);
-    if (e2.getType() == e.getType()) {
-      return e2;
-    }
-    final RexNode e3 = rexBuilder.makeCast(e.getType(), e2, true);
-    if (e3.equals(e)) {
-      return e;
-    }
-    return e3;
+      RexNode e) {
+    return new RexSimplify(rexBuilder, false, EXECUTOR)
+        .simplifyPreservingType(e);
   }
 
   /**
    * Simplifies a boolean expression, leaving UNKNOWN values as UNKNOWN, and
    * using the default executor.
+   *
+   * @deprecated Use {@link RexSimplify#simplify(RexNode)},
+   * which allows you to specify an {@link RexExecutor}.
    */
+  @Deprecated // to be removed before 2.0
   public static RexNode simplify(RexBuilder rexBuilder, RexNode e) {
-    return simplify(rexBuilder, e, false, EXECUTOR);
+    return new RexSimplify(rexBuilder, false, EXECUTOR)
+        .simplify(e);
   }
 
   /**
    * Simplifies a boolean expression,
    * using the default executor.
-   */
-  public static RexNode simplify(RexBuilder rexBuilder, RexNode e,
-      boolean unknownAsFalse) {
-    return simplify(rexBuilder, e, unknownAsFalse, EXECUTOR);
-  }
-
-  /**
-   * Simplifies a boolean expression.
    *
    * <p>In particular:</p>
    * <ul>
@@ -1615,180 +1614,35 @@ public class RexUtil {
    * @param rexBuilder Rex builder
    * @param e Expression to simplify
    * @param unknownAsFalse Whether to convert UNKNOWN values to FALSE
-   * @param executor Executor for constant reduction, not null
+   *
+   * @deprecated Use {@link RexSimplify#simplify(RexNode)},
+   * which allows you to specify an {@link RexExecutor}.
    */
+  @Deprecated // to be removed before 2.0
   public static RexNode simplify(RexBuilder rexBuilder, RexNode e,
-      boolean unknownAsFalse, RexExecutor executor) {
-    Preconditions.checkNotNull(executor);
-    switch (e.getKind()) {
-    case AND:
-      return simplifyAnd(rexBuilder, (RexCall) e, unknownAsFalse);
-    case OR:
-      return simplifyOr(rexBuilder, (RexCall) e);
-    case NOT:
-      return simplifyNot(rexBuilder, (RexCall) e);
-    case CASE:
-      return simplifyCase(rexBuilder, (RexCall) e, unknownAsFalse);
-    case CAST:
-      return simplifyCast(rexBuilder, (RexCall) e, executor);
-    case IS_NULL:
-    case IS_NOT_NULL:
-    case IS_TRUE:
-    case IS_NOT_TRUE:
-    case IS_FALSE:
-    case IS_NOT_FALSE:
-      assert e instanceof RexCall;
-      return simplifyIs(rexBuilder, (RexCall) e);
-    case EQUALS:
-    case GREATER_THAN:
-    case GREATER_THAN_OR_EQUAL:
-    case LESS_THAN:
-    case LESS_THAN_OR_EQUAL:
-    case NOT_EQUALS:
-      return simplifyComparison(rexBuilder, (RexCall) e, unknownAsFalse);
-    default:
-      return e;
-    }
-  }
-
-  // e must be a comparison (=, >, >=, <, <=, !=)
-  private static RexNode simplifyComparison(RexBuilder rexBuilder, RexCall e,
       boolean unknownAsFalse) {
-    final List<RexNode> operands = new ArrayList<>(e.operands);
-    simplifyList(rexBuilder, operands);
-
-    // Simplify "x <op> x"
-    final RexNode o0 = operands.get(0);
-    final RexNode o1 = operands.get(1);
-    if (RexUtil.eq(o0, o1)
-        && (unknownAsFalse
-            || (!o0.getType().isNullable()
-                && !o1.getType().isNullable()))) {
-      switch (e.getKind()) {
-      case EQUALS:
-      case GREATER_THAN_OR_EQUAL:
-      case LESS_THAN_OR_EQUAL:
-        // "x = x" simplifies to "x is not null" (similarly <= and >=)
-        return simplify(rexBuilder,
-            rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, o0));
-      default:
-        // "x != x" simplifies to "false" (similarly < and >)
-        return rexBuilder.makeLiteral(false);
-      }
-    }
-
-    // Simplify "<literal1> <op> <literal2>"
-    // For example, "1 = 2" becomes FALSE;
-    // "1 != 1" becomes FALSE;
-    // "1 != NULL" becomes UNKNOWN (or FALSE if unknownAsFalse);
-    // "1 != '1'" is unchanged because the types are not the same.
-    if (o0.isA(SqlKind.LITERAL)
-        && o1.isA(SqlKind.LITERAL)
-        && o0.getType().equals(o1.getType())) {
-      final Comparable v0 = ((RexLiteral) o0).getValue();
-      final Comparable v1 = ((RexLiteral) o1).getValue();
-      if (v0 == null || v1 == null) {
-        return unknownAsFalse
-            ? rexBuilder.makeLiteral(false)
-            : rexBuilder.makeNullLiteral(e.getType());
-      }
-      @SuppressWarnings("unchecked")
-      final int comparisonResult = v0.compareTo(v1);
-      switch (e.getKind()) {
-      case EQUALS:
-        return rexBuilder.makeLiteral(comparisonResult == 0);
-      case GREATER_THAN:
-        return rexBuilder.makeLiteral(comparisonResult > 0);
-      case GREATER_THAN_OR_EQUAL:
-        return rexBuilder.makeLiteral(comparisonResult >= 0);
-      case LESS_THAN:
-        return rexBuilder.makeLiteral(comparisonResult < 0);
-      case LESS_THAN_OR_EQUAL:
-        return rexBuilder.makeLiteral(comparisonResult <= 0);
-      case NOT_EQUALS:
-        return rexBuilder.makeLiteral(comparisonResult != 0);
-      default:
-        throw new AssertionError();
-      }
-    }
-
-    // If none of the arguments were simplified, return the call unchanged.
-    if (operands.equals(e.operands)) {
-      return e;
-    }
-    return rexBuilder.makeCall(e.op, operands);
+    return new RexSimplify(rexBuilder, unknownAsFalse, EXECUTOR)
+        .simplify(e);
   }
 
   /**
    * Simplifies a conjunction of boolean expressions.
+   *
+   * @deprecated Use {@link RexSimplify#simplifyAnds(Iterable)},
+   * which allows you to specify an {@link RexExecutor}.
    */
+  @Deprecated // to be removed before 2.0
   public static RexNode simplifyAnds(RexBuilder rexBuilder,
       Iterable<? extends RexNode> nodes) {
-    return simplifyAnds(rexBuilder, nodes, false);
+    return new RexSimplify(rexBuilder, false, EXECUTOR)
+        .simplifyAnds(nodes);
   }
 
+  @Deprecated // to be removed before 2.0
   public static RexNode simplifyAnds(RexBuilder rexBuilder,
       Iterable<? extends RexNode> nodes, boolean unknownAsFalse) {
-    final List<RexNode> terms = new ArrayList<>();
-    final List<RexNode> notTerms = new ArrayList<>();
-    for (RexNode e : nodes) {
-      RelOptUtil.decomposeConjunction(e, terms, notTerms);
-    }
-    simplifyList(rexBuilder, terms);
-    simplifyList(rexBuilder, notTerms);
-    if (unknownAsFalse) {
-      return simplifyAnd2ForUnknownAsFalse(rexBuilder, terms, notTerms);
-    }
-    return simplifyAnd2(rexBuilder, terms, notTerms);
-  }
-
-  private static void simplifyList(RexBuilder rexBuilder, List<RexNode> terms) 
{
-    for (int i = 0; i < terms.size(); i++) {
-      terms.set(i, simplify(rexBuilder, terms.get(i)));
-    }
-  }
-
-  private static RexNode simplifyNot(RexBuilder rexBuilder, RexCall call) {
-    final RexNode a = call.getOperands().get(0);
-    switch (a.getKind()) {
-    case NOT:
-      // NOT NOT x ==> x
-      return simplify(rexBuilder, ((RexCall) a).getOperands().get(0));
-    }
-    final SqlKind negateKind = a.getKind().negate();
-    if (a.getKind() != negateKind) {
-      return simplify(rexBuilder,
-          rexBuilder.makeCall(op(negateKind),
-              ImmutableList.of(((RexCall) a).getOperands().get(0))));
-    }
-    final SqlKind negateKind2 = a.getKind().negateNullSafe();
-    if (a.getKind() != negateKind2) {
-      return simplify(rexBuilder,
-          rexBuilder.makeCall(op(negateKind2), ((RexCall) a).getOperands()));
-    }
-    if (a.getKind() == SqlKind.AND) {
-      // NOT distributivity for AND
-      final List<RexNode> newOperands = new ArrayList<>();
-      for (RexNode operand : ((RexCall) a).getOperands()) {
-        newOperands.add(
-            simplify(rexBuilder,
-                rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand)));
-      }
-      return simplify(rexBuilder,
-          rexBuilder.makeCall(SqlStdOperatorTable.OR, newOperands));
-    }
-    if (a.getKind() == SqlKind.OR) {
-      // NOT distributivity for OR
-      final List<RexNode> newOperands = new ArrayList<>();
-      for (RexNode operand : ((RexCall) a).getOperands()) {
-        newOperands.add(
-            simplify(rexBuilder,
-                rexBuilder.makeCall(SqlStdOperatorTable.NOT, operand)));
-      }
-      return simplify(rexBuilder,
-          rexBuilder.makeCall(SqlStdOperatorTable.AND, newOperands));
-    }
-    return call;
+    return new RexSimplify(rexBuilder, unknownAsFalse, EXECUTOR)
+        .simplifyAnds(nodes);
   }
 
   /** Negates a logical expression by adding or removing a NOT. */
@@ -1802,103 +1656,7 @@ public class RexUtil {
     }
   }
 
-  private static RexNode simplifyIs(RexBuilder rexBuilder, RexCall call) {
-    final SqlKind kind = call.getKind();
-    final RexNode a = call.getOperands().get(0);
-    final RexNode simplified = simplifyIs2(rexBuilder, kind, a);
-    if (simplified != null) {
-      return simplified;
-    }
-    return call;
-  }
-
-  private static RexNode simplifyIs2(RexBuilder rexBuilder, SqlKind kind,
-      RexNode a) {
-    switch (kind) {
-    case IS_NULL:
-      // x IS NULL ==> FALSE (if x is not nullable)
-      if (!a.getType().isNullable()) {
-        return rexBuilder.makeLiteral(false);
-      }
-      break;
-    case IS_NOT_NULL:
-      // x IS NOT NULL ==> TRUE (if x is not nullable)
-      RexNode simplified = simplifyIsNotNull(rexBuilder, a);
-      if (simplified != null) {
-        return simplified;
-      }
-      break;
-    case IS_TRUE:
-    case IS_NOT_FALSE:
-      // x IS TRUE ==> x (if x is not nullable)
-      // x IS NOT FALSE ==> x (if x is not nullable)
-      if (!a.getType().isNullable()) {
-        return simplify(rexBuilder, a);
-      }
-      break;
-    case IS_FALSE:
-    case IS_NOT_TRUE:
-      // x IS NOT TRUE ==> NOT x (if x is not nullable)
-      // x IS FALSE ==> NOT x (if x is not nullable)
-      if (!a.getType().isNullable()) {
-        return simplify(rexBuilder,
-            rexBuilder.makeCall(SqlStdOperatorTable.NOT, a));
-      }
-      break;
-    }
-    switch (a.getKind()) {
-    case NOT:
-      // (NOT x) IS TRUE ==> x IS FALSE
-      // Similarly for IS NOT TRUE, IS FALSE, etc.
-      //
-      // Note that
-      //   (NOT x) IS TRUE !=> x IS FALSE
-      // because of null values.
-      return simplify(rexBuilder,
-          rexBuilder.makeCall(op(kind.negate()),
-              ((RexCall) a).getOperands().get(0)));
-    }
-    RexNode a2 = simplify(rexBuilder, a);
-    if (a != a2) {
-      return rexBuilder.makeCall(op(kind), ImmutableList.of(a2));
-    }
-    return null; // cannot be simplified
-  }
-
-  private static RexNode simplifyIsNotNull(RexBuilder rexBuilder, RexNode a) {
-    if (!a.getType().isNullable()) {
-      return rexBuilder.makeLiteral(true);
-    }
-    switch (Strong.policy(a.getKind())) {
-    case ANY:
-      final List<RexNode> operands = new ArrayList<>();
-      for (RexNode operand : ((RexCall) a).getOperands()) {
-        final RexNode simplified = simplifyIsNotNull(rexBuilder, operand);
-        if (simplified == null) {
-          operands.add(
-              rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, operand));
-        } else if (simplified.isAlwaysFalse()) {
-          return rexBuilder.makeLiteral(false);
-        } else {
-          operands.add(simplified);
-        }
-      }
-      return composeConjunction(rexBuilder, operands, false);
-    case CUSTOM:
-      switch (a.getKind()) {
-      case LITERAL:
-        return rexBuilder.makeLiteral(((RexLiteral) a).getValue() != null);
-      default:
-        throw new AssertionError("every CUSTOM policy needs a handler, "
-            + a.getKind());
-      }
-    case AS_IS:
-    default:
-      return null;
-    }
-  }
-
-  private static SqlOperator op(SqlKind kind) {
+  static SqlOperator op(SqlKind kind) {
     switch (kind) {
     case IS_FALSE:
       return SqlStdOperatorTable.IS_FALSE;
@@ -1931,371 +1689,25 @@ public class RexUtil {
     }
   }
 
-  private static RexNode simplifyCase(RexBuilder rexBuilder, RexCall call,
-      boolean unknownAsFalse) {
-    final List<RexNode> operands = call.getOperands();
-    final List<RexNode> newOperands = new ArrayList<>();
-    final Set<String> values = new HashSet<>();
-    for (int i = 0; i < operands.size(); i++) {
-      RexNode operand = operands.get(i);
-      if (isCasePredicate(call, i)) {
-        if (operand.isAlwaysTrue()) {
-          // Predicate is always TRUE. Make value the ELSE and quit.
-          newOperands.add(operands.get(++i));
-          if (unknownAsFalse && isNull(operands.get(i))) {
-            values.add(rexBuilder.makeLiteral(false).toString());
-          } else {
-            values.add(operands.get(i).toString());
-          }
-          break;
-        } else if (operand.isAlwaysFalse() || isNull(operand)) {
-          // Predicate is always FALSE or NULL. Skip predicate and value.
-          ++i;
-          continue;
-        }
-      } else {
-        if (unknownAsFalse && isNull(operand)) {
-          values.add(rexBuilder.makeLiteral(false).toString());
-        } else {
-          values.add(operand.toString());
-        }
-      }
-      newOperands.add(operand);
-    }
-    assert newOperands.size() % 2 == 1;
-    if (newOperands.size() == 1 || values.size() == 1) {
-      final RexNode last = Util.last(newOperands);
-      if (!call.getType().equals(last.getType())) {
-        return rexBuilder.makeAbstractCast(call.getType(), last);
-      }
-      return last;
-    }
-  trueFalse:
-    if (call.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
-      // Optimize CASE where every branch returns constant true or constant
-      // false.
-      final List<Pair<RexNode, RexNode>> pairs =
-          casePairs(rexBuilder, newOperands);
-      // 1) Possible simplification if unknown is treated as false:
-      //   CASE
-      //   WHEN p1 THEN TRUE
-      //   WHEN p2 THEN TRUE
-      //   ELSE FALSE
-      //   END
-      // can be rewritten to: (p1 or p2)
-      if (unknownAsFalse) {
-        final List<RexNode> terms = new ArrayList<>();
-        int pos = 0;
-        for (; pos < pairs.size(); pos++) {
-          // True block
-          Pair<RexNode, RexNode> pair = pairs.get(pos);
-          if (!pair.getValue().isAlwaysTrue()) {
-            break;
-          }
-          terms.add(pair.getKey());
-        }
-        for (; pos < pairs.size(); pos++) {
-          // False block
-          Pair<RexNode, RexNode> pair = pairs.get(pos);
-          if (!pair.getValue().isAlwaysFalse() && !isNull(pair.getValue())) {
-            break;
-          }
-        }
-        if (pos == pairs.size()) {
-          final RexNode disjunction = composeDisjunction(rexBuilder, terms, 
false);
-          if (!call.getType().equals(disjunction.getType())) {
-            return rexBuilder.makeCast(call.getType(), disjunction);
-          }
-          return disjunction;
-        }
-      }
-      // 2) Another simplification
-      //   CASE
-      //   WHEN p1 THEN TRUE
-      //   WHEN p2 THEN FALSE
-      //   WHEN p3 THEN TRUE
-      //   ELSE FALSE
-      //   END
-      // if p1...pn cannot be nullable
-      for (Ord<Pair<RexNode, RexNode>> pair : Ord.zip(pairs)) {
-        if (pair.e.getKey().getType().isNullable()) {
-          break trueFalse;
-        }
-        if (!pair.e.getValue().isAlwaysTrue()
-            && !pair.e.getValue().isAlwaysFalse()
-            && (!unknownAsFalse || !isNull(pair.e.getValue()))) {
-          break trueFalse;
-        }
-      }
-      final List<RexNode> terms = new ArrayList<>();
-      final List<RexNode> notTerms = new ArrayList<>();
-      for (Ord<Pair<RexNode, RexNode>> pair : Ord.zip(pairs)) {
-        if (pair.e.getValue().isAlwaysTrue()) {
-          terms.add(andNot(rexBuilder, pair.e.getKey(), notTerms));
-        } else {
-          notTerms.add(pair.e.getKey());
-        }
-      }
-      final RexNode disjunction = composeDisjunction(rexBuilder, terms, false);
-      if (!call.getType().equals(disjunction.getType())) {
-        return rexBuilder.makeCast(call.getType(), disjunction);
-      }
-      return disjunction;
-    }
-    if (newOperands.equals(operands)) {
-      return call;
-    }
-    return call.clone(call.getType(), newOperands);
-  }
-
-  /** Given "CASE WHEN p1 THEN v1 ... ELSE e END"
-   * returns [(p1, v1), ..., (true, e)]. */
-  private static List<Pair<RexNode, RexNode>> casePairs(RexBuilder rexBuilder,
-      List<RexNode> operands) {
-    final ImmutableList.Builder<Pair<RexNode, RexNode>> builder =
-        ImmutableList.builder();
-    for (int i = 0; i < operands.size() - 1; i += 2) {
-      builder.add(Pair.of(operands.get(i), operands.get(i + 1)));
-    }
-    builder.add(
-        Pair.of((RexNode) rexBuilder.makeLiteral(true), Util.last(operands)));
-    return builder.build();
-  }
-
+  @Deprecated // to be removed before 2.0
   public static RexNode simplifyAnd(RexBuilder rexBuilder, RexCall e,
       boolean unknownAsFalse) {
-    final List<RexNode> terms = new ArrayList<>();
-    final List<RexNode> notTerms = new ArrayList<>();
-    RelOptUtil.decomposeConjunction(e, terms, notTerms);
-    simplifyList(rexBuilder, terms);
-    simplifyList(rexBuilder, notTerms);
-    if (unknownAsFalse) {
-      return simplifyAnd2ForUnknownAsFalse(rexBuilder, terms, notTerms);
-    }
-    return simplifyAnd2(rexBuilder, terms, notTerms);
+    return new RexSimplify(rexBuilder, unknownAsFalse, EXECUTOR)
+        .simplifyAnd(e);
   }
 
+  @Deprecated // to be removed before 2.0
   public static RexNode simplifyAnd2(RexBuilder rexBuilder,
       List<RexNode> terms, List<RexNode> notTerms) {
-    for (RexNode term : terms) {
-      if (term.isAlwaysFalse()) {
-        return rexBuilder.makeLiteral(false);
-      }
-    }
-    if (terms.isEmpty() && notTerms.isEmpty()) {
-      return rexBuilder.makeLiteral(true);
-    }
-    if (terms.size() == 1 && notTerms.isEmpty()) {
-      // Make sure "x OR y OR x" (a single-term conjunction) gets simplified.
-      return simplify(rexBuilder, terms.get(0));
-    }
-    // If one of the not-disjunctions is a disjunction that is wholly
-    // contained in the disjunctions list, the expression is not
-    // satisfiable.
-    //
-    // Example #1. x AND y AND z AND NOT (x AND y)  - not satisfiable
-    // Example #2. x AND y AND NOT (x AND y)        - not satisfiable
-    // Example #3. x AND y AND NOT (x AND y AND z)  - may be satisfiable
-    for (RexNode notDisjunction : notTerms) {
-      final List<RexNode> terms2 = RelOptUtil.conjunctions(notDisjunction);
-      if (terms.containsAll(terms2)) {
-        return rexBuilder.makeLiteral(false);
-      }
-    }
-    // Add the NOT disjunctions back in.
-    for (RexNode notDisjunction : notTerms) {
-      terms.add(
-          simplify(rexBuilder,
-              rexBuilder.makeCall(SqlStdOperatorTable.NOT, notDisjunction)));
-    }
-    return composeConjunction(rexBuilder, terms, false);
+    return new RexSimplify(rexBuilder, false, EXECUTOR)
+        .simplifyAnd2(terms, notTerms);
   }
 
-  /** As {@link #simplifyAnd2(RexBuilder, List, List)} but we assume that if 
the expression returns
-   * UNKNOWN it will be interpreted as FALSE. */
+  @Deprecated // to be removed before 2.0
   public static RexNode simplifyAnd2ForUnknownAsFalse(RexBuilder rexBuilder,
       List<RexNode> terms, List<RexNode> notTerms) {
-    final RexExecutor executor = EXECUTOR;
-    for (RexNode term : terms) {
-      if (term.isAlwaysFalse()) {
-        return rexBuilder.makeLiteral(false);
-      }
-    }
-    if (terms.isEmpty() && notTerms.isEmpty()) {
-      return rexBuilder.makeLiteral(true);
-    }
-    if (terms.size() == 1 && notTerms.isEmpty()) {
-      // Make sure "x OR y OR x" (a single-term conjunction) gets simplified.
-      return simplify(rexBuilder, terms.get(0), true);
-    }
-    // Try to simplify the expression
-    final Multimap<String, Pair<String, RexNode>> equalityTerms = 
ArrayListMultimap.create();
-    final Map<String, String> equalityConstantTerms = new HashMap<>();
-    final Set<String> negatedTerms = new HashSet<>();
-    final Set<String> nullOperands = new HashSet<>();
-    final Set<RexNode> notNullOperands = new LinkedHashSet<>();
-    final Set<String> comparedOperands = new HashSet<>();
-    for (int i = 0; i < terms.size(); i++) {
-      RexNode term = terms.get(i);
-      if (!isDeterministic(term)) {
-        continue;
-      }
-      // Simplify BOOLEAN expressions if possible
-      while (term.getKind() == SqlKind.EQUALS) {
-        RexCall call = (RexCall) term;
-        if (call.getOperands().get(0).isAlwaysTrue()) {
-          term = call.getOperands().get(1);
-          terms.set(i, term);
-          continue;
-        } else if (call.getOperands().get(1).isAlwaysTrue()) {
-          term = call.getOperands().get(0);
-          terms.set(i, term);
-          continue;
-        }
-        break;
-      }
-      switch (term.getKind()) {
-      case EQUALS:
-      case NOT_EQUALS:
-      case LESS_THAN:
-      case GREATER_THAN:
-      case LESS_THAN_OR_EQUAL:
-      case GREATER_THAN_OR_EQUAL:
-        RexCall call = (RexCall) term;
-        RexNode left = call.getOperands().get(0);
-        comparedOperands.add(left.toString());
-        // if it is a cast, we include the inner reference
-        if (left.getKind() == SqlKind.CAST) {
-          RexCall leftCast = (RexCall) left;
-          comparedOperands.add(leftCast.getOperands().get(0).toString());
-        }
-        RexNode right = call.getOperands().get(1);
-        comparedOperands.add(right.toString());
-        // if it is a cast, we include the inner reference
-        if (right.getKind() == SqlKind.CAST) {
-          RexCall rightCast = (RexCall) right;
-          comparedOperands.add(rightCast.getOperands().get(0).toString());
-        }
-        // Check for equality on different constants. If the same ref or 
CAST(ref)
-        // is equal to different constants, this condition cannot be satisfied,
-        // and hence it can be evaluated to FALSE
-        if (term.getKind() == SqlKind.EQUALS) {
-          final boolean leftRef = isReferenceOrAccess(left, true);
-          final boolean rightRef = isReferenceOrAccess(right, true);
-          if (right instanceof RexLiteral && leftRef) {
-            final String literal = right.toString();
-            final String prevLiteral = 
equalityConstantTerms.put(left.toString(), literal);
-            if (prevLiteral != null && !literal.equals(prevLiteral)) {
-              return rexBuilder.makeLiteral(false);
-            }
-          } else if (left instanceof RexLiteral && rightRef) {
-            final String literal = left.toString();
-            final String prevLiteral = 
equalityConstantTerms.put(right.toString(), literal);
-            if (prevLiteral != null && !literal.equals(prevLiteral)) {
-              return rexBuilder.makeLiteral(false);
-            }
-          } else if (leftRef && rightRef) {
-            equalityTerms.put(left.toString(), Pair.of(right.toString(), 
term));
-          }
-        }
-        // Assume the expression a > 5 is part of a Filter condition.
-        // Then we can derive the negated term: a <= 5.
-        // But as the comparison is string based and thus operands order 
dependent,
-        // we should also add the inverted negated term: 5 >= a.
-        // Observe that for creating the inverted term we invert the list of 
operands.
-        RexNode negatedTerm = negate(rexBuilder, call);
-        if (negatedTerm != null) {
-          negatedTerms.add(negatedTerm.toString());
-          RexNode invertNegatedTerm = invert(rexBuilder, (RexCall) 
negatedTerm);
-          if (invertNegatedTerm != null) {
-            negatedTerms.add(invertNegatedTerm.toString());
-          }
-        }
-        break;
-      case IN:
-        comparedOperands.add(((RexCall) term).operands.get(0).toString());
-        break;
-      case BETWEEN:
-        comparedOperands.add(((RexCall) term).operands.get(1).toString());
-        break;
-      case IS_NOT_NULL:
-        notNullOperands.add(((RexCall) term).getOperands().get(0));
-        terms.remove(i);
-        --i;
-        break;
-      case IS_NULL:
-        nullOperands.add(((RexCall) term).getOperands().get(0).toString());
-      }
-    }
-    // If one column should be null and is in a comparison predicate,
-    // it is not satisfiable.
-    // Example. IS NULL(x) AND x < 5  - not satisfiable
-    if (!Collections.disjoint(nullOperands, comparedOperands)) {
-      return rexBuilder.makeLiteral(false);
-    }
-    // Check for equality of two refs wrt equality with constants
-    // Example #1. x=5 AND y=5 AND x=y : x=5 AND y=5
-    // Example #2. x=5 AND y=6 AND x=y - not satisfiable
-    for (String ref1 : equalityTerms.keySet()) {
-      final String literal1 = equalityConstantTerms.get(ref1);
-      if (literal1 == null) {
-        continue;
-      }
-      Collection<Pair<String, RexNode>> references = equalityTerms.get(ref1);
-      for (Pair<String, RexNode> ref2 : references) {
-        final String literal2 = equalityConstantTerms.get(ref2.left);
-        if (literal2 == null) {
-          continue;
-        }
-        if (!literal1.equals(literal2)) {
-          // If an expression is equal to two different constants,
-          // it is not satisfiable
-          return rexBuilder.makeLiteral(false);
-        }
-        // Otherwise we can remove the term, as we already know that
-        // the expression is equal to two constants
-        terms.remove(ref2.right);
-      }
-    }
-    // Remove not necessary IS NOT NULL expressions.
-    //
-    // Example. IS NOT NULL(x) AND x < 5  : x < 5
-    for (RexNode operand : notNullOperands) {
-      if (!comparedOperands.contains(operand.toString())) {
-        terms.add(
-            rexBuilder.makeCall(SqlStdOperatorTable.IS_NOT_NULL, operand));
-      }
-    }
-    // If one of the not-disjunctions is a disjunction that is wholly
-    // contained in the disjunctions list, the expression is not
-    // satisfiable.
-    //
-    // Example #1. x AND y AND z AND NOT (x AND y)  - not satisfiable
-    // Example #2. x AND y AND NOT (x AND y)        - not satisfiable
-    // Example #3. x AND y AND NOT (x AND y AND z)  - may be satisfiable
-    final Set<String> termsSet = new HashSet<String>(strings(terms));
-    for (RexNode notDisjunction : notTerms) {
-      if (!isDeterministic(notDisjunction)) {
-        continue;
-      }
-      final List<String> terms2Set = 
strings(RelOptUtil.conjunctions(notDisjunction));
-      if (termsSet.containsAll(terms2Set)) {
-        return rexBuilder.makeLiteral(false);
-      }
-    }
-    // Add the NOT disjunctions back in.
-    for (RexNode notDisjunction : notTerms) {
-      final RexNode call =
-          rexBuilder.makeCall(SqlStdOperatorTable.NOT, notDisjunction);
-      terms.add(simplify(rexBuilder, call, true, executor));
-    }
-    // The negated terms: only deterministic expressions
-    for (String negatedTerm : negatedTerms) {
-      if (termsSet.contains(negatedTerm)) {
-        return rexBuilder.makeLiteral(false);
-      }
-    }
-    return composeConjunction(rexBuilder, terms, false);
+    return new RexSimplify(rexBuilder, true, EXECUTOR)
+        .simplifyAnd2ForUnknownAsFalse(terms, notTerms);
   }
 
   public static RexNode negate(RexBuilder rexBuilder, RexCall call) {
@@ -2326,34 +1738,17 @@ public class RexUtil {
     return null;
   }
 
-  /** Simplifies OR(x, x) into x, and similar. */
+  @Deprecated // to be removed before 2.0
   public static RexNode simplifyOr(RexBuilder rexBuilder, RexCall call) {
-    assert call.getKind() == SqlKind.OR;
-    final List<RexNode> terms = RelOptUtil.disjunctions(call);
-    return simplifyOrs(rexBuilder, terms);
+    return new RexSimplify(rexBuilder, false, EXECUTOR)
+        .simplifyOr(call);
   }
 
-  /** Simplifies a list of terms and combines them into an OR.
-   * Modifies the list in place. */
+  @Deprecated // to be removed before 2.0
   public static RexNode simplifyOrs(RexBuilder rexBuilder,
       List<RexNode> terms) {
-    for (int i = 0; i < terms.size(); i++) {
-      final RexNode term = simplify(rexBuilder, terms.get(i));
-      switch (term.getKind()) {
-      case LITERAL:
-        if (!RexLiteral.isNullLiteral(term)) {
-          if (RexLiteral.booleanValue(term)) {
-            return term; // true
-          } else {
-            terms.remove(i);
-            --i;
-            continue;
-          }
-        }
-      }
-      terms.set(i, term);
-    }
-    return composeDisjunction(rexBuilder, terms, false);
+    return new RexSimplify(rexBuilder, false, EXECUTOR)
+        .simplifyOrs(terms);
   }
 
   /**
@@ -2420,41 +1815,6 @@ public class RexUtil {
         && (call.operands.size() - i) % 2 == 1;
   }
 
-  private static RexNode simplifyCast(RexBuilder rexBuilder, RexCall e,
-      RexExecutor executor) {
-    Preconditions.checkNotNull(executor);
-    final RexNode operand = e.getOperands().get(0);
-    switch (operand.getKind()) {
-    case LITERAL:
-      final RexLiteral literal = (RexLiteral) operand;
-      final Comparable value = literal.getValue();
-      final SqlTypeName typeName = literal.getTypeName();
-
-      // First, try to remove the cast without changing the value.
-      // makeCast and canRemoveCastFromLiteral have the same logic, so we are
-      // sure to be able to remove the cast.
-      if (rexBuilder.canRemoveCastFromLiteral(e.getType(), value, typeName)) {
-        return rexBuilder.makeCast(e.getType(), operand);
-      }
-
-      // Next, try to convert the value to a different type,
-      // e.g. CAST('123' as integer)
-      switch (literal.getTypeName()) {
-      case TIME:
-        switch (e.getType().getSqlTypeName()) {
-        case TIMESTAMP:
-          return e;
-        }
-      }
-      final List<RexNode> reducedValues = new ArrayList<>();
-      executor.reduce(rexBuilder, ImmutableList.<RexNode>of(e), reducedValues);
-      return Preconditions.checkNotNull(
-          Iterables.getOnlyElement(reducedValues));
-    default:
-      return e;
-    }
-  }
-
   /** Returns a function that applies NOT to its argument. */
   public static Function<RexNode, RexNode> notFn(final RexBuilder rexBuilder) {
     return new Function<RexNode, RexNode>() {
@@ -2799,7 +2159,7 @@ public class RexUtil {
     }
 
     private RexNode or(Iterable<? extends RexNode> nodes) {
-      return composeDisjunction(rexBuilder, nodes, false);
+      return composeDisjunction(rexBuilder, nodes);
     }
   }
 
@@ -2876,7 +2236,7 @@ public class RexUtil {
     }
 
     private RexNode or(Iterable<? extends RexNode> nodes) {
-      return composeDisjunction(rexBuilder, nodes, false);
+      return composeDisjunction(rexBuilder, nodes);
     }
   }
 
@@ -3014,29 +2374,26 @@ public class RexUtil {
 
   /** Deep expressions simplifier. */
   public static class ExprSimplifier extends RexShuttle {
-    private final RexBuilder rexBuilder;
-    private final RexExecutor executor;
-    private final boolean unknownAsFalse;
+    private final RexSimplify simplify;
     private final Map<RexNode, Boolean> unknownAsFalseMap;
 
-    public ExprSimplifier(RexBuilder rexBuilder, boolean unknownAsFalse,
-        RexExecutor executor) {
-      this.rexBuilder = Preconditions.checkNotNull(rexBuilder);
-      this.executor = Preconditions.checkNotNull(executor);
-      this.unknownAsFalse = unknownAsFalse;
+    public ExprSimplifier(RexSimplify simplify) {
+      this.simplify = simplify;
       this.unknownAsFalseMap = new HashMap<>();
     }
 
     @Override public RexNode visitCall(RexCall call) {
-      Boolean unknownAsFalseCall = unknownAsFalse;
+      boolean unknownAsFalseCall = simplify.unknownAsFalse;
       if (unknownAsFalseCall) {
         switch (call.getKind()) {
         case AND:
         case CASE:
-          unknownAsFalseCall = this.unknownAsFalseMap.get(call);
-          if (unknownAsFalseCall == null) {
+          final Boolean b = this.unknownAsFalseMap.get(call);
+          if (b == null) {
             // Top operator
             unknownAsFalseCall = true;
+          } else {
+            unknownAsFalseCall = b;
           }
           break;
         default:
@@ -3048,14 +2405,15 @@ public class RexUtil {
       }
       RexNode node = super.visitCall(call);
       RexNode simplifiedNode =
-          simplify(rexBuilder, node, unknownAsFalseCall, executor);
+          simplify.withUnknownAsFalse(unknownAsFalseCall)
+              .simplify(node);
       if (node == simplifiedNode) {
         return node;
       }
       if (simplifiedNode.getType().equals(call.getType())) {
         return simplifiedNode;
       }
-      return rexBuilder.makeCast(call.getType(), simplifiedNode, true);
+      return simplify.rexBuilder.makeCast(call.getType(), simplifiedNode, 
true);
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
----------------------------------------------------------------------
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 33856d5..079e8e4 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -1445,7 +1445,7 @@ public class StandardConvertletTable extends 
ReflectiveConvertletTable {
       for (RexNode expr : exprs) {
         orList.add(rexBuilder.makeCall(SqlStdOperatorTable.IS_NULL, expr));
       }
-      list.add(RexUtil.composeDisjunction(rexBuilder, orList, false));
+      list.add(RexUtil.composeDisjunction(rexBuilder, orList));
       list.add(rexBuilder.makeNullLiteral(type));
       for (int i = 0; i < exprs.size() - 1; i++) {
         RexNode expr = exprs.get(i);

http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
----------------------------------------------------------------------
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 ddc0c43..c2d76f0 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -49,6 +49,7 @@ 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.RexSimplify;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.schema.SchemaPlus;
@@ -133,7 +134,8 @@ public class RelBuilder {
   private final RelFactories.TableScanFactory scanFactory;
   private final Deque<Frame> stack = new ArrayDeque<>();
   private final boolean simplify;
-  private final RexExecutor executor;
+  private final RexSimplify simplifier;
+  private final RexSimplify simplifierUnknownAsFalse;
 
   protected RelBuilder(Context context, RelOptCluster cluster,
       RelOptSchema relOptSchema) {
@@ -173,9 +175,12 @@ public class RelBuilder {
     this.scanFactory =
         Util.first(context.unwrap(RelFactories.TableScanFactory.class),
             RelFactories.DEFAULT_TABLE_SCAN_FACTORY);
-    this.executor =
+    final RexExecutor executor =
         Util.first(context.unwrap(RexExecutor.class),
             Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR));
+    this.simplifier = new RexSimplify(cluster.getRexBuilder(), false, 
executor);
+    this.simplifierUnknownAsFalse =
+        new RexSimplify(cluster.getRexBuilder(), true, executor);
   }
 
   /** Creates a RelBuilder. */
@@ -552,7 +557,7 @@ public class RelBuilder {
    * {@code e AND TRUE} becomes {@code e};
    * {@code e AND e2 AND NOT e} becomes {@code e2}. */
   public RexNode and(Iterable<? extends RexNode> operands) {
-    return RexUtil.simplifyAnds(cluster.getRexBuilder(), operands);
+    return simplifier.simplifyAnds(operands);
   }
 
   /** Creates an OR. */
@@ -562,7 +567,7 @@ public class RelBuilder {
 
   /** Creates an OR. */
   public RexNode or(Iterable<? extends RexNode> operands) {
-    return RexUtil.composeDisjunction(cluster.getRexBuilder(), operands, 
false);
+    return RexUtil.composeDisjunction(cluster.getRexBuilder(), operands);
   }
 
   /** Creates a NOT. */
@@ -803,7 +808,7 @@ public class RelBuilder {
    * and optimized in a similar way to the {@link #and} method.
    * If the result is TRUE no filter is created. */
   public RelBuilder filter(Iterable<? extends RexNode> predicates) {
-    final RexNode x = RexUtil.simplifyAnds(cluster.getRexBuilder(), 
predicates, true);
+    final RexNode x = simplifierUnknownAsFalse.simplifyAnds(predicates);
     if (x.isAlwaysFalse()) {
       return empty();
     }
@@ -870,7 +875,7 @@ public class RelBuilder {
     final Iterator<String> nameIterator = fieldNames.iterator();
     for (RexNode node : nodes) {
       if (simplify) {
-        node = RexUtil.simplifyPreservingType(getRexBuilder(), node, executor);
+        node = simplifier.simplifyPreservingType(node);
       }
       exprList.add(node);
       String name = nameIterator.hasNext() ? nameIterator.next() : null;

http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java 
b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java
index 63a84f1..ea7b58b 100644
--- a/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/rel/rules/DateRangeRulesTest.java
@@ -18,7 +18,6 @@ package org.apache.calcite.rel.rules;
 
 import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.test.RexImplicationCheckerTest.Fixture;
 
@@ -204,7 +203,7 @@ public class DateRangeRulesTest {
               operandRanges));
     }
     assertThat(e.toString(), matcher);
-    final RexNode e2 = RexUtil.simplify(f.rexBuilder, e);
+    final RexNode e2 = f.simplify.simplify(e);
     assertThat(e2.toString(), simplifyMatcher);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java 
b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
index 9a5d605..4ad07d4 100644
--- a/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
+++ b/core/src/test/java/org/apache/calcite/test/MaterializationTest.java
@@ -33,6 +33,7 @@ import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexSimplify;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.runtime.Hook;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
@@ -86,7 +87,9 @@ public class MaterializationTest {
 
   final JavaTypeFactoryImpl typeFactory =
       new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
-  final RexBuilder rexBuilder = new RexBuilder(typeFactory);
+  private final RexBuilder rexBuilder = new RexBuilder(typeFactory);
+  private final RexSimplify simplify =
+      new RexSimplify(rexBuilder, false, RexUtil.EXECUTOR);
 
   @Test public void testScan() {
     CalciteAssert.that()
@@ -716,13 +719,13 @@ public class MaterializationTest {
 
   private void checkNotSatisfiable(RexNode e) {
     assertFalse(SubstitutionVisitor.mayBeSatisfiable(e));
-    final RexNode simple = RexUtil.simplify(rexBuilder, e);
+    final RexNode simple = simplify.simplify(e);
     assertFalse(RexLiteral.booleanValue(simple));
   }
 
   private void checkSatisfiable(RexNode e, String s) {
     assertTrue(SubstitutionVisitor.mayBeSatisfiable(e));
-    final RexNode simple = RexUtil.simplify(rexBuilder, e);
+    final RexNode simple = simplify.simplify(e);
     assertEquals(s, simple.toString());
   }
 
@@ -755,7 +758,7 @@ public class MaterializationTest {
     //   target:    x = 1 or z = 3
     // yields
     //   residue:   not (z = 3)
-    newFilter = SubstitutionVisitor.splitFilter(rexBuilder,
+    newFilter = SubstitutionVisitor.splitFilter(simplify,
         x_eq_1,
         rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, z_eq_3));
     assertThat(newFilter.toString(), equalTo("NOT(=($2, 3))"));
@@ -765,7 +768,7 @@ public class MaterializationTest {
     //   target:    x = 1 or y = 2 or z = 3
     // yields
     //   residue:   not (z = 3)
-    newFilter = SubstitutionVisitor.splitFilter(rexBuilder,
+    newFilter = SubstitutionVisitor.splitFilter(simplify,
         rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, y_eq_2),
         rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, y_eq_2, z_eq_3));
     assertThat(newFilter.toString(), equalTo("NOT(=($2, 3))"));
@@ -775,7 +778,7 @@ public class MaterializationTest {
     //   target:    x = 1 or y = 2 or z = 3
     // yields
     //   residue:   not (y = 2) and not (z = 3)
-    newFilter = SubstitutionVisitor.splitFilter(rexBuilder,
+    newFilter = SubstitutionVisitor.splitFilter(simplify,
         x_eq_1,
         rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, y_eq_2, z_eq_3));
     assertThat(newFilter.toString(),
@@ -786,7 +789,7 @@ public class MaterializationTest {
     //   target:    y = 2 or x = 1
     // yields
     //   residue:   true
-    newFilter = SubstitutionVisitor.splitFilter(rexBuilder,
+    newFilter = SubstitutionVisitor.splitFilter(simplify,
         rexBuilder.makeCall(SqlStdOperatorTable.OR, x_eq_1, y_eq_2),
         rexBuilder.makeCall(SqlStdOperatorTable.OR, y_eq_2, x_eq_1));
     assertThat(newFilter.isAlwaysTrue(), equalTo(true));
@@ -796,7 +799,7 @@ public class MaterializationTest {
     //   target:    x = 1 (different object)
     // yields
     //   residue:   true
-    newFilter = SubstitutionVisitor.splitFilter(rexBuilder, x_eq_1, x_eq_1_b);
+    newFilter = SubstitutionVisitor.splitFilter(simplify, x_eq_1, x_eq_1_b);
     assertThat(newFilter.isAlwaysTrue(), equalTo(true));
 
     // 2f.

http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
----------------------------------------------------------------------
diff --git 
a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java 
b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
index 84deb87..f321551 100644
--- a/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexImplicationCheckerTest.java
@@ -29,6 +29,7 @@ import org.apache.calcite.rex.RexExecutorImpl;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
+import org.apache.calcite.rex.RexSimplify;
 import org.apache.calcite.schema.SchemaPlus;
 import org.apache.calcite.schema.Schemas;
 import org.apache.calcite.server.CalciteServerStatement;
@@ -357,6 +358,7 @@ public class RexImplicationCheckerTest {
     public final RexImplicationChecker checker;
     public final RelDataType rowType;
     public final RexExecutorImpl executor;
+    public final RexSimplify simplify;
 
     public Fixture() {
       typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
@@ -417,6 +419,7 @@ public class RexImplicationCheckerTest {
           });
 
       executor = holder.get();
+      simplify = new RexSimplify(rexBuilder, false, executor);
       checker = new RexImplicationChecker(rexBuilder, executor, rowType);
     }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
----------------------------------------------------------------------
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 c1f567c..671b685 100644
--- a/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RexProgramTest.java
@@ -32,6 +32,7 @@ import org.apache.calcite.rex.RexLocalRef;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
 import org.apache.calcite.rex.RexProgramBuilder;
+import org.apache.calcite.rex.RexSimplify;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
@@ -75,6 +76,7 @@ public class RexProgramTest {
   private RexLiteral falseLiteral;
   private RexNode nullLiteral;
   private RexNode unknownLiteral;
+  private RexSimplify simplify;
 
   //~ Methods ----------------------------------------------------------------
 
@@ -89,6 +91,7 @@ public class RexProgramTest {
   public void setUp() {
     typeFactory = new JavaTypeFactoryImpl(RelDataTypeSystem.DEFAULT);
     rexBuilder = new RexBuilder(typeFactory);
+    simplify = new RexSimplify(rexBuilder, false, RexUtil.EXECUTOR);
     trueLiteral = rexBuilder.makeLiteral(true);
     falseLiteral = rexBuilder.makeLiteral(false);
     final RelDataType intType = typeFactory.createSqlType(SqlTypeName.INTEGER);
@@ -135,16 +138,16 @@ public class RexProgramTest {
    */
   private void checkSimplify2(RexNode node, String expected,
       String expectedFalse) {
-    assertThat(RexUtil.simplify(rexBuilder, node).toString(),
+    assertThat(simplify.simplify(node).toString(),
         equalTo(expected));
     if (node.getType().getSqlTypeName() == SqlTypeName.BOOLEAN) {
-      assertThat(RexUtil.simplify(rexBuilder, node, true).toString(),
+      assertThat(simplify.withUnknownAsFalse(true).simplify(node).toString(),
           equalTo(expectedFalse));
     }
   }
 
   private void checkSimplifyFilter(RexNode node, String expected) {
-    assertThat(RexUtil.simplify(rexBuilder, node, true).toString(),
+    assertThat(simplify.withUnknownAsFalse(true).simplify(node).toString(),
         equalTo(expected));
   }
 
@@ -239,7 +242,7 @@ public class RexProgramTest {
     // Normalize the program using the RexProgramBuilder.normalize API.
     // Note that unused expression '77' is eliminated, input refs (e.g. $0)
     // become local refs (e.g. $t0), and constants are assigned to locals.
-    final RexProgram normalizedProgram = program.normalize(rexBuilder, false);
+    final RexProgram normalizedProgram = program.normalize(rexBuilder, null);
     final String normalizedProgramString = normalizedProgram.toString();
     TestUtil.assertEqualsVerbose(
         "(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], "
@@ -296,7 +299,7 @@ public class RexProgramTest {
             + "expr#13=[null], expr#14=[CASE($t9, $t10, $t11, $t12, $t13)], "
             + "expr#15=[NOT($t14)], a=[$t7], b=[$t6], $condition=[$t15])"));
 
-    assertThat(program.normalize(rexBuilder, true).toString(),
+    assertThat(program.normalize(rexBuilder, simplify).toString(),
         is("(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], "
             + "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], "
             + "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[>($t4, $t7)], "
@@ -318,7 +321,7 @@ public class RexProgramTest {
             + "expr#15=[NOT($t14)], expr#16=[IS TRUE($t15)], a=[$t7], b=[$t6], 
"
             + "$condition=[$t16])"));
 
-    assertThat(program.normalize(rexBuilder, true).toString(),
+    assertThat(program.normalize(rexBuilder, simplify).toString(),
         is("(expr#0..1=[{inputs}], expr#2=[+($t0, $t1)], expr#3=[1], "
             + "expr#4=[+($t0, $t3)], expr#5=[+($t2, $t4)], "
             + "expr#6=[+($t0, $t4)], expr#7=[5], expr#8=[>($t4, $t7)], "
@@ -1104,7 +1107,7 @@ public class RexProgramTest {
         rexBuilder.makeLiteral("S"));
     RexCall caseNode = (RexCall) case_(condition, trueLiteral, falseLiteral);
 
-    RexCall result = (RexCall) RexUtil.simplify(rexBuilder, caseNode, false);
+    RexCall result = (RexCall) simplify.simplify(caseNode);
     assertThat(result.getType().isNullable(), is(false));
     assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
     assertThat(result.getOperator(), is((SqlOperator) 
SqlStdOperatorTable.CASE));
@@ -1123,7 +1126,7 @@ public class RexProgramTest {
         rexBuilder.makeLiteral("S"));
     RexCall caseNode = (RexCall) case_(condition, trueLiteral, falseLiteral);
 
-    RexCall result = (RexCall) RexUtil.simplify(rexBuilder, caseNode, false);
+    RexCall result = (RexCall) simplify.simplify(caseNode);
     assertThat(result.getType().isNullable(), is(false));
     assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
     assertThat(result, is(condition));
@@ -1141,7 +1144,7 @@ public class RexProgramTest {
     RexCall caseNode = (RexCall) case_(condition, aLiteral, bLiteral);
 
 
-    RexCall result = (RexCall) RexUtil.simplify(rexBuilder, caseNode, false);
+    RexCall result = (RexCall) simplify.simplify(caseNode);
     assertThat(result.getType().isNullable(), is(false));
     assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.CHAR));
     assertThat(result, is(caseNode));
@@ -1158,7 +1161,7 @@ public class RexProgramTest {
         and(rexBuilder.makeInputRef(booleanNotNullableType, 0),
             rexBuilder.makeInputRef(booleanNullableType, 1),
             rexBuilder.makeInputRef(booleanNotNullableType, 2));
-    RexNode result = RexUtil.simplify(rexBuilder, andCondition, false);
+    RexNode result = simplify.simplify(andCondition);
     assertThat(result.getType().isNullable(), is(true));
     assertThat(result.getType().getSqlTypeName(), is(SqlTypeName.BOOLEAN));
   }
@@ -1261,7 +1264,7 @@ public class RexProgramTest {
               assertThat(cast.getType(), is(toType));
               continue; // makeCast already simplified
             }
-            final RexNode simplified = RexUtil.simplify(rexBuilder, cast);
+            final RexNode simplified = simplify.simplify(cast);
             boolean expectedSimplify =
                 literal.getTypeName() != toType.getSqlTypeName()
                 || (literal.getTypeName() == SqlTypeName.CHAR

http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java
----------------------------------------------------------------------
diff --git 
a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java 
b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java
index 91a29ab..bb15921 100644
--- a/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java
+++ b/druid/src/main/java/org/apache/calcite/adapter/druid/DruidRules.java
@@ -40,10 +40,12 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rex.RexBuilder;
 import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexExecutor;
 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.RexSimplify;
 import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.runtime.PredicateImpl;
 import org.apache.calcite.sql.type.SqlTypeFamily;
@@ -159,10 +161,12 @@ public class DruidRules {
           break;
         }
       }
+      final RexExecutor executor =
+          Util.first(cluster.getPlanner().getExecutor(), RexUtil.EXECUTOR);
+      final RexSimplify simplify = new RexSimplify(rexBuilder, true, executor);
       final Pair<List<RexNode>, List<RexNode>> pair =
           splitFilters(rexBuilder, query,
-              RexUtil.simplify(rexBuilder, filter.getCondition(), true),
-              timestampFieldIdx);
+              simplify.simplify(filter.getCondition()), timestampFieldIdx);
       if (pair == null) {
         // We can't push anything useful to Druid.
         return;
@@ -170,8 +174,8 @@ public class DruidRules {
       List<LocalInterval> intervals = null;
       if (!pair.left.isEmpty()) {
         intervals = DruidDateTimeUtils.createInterval(
-                
query.getRowType().getFieldList().get(timestampFieldIdx).getType(),
-                RexUtil.composeConjunction(rexBuilder, pair.left, false));
+            query.getRowType().getFieldList().get(timestampFieldIdx).getType(),
+            RexUtil.composeConjunction(rexBuilder, pair.left, false));
         if (intervals == null) {
           // We can't push anything useful to Druid.
           return;

http://git-wip-us.apache.org/repos/asf/calcite/blob/ca48431e/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
----------------------------------------------------------------------
diff --git 
a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java 
b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
index 0cf7a95..8273130 100644
--- a/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
+++ b/druid/src/test/java/org/apache/calcite/test/DruidDateRangeRulesTest.java
@@ -21,7 +21,6 @@ import org.apache.calcite.adapter.druid.LocalInterval;
 import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.rel.rules.DateRangeRules;
 import org.apache.calcite.rex.RexNode;
-import org.apache.calcite.rex.RexUtil;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.test.RexImplicationCheckerTest.Fixture;
 
@@ -130,7 +129,7 @@ public class DruidDateRangeRulesTest {
           new DateRangeRules.ExtractShuttle(f.rexBuilder, timeUnit,
               operandRanges));
     }
-    final RexNode e2 = RexUtil.simplify(f.rexBuilder, e);
+    final RexNode e2 = f.simplify.simplify(e);
     List<LocalInterval> intervals =
         DruidDateTimeUtils.createInterval(f.timeStampDataType, e2);
     if (intervals == null) {

Reply via email to