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/07/21 06:45:38 UTC

[1/3] incubator-calcite git commit: [CALCITE-783] Infer collation of Project using monotonicity (Milinda Pathirage)

Repository: incubator-calcite
Updated Branches:
  refs/heads/master ef5833f3f -> 9177063b5


[CALCITE-783] Infer collation of Project using monotonicity (Milinda Pathirage)

Close apache/incubator-calcite#104


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

Branch: refs/heads/master
Commit: c711fed6e2392f296554719a98b2d737da53c9b5
Parents: f7ec3e8
Author: Milinda Pathirage <mi...@gmail.com>
Authored: Thu Jul 9 11:46:58 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 20 20:58:24 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/logical/LogicalAggregate.java   | 21 ++++++++-
 .../calcite/rel/metadata/RelMdCollation.java    | 45 ++++++++++++++++---
 .../java/org/apache/calcite/rex/RexBuilder.java |  5 ++-
 .../org/apache/calcite/rex/RexCallBinding.java  | 46 ++++++++++++++++----
 .../calcite/sql2rel/SqlToRelConverter.java      |  3 +-
 .../sql2rel/StandardConvertletTable.java        |  3 +-
 6 files changed, 104 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
index e0bca76..650e8a6 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalAggregate.java
@@ -19,6 +19,8 @@ package org.apache.calcite.rel.logical;
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelCollationTraitDef;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
@@ -26,6 +28,9 @@ import org.apache.calcite.rel.core.Aggregate;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.util.ImmutableBitSet;
 
+import com.google.common.base.Supplier;
+import com.google.common.collect.ImmutableList;
+
 import java.util.List;
 
 /**
@@ -85,13 +90,25 @@ public final class LogicalAggregate extends Aggregate {
   }
 
   /** Creates a LogicalAggregate. */
-  public static LogicalAggregate create(RelNode input,
+  public static LogicalAggregate create(final RelNode input,
       boolean indicator,
       ImmutableBitSet groupSet,
       List<ImmutableBitSet> groupSets,
       List<AggregateCall> aggCalls) {
     final RelOptCluster cluster = input.getCluster();
-    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE);
+    final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE).replaceIfs(
+        RelCollationTraitDef.INSTANCE,
+        new Supplier<List<RelCollation>>() {
+          public List<RelCollation> get() {
+            List<RelCollation> collations =
+                input.getTraitSet().getTraits(RelCollationTraitDef.INSTANCE);
+            if (collations != null) {
+              return collations;
+            }
+
+            return ImmutableList.of();
+          }
+        });
     return new LogicalAggregate(cluster, traitSet, input, indicator, groupSet,
         groupSets, aggCalls);
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
index 52a7c43..cf0614b 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -55,7 +55,9 @@ import com.google.common.collect.Ordering;
 import com.google.common.collect.Sets;
 
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.SortedSet;
 
 /**
@@ -187,18 +189,16 @@ public class RelMdCollation {
       return ImmutableList.of();
     }
     final Multimap<Integer, Integer> targets = LinkedListMultimap.create();
+    final Map<Integer, SqlMonotonicity> targetsWithMonotonicity =
+        new HashMap<>();
     for (Ord<RexNode> project : Ord.zip(projects)) {
       if (project.e instanceof RexInputRef) {
         targets.put(((RexInputRef) project.e).getIndex(), project.i);
       } else if (project.e instanceof RexCall) {
         final RexCall call = (RexCall) project.e;
         final RexCallBinding binding =
-            RexCallBinding.create(input.getCluster().getTypeFactory(), call);
-        if (false) {
-          final SqlMonotonicity monotonicity =
-              call.getOperator().getMonotonicity(binding);
-          // TODO: do something with this monotonicity
-        }
+            RexCallBinding.create(input.getCluster().getTypeFactory(), call, inputCollations);
+        targetsWithMonotonicity.put(project.i, call.getOperator().getMonotonicity(binding));
       }
     }
     final List<RelFieldCollation> fieldCollations = Lists.newArrayList();
@@ -218,9 +218,42 @@ public class RelMdCollation {
       assert !fieldCollations.isEmpty();
       collations.add(RelCollations.of(fieldCollations));
     }
+
+    final List<RelFieldCollation> fieldCollationsForRexCalls = Lists.newArrayList();
+    for (Map.Entry<Integer, SqlMonotonicity> targetMonotonicity
+        : targetsWithMonotonicity.entrySet()) {
+      if (targetMonotonicity.getValue() != SqlMonotonicity.NOT_MONOTONIC
+          && targetMonotonicity.getValue() != SqlMonotonicity.CONSTANT) {
+        fieldCollationsForRexCalls.add(new RelFieldCollation(targetMonotonicity.getKey(),
+            monotonicityToDirection(targetMonotonicity.getValue())));
+      }
+    }
+
+    if (!fieldCollationsForRexCalls.isEmpty()) {
+      collations.add(RelCollations.of(fieldCollationsForRexCalls));
+    }
+
     return ImmutableList.copyOf(collations);
   }
 
+  private static RelFieldCollation.Direction monotonicityToDirection(SqlMonotonicity monotonicity) {
+    switch (monotonicity) {
+    case INCREASING:
+      return RelFieldCollation.Direction.ASCENDING;
+    case DECREASING:
+      return RelFieldCollation.Direction.DESCENDING;
+    case STRICTLY_INCREASING:
+      return RelFieldCollation.Direction.STRICTLY_ASCENDING;
+    case STRICTLY_DECREASING:
+      return RelFieldCollation.Direction.STRICTLY_DESCENDING;
+    case MONOTONIC:
+      return RelFieldCollation.Direction.CLUSTERED;
+    default:
+      throw new IllegalStateException(
+          String.format("SQL monotonicity of type %s is not allowed at this stage.", monotonicity));
+    }
+  }
+
   /** Helper method to determine a
    * {@link org.apache.calcite.rel.core.Window}'s collation.
    *

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
----------------------------------------------------------------------
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 335293a..2cb47d5 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -20,6 +20,7 @@ import org.apache.calcite.avatica.util.ByteString;
 import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.avatica.util.Spaces;
 import org.apache.calcite.avatica.util.TimeUnit;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.core.AggregateCall;
 import org.apache.calcite.rel.type.RelDataType;
@@ -263,7 +264,9 @@ public class RexBuilder {
   public RelDataType deriveReturnType(
       SqlOperator op,
       List<? extends RexNode> exprs) {
-    return op.inferReturnType(new RexCallBinding(typeFactory, op, exprs));
+    return op.inferReturnType(
+        new RexCallBinding(typeFactory, op, exprs,
+            ImmutableList.<RelCollation>of()));
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
index 373b90f..c2828aa 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.rex;
 
+import org.apache.calcite.rel.RelCollation;
+import org.apache.calcite.rel.RelFieldCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.runtime.CalciteException;
@@ -40,26 +42,31 @@ public class RexCallBinding extends SqlOperatorBinding {
 
   private final List<RexNode> operands;
 
+  private final List<RelCollation> inputCollations;
+
   //~ Constructors -----------------------------------------------------------
 
   public RexCallBinding(
       RelDataTypeFactory typeFactory,
       SqlOperator sqlOperator,
-      List<? extends RexNode> operands) {
+      List<? extends RexNode> operands,
+      List<RelCollation> inputCollations) {
     super(typeFactory, sqlOperator);
     this.operands = ImmutableList.copyOf(operands);
+    this.inputCollations = ImmutableList.copyOf(inputCollations);
   }
 
   /** Creates a binding of the appropriate type. */
   public static RexCallBinding create(RelDataTypeFactory typeFactory,
-      RexCall call) {
+      RexCall call,
+      List<RelCollation> inputCollations) {
     switch (call.getKind()) {
     case CAST:
       return new RexCastCallBinding(typeFactory, call.getOperator(),
-          call.getOperands(), call.getType());
+          call.getOperands(), call.getType(), inputCollations);
     }
     return new RexCallBinding(typeFactory, call.getOperator(),
-        call.getOperands());
+        call.getOperands(), inputCollations);
   }
 
   //~ Methods ----------------------------------------------------------------
