You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@calcite.apache.org by jh...@apache.org on 2015/10/05 21:18:44 UTC

[1/2] incubator-calcite git commit: [CALCITE-906] Avatica JdbcMeta statement IDs are not unique

Repository: incubator-calcite
Updated Branches:
  refs/heads/master 4c7f5c20a -> b4c4f4938


[CALCITE-906] Avatica JdbcMeta statement IDs are not unique

Solve by allocating IDs from an AtomicInteger.


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

Branch: refs/heads/master
Commit: afcf3a6c852d4827e5de10c0aa37f2cf3b0179ee
Parents: 4c7f5c2
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Oct 1 13:30:07 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Fri Oct 2 13:50:27 2015 -0700

----------------------------------------------------------------------
 .../main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java | 9 +++++++--
 avatica/src/main/java/org/apache/calcite/avatica/Meta.java  | 4 +++-
 2 files changed, 10 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/afcf3a6c/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
----------------------------------------------------------------------
diff --git a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
index 18a0554..83ba087 100644
--- a/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
+++ b/avatica-server/src/main/java/org/apache/calcite/avatica/jdbc/JdbcMeta.java
@@ -52,6 +52,7 @@ import java.util.Objects;
 import java.util.Properties;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
 
 /** Implementation of {@link Meta} upon an existing JDBC data source. */
 public class JdbcMeta implements Meta {
@@ -61,6 +62,10 @@ public class JdbcMeta implements Meta {
 
   final Calendar calendar = Calendar.getInstance();
 
+  /** Generates ids for statements. The ids are unique across all connections
+   * created by this JdbcMeta. */
+  private final AtomicInteger statementIdGenerator = new AtomicInteger();
+
   /** Configurable connection cache settings. */
   public enum ConnectionCacheSettings {
     /** JDBC connection property for setting connection cache concurrency level. */
@@ -606,7 +611,7 @@ public class JdbcMeta implements Meta {
     try {
       final Connection conn = getConnection(ch.id);
       final Statement statement = conn.createStatement();
-      final int id = System.identityHashCode(statement);
+      final int id = statementIdGenerator.getAndIncrement();
       statementCache.put(id, new StatementInfo(statement));
       StatementHandle h = new StatementHandle(ch.id, id, null);
       if (LOG.isTraceEnabled()) {
@@ -709,7 +714,7 @@ public class JdbcMeta implements Meta {
     try {
       final Connection conn = getConnection(ch.id);
       final PreparedStatement statement = conn.prepareStatement(sql);
-      final int id = System.identityHashCode(statement);
+      final int id = statementIdGenerator.getAndIncrement();
       statementCache.put(id, new StatementInfo(statement));
       StatementHandle h = new StatementHandle(ch.id, id,
           signature(statement.getMetaData(), statement.getParameterMetaData(),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/afcf3a6c/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
----------------------------------------------------------------------
diff --git a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
index e0162b3..4b0d249 100644
--- a/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
+++ b/avatica/src/main/java/org/apache/calcite/avatica/Meta.java
@@ -405,7 +405,9 @@ public interface Meta {
 
     public static MetaResultSet count(String connectionId, int statementId,
         long updateCount) {
-      assert updateCount >= 0;
+      assert updateCount >= 0
+          : "Meta.count(" + connectionId + ", " + statementId + ", "
+          + updateCount + ")";
       return new MetaResultSet(connectionId, statementId, false, null, null,
           updateCount);
     }


[2/2] incubator-calcite git commit: [CALCITE-909] Make ReduceExpressionsRule extensible

Posted by jh...@apache.org.
[CALCITE-909] Make ReduceExpressionsRule extensible

Close apache/incubator-calcite#141


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

Branch: refs/heads/master
Commit: b4c4f49389cd74cd2e748f33ced1add9278bf8f4
Parents: afcf3a6
Author: Jesus Camacho Rodriguez <jc...@apache.org>
Authored: Sat Oct 3 16:41:23 2015 +0100
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Oct 5 11:31:40 2015 -0700

----------------------------------------------------------------------
 .../rel/rules/ReduceExpressionsRule.java        | 480 ++++++++++---------
 .../org/apache/calcite/tools/RelBuilder.java    |   9 +
 2 files changed, 275 insertions(+), 214 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b4c4f493/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 4bf7685..4e2d890 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -20,15 +20,17 @@ import org.apache.calcite.plan.RelOptPlanner;
 import org.apache.calcite.plan.RelOptPredicateList;
 import org.apache.calcite.plan.RelOptRule;
 import org.apache.calcite.plan.RelOptRuleCall;
-import org.apache.calcite.plan.RelOptUtil;
 import org.apache.calcite.rel.RelNode;
+import org.apache.calcite.rel.core.Calc;
 import org.apache.calcite.rel.core.EquiJoin;
+import org.apache.calcite.rel.core.Filter;
 import org.apache.calcite.rel.core.Join;
 import org.apache.calcite.rel.core.JoinInfo;
+import org.apache.calcite.rel.core.Project;
+import org.apache.calcite.rel.core.RelFactories;
 import org.apache.calcite.rel.logical.LogicalCalc;
 import org.apache.calcite.rel.logical.LogicalFilter;
 import org.apache.calcite.rel.logical.LogicalProject;
-import org.apache.calcite.rel.logical.LogicalValues;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
@@ -53,6 +55,7 @@ import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.fun.SqlRowOperator;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.type.SqlTypeName;
+import org.apache.calcite.tools.RelBuilderFactory;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Stacks;
 import org.apache.calcite.util.Util;
@@ -91,223 +94,271 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
 
   /**
    * Singleton rule that reduces constants inside a
-   * {@link org.apache.calcite.rel.logical.LogicalFilter}. If the condition is a
-   * constant, the filter is removed (if TRUE) or replaced with an empty
-   * {@link org.apache.calcite.rel.core.Values} (if FALSE or NULL).
+   * {@link org.apache.calcite.rel.logical.LogicalFilter}.
    */
   public static final ReduceExpressionsRule FILTER_INSTANCE =
-      new ReduceExpressionsRule(LogicalFilter.class,
-          "ReduceExpressionsRule(Filter)") {
-        public void onMatch(RelOptRuleCall call) {
-          final LogicalFilter filter = call.rel(0);
-          final List<RexNode> expList =
-              Lists.newArrayList(filter.getCondition());
-          RexNode newConditionExp;
-          boolean reduced;
-          final RelOptPredicateList predicates =
-              RelMetadataQuery.getPulledUpPredicates(filter.getInput());
-          if (reduceExpressions(filter, expList, predicates)) {
-            assert expList.size() == 1;
-            newConditionExp = expList.get(0);
-            reduced = true;
-          } else {
-            // No reduction, but let's still test the original
-            // predicate to see if it was already a constant,
-            // in which case we don't need any runtime decision
-            // about filtering.
-            newConditionExp = filter.getCondition();
-            reduced = false;
-          }
-          if (newConditionExp.isAlwaysTrue()) {
-            call.transformTo(
-                filter.getInput());
-          } else if (newConditionExp instanceof RexLiteral
-              || RexUtil.isNullLiteral(newConditionExp, true)) {
-            call.transformTo(
-                LogicalValues.createEmpty(filter.getCluster(),
-                    filter.getRowType()));
-          } else if (reduced) {
-            call.transformTo(
-                RelOptUtil.createFilter(filter.getInput(), expList.get(0)));
-          } else {
-            if (newConditionExp instanceof RexCall) {
-              RexCall rexCall = (RexCall) newConditionExp;
-              boolean reverse =
-                  rexCall.getOperator()
-                      == SqlStdOperatorTable.NOT;
-              if (reverse) {
-                rexCall = (RexCall) rexCall.getOperands().get(0);
-              }
-              reduceNotNullableFilter(call, filter, rexCall, reverse);
-            }
-            return;
-          }
+      new FilterReduceExpressionsRule(LogicalFilter.class, RelFactories.LOGICAL_BUILDER);
 
-          // New plan is absolutely better than old plan.
-          call.getPlanner().setImportance(filter, 0.0);
-        }
+  /**
+   * Singleton rule that reduces constants inside a
+   * {@link org.apache.calcite.rel.logical.LogicalProject}.
+   */
+  public static final ReduceExpressionsRule PROJECT_INSTANCE =
+      new ProjectReduceExpressionsRule(LogicalProject.class, RelFactories.LOGICAL_BUILDER);
 
-        private void reduceNotNullableFilter(
-            RelOptRuleCall call,
-            LogicalFilter filter,
-            RexCall rexCall,
-            boolean reverse) {
-          // If the expression is a IS [NOT] NULL on a non-nullable
-          // column, then we can either remove the filter or replace
-          // it with an Empty.
-          boolean alwaysTrue;
-          switch (rexCall.getKind()) {
-          case IS_NULL:
-          case IS_UNKNOWN:
-            alwaysTrue = false;
-            break;
-          case IS_NOT_NULL:
-            alwaysTrue = true;
-            break;
-          default:
-            return;
-          }
+  /**
+   * Singleton rule that reduces constants inside a
+   * {@link org.apache.calcite.rel.core.Join}.
+   */
+  public static final ReduceExpressionsRule JOIN_INSTANCE =
+      new JoinReduceExpressionsRule(Join.class, RelFactories.LOGICAL_BUILDER);
+
+  /**
+   * Singleton rule that reduces constants inside a
+   * {@link org.apache.calcite.rel.logical.LogicalCalc}.
+   */
+  public static final ReduceExpressionsRule CALC_INSTANCE =
+      new CalcReduceExpressionsRule(LogicalCalc.class, RelFactories.LOGICAL_BUILDER);
+
+  /**
+   * Rule that reduces constants inside a {@link org.apache.calcite.rel.core.Filter}.
+   * If the condition is a constant, the filter is removed (if TRUE) or replaced with
+   * an empty {@link org.apache.calcite.rel.core.Values} (if FALSE or NULL).
+   */
+  public static class FilterReduceExpressionsRule extends ReduceExpressionsRule {
+
+    public FilterReduceExpressionsRule(Class<? extends Filter> filterClass,
+        RelBuilderFactory relBuilderFactory) {
+      super(filterClass, relBuilderFactory, "ReduceExpressionsRule(Filter)");
+    }
+
+    @Override public void onMatch(RelOptRuleCall call) {
+      final Filter filter = call.rel(0);
+      final List<RexNode> expList =
+          Lists.newArrayList(filter.getCondition());
+      RexNode newConditionExp;
+      boolean reduced;
+      final RelOptPredicateList predicates =
+          RelMetadataQuery.getPulledUpPredicates(filter.getInput());
+      if (reduceExpressions(filter, expList, predicates)) {
+        assert expList.size() == 1;
+        newConditionExp = expList.get(0);
+        reduced = true;
+      } else {
+        // No reduction, but let's still test the original
+        // predicate to see if it was already a constant,
+        // in which case we don't need any runtime decision
+        // about filtering.
+        newConditionExp = filter.getCondition();
+        reduced = false;
+      }
+      if (newConditionExp.isAlwaysTrue()) {
+        call.transformTo(
+            filter.getInput());
+      } else if (newConditionExp instanceof RexLiteral
+          || RexUtil.isNullLiteral(newConditionExp, true)) {
+        call.transformTo(call.builder().values(filter.getRowType()).build());
+      } else if (reduced) {
+        call.transformTo(call.builder().
+            push(filter.getInput()).filter(expList.get(0)).build());
+      } else {
+        if (newConditionExp instanceof RexCall) {
+          RexCall rexCall = (RexCall) newConditionExp;
+          boolean reverse =
+              rexCall.getOperator()
+                  == SqlStdOperatorTable.NOT;
           if (reverse) {
-            alwaysTrue = !alwaysTrue;
-          }
-          RexNode operand = rexCall.getOperands().get(0);
-          if (operand instanceof RexInputRef) {
-            RexInputRef inputRef = (RexInputRef) operand;
-            if (!inputRef.getType().isNullable()) {
-              if (alwaysTrue) {
-                call.transformTo(filter.getInput());
-              } else {
-                call.transformTo(
-                    LogicalValues.createEmpty(filter.getCluster(),
-                        filter.getRowType()));
-              }
-            }
+            rexCall = (RexCall) rexCall.getOperands().get(0);
           }
+          reduceNotNullableFilter(call, filter, rexCall, reverse);
         }
-      };
+        return;
+      }
 
-  public static final ReduceExpressionsRule PROJECT_INSTANCE =
-      new ReduceExpressionsRule(LogicalProject.class,
-          "ReduceExpressionsRule(Project)") {
-        public void onMatch(RelOptRuleCall call) {
-          LogicalProject project = call.rel(0);
-          final RelOptPredicateList predicates =
-              RelMetadataQuery.getPulledUpPredicates(project.getInput());
-          final List<RexNode> expList =
-              Lists.newArrayList(project.getProjects());
-          if (reduceExpressions(project, expList, predicates)) {
-            call.transformTo(
-                LogicalProject.create(project.getInput(), expList,
-                    project.getRowType()));
-
-            // New plan is absolutely better than old plan.
-            call.getPlanner().setImportance(project, 0.0);
+      // New plan is absolutely better than old plan.
+      call.getPlanner().setImportance(filter, 0.0);
+    }
+
+    private void reduceNotNullableFilter(
+        RelOptRuleCall call,
+        Filter filter,
+        RexCall rexCall,
+        boolean reverse) {
+      // If the expression is a IS [NOT] NULL on a non-nullable
+      // column, then we can either remove the filter or replace
+      // it with an Empty.
+      boolean alwaysTrue;
+      switch (rexCall.getKind()) {
+      case IS_NULL:
+      case IS_UNKNOWN:
+        alwaysTrue = false;
+        break;
+      case IS_NOT_NULL:
+        alwaysTrue = true;
+        break;
+      default:
+        return;
+      }
+      if (reverse) {
+        alwaysTrue = !alwaysTrue;
+      }
+      RexNode operand = rexCall.getOperands().get(0);
+      if (operand instanceof RexInputRef) {
+        RexInputRef inputRef = (RexInputRef) operand;
+        if (!inputRef.getType().isNullable()) {
+          if (alwaysTrue) {
+            call.transformTo(filter.getInput());
+          } else {
+            call.transformTo(call.builder().values(filter.getRowType()).build());
           }
         }
-      };
+      }
+    }
+  }
 
-  public static final ReduceExpressionsRule JOIN_INSTANCE =
-      new ReduceExpressionsRule(Join.class,
-          "ReduceExpressionsRule(Join)") {
-        public void onMatch(RelOptRuleCall call) {
-          final Join join = call.rel(0);
-          final List<RexNode> expList = Lists.newArrayList(join.getCondition());
-          final int fieldCount = join.getLeft().getRowType().getFieldCount();
-          final RelOptPredicateList leftPredicates =
-              RelMetadataQuery.getPulledUpPredicates(join.getLeft());
-          final RelOptPredicateList rightPredicates =
-              RelMetadataQuery.getPulledUpPredicates(join.getRight());
-          final RelOptPredicateList predicates =
-              leftPredicates.union(rightPredicates.shift(fieldCount));
-          if (!reduceExpressions(join, expList, predicates)) {
-            return;
-          }
-          if (join instanceof EquiJoin) {
-            final JoinInfo joinInfo =
-                JoinInfo.of(join.getLeft(), join.getRight(), expList.get(0));
-            if (!joinInfo.isEqui()) {
-              // This kind of join must be an equi-join, and the condition is
-              // no longer an equi-join. SemiJoin is an example of this.
-              return;
-            }
-          }
-          call.transformTo(
-              join.copy(
-                  join.getTraitSet(),
-                  expList.get(0),
-                  join.getLeft(),
-                  join.getRight(),
-                  join.getJoinType(),
-                  join.isSemiJoinDone()));
-
-          // New plan is absolutely better than old plan.
-          call.getPlanner().setImportance(join, 0.0);
+  /**
+   * Rule that reduces constants inside a {@link org.apache.calcite.rel.core.Project}.
+   */
+  public static class ProjectReduceExpressionsRule extends ReduceExpressionsRule {
+
+    public ProjectReduceExpressionsRule(Class<? extends Project> projectClass,
+        RelBuilderFactory relBuilderFactory) {
+      super(projectClass, relBuilderFactory, "ReduceExpressionsRule(Project)");
+    }
+
+    @Override public void onMatch(RelOptRuleCall call) {
+      Project project = call.rel(0);
+      final RelOptPredicateList predicates =
+          RelMetadataQuery.getPulledUpPredicates(project.getInput());
+      final List<RexNode> expList =
+          Lists.newArrayList(project.getProjects());
+      if (reduceExpressions(project, expList, predicates)) {
+        call.transformTo(
+            call.builder()
+                .push(project.getInput())
+                .project(expList, project.getRowType().getFieldNames())
+                .build());
+
+        // New plan is absolutely better than old plan.
+        call.getPlanner().setImportance(project, 0.0);
+      }
+    }
+  }
+
+  /**
+   * Rule that reduces constants inside a {@link org.apache.calcite.rel.core.Join}.
+   */
+  public static class JoinReduceExpressionsRule extends ReduceExpressionsRule {
+
+    public JoinReduceExpressionsRule(Class<? extends Join> joinClass,
+        RelBuilderFactory relBuilderFactory) {
+      super(joinClass, relBuilderFactory, "ReduceExpressionsRule(Join)");
+    }
+
+    @Override public void onMatch(RelOptRuleCall call) {
+      final Join join = call.rel(0);
+      final List<RexNode> expList = Lists.newArrayList(join.getCondition());
+      final int fieldCount = join.getLeft().getRowType().getFieldCount();
+      final RelOptPredicateList leftPredicates =
+          RelMetadataQuery.getPulledUpPredicates(join.getLeft());
+      final RelOptPredicateList rightPredicates =
+          RelMetadataQuery.getPulledUpPredicates(join.getRight());
+      final RelOptPredicateList predicates =
+          leftPredicates.union(rightPredicates.shift(fieldCount));
+      if (!reduceExpressions(join, expList, predicates)) {
+        return;
+      }
+      if (join instanceof EquiJoin) {
+        final JoinInfo joinInfo =
+            JoinInfo.of(join.getLeft(), join.getRight(), expList.get(0));
+        if (!joinInfo.isEqui()) {
+          // This kind of join must be an equi-join, and the condition is
+          // no longer an equi-join. SemiJoin is an example of this.
+          return;
         }
-      };
+      }
+      call.transformTo(
+          join.copy(
+              join.getTraitSet(),
+              expList.get(0),
+              join.getLeft(),
+              join.getRight(),
+              join.getJoinType(),
+              join.isSemiJoinDone()));
+
+      // New plan is absolutely better than old plan.
+      call.getPlanner().setImportance(join, 0.0);
+    }
+  }
 
-  public static final ReduceExpressionsRule CALC_INSTANCE =
-      new ReduceExpressionsRule(LogicalCalc.class,
-          "ReduceExpressionsRule(Calc)") {
-        public void onMatch(RelOptRuleCall call) {
-          LogicalCalc calc = call.rel(0);
-          RexProgram program = calc.getProgram();
-          final List<RexNode> exprList = program.getExprList();
-
-          // Form a list of expressions with sub-expressions fully expanded.
-          final List<RexNode> expandedExprList = Lists.newArrayList();
-          final RexShuttle shuttle =
-              new RexShuttle() {
-                public RexNode visitLocalRef(RexLocalRef localRef) {
-                  return expandedExprList.get(localRef.getIndex());
-                }
-              };
-          for (RexNode expr : exprList) {
-            expandedExprList.add(expr.accept(shuttle));
-          }
-          final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
-          if (reduceExpressions(calc, expandedExprList, predicates)) {
-            final RexProgramBuilder builder =
-                new RexProgramBuilder(
-                    calc.getInput().getRowType(),
-                    calc.getCluster().getRexBuilder());
-            final List<RexLocalRef> list = Lists.newArrayList();
-            for (RexNode expr : expandedExprList) {
-              list.add(builder.registerInput(expr));
-            }
-            if (program.getCondition() != null) {
-              final int conditionIndex =
-                  program.getCondition().getIndex();
-              final RexNode newConditionExp =
-                  expandedExprList.get(conditionIndex);
-              if (newConditionExp.isAlwaysTrue()) {
-                // condition is always TRUE - drop it
-              } else if (newConditionExp instanceof RexLiteral
-                  || RexUtil.isNullLiteral(newConditionExp, true)) {
-                // condition is always NULL or FALSE - replace calc
-                // with empty
-                call.transformTo(
-                    LogicalValues.createEmpty(calc.getCluster(),
-                        calc.getRowType()));
-                return;
-              } else {
-                builder.addCondition(list.get(conditionIndex));
-              }
-            }
-            int k = 0;
-            for (RexLocalRef projectExpr : program.getProjectList()) {
-              final int index = projectExpr.getIndex();
-              builder.addProject(
-                  list.get(index).getIndex(),
-                  program.getOutputRowType().getFieldNames().get(k++));
-            }
-            call.transformTo(
-                LogicalCalc.create(calc.getInput(), builder.getProgram()));
+  /**
+   * Rule that reduces constants inside a {@link org.apache.calcite.rel.core.Calc}.
+   */
+  public static class CalcReduceExpressionsRule extends ReduceExpressionsRule {
 
-            // New plan is absolutely better than old plan.
-            call.getPlanner().setImportance(calc, 0.0);
+    public CalcReduceExpressionsRule(Class<? extends Calc> calcClass,
+        RelBuilderFactory relBuilderFactory) {
+      super(calcClass, relBuilderFactory, "ReduceExpressionsRule(Calc)");
+    }
+
+    @Override public void onMatch(RelOptRuleCall call) {
+      Calc calc = call.rel(0);
+      RexProgram program = calc.getProgram();
+      final List<RexNode> exprList = program.getExprList();
+
+      // Form a list of expressions with sub-expressions fully expanded.
+      final List<RexNode> expandedExprList = Lists.newArrayList();
+      final RexShuttle shuttle =
+          new RexShuttle() {
+            public RexNode visitLocalRef(RexLocalRef localRef) {
+              return expandedExprList.get(localRef.getIndex());
+            }
+          };
+      for (RexNode expr : exprList) {
+        expandedExprList.add(expr.accept(shuttle));
+      }
+      final RelOptPredicateList predicates = RelOptPredicateList.EMPTY;
+      if (reduceExpressions(calc, expandedExprList, predicates)) {
+        final RexProgramBuilder builder =
+            new RexProgramBuilder(
+                calc.getInput().getRowType(),
+                calc.getCluster().getRexBuilder());
+        final List<RexLocalRef> list = Lists.newArrayList();
+        for (RexNode expr : expandedExprList) {
+          list.add(builder.registerInput(expr));
+        }
+        if (program.getCondition() != null) {
+          final int conditionIndex =
+              program.getCondition().getIndex();
+          final RexNode newConditionExp =
+              expandedExprList.get(conditionIndex);
+          if (newConditionExp.isAlwaysTrue()) {
+            // condition is always TRUE - drop it
+          } else if (newConditionExp instanceof RexLiteral
+              || RexUtil.isNullLiteral(newConditionExp, true)) {
+            // condition is always NULL or FALSE - replace calc
+            // with empty
+            call.transformTo(call.builder().values(calc.getRowType()).build());
+            return;
+          } else {
+            builder.addCondition(list.get(conditionIndex));
           }
         }
-      };
+        int k = 0;
+        for (RexLocalRef projectExpr : program.getProjectList()) {
+          final int index = projectExpr.getIndex();
+          builder.addProject(
+              list.get(index).getIndex(),
+              program.getOutputRowType().getFieldNames().get(k++));
+        }
+        call.transformTo(
+            calc.copy(calc.getTraitSet(), calc.getInput(), builder.getProgram()));
+
+        // New plan is absolutely better than old plan.
+        call.getPlanner().setImportance(calc, 0.0);
+      }
+    }
+  }
 
   //~ Constructors -----------------------------------------------------------
 
@@ -316,8 +367,9 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
    *
    * @param clazz class of rels to which this rule should apply
    */
-  private ReduceExpressionsRule(Class<? extends RelNode> clazz, String desc) {
-    super(operand(clazz, any()), desc);
+  protected ReduceExpressionsRule(Class<? extends RelNode> clazz,
+      RelBuilderFactory relBuilderFactory, String desc) {
+    super(operand(clazz, any()), relBuilderFactory, desc);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -330,7 +382,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
    * @param predicates Constraints known to hold on input expressions
    * @return whether reduction found something to change, and succeeded
    */
-  static boolean reduceExpressions(RelNode rel, List<RexNode> expList,
+  protected static boolean reduceExpressions(RelNode rel, List<RexNode> expList,
       RelOptPredicateList predicates) {
     RexBuilder rexBuilder = rel.getCluster().getRexBuilder();
 
@@ -411,7 +463,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
     // analysis, which require bare literals.  But there are special cases,
     // like when the expression is a UDR argument, that need to be
     // handled as special cases.
-    if (rel instanceof LogicalProject) {
+    if (rel instanceof Project) {
       addCasts = Collections.nCopies(reducedValues.size(), true);
     }
 
@@ -440,7 +492,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
    *                       expression is potentially necessary
    * @param removableCasts returns the list of cast expressions where the cast
    */
-  private static void findReducibleExps(RelDataTypeFactory typeFactory,
+  protected static void findReducibleExps(RelDataTypeFactory typeFactory,
       List<RexNode> exps, ImmutableMap<RexNode, RexLiteral> constants,
       List<RexNode> constExps, List<Boolean> addCasts,
       List<RexNode> removableCasts) {
@@ -453,7 +505,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
     assert constExps.size() == addCasts.size();
   }
 
-  private static ImmutableMap<RexNode, RexLiteral> predicateConstants(
+  protected static ImmutableMap<RexNode, RexLiteral> predicateConstants(
       RelOptPredicateList predicates) {
     // We cannot use an ImmutableMap.Builder here. If there are multiple entries
     // with the same key (e.g. "WHERE deptno = 1 AND deptno = 2"), it doesn't
@@ -476,7 +528,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
    * <p>We have a loose definition of 'predicate': any boolean expression will
    * do, except CASE. For example '(CASE ...) = 5' or '(CASE ...) IS NULL'.
    */
-  private static RexCall pushPredicateIntoCase(RexCall call) {
+  protected static RexCall pushPredicateIntoCase(RexCall call) {
     if (call.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
       return call;
     }
@@ -515,7 +567,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
   }
 
   /** Converts op(arg0, ..., argOrdinal, ..., argN) to op(arg0,..., node, ..., argN). */
-  private static RexNode substitute(RexCall call, int ordinal, RexNode node) {
+  protected static RexNode substitute(RexCall call, int ordinal, RexNode node) {
     final List<RexNode> newOperands = Lists.newArrayList(call.getOperands());
     newOperands.set(ordinal, node);
     return call.clone(call.getType(), newOperands);
@@ -527,7 +579,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
    * Replaces expressions with their reductions. Note that we only have to
    * look for RexCall, since nothing else is reducible in the first place.
    */
-  private static class RexReplacer extends RexShuttle {
+  protected static class RexReplacer extends RexShuttle {
     private final RexBuilder rexBuilder;
     private final List<RexNode> reducibleExps;
     private final List<RexNode> reducedValues;
@@ -590,7 +642,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
    * Helper class used to locate expressions that either can be reduced to
    * literals or contain redundant casts.
    */
-  private static class ReducibleExprLocator extends RexVisitorImpl<Void> {
+  protected static class ReducibleExprLocator extends RexVisitorImpl<Void> {
     /** Whether an expression is constant, and if so, whether it can be
      * reduced to a simpler constant. */
     enum Constancy {
@@ -820,7 +872,7 @@ public abstract class ReduceExpressionsRule extends RelOptRule {
   }
 
   /** Shuttle that pushes predicates into a CASE. */
-  private static class CaseShuttle extends RexShuttle {
+  protected static class CaseShuttle extends RexShuttle {
     @Override public RexNode visitCall(RexCall call) {
       for (;;) {
         call = (RexCall) super.visitCall(call);

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/b4c4f493/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 34eb219..ca74f31 100644
--- a/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
+++ b/core/src/main/java/org/apache/calcite/tools/RelBuilder.java
@@ -1117,6 +1117,15 @@ public class RelBuilder {
     return this;
   }
 
+  /** Creates a {@link Values} with a specified row type and
+   * zero rows.
+   *
+   * @param rowType Row type
+   */
+  public RelBuilder values(RelDataType rowType) {
+    return values(rowType, ImmutableList.<ImmutableList<RexLiteral>>of());
+  }
+
   /** Creates a limit without a sort. */
   public RelBuilder limit(int offset, int fetch) {
     return sortLimit(offset, fetch, ImmutableList.<RexNode>of());