@@ -77,7 +84,28 @@ public class RexCallBinding extends SqlOperatorBinding {
   }
 
   @Override public SqlMonotonicity getOperandMonotonicity(int ordinal) {
-    throw new AssertionError(); // to be completed
+    RexNode operand = operands.get(ordinal);
+
+    if (operand instanceof RexInputRef) {
+      for (RelCollation ic : inputCollations) {
+        if (ic.getFieldCollations().isEmpty()) {
+          continue;
+        }
+
+        for (RelFieldCollation rfc : ic.getFieldCollations()) {
+          if (rfc.getFieldIndex() == ((RexInputRef) operand).getIndex()) {
+            return rfc.direction.monotonicity();
+            // TODO: Is it possible to have more than one RelFieldCollation for a RexInputRef?
+          }
+        }
+      }
+    } else if (operand instanceof RexCall) {
+      final RexCallBinding binding =
+          RexCallBinding.create(typeFactory, (RexCall) operand, inputCollations);
+      ((RexCall) operand).getOperator().getMonotonicity(binding);
+    }
+
+    return SqlMonotonicity.NOT_MONOTONIC;
   }
 
   @Override public boolean isOperandNull(int ordinal, boolean allowCast) {
@@ -104,10 +132,12 @@ public class RexCallBinding extends SqlOperatorBinding {
   private static class RexCastCallBinding extends RexCallBinding {
     private final RelDataType type;
 
-    public RexCastCallBinding(RelDataTypeFactory typeFactory,
+    public RexCastCallBinding(
+        RelDataTypeFactory typeFactory,
         SqlOperator sqlOperator, List<? extends RexNode> operands,
-        RelDataType type) {
-      super(typeFactory, sqlOperator, operands);
+        RelDataType type,
+        List<RelCollation> inputCollations) {
+      super(typeFactory, sqlOperator, operands, inputCollations);
       this.type = type;
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
index e733d13..fe16f23 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -4688,7 +4688,8 @@ public class SqlToRelConverter {
             new RexCallBinding(
                 rexBuilder.getTypeFactory(),
                 SqlStdOperatorTable.HISTOGRAM_AGG,
-                exprs);
+                exprs,
+                ImmutableList.<RelCollation>of());
 
         RexNode over =
             rexBuilder.makeOver(

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/c711fed6/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 8bf28e0..b184982 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/StandardConvertletTable.java
@@ -20,6 +20,7 @@ import org.apache.calcite.avatica.util.DateTimeUtils;
 import org.apache.calcite.avatica.util.TimeUnit;
 import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelCollation;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.rel.type.RelDataTypeFamily;
@@ -718,7 +719,7 @@ public class StandardConvertletTable extends ReflectiveConvertletTable {
     final int groupCount = cx.getGroupCount();
     if (returnType == null) {
       RexCallBinding binding =
-          new RexCallBinding(cx.getTypeFactory(), fun, exprs) {
+          new RexCallBinding(cx.getTypeFactory(), fun, exprs, ImmutableList.<RelCollation>of()) {
             @Override public int getGroupCount() {
               return groupCount;
             }


[2/3] incubator-calcite git commit: Change the argument types of SqlOperator.getMonotonicity to allow it to be used for RexNode as well as SqlNode

Posted by jh...@apache.org.
Change the argument types of SqlOperator.getMonotonicity to allow it to be used for RexNode as well as SqlNode


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

Branch: refs/heads/master
Commit: f7ec3e847eb3ba82c182a63327fd1da490df648b
Parents: ef5833f
Author: Julian Hyde <jh...@apache.org>
Authored: Mon Jul 6 17:42:16 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 20 20:58:24 2015 -0700

----------------------------------------------------------------------
 .../calcite/rel/metadata/RelMdCollation.java    | 13 +++-
 .../org/apache/calcite/rex/RexCallBinding.java  | 50 ++++++++++++++--
 .../java/org/apache/calcite/rex/RexLiteral.java |  4 ++
 .../org/apache/calcite/sql/SqlAsOperator.java   |  6 +-
 .../apache/calcite/sql/SqlBinaryOperator.java   | 20 +++----
 .../java/org/apache/calcite/sql/SqlCall.java    |  6 +-
 .../org/apache/calcite/sql/SqlCallBinding.java  | 54 +++++++++--------
 .../java/org/apache/calcite/sql/SqlLiteral.java | 61 +++++++++++++++++++
 .../org/apache/calcite/sql/SqlOperator.java     | 16 +++++
 .../apache/calcite/sql/SqlOperatorBinding.java  | 39 ++++++++++++
 .../apache/calcite/sql/SqlPrefixOperator.java   |  9 +--
 .../sql/fun/SqlAbstractTimeFunction.java        |  6 +-
 .../apache/calcite/sql/fun/SqlCastFunction.java | 13 ++--
 .../calcite/sql/fun/SqlCurrentDateFunction.java |  7 +--
 .../sql/fun/SqlDatetimeSubtractionOperator.java |  8 +--
 .../calcite/sql/fun/SqlExtractFunction.java     | 12 ++--
 .../calcite/sql/fun/SqlFloorFunction.java       |  8 +--
 .../sql/fun/SqlMonotonicBinaryOperator.java     | 63 ++++++++++----------
 .../sql/fun/SqlMonotonicUnaryFunction.java      |  9 +--
 .../sql/fun/SqlStringContextVariable.java       |  7 +--
 .../calcite/sql/fun/SqlSubstringFunction.java   | 24 +++-----
 21 files changed, 286 insertions(+), 149 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
index 614c111..52a7c43 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -35,10 +35,13 @@ import org.apache.calcite.rel.core.TableScan;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rel.core.Window;
 import org.apache.calcite.rel.type.RelDataType;
+import org.apache.calcite.rex.RexCall;
+import org.apache.calcite.rex.RexCallBinding;
 import org.apache.calcite.rex.RexInputRef;
 import org.apache.calcite.rex.RexLiteral;
 import org.apache.calcite.rex.RexNode;
 import org.apache.calcite.rex.RexProgram;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.util.BuiltInMethod;
 import org.apache.calcite.util.ImmutableIntList;
 import org.apache.calcite.util.Pair;
@@ -177,7 +180,6 @@ public class RelMdCollation {
   /** Helper method to determine a {@link Project}'s collation. */
   public static List<RelCollation> project(RelNode input,
       List<? extends RexNode> projects) {
-    // TODO: also monotonic expressions
     final SortedSet<RelCollation> collations = Sets.newTreeSet();
     final List<RelCollation> inputCollations =
         RelMetadataQuery.collations(input);
@@ -188,6 +190,15 @@ public class RelMdCollation {
     for (Ord<RexNode> project : Ord.zip(projects)) {
       if (project.e instanceof RexInputRef) {
         targets.put(((RexInputRef) project.e).getIndex(), project.i);
+      } else if (project.e instanceof RexCall) {
+        final RexCall call = (RexCall) project.e;
+        final RexCallBinding binding =
+            RexCallBinding.create(input.getCluster().getTypeFactory(), call);
+        if (false) {
+          final SqlMonotonicity monotonicity =
+              call.getOperator().getMonotonicity(binding);
+          // TODO: do something with this monotonicity
+        }
       }
     }
     final List<RelFieldCollation> fieldCollations = Lists.newArrayList();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
index fc80c19..373b90f 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexCallBinding.java
@@ -24,6 +24,7 @@ import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidatorException;
 
 import com.google.common.collect.ImmutableList;
@@ -49,20 +50,37 @@ public class RexCallBinding extends SqlOperatorBinding {
     this.operands = ImmutableList.copyOf(operands);
   }
 
+  /** Creates a binding of the appropriate type. */
+  public static RexCallBinding create(RelDataTypeFactory typeFactory,
+      RexCall call) {
+    switch (call.getKind()) {
+    case CAST:
+      return new RexCastCallBinding(typeFactory, call.getOperator(),
+          call.getOperands(), call.getType());
+    }
+    return new RexCallBinding(typeFactory, call.getOperator(),
+        call.getOperands());
+  }
+
   //~ Methods ----------------------------------------------------------------
 
-  // implement SqlOperatorBinding
-  public String getStringLiteralOperand(int ordinal) {
+  @Override public String getStringLiteralOperand(int ordinal) {
     return RexLiteral.stringValue(operands.get(ordinal));
   }
 
-  // implement SqlOperatorBinding
-  public int getIntLiteralOperand(int ordinal) {
+  @Override public int getIntLiteralOperand(int ordinal) {
     return RexLiteral.intValue(operands.get(ordinal));
   }
 
-  // implement SqlOperatorBinding
-  public boolean isOperandNull(int ordinal, boolean allowCast) {
+  @Override public Comparable getOperandLiteralValue(int ordinal) {
+    return RexLiteral.value(operands.get(ordinal));
+  }
+
+  @Override public SqlMonotonicity getOperandMonotonicity(int ordinal) {
+    throw new AssertionError(); // to be completed
+  }
+
+  @Override public boolean isOperandNull(int ordinal, boolean allowCast) {
     return RexUtil.isNullLiteral(operands.get(ordinal), allowCast);
   }
 
@@ -80,6 +98,26 @@ public class RexCallBinding extends SqlOperatorBinding {
       Resources.ExInst<SqlValidatorException> e) {
     return SqlUtil.newContextException(SqlParserPos.ZERO, e);
   }
+
+  /** To be compatible with {@code SqlCall}, CAST needs to pretend that it
+   * has two arguments, the second of which is the target type. */
+  private static class RexCastCallBinding extends RexCallBinding {
+    private final RelDataType type;
+
+    public RexCastCallBinding(RelDataTypeFactory typeFactory,
+        SqlOperator sqlOperator, List<? extends RexNode> operands,
+        RelDataType type) {
+      super(typeFactory, sqlOperator, operands);
+      this.type = type;
+    }
+
+    @Override public RelDataType getOperandType(int ordinal) {
+      if (ordinal == 1) {
+        return type;
+      }
+      return super.getOperandType(ordinal);
+    }
+  }
 }
 
 // End RexCallBinding.java

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
index 767734d..0f8dceb 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
@@ -593,6 +593,10 @@ public class RexLiteral extends RexNode {
     return com.google.common.base.Objects.hashCode(value, type);
   }
 
+  public static Comparable value(RexNode node) {
+    return findValue(node);
+  }
+
   public static int intValue(RexNode node) {
     final Comparable value = findValue(node);
     return ((Number) value).intValue();

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
index 1d260cc..6f4aaf3 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlAsOperator.java
@@ -124,10 +124,8 @@ public class SqlAsOperator extends SqlSpecialOperator {
     return validateOperands(validator, scope, call);
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    return call.getOperandList().get(0).getMonotonicity(scope);
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    return call.getOperandMonotonicity(0);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
index bdcf961..c5f9f66 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
@@ -180,20 +180,14 @@ public class SqlBinaryOperator extends SqlOperator {
     return type;
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     if (getName().equals("/")) {
-      final SqlNode operand0 = call.operand(0);
-      final SqlNode operand1 = call.operand(1);
-      final SqlMonotonicity mono0 = operand0.getMonotonicity(scope);
-      final SqlMonotonicity mono1 = operand1.getMonotonicity(scope);
+      final SqlMonotonicity mono0 = call.getOperandMonotonicity(0);
+      final SqlMonotonicity mono1 = call.getOperandMonotonicity(1);
       if (mono1 == SqlMonotonicity.CONSTANT) {
-        if (operand1 instanceof SqlLiteral) {
-          SqlLiteral literal = (SqlLiteral) operand1;
-          switch (
-              literal.bigDecimalValue().compareTo(
-                  BigDecimal.ZERO)) {
+        final Object o = call.getOperandLiteralValue(1);
+        if (o instanceof BigDecimal) {
+          switch (((BigDecimal) o).compareTo(BigDecimal.ZERO)) {
           case -1:
 
             // mono / -ve constant --> reverse mono, unstrict
@@ -211,7 +205,7 @@ public class SqlBinaryOperator extends SqlOperator {
       }
     }
 
-    return super.getMonotonicity(call, scope);
+    return super.getMonotonicity(call);
   }
 
   @Override public boolean validRexOperands(int count, boolean fail) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlCall.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCall.java b/core/src/main/java/org/apache/calcite/sql/SqlCall.java
index 7548e01..41e9eb3 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCall.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCall.java
@@ -156,7 +156,7 @@ public abstract class SqlCall extends SqlNode {
   protected String getCallSignature(
       SqlValidator validator,
       SqlValidatorScope scope) {
-    List<String> signatureList = new ArrayList<String>();
+    List<String> signatureList = new ArrayList<>();
     for (final SqlNode operand : getOperandList()) {
       final RelDataType argType = validator.deriveType(scope, operand);
       if (null == argType) {
@@ -169,7 +169,9 @@ public abstract class SqlCall extends SqlNode {
 
   public SqlMonotonicity getMonotonicity(SqlValidatorScope scope) {
     // Delegate to operator.
-    return getOperator().getMonotonicity(this, scope);
+    final SqlCallBinding binding =
+        new SqlCallBinding(scope.getValidator(), scope, this);
+    return getOperator().getMonotonicity(binding);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
index ceb7b49..aaa8c96 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCallBinding.java
@@ -21,13 +21,16 @@ import org.apache.calcite.runtime.CalciteException;
 import org.apache.calcite.runtime.Resources;
 import org.apache.calcite.sql.fun.SqlStdOperatorTable;
 import org.apache.calcite.sql.validate.SelectScope;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorException;
 import org.apache.calcite.sql.validate.SqlValidatorNamespace;
 import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.sql.validate.SqlValidatorUtil;
+import org.apache.calcite.util.NlsString;
 import org.apache.calcite.util.Util;
 
+import java.math.BigDecimal;
 import java.util.List;
 
 import static org.apache.calcite.util.Static.RESOURCE;
@@ -109,43 +112,45 @@ public class SqlCallBinding extends SqlOperatorBinding {
     return call;
   }
 
-  // implement SqlOperatorBinding
-  public String getStringLiteralOperand(int ordinal) {
+  public SqlMonotonicity getOperandMonotonicity(int ordinal) {
+    return call.getOperandList().get(ordinal).getMonotonicity(scope);
+  }
+
+  @Override public String getStringLiteralOperand(int ordinal) {
     SqlNode node = call.operand(ordinal);
-    return SqlLiteral.stringValue(node);
+    final Object o = SqlLiteral.value(node);
+    return o instanceof NlsString ? ((NlsString) o).getValue() : null;
   }
 
-  // implement SqlOperatorBinding
-  public int getIntLiteralOperand(int ordinal) {
-    // todo: move this to SqlTypeUtil
+  @Override public int getIntLiteralOperand(int ordinal) {
     SqlNode node = call.operand(ordinal);
-    if (node instanceof SqlLiteral) {
-      SqlLiteral sqlLiteral = (SqlLiteral) node;
-      return sqlLiteral.intValue(true);
-    } else if (node instanceof SqlCall) {
-      final SqlCall c = (SqlCall) node;
-      if (c.getKind() == SqlKind.MINUS_PREFIX) {
-        SqlNode child = c.operand(0);
-        if (child instanceof SqlLiteral) {
-          return -((SqlLiteral) child).intValue(true);
-        }
+    final Object o = SqlLiteral.value(node);
+    if (o instanceof BigDecimal) {
+      BigDecimal bd = (BigDecimal) o;
+      try {
+        return bd.intValueExact();
+      } catch (ArithmeticException e) {
+        throw SqlUtil.newContextException(node.pos,
+            RESOURCE.numberLiteralOutOfRange(bd.toString()));
       }
     }
     throw Util.newInternal("should never come here");
   }
 
-  // implement SqlOperatorBinding
-  public boolean isOperandNull(int ordinal, boolean allowCast) {
+  @Override public Comparable getOperandLiteralValue(int ordinal) {
+    SqlNode node = call.operand(ordinal);
+    return SqlLiteral.value(node);
+  }
+
+  @Override public boolean isOperandNull(int ordinal, boolean allowCast) {
     return SqlUtil.isNullLiteral(call.operand(ordinal), allowCast);
   }
 
-  // implement SqlOperatorBinding
-  public int getOperandCount() {
+  @Override public int getOperandCount() {
     return call.getOperandList().size();
   }
 
-  // implement SqlOperatorBinding
-  public RelDataType getOperandType(int ordinal) {
+  @Override public RelDataType getOperandType(int ordinal) {
     final SqlNode operand = call.operand(ordinal);
     final RelDataType type = validator.deriveType(scope, operand);
     final SqlValidatorNamespace namespace = validator.getNamespace(operand);
@@ -155,7 +160,7 @@ public class SqlCallBinding extends SqlOperatorBinding {
     return type;
   }
 
-  public RelDataType getCursorOperand(int ordinal) {
+  @Override public RelDataType getCursorOperand(int ordinal) {
     final SqlNode operand = call.operand(ordinal);
     if (!SqlUtil.isCallTo(operand, SqlStdOperatorTable.CURSOR)) {
       return null;
@@ -165,8 +170,7 @@ public class SqlCallBinding extends SqlOperatorBinding {
     return validator.deriveType(scope, query);
   }
 
-  // implement SqlOperatorBinding
-  public String getColumnListParamInfo(
+  @Override public String getColumnListParamInfo(
       int ordinal,
       String paramName,
       List<String> columnList) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
index 3990a8a..b7aa493 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
@@ -259,9 +259,68 @@ public class SqlLiteral extends SqlNode {
   }
 
   /**
+   * Extracts the value from a literal.
+   *
+   * <p>Cases:
+   * <ul>
+   * <li>If the node is a character literal, a chain of string
+   * literals, or a CAST of a character literal, returns the value as a
+   * {@link NlsString}.
+   *
+   * <li>If the node is a numeric literal, or a negated numeric literal,
+   * returns the value as a {@link BigDecimal}.
+   *
+   * <li>If the node is a {@link SqlIntervalQualifier},
+   * returns its {@link TimeUnitRange}.
+   *
+   * <li>Otherwise the behavior is not specified.
+   * </ul>
+   */
+  public static Comparable value(SqlNode node) {
+    if (node instanceof SqlLiteral) {
+      SqlLiteral literal = (SqlLiteral) node;
+      switch (literal.getTypeName().getFamily()) {
+      case CHARACTER:
+        return (NlsString) literal.value;
+      case NUMERIC:
+        return (BigDecimal) literal.value;
+      }
+    }
+    if (SqlUtil.isLiteralChain(node)) {
+      assert node instanceof SqlCall;
+      final SqlLiteral literal =
+          SqlLiteralChainOperator.concatenateOperands((SqlCall) node);
+      assert SqlTypeUtil.inCharFamily(literal.getTypeName());
+      return (NlsString) literal.value;
+    }
+    if (node instanceof SqlIntervalQualifier) {
+      SqlIntervalQualifier qualifier = (SqlIntervalQualifier) node;
+      return qualifier.timeUnitRange;
+    }
+    switch (node.getKind()) {
+    case CAST:
+      assert node instanceof SqlCall;
+      return value(((SqlCall) node).operand(0));
+    case MINUS_PREFIX:
+      assert node instanceof SqlCall;
+      Comparable o = value(((SqlCall) node).operand(0));
+      if (o instanceof BigDecimal) {
+        BigDecimal bigDecimal = (BigDecimal) o;
+        return bigDecimal.negate();
+      }
+      // fall through
+    default:
+      throw Util.newInternal("invalid literal: " + node);
+    }
+  }
+
+  /**
    * Extracts the string value from a string literal, a chain of string
    * literals, or a CAST of a string literal.
+   *
+   * @deprecated Use {@link #value(SqlNode)}
    */
+  @Deprecated // to be removed before 2.0
   public static String stringValue(SqlNode node) {
     if (node instanceof SqlLiteral) {
       SqlLiteral literal = (SqlLiteral) node;
@@ -466,6 +525,7 @@ public class SqlLiteral extends SqlNode {
    *
    * @return -1, 0 or 1
    */
+  @Deprecated // to be removed before 2.0
   public int signum() {
     return bigDecimalValue().compareTo(
         BigDecimal.ZERO);
@@ -484,6 +544,7 @@ public class SqlLiteral extends SqlNode {
     }
   }
 
+  @Deprecated // to be removed before 2.0
   public String getStringValue() {
     return ((NlsString) value).getValue();
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
index e8914b2..ee35b09 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
@@ -723,10 +723,26 @@ public abstract class SqlOperator {
    *
    * @param call  Call to this operator
    * @param scope Scope in which the call occurs
+   *
+   * @deprecated Use {@link #getMonotonicity(SqlOperatorBinding)}
    */
+  @Deprecated // to be removed before 2.0
   public SqlMonotonicity getMonotonicity(
       SqlCall call,
       SqlValidatorScope scope) {
+    return getMonotonicity(
+        new SqlCallBinding(scope.getValidator(), scope, call));
+  }
+
+  /**
+   * Returns whether a call to this operator is monotonic.
+   *
+   * <p>Default implementation returns {@link SqlMonotonicity#NOT_MONOTONIC}.
+   *
+   * @param call Call to this operator with particular arguments and information
+   *             about the monotonicity of the arguments
+   */
+  public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     return SqlMonotonicity.NOT_MONOTONIC;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java b/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java
index 3e3b6f6..2ca13f9 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperatorBinding.java
@@ -20,6 +20,7 @@ import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.runtime.CalciteException;
 import org.apache.calcite.runtime.Resources;
+import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidatorException;
 
 import java.util.AbstractList;
@@ -94,6 +95,7 @@ public abstract class SqlOperatorBinding {
    * @param ordinal zero-based ordinal of operand of interest
    * @return string value
    */
+  @Deprecated // to be removed before 2.0
   public String getStringLiteralOperand(int ordinal) {
     throw new UnsupportedOperationException();
   }
@@ -104,11 +106,38 @@ public abstract class SqlOperatorBinding {
    * @param ordinal zero-based ordinal of operand of interest
    * @return integer value
    */
+  @Deprecated // to be removed before 2.0
   public int getIntLiteralOperand(int ordinal) {
     throw new UnsupportedOperationException();
   }
 
   /**
+   * Gets the value of a literal operand.
+   *
+   * <p>Cases:
+   * <ul>
+   * <li>If the operand is not a literal, the value is null.
+   *
+   * <li>If the operand is a string literal,
+   * the value will be of type {@link org.apache.calcite.util.NlsString}.
+   *
+   * <li>If the operand is a numeric literal,
+   * the value will be of type {@link java.math.BigDecimal}.
+   *
+   * <li>If the operand is an interval qualifier,
+   * the value will be of type {@link SqlIntervalQualifier}</li>
+   *
+   * <li>Otherwise the type is undefined, and the value may be null.
+   * </ul>
+   *
+   * @param ordinal zero-based ordinal of operand of interest
+   * @return value of operand
+   */
+  public Comparable getOperandLiteralValue(int ordinal) {
+    throw new UnsupportedOperationException();
+  }
+
+  /**
    * Determines whether a bound operand is NULL.
    *
    * <p>This is only relevant for SQL validation.
@@ -136,6 +165,16 @@ public abstract class SqlOperatorBinding {
   public abstract RelDataType getOperandType(int ordinal);
 
   /**
+   * Gets the monotonicity of a bound operand.
+   *
+   * @param ordinal zero-based ordinal of operand of interest
+   * @return monotonicity of operand
+   */
+  public SqlMonotonicity getOperandMonotonicity(int ordinal) {
+    return SqlMonotonicity.NOT_MONOTONIC;
+  }
+
+  /**
    * Collects the types of the bound operands into a list.
    *
    * @return collected list

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
index b99abf2..8923645 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
@@ -23,7 +23,6 @@ import org.apache.calcite.sql.type.SqlReturnTypeInference;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
 import org.apache.calcite.sql.validate.SqlValidator;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.util.Util;
 
 /**
@@ -90,14 +89,12 @@ public class SqlPrefixOperator extends SqlOperator {
     return type;
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     if (getName().equals("-")) {
-      return scope.getMonotonicity(call.operand(0)).reverse();
+      return call.getOperandMonotonicity(0).reverse();
     }
 
-    return super.getMonotonicity(call, scope);
+    return super.getMonotonicity(call);
   }
 
   @Override public boolean validRexOperands(int count, boolean fail) {

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java
index 6469927..82c660e 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlAbstractTimeFunction.java
@@ -17,7 +17,6 @@
 package org.apache.calcite.sql.fun;
 
 import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
@@ -28,7 +27,6 @@ import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 import static org.apache.calcite.util.Static.RESOURCE;
 
@@ -81,9 +79,7 @@ public class SqlAbstractTimeFunction extends SqlFunction {
   }
 
   // All of the time functions are increasing. Not strictly increasing.
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     return SqlMonotonicity.INCREASING;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
index 08bd3b3..f4e933a 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCastFunction.java
@@ -37,7 +37,6 @@ import org.apache.calcite.sql.type.SqlOperandCountRanges;
 import org.apache.calcite.sql.type.SqlTypeFamily;
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 import com.google.common.collect.ImmutableSet;
 
@@ -199,15 +198,11 @@ public class SqlCastFunction extends SqlFunction {
     writer.endFunCall(frame);
   }
 
-  @Override public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    RelDataTypeFamily castFrom =
-        scope.getValidator().deriveType(scope, call.operand(0)).getFamily();
-    RelDataTypeFamily castTo =
-        scope.getValidator().deriveType(scope, call.operand(1)).getFamily();
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    RelDataTypeFamily castFrom = call.getOperandType(0).getFamily();
+    RelDataTypeFamily castTo = call.getOperandType(1).getFamily();
     if (isMonotonicPreservingCast(castFrom, castTo)) {
-      return call.operand(0).getMonotonicity(scope);
+      return call.getOperandMonotonicity(0);
     } else {
       return SqlMonotonicity.NOT_MONOTONIC;
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java
index cdab873..ceb9b78 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlCurrentDateFunction.java
@@ -16,15 +16,14 @@
  */
 package org.apache.calcite.sql.fun;
 
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlSyntax;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 /**
  * The <code>CURRENT_DATE</code> function.
@@ -48,9 +47,7 @@ public class SqlCurrentDateFunction extends SqlFunction {
     return SqlSyntax.FUNCTION_ID;
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     return SqlMonotonicity.INCREASING;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java
index 9ff4ee1..f79c366 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlDatetimeSubtractionOperator.java
@@ -18,6 +18,7 @@ package org.apache.calcite.sql.fun;
 
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlSpecialOperator;
 import org.apache.calcite.sql.SqlSyntax;
 import org.apache.calcite.sql.SqlWriter;
@@ -25,7 +26,6 @@ import org.apache.calcite.sql.type.InferTypes;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 /**
  * A special operator for the subtraction of two DATETIMEs. The format of
@@ -70,10 +70,8 @@ public class SqlDatetimeSubtractionOperator extends SqlSpecialOperator {
     call.operand(2).unparse(writer, leftPrec, rightPrec);
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    return SqlStdOperatorTable.MINUS.getMonotonicity(call, scope);
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    return SqlStdOperatorTable.MINUS.getMonotonicity(call);
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java
index 86c6893..fd3bad6 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlExtractFunction.java
@@ -16,16 +16,16 @@
  */
 package org.apache.calcite.sql.fun;
 
+import org.apache.calcite.avatica.util.TimeUnitRange;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
-import org.apache.calcite.sql.SqlIntervalQualifier;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.util.Util;
 
 /**
@@ -68,12 +68,10 @@ public class SqlExtractFunction extends SqlFunction {
     writer.endFunCall(frame);
   }
 
-  @Override public SqlMonotonicity getMonotonicity(SqlCall call,
-      SqlValidatorScope scope) {
-    final SqlIntervalQualifier o = call.operand(0);
-    switch (o.timeUnitRange) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    switch ((TimeUnitRange) call.getOperandLiteralValue(0)) {
     case YEAR:
-      return scope.getMonotonicity(call.operand(1)).unstrict();
+      return call.getOperandMonotonicity(1).unstrict();
     default:
       return SqlMonotonicity.NOT_MONOTONIC;
     }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java
index e9d147f..c5986a0 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlFloorFunction.java
@@ -19,11 +19,11 @@ package org.apache.calcite.sql.fun;
 import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 import com.google.common.base.Preconditions;
 
@@ -48,11 +48,9 @@ public class SqlFloorFunction extends SqlMonotonicUnaryFunction {
 
   //~ Methods ----------------------------------------------------------------
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     // Monotonic iff its first argument is, but not strict.
-    return scope.getMonotonicity(call.operand(0)).unstrict();
+    return call.getOperandMonotonicity(0).unstrict();
   }
 
   @Override public void unparse(SqlWriter writer, SqlCall call, int leftPrec,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java
index 42599a1..dc35783 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicBinaryOperator.java
@@ -17,14 +17,15 @@
 package org.apache.calcite.sql.fun;
 
 import org.apache.calcite.sql.SqlBinaryOperator;
-import org.apache.calcite.sql.SqlCall;
+import org.apache.calcite.sql.SqlIntervalLiteral;
 import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlOperandTypeInference;
 import org.apache.calcite.sql.type.SqlReturnTypeInference;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
+
+import java.math.BigDecimal;
 
 /**
  * Base class for binary operators such as addition, subtraction, and
@@ -54,11 +55,9 @@ public class SqlMonotonicBinaryOperator extends SqlBinaryOperator {
 
   //~ Methods ----------------------------------------------------------------
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    final SqlMonotonicity mono0 = scope.getMonotonicity(call.operand(0));
-    final SqlMonotonicity mono1 = scope.getMonotonicity(call.operand(1));
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    final SqlMonotonicity mono0 = call.getOperandMonotonicity(0);
+    final SqlMonotonicity mono1 = call.getOperandMonotonicity(1);
 
     // constant <op> constant --> constant
     if ((mono1 == SqlMonotonicity.CONSTANT)
@@ -75,24 +74,19 @@ public class SqlMonotonicBinaryOperator extends SqlBinaryOperator {
         return mono0;
       }
       assert getName().equals("*");
-      if (call.operand(1) instanceof SqlLiteral) {
-        SqlLiteral literal = call.operand(1);
-        switch (literal.signum()) {
-        case -1:
-
-          // mono0 * negative constant --> reverse mono0
-          return mono0.reverse();
-        case 0:
+      switch (signum(call.getOperandLiteralValue(1))) {
+      case -1:
+        // mono0 * negative constant --> reverse mono0
+        return mono0.reverse();
 
-          // mono0 * 0 --> constant (zero)
-          return SqlMonotonicity.CONSTANT;
-        default:
+      case 0:
+        // mono0 * 0 --> constant (zero)
+        return SqlMonotonicity.CONSTANT;
 
-          // mono0 * positiove constant --> mono0
-          return mono0;
-        }
+      default:
+        // mono0 * positive constant --> mono0
+        return mono0;
       }
-      return mono0;
     }
 
     // constant <op> mono
@@ -106,19 +100,18 @@ public class SqlMonotonicBinaryOperator extends SqlBinaryOperator {
         return mono1;
       }
       assert getName().equals("*");
-      if (call.operand(0) instanceof SqlLiteral) {
-        SqlLiteral literal = call.operand(0);
-        switch (literal.signum()) {
+      final Object v0 = call.getOperandLiteralValue(0);
+      if (v0 != null) {
+        switch (signum(v0)) {
         case -1:
-
           // negative constant * mono1 --> reverse mono1
           return mono1.reverse();
-        case 0:
 
+        case 0:
           // 0 * mono1 --> constant (zero)
           return SqlMonotonicity.CONSTANT;
-        default:
 
+        default:
           // positive constant * mono1 --> mono1
           return mono1;
         }
@@ -156,7 +149,17 @@ public class SqlMonotonicBinaryOperator extends SqlBinaryOperator {
       return SqlMonotonicity.NOT_MONOTONIC;
     }
 
-    return super.getMonotonicity(call, scope);
+    return super.getMonotonicity(call);
+  }
+
+  private int signum(Object o) {
+    if (o instanceof BigDecimal) {
+      return ((BigDecimal) o).signum();
+    } else if (o instanceof SqlIntervalLiteral.IntervalValue) {
+      return ((SqlIntervalLiteral.IntervalValue) o).getSign();
+    } else {
+      return 1;
+    }
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java
index d347fbc..2a194ba 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlMonotonicUnaryFunction.java
@@ -16,15 +16,14 @@
  */
 package org.apache.calcite.sql.fun;
 
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlOperandTypeInference;
 import org.apache.calcite.sql.type.SqlReturnTypeInference;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 /**
  * Base class for unary operators such as FLOOR/CEIL which are monotonic for
@@ -51,10 +50,8 @@ public class SqlMonotonicUnaryFunction extends SqlFunction {
 
   //~ Methods ----------------------------------------------------------------
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
-    return scope.getMonotonicity(call.operand(0)).unstrict();
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
+    return call.getOperandMonotonicity(0).unstrict();
   }
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java
index db7057e..caedd64 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStringContextVariable.java
@@ -16,15 +16,14 @@
  */
 package org.apache.calcite.sql.fun;
 
-import org.apache.calcite.sql.SqlCall;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlSyntax;
 import org.apache.calcite.sql.type.OperandTypes;
 import org.apache.calcite.sql.type.ReturnTypes;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
-import org.apache.calcite.sql.validate.SqlValidatorScope;
 
 /**
  * Base class for functions such as "USER", "CURRENT_ROLE", and "CURRENT_PATH".
@@ -49,9 +48,7 @@ public class SqlStringContextVariable extends SqlFunction {
   }
 
   // All of the string constants are monotonic.
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     return SqlMonotonicity.CONSTANT;
   }
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/f7ec3e84/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
index 5cac08f..73eda82 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlSubstringFunction.java
@@ -23,9 +23,9 @@ import org.apache.calcite.sql.SqlCallBinding;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlKind;
-import org.apache.calcite.sql.SqlLiteral;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlOperandCountRange;
+import org.apache.calcite.sql.SqlOperatorBinding;
 import org.apache.calcite.sql.SqlUtil;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.type.OperandTypes;
@@ -190,25 +190,19 @@ public class SqlSubstringFunction extends SqlFunction {
     writer.endFunCall(frame);
   }
 
-  public SqlMonotonicity getMonotonicity(
-      SqlCall call,
-      SqlValidatorScope scope) {
+  @Override public SqlMonotonicity getMonotonicity(SqlOperatorBinding call) {
     // SUBSTRING(x FROM 0 FOR constant) has same monotonicity as x
-    final List<SqlNode> operands = call.getOperandList();
-    if (operands.size() == 3) {
-      final SqlNode op0 = operands.get(0);
-      final SqlNode op1 = operands.get(1);
-      final SqlNode op2 = operands.get(2);
-      final SqlMonotonicity mono0 = op0.getMonotonicity(scope);
+    if (call.getOperandCount() == 3) {
+      final SqlMonotonicity mono0 = call.getOperandMonotonicity(0);
       if ((mono0 != SqlMonotonicity.NOT_MONOTONIC)
-          && op1.getMonotonicity(scope) == SqlMonotonicity.CONSTANT
-          && op1 instanceof SqlLiteral
-          && ((SqlLiteral) op1).bigDecimalValue().equals(BigDecimal.ZERO)
-          && op2.getMonotonicity(scope) == SqlMonotonicity.CONSTANT) {
+          && call.getOperandMonotonicity(1) == SqlMonotonicity.CONSTANT
+          && call.getOperandLiteralValue(1) instanceof BigDecimal
+          && call.getOperandLiteralValue(1).equals(BigDecimal.ZERO)
+          && call.getOperandMonotonicity(2) == SqlMonotonicity.CONSTANT) {
         return mono0.unstrict();
       }
     }
-    return super.getMonotonicity(call, scope);
+    return super.getMonotonicity(call);
   }
 }
 



[3/3] incubator-calcite git commit: Complete [CALCITE-783] by fixing some planner rules

Posted by jh...@apache.org.
Complete [CALCITE-783] by fixing some planner rules


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

Branch: refs/heads/master
Commit: 9177063b5217ba01a7a34f85a0bf8e8753adeb20
Parents: c711fed
Author: Julian Hyde <jh...@apache.org>
Authored: Thu Jul 9 15:36:03 2015 -0700
Committer: Julian Hyde <jh...@apache.org>
Committed: Mon Jul 20 21:20:05 2015 -0700

----------------------------------------------------------------------
 .../enumerable/EnumerableAggregateRule.java     |  2 +-
 .../enumerable/EnumerableProjectRule.java       | 12 ++++++
 .../apache/calcite/adapter/jdbc/JdbcRules.java  |  2 +-
 .../apache/calcite/prepare/RelOptTableImpl.java | 22 +----------
 .../apache/calcite/rel/RelFieldCollation.java   | 39 ++++++++++++++++++++
 .../calcite/rel/metadata/RelMdCollation.java    | 38 +++++++------------
 .../rel/rules/AggregateReduceFunctionsRule.java |  2 +-
 .../calcite/rel/rules/AggregateRemoveRule.java  |  2 +-
 .../apache/calcite/sql2rel/RelFieldTrimmer.java |  2 +-
 .../java/org/apache/calcite/test/JdbcTest.java  |  2 +-
 .../org/apache/calcite/test/LatticeTest.java    |  2 +-
 core/src/test/resources/sql/join.oq             | 10 ++---
 .../calcite/adapter/mongodb/MongoRules.java     |  2 +-
 13 files changed, 79 insertions(+), 58 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java
index 340801f..aec578a 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableAggregateRule.java
@@ -41,7 +41,7 @@ class EnumerableAggregateRule extends ConverterRule {
       return new EnumerableAggregate(
           rel.getCluster(),
           traitSet,
-          convert(agg.getInput(), traitSet),
+          convert(agg.getInput(), EnumerableConvention.INSTANCE),
           agg.indicator,
           agg.getGroupSet(),
           agg.getGroupSets(),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
index b7dcc69..459e025 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableProjectRule.java
@@ -18,6 +18,8 @@ package org.apache.calcite.adapter.enumerable;
 
 import org.apache.calcite.plan.Convention;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelCollations;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.convert.ConverterRule;
 import org.apache.calcite.rel.logical.LogicalProject;
@@ -34,6 +36,16 @@ class EnumerableProjectRule extends ConverterRule {
 
   public RelNode convert(RelNode rel) {
     final LogicalProject project = (LogicalProject) rel;
+    if (rel.getTraitSet().getTrait(RelCollationTraitDef.INSTANCE)
+        != RelCollations.PRESERVE) {
+      return EnumerableProject.create(
+          convert(project.getInput(),
+              project.getInput().getTraitSet()
+                  .replace(EnumerableConvention.INSTANCE)),
+          project.getProjects(),
+          project.getRowType());
+    }
+    // Special case for PRESERVE, to hand-create collation.
     return new EnumerableProject(rel.getCluster(),
         rel.getTraitSet().replace(EnumerableConvention.INSTANCE),
         convert(project.getInput(),

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
index f48f675..c52d7f3 100644
--- a/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
+++ b/core/src/main/java/org/apache/calcite/adapter/jdbc/JdbcRules.java
@@ -680,7 +680,7 @@ public class JdbcRules {
           agg.getTraitSet().replace(out);
       try {
         return new JdbcAggregate(rel.getCluster(), traitSet,
-            convert(agg.getInput(), traitSet), agg.indicator, agg.getGroupSet(),
+            convert(agg.getInput(), out), agg.indicator, agg.getGroupSet(),
             agg.getGroupSets(), agg.getAggCallList());
       } catch (InvalidRelException e) {
         LOGGER.fine(e.toString());

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
index 9919cec..3a77256 100644
--- a/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
+++ b/core/src/main/java/org/apache/calcite/prepare/RelOptTableImpl.java
@@ -290,33 +290,13 @@ public class RelOptTableImpl implements Prepare.PreparingTable {
         final RelFieldCollation fieldCollation =
             collation.getFieldCollations().get(0);
         if (fieldCollation.getFieldIndex() == i) {
-          return monotonicity(fieldCollation.direction);
+          return fieldCollation.direction.monotonicity();
         }
       }
     }
     return SqlMonotonicity.NOT_MONOTONIC;
   }
 
-  /** Converts a {@link org.apache.calcite.rel.RelFieldCollation.Direction}
-   * value to a {@link org.apache.calcite.sql.validate.SqlMonotonicity}. */
-  private static SqlMonotonicity
-  monotonicity(RelFieldCollation.Direction direction) {
-    switch (direction) {
-    case ASCENDING:
-      return SqlMonotonicity.INCREASING;
-    case STRICTLY_ASCENDING:
-      return SqlMonotonicity.STRICTLY_INCREASING;
-    case DESCENDING:
-      return SqlMonotonicity.DECREASING;
-    case STRICTLY_DESCENDING:
-      return SqlMonotonicity.STRICTLY_DECREASING;
-    case CLUSTERED:
-      return SqlMonotonicity.MONOTONIC;
-    default:
-      throw new AssertionError("unknown: " + direction);
-    }
-  }
-
   public SqlAccessType getAllowedAccess() {
     return SqlAccessType.ALL;
   }

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java b/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
index fb54412..7fa2274 100644
--- a/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/RelFieldCollation.java
@@ -16,6 +16,8 @@
  */
 package org.apache.calcite.rel;
 
+import org.apache.calcite.sql.validate.SqlMonotonicity;
+
 /**
  * Definition of the ordering of one field of a {@link RelNode} whose
  * output is to be sorted.
@@ -81,6 +83,43 @@ public class RelFieldCollation {
     Direction(String shortString) {
       this.shortString = shortString;
     }
+
+    /** Converts thie direction to a
+     * {@link org.apache.calcite.sql.validate.SqlMonotonicity}. */
+    public SqlMonotonicity monotonicity() {
+      switch (this) {
+      case ASCENDING:
+        return SqlMonotonicity.INCREASING;
+      case STRICTLY_ASCENDING:
+        return SqlMonotonicity.STRICTLY_INCREASING;
+      case DESCENDING:
+        return SqlMonotonicity.DECREASING;
+      case STRICTLY_DESCENDING:
+        return SqlMonotonicity.STRICTLY_DECREASING;
+      case CLUSTERED:
+        return SqlMonotonicity.MONOTONIC;
+      default:
+        throw new AssertionError("unknown: " + this);
+      }
+    }
+
+    /** Converts a {@link SqlMonotonicity} to a direction. */
+    public static Direction of(SqlMonotonicity monotonicity) {
+      switch (monotonicity) {
+      case INCREASING:
+        return ASCENDING;
+      case DECREASING:
+        return DESCENDING;
+      case STRICTLY_INCREASING:
+        return STRICTLY_ASCENDING;
+      case STRICTLY_DECREASING:
+        return STRICTLY_DESCENDING;
+      case MONOTONIC:
+        return CLUSTERED;
+      default:
+        throw new AssertionError("unknown: " + monotonicity);
+      }
+    }
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
index cf0614b..37ce6da 100644
--- a/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
+++ b/core/src/main/java/org/apache/calcite/rel/metadata/RelMdCollation.java
@@ -54,6 +54,7 @@ import com.google.common.collect.Multimap;
 import com.google.common.collect.Ordering;
 import com.google.common.collect.Sets;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.HashMap;
 import java.util.List;
@@ -219,13 +220,20 @@ public class RelMdCollation {
       collations.add(RelCollations.of(fieldCollations));
     }
 
-    final List<RelFieldCollation> fieldCollationsForRexCalls = Lists.newArrayList();
-    for (Map.Entry<Integer, SqlMonotonicity> targetMonotonicity
+    final List<RelFieldCollation> fieldCollationsForRexCalls =
+        new ArrayList<>();
+    for (Map.Entry<Integer, SqlMonotonicity> entry
         : targetsWithMonotonicity.entrySet()) {
-      if (targetMonotonicity.getValue() != SqlMonotonicity.NOT_MONOTONIC
-          && targetMonotonicity.getValue() != SqlMonotonicity.CONSTANT) {
-        fieldCollationsForRexCalls.add(new RelFieldCollation(targetMonotonicity.getKey(),
-            monotonicityToDirection(targetMonotonicity.getValue())));
+      final SqlMonotonicity value = entry.getValue();
+      switch (value) {
+      case NOT_MONOTONIC:
+      case CONSTANT:
+        break;
+      default:
+        fieldCollationsForRexCalls.add(
+            new RelFieldCollation(entry.getKey(),
+                RelFieldCollation.Direction.of(value)));
+        break;
       }
     }
 
@@ -236,24 +244,6 @@ public class RelMdCollation {
     return ImmutableList.copyOf(collations);
   }
 
-  private static RelFieldCollation.Direction monotonicityToDirection(SqlMonotonicity monotonicity) {
-    switch (monotonicity) {
-    case INCREASING:
-      return RelFieldCollation.Direction.ASCENDING;
-    case DECREASING:
-      return RelFieldCollation.Direction.DESCENDING;
-    case STRICTLY_INCREASING:
-      return RelFieldCollation.Direction.STRICTLY_ASCENDING;
-    case STRICTLY_DECREASING:
-      return RelFieldCollation.Direction.STRICTLY_DESCENDING;
-    case MONOTONIC:
-      return RelFieldCollation.Direction.CLUSTERED;
-    default:
-      throw new IllegalStateException(
-          String.format("SQL monotonicity of type %s is not allowed at this stage.", monotonicity));
-    }
-  }
-
   /** Helper method to determine a
    * {@link org.apache.calcite.rel.core.Window}'s collation.
    *

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/rel/rules/AggregateReduceFunctionsRule.java
----------------------------------------------------------------------
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 2a79f14..3a33e16 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
@@ -340,7 +340,7 @@ public class AggregateReduceFunctionsRule extends RelOptRule {
             argType, argType.isNullable());
     final AggregateCall sumZeroCall =
         AggregateCall.create(SqlStdOperatorTable.SUM0, oldCall.isDistinct(),
-            oldCall.getArgList(), oldCall.filterArg, sumType, null);
+            oldCall.getArgList(), oldCall.filterArg, sumType, oldCall.name);
     final AggregateCall countCall =
         AggregateCall.create(
             SqlStdOperatorTable.COUNT,

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
index 6031717..12f735c 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/AggregateRemoveRule.java
@@ -63,7 +63,7 @@ public class AggregateRemoveRule extends RelOptRule {
     // Distinct is "GROUP BY c1, c2" (where c1, c2 are a set of columns on
     // which the input is unique, i.e. contain a key) and has no aggregate
     // functions. It can be removed.
-    final RelNode newInput = convert(input, aggregate.getTraitSet());
+    final RelNode newInput = convert(input, aggregate.getTraitSet().simplify());
 
     // If aggregate was projecting a subset of columns, add a project for the
     // same effect.

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
index 5e9e333..9e17837 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelFieldTrimmer.java
@@ -200,7 +200,7 @@ public class RelFieldTrimmer implements ReflectiveVisitor {
       fieldsUsed = ImmutableBitSet.range(input.getRowType().getFieldCount());
     }
     final ImmutableList<RelCollation> collations =
-        RelMetadataQuery.collations(rel);
+        RelMetadataQuery.collations(input);
     for (RelCollation collation : collations) {
       for (RelFieldCollation fieldCollation : collation.getFieldCollations()) {
         fieldsUsed = fieldsUsed.set(fieldCollation.getFieldIndex());

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/JdbcTest.java b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
index 941b88a..a037a23 100644
--- a/core/src/test/java/org/apache/calcite/test/JdbcTest.java
+++ b/core/src/test/java/org/apache/calcite/test/JdbcTest.java
@@ -3332,7 +3332,7 @@ public class JdbcTest {
             + "where \"deptno\" < 0")
         .explainContains(""
             + "PLAN=EnumerableCalc(expr#0..1=[{inputs}], expr#2=[0], expr#3=[=($t0, $t2)], expr#4=[null], expr#5=[CASE($t3, $t4, $t1)], expr#6=[/($t5, $t0)], expr#7=[CAST($t6):JavaType(class java.lang.Integer)], CS=[$t0], C=[$t0], S=[$t5], A=[$t7])\n"
-            + "  EnumerableAggregate(group=[{}], CS=[COUNT()], agg#1=[$SUM0($1)])\n"
+            + "  EnumerableAggregate(group=[{}], CS=[COUNT()], S=[$SUM0($1)])\n"
             + "    EnumerableCalc(expr#0..4=[{inputs}], expr#5=[0], expr#6=[<($t1, $t5)], proj#0..4=[{exprs}], $condition=[$t6])\n"
             + "      EnumerableTableScan(table=[[hr, emps]])\n")
         .returns("CS=0; C=0; S=null; A=null\n");

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/LatticeTest.java b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
index 77e7943..b1155f0 100644
--- a/core/src/test/java/org/apache/calcite/test/LatticeTest.java
+++ b/core/src/test/java/org/apache/calcite/test/LatticeTest.java
@@ -436,7 +436,7 @@ public class LatticeTest {
                 + "GROUP BY \"s\".\"unit_sales\", \"p\".\"recyclable_package\", \"t\".\"the_day\", \"t\".\"the_year\", \"t\".\"quarter\", \"pc\".\"product_family\"")
         .explainContains(
             "JdbcToEnumerableConverter\n"
-                + "  JdbcAggregate(group=[{7, 16, 25, 27, 31, 37}], m0=[COUNT()], m1=[SUM($5)], m2=[SUM($7)])\n"
+                + "  JdbcAggregate(group=[{7, 16, 25, 27, 31, 37}], m0=[COUNT()], m1=[$SUM0($5)], m2=[$SUM0($7)])\n"
                 + "    JdbcJoin(condition=[=($8, $33)], joinType=[inner])\n"
                 + "      JdbcJoin(condition=[=($1, $23)], joinType=[inner])\n"
                 + "        JdbcJoin(condition=[=($0, $9)], joinType=[inner])\n"

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/core/src/test/resources/sql/join.oq
----------------------------------------------------------------------
diff --git a/core/src/test/resources/sql/join.oq b/core/src/test/resources/sql/join.oq
index 83cfb7c..bb273dc 100644
--- a/core/src/test/resources/sql/join.oq
+++ b/core/src/test/resources/sql/join.oq
@@ -142,10 +142,10 @@ from "scott".emp join "scott".dept using (deptno);
 
 !ok
 EnumerableAggregate(group=[{0}])
-  EnumerableJoin(condition=[=($0, $1)], joinType=[inner])
+  EnumerableJoin(condition=[=($0, $2)], joinType=[inner])
     EnumerableCalc(expr#0..2=[{inputs}], DEPTNO=[$t0])
       EnumerableTableScan(table=[[scott, DEPT]])
-    EnumerableCalc(expr#0..7=[{inputs}], DEPTNO=[$t7])
+    EnumerableCalc(expr#0..7=[{inputs}], EMPNO=[$t0], DEPTNO=[$t7])
       EnumerableTableScan(table=[[scott, EMP]])
 !plan
 
@@ -227,11 +227,11 @@ where e.deptno + 10 = d.deptno * 2;
 (9 rows)
 
 !ok
-EnumerableCalc(expr#0..3=[{inputs}], DEPTNO=[$t2], DEPTNO0=[$t0])
-  EnumerableJoin(condition=[=($1, $3)], joinType=[inner])
+EnumerableCalc(expr#0..4=[{inputs}], DEPTNO=[$t3], DEPTNO0=[$t0])
+  EnumerableJoin(condition=[=($1, $4)], joinType=[inner])
     EnumerableCalc(expr#0..2=[{inputs}], expr#3=[2], expr#4=[*($t0, $t3)], DEPTNO=[$t0], $f1=[$t4])
       EnumerableTableScan(table=[[scott, DEPT]])
-    EnumerableCalc(expr#0..7=[{inputs}], expr#8=[10], expr#9=[+($t7, $t8)], DEPTNO=[$t7], $f1=[$t9])
+    EnumerableCalc(expr#0..7=[{inputs}], expr#8=[10], expr#9=[+($t7, $t8)], EMPNO=[$t0], DEPTNO=[$t7], $f2=[$t9])
       EnumerableTableScan(table=[[scott, EMP]])
 !plan
 

http://git-wip-us.apache.org/repos/asf/incubator-calcite/blob/9177063b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
----------------------------------------------------------------------
diff --git a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
index e7596b3..50478ee 100644
--- a/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
+++ b/mongodb/src/main/java/org/apache/calcite/adapter/mongodb/MongoRules.java
@@ -512,7 +512,7 @@ public class MongoRules {
         return new MongoAggregate(
             rel.getCluster(),
             traitSet,
-            convert(agg.getInput(), traitSet),
+            convert(agg.getInput(), traitSet.simplify()),
             agg.indicator,
             agg.getGroupSet(),
             agg.getGroupSets(),