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 2016/02/10 01:05:43 UTC

[1/3] calcite git commit: [CALCITE-1083] SqlNode.equalsDeep has O(n ^ 2) performance

Repository: calcite
Updated Branches:
  refs/heads/master e0f29dd79 -> 72b2cfb79


[CALCITE-1083] SqlNode.equalsDeep has O(n ^ 2) performance

Cause of the problem is that Litmus.fail constructs an error message string, even if the particular implementation of Litmus does not use the string. Solution is to pass a format string and arguments, which are only converted to strings if the message is used, the same as SLF4J Logger does.


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

Branch: refs/heads/master
Commit: 670fa73e24a7b72d6ddafd69793474083bb4b9f0
Parents: e0f29dd
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Feb 9 15:04:03 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Feb 9 15:17:40 2016 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/plan/RelOptUtil.java     | 18 ++++++---------
 .../org/apache/calcite/rel/core/Aggregate.java  |  3 ++-
 .../java/org/apache/calcite/rel/core/Join.java  |  4 ++--
 .../org/apache/calcite/rel/core/Project.java    |  8 +++----
 .../java/org/apache/calcite/rex/RexChecker.java |  4 ++--
 .../java/org/apache/calcite/rex/RexLiteral.java |  8 +++----
 .../java/org/apache/calcite/rex/RexProgram.java |  7 +++---
 .../java/org/apache/calcite/rex/RexUtil.java    |  9 ++++----
 .../apache/calcite/sql/SqlBinaryOperator.java   |  2 +-
 .../java/org/apache/calcite/sql/SqlCall.java    |  4 ++--
 .../org/apache/calcite/sql/SqlDataTypeSpec.java | 10 ++++-----
 .../org/apache/calcite/sql/SqlDynamicParam.java |  4 ++--
 .../org/apache/calcite/sql/SqlIdentifier.java   |  6 ++---
 .../calcite/sql/SqlIntervalQualifier.java       |  2 +-
 .../java/org/apache/calcite/sql/SqlLiteral.java |  4 ++--
 .../org/apache/calcite/sql/SqlNodeList.java     |  4 ++--
 .../apache/calcite/sql/SqlPostfixOperator.java  |  2 +-
 .../apache/calcite/sql/SqlPrefixOperator.java   |  2 +-
 .../apache/calcite/sql/fun/SqlInOperator.java   |  2 +-
 .../calcite/sql/fun/SqlStdOperatorTable.java    |  2 +-
 .../apache/calcite/sql2rel/RelDecorrelator.java |  2 +-
 .../java/org/apache/calcite/util/Litmus.java    | 23 ++++++++++++--------
 22 files changed, 66 insertions(+), 64 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
index 610867a..a03a0fa 100644
--- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
+++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java
@@ -227,7 +227,7 @@ public abstract class RelOptUtil {
     if (!set.contains(correlationId)) {
       return litmus.succeed();
     } else {
-      return litmus.fail("contains " + correlationId);
+      return litmus.fail("contains {}", correlationId);
     }
   }
 
@@ -1662,11 +1662,9 @@ public abstract class RelOptUtil {
     }
 
     if (type1 != type2) {
-      return litmus.fail("type mismatch:\n"
-          + desc1 + ":\n"
-          + type1.getFullTypeString() + "\n"
-          + desc2 + ":\n"
-          + type2.getFullTypeString());
+      return litmus.fail("type mismatch:\n{}:\n{}\n{}:\n{}",
+          desc1, type1.getFullTypeString(),
+          desc2, type2.getFullTypeString());
     }
     return litmus.succeed();
   }
@@ -1690,11 +1688,9 @@ public abstract class RelOptUtil {
       RelDataType type2,
       Litmus litmus) {
     if (!areRowTypesEqual(type1, type2, false)) {
-      return litmus.fail("Type mismatch:\n"
-          + desc1 + ":\n"
-          + type1.getFullTypeString() + "\n"
-          + desc2 + ":\n"
-          + type2.getFullTypeString());
+      return litmus.fail("Type mismatch:\n{}:\n{}\n{}:\n{}",
+          desc1, type1.getFullTypeString(),
+          desc2, type2.getFullTypeString());
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
index 4eedee7..2408ae5 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Aggregate.java
@@ -382,7 +382,8 @@ public abstract class Aggregate extends SingleRel {
 
   public boolean isValid(Litmus litmus) {
     return super.isValid(litmus)
-        && litmus.check(Util.isDistinct(getRowType().getFieldNames()), getRowType());
+        && litmus.check(Util.isDistinct(getRowType().getFieldNames()),
+            "distinct field names: {}", getRowType());
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rel/core/Join.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Join.java b/core/src/main/java/org/apache/calcite/rel/core/Join.java
index 7c20f14..4a99f0d 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Join.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Join.java
@@ -155,8 +155,8 @@ public abstract class Join extends BiRel {
     }
     if (condition != null) {
       if (condition.getType().getSqlTypeName() != SqlTypeName.BOOLEAN) {
-        return litmus.fail("condition must be boolean: "
-            + condition.getType());
+        return litmus.fail("condition must be boolean: {}",
+            condition.getType());
       }
       // The input to the condition is a row type consisting of system
       // fields, left fields, and right fields. Very similar to the

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rel/core/Project.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Project.java b/core/src/main/java/org/apache/calcite/rel/core/Project.java
index e92b04d..8089506 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Project.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Project.java
@@ -184,12 +184,12 @@ public abstract class Project extends SingleRel {
     for (RexNode exp : exps) {
       exp.accept(checker);
       if (checker.getFailureCount() > 0) {
-        return litmus.fail(checker.getFailureCount()
-            + " failures in expression " + exp);
+        return litmus.fail("{} failures in expression {}",
+            checker.getFailureCount(), exp);
       }
     }
     if (!Util.isDistinct(rowType.getFieldNames())) {
-      return litmus.fail("field names not distinct: " + rowType);
+      return litmus.fail("field names not distinct: {}", rowType);
     }
     //CHECKSTYLE: IGNORE 1
     if (false && !Util.isDistinct(
@@ -205,7 +205,7 @@ public abstract class Project extends SingleRel {
       // because we need to allow
       //
       //  SELECT a, b FROM c UNION SELECT x, x FROM z
-      return litmus.fail("duplicate expressions: " + exps);
+      return litmus.fail("duplicate expressions: {}", exps);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rex/RexChecker.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexChecker.java b/core/src/main/java/org/apache/calcite/rex/RexChecker.java
index c51d923..d573c51 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexChecker.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexChecker.java
@@ -111,8 +111,8 @@ public class RexChecker extends RexVisitorImpl<Boolean> {
     final int index = ref.getIndex();
     if ((index < 0) || (index >= inputTypeList.size())) {
       ++failCount;
-      return litmus.fail("RexInputRef index " + index
-          + " out of range 0.." + (inputTypeList.size() - 1));
+      return litmus.fail("RexInputRef index {} out of range 0..{}",
+          index, inputTypeList.size() - 1);
     }
     if (!ref.getType().isStruct()
         && !RelOptUtil.eq("ref", ref.getType(), "input",

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/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 26f8e4a..e28653f 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexLiteral.java
@@ -275,7 +275,7 @@ public class RexLiteral extends RexNode {
       List list = (List) o;
       for (Object o1 : list) {
         if (!validConstant(o1, litmus)) {
-          return litmus.fail("not a constant: " + o1);
+          return litmus.fail("not a constant: {}", o1);
         }
       }
       return litmus.succeed();
@@ -283,15 +283,15 @@ public class RexLiteral extends RexNode {
       @SuppressWarnings("unchecked") final Map<Object, Object> map = (Map) o;
       for (Map.Entry entry : map.entrySet()) {
         if (!validConstant(entry.getKey(), litmus)) {
-          return litmus.fail("not a constant: " + entry.getKey());
+          return litmus.fail("not a constant: {}", entry.getKey());
         }
         if (!validConstant(entry.getValue(), litmus)) {
-          return litmus.fail("not a constant: " + entry.getValue());
+          return litmus.fail("not a constant: {}", entry.getValue());
         }
       }
       return litmus.succeed();
     } else {
-      return litmus.fail("not a constant: " + o);
+      return litmus.fail("not a constant: {}", o);
     }
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rex/RexProgram.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexProgram.java b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
index 30382c5..2762180 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexProgram.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexProgram.java
@@ -766,9 +766,10 @@ public class RexProgram {
     String normalized = normalizedProgram.toString();
     String string = toString();
     if (!normalized.equals(string)) {
-      return litmus.fail("Program is not normalized:\n"
-          + "program:    " + string + "\n"
-          + "normalized: " + normalized + "\n");
+      final String message = "Program is not normalized:\n"
+          + "program:    {}\n"
+          + "normalized: {}\n";
+      return litmus.fail(message, string, normalized);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/rex/RexUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/rex/RexUtil.java b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
index ce3e936..f26c783 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexUtil.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexUtil.java
@@ -521,7 +521,7 @@ public class RexUtil {
         expr.accept(visitor);
       } catch (ForwardRefFinder.IllegalForwardRefException e) {
         Util.swallow(e, null);
-        return litmus.fail("illegal forward reference in " + expr);
+        return litmus.fail("illegal forward reference in {}", expr);
       }
     }
     return litmus.succeed();
@@ -542,7 +542,7 @@ public class RexUtil {
           for (RexNode operand : rexCall.operands) {
             if (!(operand instanceof RexLocalRef)
                 && !(operand instanceof RexLiteral)) {
-              return litmus.fail("contains non trivial agg: " + operand);
+              return litmus.fail("contains non trivial agg: {}", operand);
             }
           }
         }
@@ -680,12 +680,11 @@ public class RexUtil {
     }
     for (int i = 0; i < fields.size(); i++) {
       if (!(exprs.get(i) instanceof RexInputRef)) {
-        return litmus.fail("expr[" + i + "] is not a RexInputRef");
+        return litmus.fail("expr[{}] is not a RexInputRef", i);
       }
       RexInputRef inputRef = (RexInputRef) exprs.get(i);
       if (inputRef.getIndex() != i) {
-        return litmus.fail("expr[" + i + "] has ordinal "
-            + inputRef.getIndex());
+        return litmus.fail("expr[{}] has ordinal {}", i, inputRef.getIndex());
       }
       if (!RelOptUtil.eq("type1",
           exprs.get(i).getType(),

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/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 34943c2..c1dece3 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlBinaryOperator.java
@@ -217,7 +217,7 @@ public class SqlBinaryOperator extends SqlOperator {
           && count > 2) {
         return true;
       }
-      return litmus.fail("wrong operand count " + count + " for " + this);
+      return litmus.fail("wrong operand count {} for {}", count, this);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/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 59066b3..620f1a8 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlCall.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlCall.java
@@ -140,14 +140,14 @@ public abstract class SqlCall extends SqlNode {
       return true;
     }
     if (!(node instanceof SqlCall)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     SqlCall that = (SqlCall) node;
 
     // Compare operators by name, not identity, because they may not
     // have been resolved yet.
     if (!this.getOperator().getName().equals(that.getOperator().getName())) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     return equalDeep(this.getOperandList(), that.getOperandList(), litmus);
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
index 2cffb82..d4bfc6c 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDataTypeSpec.java
@@ -236,7 +236,7 @@ public class SqlDataTypeSpec extends SqlNode {
 
   public boolean equalsDeep(SqlNode node, Litmus litmus) {
     if (!(node instanceof SqlDataTypeSpec)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     SqlDataTypeSpec that = (SqlDataTypeSpec) node;
     if (!SqlNode.equalDeep(
@@ -248,16 +248,16 @@ public class SqlDataTypeSpec extends SqlNode {
       return litmus.fail(null);
     }
     if (this.precision != that.precision) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     if (this.scale != that.scale) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     if (!Objects.equals(this.timeZone, that.timeZone)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     if (!Objects.equals(this.charSetName, that.charSetName)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java b/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java
index 8fc771c..7db5fd7 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDynamicParam.java
@@ -79,11 +79,11 @@ public class SqlDynamicParam extends SqlNode {
 
   public boolean equalsDeep(SqlNode node, Litmus litmus) {
     if (!(node instanceof SqlDynamicParam)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     SqlDynamicParam that = (SqlDynamicParam) node;
     if (this.index != that.index) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
index bd0c5d5..2a6bca0 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlIdentifier.java
@@ -289,15 +289,15 @@ public class SqlIdentifier extends SqlNode {
 
   public boolean equalsDeep(SqlNode node, Litmus litmus) {
     if (!(node instanceof SqlIdentifier)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     SqlIdentifier that = (SqlIdentifier) node;
     if (this.names.size() != that.names.size()) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     for (int i = 0; i < names.size(); i++) {
       if (!this.names.get(i).equals(that.names.get(i))) {
-        return litmus.fail(this + "!=" + node);
+        return litmus.fail("{} != {}", this, node);
       }
     }
     return litmus.succeed();

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
index aa9729d..ae36bee 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlIntervalQualifier.java
@@ -147,7 +147,7 @@ public class SqlIntervalQualifier extends SqlNode {
     final String thisString = this.toString();
     final String thatString = node.toString();
     if (!thisString.equals(thatString)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/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 625e11c..f535c53 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlLiteral.java
@@ -407,11 +407,11 @@ public class SqlLiteral extends SqlNode {
 
   public boolean equalsDeep(SqlNode node, Litmus litmus) {
     if (!(node instanceof SqlLiteral)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     SqlLiteral that = (SqlLiteral) node;
     if (!this.equals(that)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java b/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java
index 392d967..0925864 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlNodeList.java
@@ -155,11 +155,11 @@ public class SqlNodeList extends SqlNode implements Iterable<SqlNode> {
 
   public boolean equalsDeep(SqlNode node, Litmus litmus) {
     if (!(node instanceof SqlNodeList)) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     SqlNodeList that = (SqlNodeList) node;
     if (this.size() != that.size()) {
-      return litmus.fail(this + "!=" + node);
+      return litmus.fail("{} != {}", this, node);
     }
     for (int i = 0; i < list.size(); i++) {
       SqlNode thisChild = list.get(i);

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java b/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java
index 5fef8ae..31020d1 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlPostfixOperator.java
@@ -91,7 +91,7 @@ public class SqlPostfixOperator extends SqlOperator {
 
   @Override public boolean validRexOperands(int count, Litmus litmus) {
     if (count != 1) {
-      return litmus.fail("wrong operand count " + count + " for " + this);
+      return litmus.fail("wrong operand count {} for {}", count, this);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/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 8976a56..11eeb26 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlPrefixOperator.java
@@ -100,7 +100,7 @@ public class SqlPrefixOperator extends SqlOperator {
 
   @Override public boolean validRexOperands(int count, Litmus litmus) {
     if (count != 1) {
-      return litmus.fail("wrong operand count " + count + " for " + this);
+      return litmus.fail("wrong operand count {} for {}", count, this);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
index 9e8105a..a20cea3 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlInOperator.java
@@ -87,7 +87,7 @@ public class SqlInOperator extends SqlBinaryOperator {
 
   @Override public boolean validRexOperands(int count, Litmus litmus) {
     if (count == 0) {
-      return litmus.fail("wrong operand count " + count + " for " + this);
+      return litmus.fail("wrong operand count {} for {}", count, this);
     }
     return litmus.succeed();
   }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 464945d..db755a2 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -617,7 +617,7 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
 
         @Override public boolean validRexOperands(int count, Litmus litmus) {
           if (count != 0) {
-            return litmus.fail("wrong operand count " + count + " for " + this);
+            return litmus.fail("wrong operand count {} for {}", count, this);
           }
           return litmus.succeed();
         }

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
index ecfd124..024cb5f 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/RelDecorrelator.java
@@ -1323,7 +1323,7 @@ public class RelDecorrelator implements ReflectiveVisitor {
       Litmus ret) {
     for (int value : integers) {
       if (value >= limit) {
-        return ret.fail("out of range; value: " + value + ", limit: " + limit);
+        return ret.fail("out of range; value: {}, limit: {}", value, limit);
       }
     }
     return ret.succeed();

http://git-wip-us.apache.org/repos/asf/calcite/blob/670fa73e/core/src/main/java/org/apache/calcite/util/Litmus.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/util/Litmus.java b/core/src/main/java/org/apache/calcite/util/Litmus.java
index 1a74e6c..0f0be55 100644
--- a/core/src/main/java/org/apache/calcite/util/Litmus.java
+++ b/core/src/main/java/org/apache/calcite/util/Litmus.java
@@ -23,19 +23,20 @@ public interface Litmus {
   /** Implementation of {@link org.apache.calcite.util.Litmus} that throws
    * an {@link java.lang.AssertionError} on failure. */
   Litmus THROW = new Litmus() {
-    public boolean fail(String message) {
-      throw new AssertionError(message);
+    public boolean fail(String message, Object... args) {
+      final String s = message == null ? null : String.format(message, args);
+      throw new AssertionError(s);
     }
 
     public boolean succeed() {
       return true;
     }
 
-    public boolean check(boolean condition, Object info) {
+    public boolean check(boolean condition, String message, Object... args) {
       if (condition) {
         return succeed();
       } else {
-        return fail(info == null ? null : info.toString());
+        return fail(message, args);
       }
     }
   };
@@ -43,7 +44,7 @@ public interface Litmus {
   /** Implementation of {@link org.apache.calcite.util.Litmus} that returns
    * a status code but does not throw. */
   Litmus IGNORE = new Litmus() {
-    public boolean fail(String message) {
+    public boolean fail(String message, Object... args) {
       return false;
     }
 
@@ -51,13 +52,17 @@ public interface Litmus {
       return true;
     }
 
-    public boolean check(boolean condition, Object info) {
+    public boolean check(boolean condition, String message, Object... args) {
       return condition;
     }
   };
 
-  /** Called when test fails. Returns false or throws. */
-  boolean fail(String message);
+  /** Called when test fails. Returns false or throws.
+   *
+   * @param message Message
+   * @param args Arguments
+   */
+  boolean fail(String message, Object... args);
 
   /** Called when test succeeds. Returns true. */
   boolean succeed();
@@ -68,7 +73,7 @@ public interface Litmus {
    * if the condition is false, calls {@link #fail},
    * converting {@code info} into a string message.
    */
-  boolean check(boolean condition, Object info);
+  boolean check(boolean condition, String message, Object... args);
 }
 
 // End Litmus.java


[2/3] calcite git commit: [CALCITE-1062] In validation, lookup a (possibly overloaded) operator from an operator table (Hsuan-Yi Chu)

Posted by jh...@apache.org.
[CALCITE-1062] In validation, lookup a (possibly overloaded) operator from an operator table (Hsuan-Yi Chu)

Close apache/calcite#188


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

Branch: refs/heads/master
Commit: c1ceba45e5939be812bbe0bba6ee27586862b8e0
Parents: 670fa73
Author: Hsuan-Yi Chu <hs...@usc.edu>
Authored: Mon Jan 18 23:20:57 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Feb 9 16:02:19 2016 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/sql/SqlFunction.java     |  77 ++++-------
 .../org/apache/calcite/sql/SqlOperator.java     | 113 +++++++++++++++-
 .../java/org/apache/calcite/sql/SqlUtil.java    | 132 ++++++++++++++-----
 .../calcite/sql/fun/SqlBetweenOperator.java     |   8 +-
 .../sql/util/ReflectiveSqlOperatorTable.java    |   4 +-
 .../calcite/sql2rel/SqlToRelConverter.java      |  11 +-
 .../calcite/sql/test/SqlOperatorBaseTest.java   |  27 ++++
 .../apache/calcite/test/SqlValidatorTest.java   |   2 +-
 8 files changed, 276 insertions(+), 98 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
index dc63209..2ed8bda 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
@@ -19,12 +19,10 @@ package org.apache.calcite.sql;
 import org.apache.calcite.linq4j.function.Function1;
 import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.rel.type.RelDataTypeFactory;
 import org.apache.calcite.sql.parser.SqlParserPos;
 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.type.SqlTypeName;
 import org.apache.calcite.sql.validate.SqlValidator;
 import org.apache.calcite.sql.validate.SqlValidatorScope;
 import org.apache.calcite.util.Util;
@@ -235,71 +233,44 @@ public class SqlFunction extends SqlOperator {
       SqlValidatorScope scope,
       SqlCall call,
       boolean convertRowArgToColumnList) {
-
     // Scope for operands. Usually the same as 'scope'.
     final SqlValidatorScope operandScope = scope.getOperandScope(call);
 
     // Indicate to the validator that we're validating a new function call
     validator.pushFunctionCall();
 
-    // If any arguments are named, construct a map.
-    final ImmutableList.Builder<String> nameBuilder = ImmutableList.builder();
-    final ImmutableList.Builder<SqlNode> argBuilder = ImmutableList.builder();
-    for (SqlNode operand : call.getOperandList()) {
-      if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
-        final List<SqlNode> operandList = ((SqlCall) operand).getOperandList();
-        nameBuilder.add(((SqlIdentifier) operandList.get(1)).getSimple());
-        argBuilder.add(operandList.get(0));
-      }
-    }
-    ImmutableList<String> argNames = nameBuilder.build();
-    final List<SqlNode> args;
-    if (argNames.isEmpty()) {
-      args = call.getOperandList();
-      argNames = null;
-    } else {
-      if (argNames.size() < call.getOperandList().size()) {
-        throw validator.newValidationError(call,
-            RESOURCE.someButNotAllArgumentsAreNamed());
-      }
-      int duplicate = Util.firstDuplicate(argNames);
-      if (duplicate >= 0) {
-        throw validator.newValidationError(call,
-            RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
-      }
-      args = argBuilder.build();
-    }
+    List<String> argNames = constructArgNameList(
+        call);
+
+    List<SqlNode> args = constructOperandList(
+        validator,
+        call,
+        argNames);
+
+    List<RelDataType> argTypes = constructArgTypeList(
+        validator,
+        scope,
+        call,
+        args,
+        convertRowArgToColumnList);
+
+    SqlFunction function = (SqlFunction) SqlUtil.lookupRoutine(
+        validator.getOperatorTable(),
+        getNameAsId(),
+        argTypes,
+        argNames,
+        SqlSyntax.FUNCTION,
+        getKind(),
+        getFunctionType());
     try {
-      final ImmutableList.Builder<RelDataType> argTypeBuilder =
-          ImmutableList.builder();
       boolean containsRowArg = false;
       for (SqlNode operand : args) {
-        RelDataType nodeType;
-
-        // for row arguments that should be converted to ColumnList
-        // types, set the nodeType to a ColumnList type but defer
-        // validating the arguments of the row constructor until we know
-        // for sure that the row argument maps to a ColumnList type
         if (operand.getKind() == SqlKind.ROW && convertRowArgToColumnList) {
           containsRowArg = true;
-          RelDataTypeFactory typeFactory = validator.getTypeFactory();
-          nodeType = typeFactory.createSqlType(SqlTypeName.COLUMN_LIST);
-        } else {
-          nodeType = validator.deriveType(operandScope, operand);
+          break;
         }
-        validator.setValidatedNodeType(operand, nodeType);
-        argTypeBuilder.add(nodeType);
       }
 
-      final List<RelDataType> argTypes = argTypeBuilder.build();
-      SqlFunction function =
-          SqlUtil.lookupRoutine(
-              validator.getOperatorTable(),
-              getNameAsId(),
-              argTypes,
-              argNames,
-              getFunctionType());
-
       // if we have a match on function name and parameter count, but
       // couldn't find a function with  a COLUMN_LIST type, retry, but
       // this time, don't convert the row argument to a COLUMN_LIST type;

http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/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 476a1c5..e3d9c27 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
@@ -23,6 +23,7 @@ import org.apache.calcite.sql.parser.SqlParserPos;
 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.type.SqlTypeName;
 import org.apache.calcite.sql.util.SqlBasicVisitor;
 import org.apache.calcite.sql.util.SqlVisitor;
 import org.apache.calcite.sql.validate.SqlMonotonicity;
@@ -32,6 +33,8 @@ import org.apache.calcite.sql.validate.SqlValidatorUtil;
 import org.apache.calcite.util.Litmus;
 import org.apache.calcite.util.Util;
 
+import com.google.common.collect.ImmutableList;
+
 import java.util.Arrays;
 import java.util.List;
 import java.util.Objects;
@@ -480,12 +483,32 @@ public abstract class SqlOperator {
       SqlValidator validator,
       SqlValidatorScope scope,
       SqlCall call) {
-    for (SqlNode operand : call.getOperandList()) {
-      RelDataType nodeType = validator.deriveType(scope, operand);
-      assert nodeType != null;
-    }
 
-    RelDataType type = validateOperands(validator, scope, call);
+    List<SqlNode> args = constructOperandList(
+        validator,
+        call,
+        null);
+
+    List<RelDataType> argTypes = constructArgTypeList(
+        validator,
+        scope,
+        call,
+        args,
+        false);
+
+    SqlOperator sqlOperator = SqlUtil.lookupRoutine(
+        validator.getOperatorTable(),
+        new SqlIdentifier(
+            call.getOperator().getName(),
+            call.getParserPosition()),
+        argTypes,
+        null,
+        getSyntax(),
+        getKind(),
+        null);
+
+    ((SqlBasicCall) call).setOperator(sqlOperator);
+    RelDataType type = call.getOperator().validateOperands(validator, scope, call);
 
     // Validate and determine coercibility and resulting collation
     // name of binary operator if needed.
@@ -494,6 +517,86 @@ public abstract class SqlOperator {
     return type;
   }
 
+  protected List<String> constructArgNameList(SqlCall call) {
+    // If any arguments are named, construct a map.
+    final ImmutableList.Builder<String> nameBuilder = ImmutableList.builder();
+    for (SqlNode operand : call.getOperandList()) {
+      if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
+        final List<SqlNode> operandList = ((SqlCall) operand).getOperandList();
+        nameBuilder.add(((SqlIdentifier) operandList.get(1)).getSimple());
+      }
+    }
+    ImmutableList<String> argNames = nameBuilder.build();
+
+    if (argNames.isEmpty()) {
+      return null;
+    } else {
+      return argNames;
+    }
+  }
+
+  protected List<SqlNode> constructOperandList(
+      SqlValidator validator,
+      SqlCall call,
+      List<String> argNames) {
+    final ImmutableList.Builder<SqlNode> argBuilder = ImmutableList.builder();
+    for (SqlNode operand : call.getOperandList()) {
+      if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
+        final List<SqlNode> operandList = ((SqlCall) operand).getOperandList();
+        argBuilder.add(operandList.get(0));
+      }
+    }
+
+    final List<SqlNode> args;
+    if (argNames == null) {
+      args = call.getOperandList();
+    } else {
+      if (argNames.size() < call.getOperandList().size()) {
+        throw validator.newValidationError(call,
+            RESOURCE.someButNotAllArgumentsAreNamed());
+      }
+      int duplicate = Util.firstDuplicate(argNames);
+      if (duplicate >= 0) {
+        throw validator.newValidationError(call,
+            RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
+      }
+      args = argBuilder.build();
+    }
+
+    return args;
+  }
+
+  protected List<RelDataType> constructArgTypeList(
+      SqlValidator validator,
+      SqlValidatorScope scope,
+      SqlCall call,
+      List<SqlNode> args,
+      boolean convertRowArgToColumnList) {
+    // Scope for operands. Usually the same as 'scope'.
+    final SqlValidatorScope operandScope = scope.getOperandScope(call);
+
+    final ImmutableList.Builder<RelDataType> argTypeBuilder =
+            ImmutableList.builder();
+    for (SqlNode operand : args) {
+      RelDataType nodeType;
+      // for row arguments that should be converted to ColumnList
+      // types, set the nodeType to a ColumnList type but defer
+      // validating the arguments of the row constructor until we know
+      // for sure that the row argument maps to a ColumnList type
+      if (operand.getKind() == SqlKind.ROW && convertRowArgToColumnList) {
+        RelDataTypeFactory typeFactory = validator.getTypeFactory();
+        nodeType = typeFactory.createSqlType(SqlTypeName.COLUMN_LIST);
+      } else {
+        nodeType = validator.deriveType(operandScope, operand);
+      }
+      validator.setValidatedNodeType(operand, nodeType);
+      argTypeBuilder.add(nodeType);
+    }
+
+    final List<RelDataType> argTypes = argTypeBuilder.build();
+    return argTypes;
+  }
+
   /**
    * Returns whether this operator should be surrounded by space when
    * unparsed.

http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
index 87e73e0..2ba78aa 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
@@ -325,15 +325,22 @@ public abstract class SqlUtil {
    * @return matching routine, or null if none found
    * @sql.99 Part 2 Section 10.4
    */
-  public static SqlFunction lookupRoutine(SqlOperatorTable opTab,
-      SqlIdentifier funcName, List<RelDataType> argTypes,
-      List<String> argNames, SqlFunctionCategory category) {
-    List<SqlFunction> list =
+  public static SqlOperator lookupRoutine(
+      SqlOperatorTable opTab,
+      SqlIdentifier funcName,
+      List<RelDataType> argTypes,
+      List<String> argNames,
+      SqlSyntax sqlSyntax,
+      SqlKind sqlKind,
+      SqlFunctionCategory category) {
+    List<SqlOperator> list =
         lookupSubjectRoutines(
             opTab,
             funcName,
             argTypes,
             argNames,
+            sqlSyntax,
+            sqlKind,
             category);
     if (list.isEmpty()) {
       return null;
@@ -343,23 +350,42 @@ public abstract class SqlUtil {
     }
   }
 
+  private static void filterOperatorRoutinesByKind(
+      List<SqlOperator> routines,
+      SqlKind sqlKind) {
+    Iterator<SqlOperator> iter = routines.iterator();
+    while (iter.hasNext()) {
+      SqlOperator sqlOperator = iter.next();
+      if (sqlKind != sqlOperator.getKind()) {
+        iter.remove();
+      }
+    }
+  }
+
   /**
    * Looks up all subject routines matching the given name and argument types.
    *
-   * @param opTab    operator table to search
-   * @param funcName name of function being invoked
-   * @param argTypes argument types
-   * @param argNames argument names, or null if call by position
+   * @param opTab     operator table to search
+   * @param funcName  name of function being invoked
+   * @param argTypes  argument types
+   * @param argNames  argument names, or null if call by position
+   * @param sqlSyntax the SqlSyntax of the SqlOperator being looked up
+   * @param sqlKind   the SqlKind of the SqlOperator being looked up
    * @param category category of routine to look up
    * @return list of matching routines
    * @sql.99 Part 2 Section 10.4
    */
-  public static List<SqlFunction> lookupSubjectRoutines(SqlOperatorTable opTab,
-      SqlIdentifier funcName, List<RelDataType> argTypes,
-      List<String> argNames, SqlFunctionCategory category) {
+  public static List<SqlOperator> lookupSubjectRoutines(
+      SqlOperatorTable opTab,
+      SqlIdentifier funcName,
+      List<RelDataType> argTypes,
+      List<String> argNames,
+      SqlSyntax sqlSyntax,
+      SqlKind sqlKind,
+      SqlFunctionCategory category) {
     // start with all routines matching by name
-    List<SqlFunction> routines =
-        lookupSubjectRoutinesByName(opTab, funcName, category);
+    List<SqlOperator> routines =
+        lookupSubjectRoutinesByName(opTab, funcName, sqlSyntax, category);
 
     // first pass:  eliminate routines which don't accept the given
     // number of arguments
@@ -373,8 +399,7 @@ public abstract class SqlUtil {
 
     // second pass:  eliminate routines which don't accept the given
     // argument types
-    filterRoutinesByParameterType(routines, argTypes, argNames);
-
+    filterRoutinesByParameterType(sqlSyntax, routines, argTypes, argNames);
     // see if we can stop now; this is necessary for the case
     // of builtin functions where we don't have param type info
     if (routines.size() < 2) {
@@ -384,8 +409,11 @@ public abstract class SqlUtil {
     // third pass:  for each parameter from left to right, eliminate
     // all routines except those with the best precedence match for
     // the given arguments
-    filterRoutinesByTypePrecedence(routines, argTypes);
+    filterRoutinesByTypePrecedence(sqlSyntax, routines, argTypes);
 
+    // fourth pass: eliminate routines which do not have the same
+    // SqlKind as requested
+    filterOperatorRoutinesByKind(routines, sqlKind);
     return routines;
   }
 
@@ -406,8 +434,8 @@ public abstract class SqlUtil {
       List<RelDataType> argTypes,
       SqlFunctionCategory category) {
     // start with all routines matching by name
-    List<SqlFunction> routines =
-        lookupSubjectRoutinesByName(opTab, funcName, category);
+    List<SqlOperator> routines =
+        lookupSubjectRoutinesByName(opTab, funcName, SqlSyntax.FUNCTION, category);
 
     // first pass:  eliminate routines which don't accept the given
     // number of arguments
@@ -416,29 +444,37 @@ public abstract class SqlUtil {
     return routines.size() > 0;
   }
 
-  private static List<SqlFunction> lookupSubjectRoutinesByName(
+  private static List<SqlOperator> lookupSubjectRoutinesByName(
       SqlOperatorTable opTab,
       SqlIdentifier funcName,
+      SqlSyntax sqlSyntax,
       SqlFunctionCategory category) {
-    final List<SqlOperator> operators = Lists.newArrayList();
-    opTab.lookupOperatorOverloads(funcName, category, SqlSyntax.FUNCTION,
-        operators);
-    List<SqlFunction> routines = new ArrayList<SqlFunction>();
-    for (SqlOperator operator : operators) {
-      if (operator instanceof SqlFunction) {
-        routines.add((SqlFunction) operator);
+    final List<SqlOperator> sqlOperators = Lists.newArrayList();
+    opTab.lookupOperatorOverloads(
+        funcName,
+        category,
+        sqlSyntax,
+        sqlOperators);
+    List<SqlOperator> routines = Lists.newArrayList();
+    for (SqlOperator sqlOperator : sqlOperators) {
+      if (sqlSyntax == SqlSyntax.FUNCTION) {
+        if (sqlOperator instanceof SqlFunction) {
+          routines.add(sqlOperator);
+        }
+      } else if (sqlSyntax == sqlOperator.getSyntax()) {
+        routines.add(sqlOperator);
       }
     }
     return routines;
   }
 
   private static void filterRoutinesByParameterCount(
-      List<SqlFunction> routines,
+      List<SqlOperator> routines,
       List<RelDataType> argTypes) {
-    Iterator<SqlFunction> iter = routines.iterator();
+    Iterator<? extends SqlOperator> iter = routines.iterator();
     while (iter.hasNext()) {
-      SqlFunction function = iter.next();
-      SqlOperandCountRange od = function.getOperandCountRange();
+      SqlOperator operator = iter.next();
+      SqlOperandCountRange od = operator.getOperandCountRange();
       if (!od.isValidCount(argTypes.size())) {
         iter.remove();
       }
@@ -448,9 +484,21 @@ public abstract class SqlUtil {
   /**
    * @sql.99 Part 2 Section 10.4 Syntax Rule 6.b.iii.2.B
    */
-  private static void filterRoutinesByParameterType(List<SqlFunction> routines,
+  private static void filterRoutinesByParameterType(
+      SqlSyntax sqlSyntax,
+      List<SqlOperator> routines,
       final List<RelDataType> argTypes, List<String> argNames) {
-    Iterator<SqlFunction> iter = routines.iterator();
+    if (sqlSyntax != SqlSyntax.FUNCTION) {
+      return;
+    }
+
+    List<SqlFunction> sqlFunctions = Lists.newArrayList();
+    for (SqlOperator sqlOperator : routines) {
+      sqlFunctions.add((SqlFunction) sqlOperator);
+    }
+    routines.clear();
+
+    Iterator<SqlFunction> iter = sqlFunctions.iterator();
   loop:
     while (iter.hasNext()) {
       SqlFunction function = iter.next();
@@ -499,19 +547,32 @@ public abstract class SqlUtil {
         }
       }
     }
+
+    routines.addAll(sqlFunctions);
   }
 
   /**
    * @sql.99 Part 2 Section 9.4
    */
   private static void filterRoutinesByTypePrecedence(
-      List<SqlFunction> routines,
+      SqlSyntax sqlSyntax,
+      List<SqlOperator> routines,
       List<RelDataType> argTypes) {
+    if (sqlSyntax != SqlSyntax.FUNCTION) {
+      return;
+    }
+
+    List<SqlFunction> sqlFunctions = Lists.newArrayList();
+    for (SqlOperator sqlOperator : routines) {
+      sqlFunctions.add((SqlFunction) sqlOperator);
+    }
+    routines.clear();
+
     for (int i = 0; i < argTypes.size(); ++i) {
       RelDataTypePrecedenceList precList =
           argTypes.get(i).getPrecedenceList();
       RelDataType bestMatch = null;
-      for (SqlFunction function : routines) {
+      for (SqlFunction function : sqlFunctions) {
         List<RelDataType> paramTypes = function.getParamTypes();
         if (paramTypes == null) {
           continue;
@@ -530,7 +591,7 @@ public abstract class SqlUtil {
         }
       }
       if (bestMatch != null) {
-        Iterator<SqlFunction> iter = routines.iterator();
+        Iterator<SqlFunction> iter = sqlFunctions.iterator();
         while (iter.hasNext()) {
           SqlFunction function = iter.next();
           List<RelDataType> paramTypes = function.getParamTypes();
@@ -548,6 +609,7 @@ public abstract class SqlUtil {
         }
       }
     }
+    routines.addAll(sqlFunctions);
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
index 03b6646..4dff351 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlBetweenOperator.java
@@ -159,6 +159,12 @@ public class SqlBetweenOperator extends SqlInfixOperator {
     return "{1} {0} {2} AND {3}";
   }
 
+  @Override public String getName() {
+    return super.getName()
+        + " "
+        + flag.name();
+  }
+
   public void unparse(
       SqlWriter writer,
       SqlCall call,
@@ -167,7 +173,7 @@ public class SqlBetweenOperator extends SqlInfixOperator {
     final SqlWriter.Frame frame =
         writer.startList(FRAME_TYPE, "", "");
     call.operand(VALUE_OPERAND).unparse(writer, getLeftPrec(), 0);
-    writer.sep(getName());
+    writer.sep(super.getName());
     writer.sep(flag.name());
 
     // If the expression for the lower bound contains a call to an AND

http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
index 97691fa..3291095 100644
--- a/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
@@ -143,7 +143,7 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
   }
 
   public void register(SqlOperator op) {
-    operators.put(op.getName(), op);
+    operators.put(op.getName().toUpperCase(), op);
     if (op instanceof SqlBinaryOperator) {
       mapNameToOp.put(Pair.of(op.getName(), SqlSyntax.BINARY), op);
     } else if (op instanceof SqlPrefixOperator) {
@@ -159,7 +159,7 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
    * @param function Function to register
    */
   public void register(SqlFunction function) {
-    operators.put(function.getName(), function);
+    operators.put(function.getName().toUpperCase(), function);
     SqlFunctionCategory funcType = function.getFunctionType();
     assert funcType != null
         : "Function type for " + function.getName() + " not set";

http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/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 5a51ca9..31a2b5c 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1831,8 +1831,17 @@ public class SqlToRelConverter {
     SqlNode windowOrRef = call.operand(1);
     final SqlWindow window =
         validator.resolveWindow(windowOrRef, bb.scope, true);
+    final SqlOperator row_number_function = SqlUtil.lookupRoutine(
+        opTab,
+        SqlStdOperatorTable.ROW_NUMBER.getNameAsId(),
+        ImmutableList.<RelDataType>of(),
+        ImmutableList.<String>of(),
+        SqlStdOperatorTable.ROW_NUMBER.getSyntax(),
+        SqlStdOperatorTable.ROW_NUMBER.getKind(),
+        SqlStdOperatorTable.ROW_NUMBER.getFunctionType());
+
     // ROW_NUMBER() expects specific kind of framing.
-    if (aggCall.getOperator() == SqlStdOperatorTable.ROW_NUMBER) {
+    if (aggCall.getOperator() == row_number_function) {
       window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO));
       window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO));
       window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO));

http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
index 54e808a..c11571a 100644
--- a/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
+++ b/core/src/test/java/org/apache/calcite/sql/test/SqlOperatorBaseTest.java
@@ -67,11 +67,14 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Calendar;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.List;
 import java.util.TimeZone;
 import java.util.regex.Pattern;
 
+import static org.hamcrest.CoreMatchers.equalTo;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
 import static org.junit.Assert.fail;
 
 /**
@@ -297,6 +300,30 @@ public abstract class SqlOperatorBaseTest {
   @Test public void testDummy() {
   }
 
+  @Test public void testSqlOperatorOverloading() {
+    final SqlStdOperatorTable operatorTable = SqlStdOperatorTable.instance();
+    for (SqlOperator sqlOperator : operatorTable.getOperatorList()) {
+      String operatorName = sqlOperator.getName();
+      List<SqlOperator> routines = new ArrayList<>();
+      operatorTable.lookupOperatorOverloads(
+          new SqlIdentifier(operatorName, SqlParserPos.ZERO),
+          null,
+          sqlOperator.getSyntax(),
+          routines);
+
+      Iterator<SqlOperator> iter = routines.iterator();
+      while (iter.hasNext()) {
+        SqlOperator operator = iter.next();
+        if (!sqlOperator.getClass().isInstance(operator)) {
+          iter.remove();
+        }
+      }
+      assertThat(routines.size(), equalTo(1));
+      assertThat(sqlOperator, equalTo(routines.get(0)));
+    }
+  }
+
+
   @Test public void testBetween() {
     tester.setFor(
         SqlStdOperatorTable.BETWEEN,

http://git-wip-us.apache.org/repos/asf/calcite/blob/c1ceba45/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
----------------------------------------------------------------------
diff --git a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
index cde2b8c..b3a8699 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
@@ -632,7 +632,7 @@ public class SqlValidatorTest extends SqlValidatorTestCase {
     checkExp("'a' between 'b' and 'c'");
     checkExp("'' between 2 and 3"); // can implicitly convert CHAR to INTEGER
     checkWholeExpFails("date '2012-02-03' between 2 and 3",
-        "(?s).*Cannot apply 'BETWEEN' to arguments of type.*");
+        "(?s).*Cannot apply 'BETWEEN ASYMMETRIC' to arguments of type.*");
   }
 
   @Test public void testCharsetMismatch() {


[3/3] calcite git commit: Fix up [CALCITE-1062]

Posted by jh...@apache.org.
Fix up [CALCITE-1062]

Add SqlKind for ROW_NUMBER and other rank functions.

Use iterator rather than list when resolving operator overloads.


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

Branch: refs/heads/master
Commit: 72b2cfb799242e0d1d7e6aed8bfe43cceb554c7c
Parents: c1ceba4
Author: Julian Hyde <jh...@apache.org>
Authored: Tue Feb 9 15:16:11 2016 -0800
Committer: Julian Hyde <jh...@apache.org>
Committed: Tue Feb 9 16:04:56 2016 -0800

----------------------------------------------------------------------
 .../org/apache/calcite/sql/SqlFunction.java     |  63 ++--
 .../java/org/apache/calcite/sql/SqlKind.java    |  15 +
 .../org/apache/calcite/sql/SqlOperator.java     |  75 ++--
 .../org/apache/calcite/sql/SqlRankFunction.java |  13 +-
 .../java/org/apache/calcite/sql/SqlUtil.java    | 340 +++++++++----------
 .../calcite/sql/fun/SqlStdOperatorTable.java    |  21 +-
 .../sql/util/ReflectiveSqlOperatorTable.java    |  81 +++--
 .../calcite/sql2rel/SqlToRelConverter.java      |  10 +-
 8 files changed, 289 insertions(+), 329 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
index 2ed8bda..3bdc91c 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlFunction.java
@@ -19,7 +19,6 @@ package org.apache.calcite.sql;
 import org.apache.calcite.linq4j.function.Function1;
 import org.apache.calcite.linq4j.function.Functions;
 import org.apache.calcite.rel.type.RelDataType;
-import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.type.SqlOperandTypeChecker;
 import org.apache.calcite.sql.type.SqlOperandTypeInference;
 import org.apache.calcite.sql.type.SqlReturnTypeInference;
@@ -141,16 +140,11 @@ public class SqlFunction extends SqlOperator {
     return sqlIdentifier;
   }
 
-  /**
-   * @return fully qualified name of function
-   */
-  public SqlIdentifier getNameAsId() {
+  @Override public SqlIdentifier getNameAsId() {
     if (sqlIdentifier != null) {
       return sqlIdentifier;
     }
-    return new SqlIdentifier(
-        getName(),
-        SqlParserPos.ZERO);
+    return super.getNameAsId();
   }
 
   /**
@@ -239,38 +233,18 @@ public class SqlFunction extends SqlOperator {
     // Indicate to the validator that we're validating a new function call
     validator.pushFunctionCall();
 
-    List<String> argNames = constructArgNameList(
-        call);
-
-    List<SqlNode> args = constructOperandList(
-        validator,
-        call,
-        argNames);
-
-    List<RelDataType> argTypes = constructArgTypeList(
-        validator,
-        scope,
-        call,
-        args,
-        convertRowArgToColumnList);
-
-    SqlFunction function = (SqlFunction) SqlUtil.lookupRoutine(
-        validator.getOperatorTable(),
-        getNameAsId(),
-        argTypes,
-        argNames,
-        SqlSyntax.FUNCTION,
-        getKind(),
-        getFunctionType());
-    try {
-      boolean containsRowArg = false;
-      for (SqlNode operand : args) {
-        if (operand.getKind() == SqlKind.ROW && convertRowArgToColumnList) {
-          containsRowArg = true;
-          break;
-        }
-      }
+    final List<String> argNames = constructArgNameList(call);
+
+    final List<SqlNode> args = constructOperandList(validator, call, argNames);
+
+    final List<RelDataType> argTypes = constructArgTypeList(validator, scope,
+        call, args, convertRowArgToColumnList);
 
+    final SqlFunction function =
+        (SqlFunction) SqlUtil.lookupRoutine(validator.getOperatorTable(),
+            getNameAsId(), argTypes, argNames, getFunctionType(), SqlSyntax.FUNCTION, getKind()
+        );
+    try {
       // if we have a match on function name and parameter count, but
       // couldn't find a function with  a COLUMN_LIST type, retry, but
       // this time, don't convert the row argument to a COLUMN_LIST type;
@@ -278,7 +252,7 @@ public class SqlFunction extends SqlOperator {
       // (corresponding to column references), now that we can set the
       // scope to that of the source cursor referenced by that ColumnList
       // type
-      if (containsRowArg) {
+      if (convertRowArgToColumnList && containsRowArg(args)) {
         if (function == null
             && SqlUtil.matchRoutinesByParameterCount(
                 validator.getOperatorTable(), getNameAsId(), argTypes,
@@ -318,6 +292,15 @@ public class SqlFunction extends SqlOperator {
       validator.popFunctionCall();
     }
   }
+
+  private boolean containsRowArg(List<SqlNode> args) {
+    for (SqlNode operand : args) {
+      if (operand.getKind() == SqlKind.ROW) {
+        return true;
+      }
+    }
+    return false;
+  }
 }
 
 // End SqlFunction.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/SqlKind.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlKind.java b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
index 270a311..bbc7e7e 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlKind.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlKind.java
@@ -693,6 +693,21 @@ public enum SqlKind {
   /** The {@code SINGLE_VALUE} aggregate function. */
   SINGLE_VALUE,
 
+  /** The {@code ROW_NUMBER} window function. */
+  ROW_NUMBER,
+
+  /** The {@code RANK} window function. */
+  RANK,
+
+  /** The {@code PERCENT_RANK} window function. */
+  PERCENT_RANK,
+
+  /** The {@code DENSE_RANK} window function. */
+  DENSE_RANK,
+
+  /** The {@code ROW_NUMBER} window function. */
+  CUME_DIST,
+
   // DDL and session control statements follow. The list is not exhaustive: feel
   // free to add more.
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/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 e3d9c27..d3bd645 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlOperator.java
@@ -204,6 +204,13 @@ public abstract class SqlOperator {
     return name;
   }
 
+  /**
+   * Returns the fully-qualified name of this operator.
+   */
+  public SqlIdentifier getNameAsId() {
+    return new SqlIdentifier(getName(), SqlParserPos.ZERO);
+  }
+
   public SqlKind getKind() {
     return kind;
   }
@@ -483,29 +490,19 @@ public abstract class SqlOperator {
       SqlValidator validator,
       SqlValidatorScope scope,
       SqlCall call) {
+    for (SqlNode operand : call.getOperandList()) {
+      RelDataType nodeType = validator.deriveType(scope, operand);
+      assert nodeType != null;
+    }
 
-    List<SqlNode> args = constructOperandList(
-        validator,
-        call,
-        null);
-
-    List<RelDataType> argTypes = constructArgTypeList(
-        validator,
-        scope,
-        call,
-        args,
-        false);
-
-    SqlOperator sqlOperator = SqlUtil.lookupRoutine(
-        validator.getOperatorTable(),
-        new SqlIdentifier(
-            call.getOperator().getName(),
-            call.getParserPosition()),
-        argTypes,
-        null,
-        getSyntax(),
-        getKind(),
-        null);
+    final List<SqlNode> args = constructOperandList(validator, call, null);
+
+    final List<RelDataType> argTypes = constructArgTypeList(validator, scope,
+        call, args, false);
+
+    final SqlOperator sqlOperator =
+        SqlUtil.lookupRoutine(validator.getOperatorTable(), getNameAsId(),
+            argTypes, null, null, getSyntax(), getKind());
 
     ((SqlBasicCall) call).setOperator(sqlOperator);
     RelDataType type = call.getOperator().validateOperands(validator, scope, call);
@@ -539,6 +536,18 @@ public abstract class SqlOperator {
       SqlValidator validator,
       SqlCall call,
       List<String> argNames) {
+    if (argNames == null) {
+      return call.getOperandList();
+    }
+    if (argNames.size() < call.getOperandList().size()) {
+      throw validator.newValidationError(call,
+          RESOURCE.someButNotAllArgumentsAreNamed());
+    }
+    final int duplicate = Util.firstDuplicate(argNames);
+    if (duplicate >= 0) {
+      throw validator.newValidationError(call,
+          RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
+    }
     final ImmutableList.Builder<SqlNode> argBuilder = ImmutableList.builder();
     for (SqlNode operand : call.getOperandList()) {
       if (operand.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
@@ -546,24 +555,7 @@ public abstract class SqlOperator {
         argBuilder.add(operandList.get(0));
       }
     }
-
-    final List<SqlNode> args;
-    if (argNames == null) {
-      args = call.getOperandList();
-    } else {
-      if (argNames.size() < call.getOperandList().size()) {
-        throw validator.newValidationError(call,
-            RESOURCE.someButNotAllArgumentsAreNamed());
-      }
-      int duplicate = Util.firstDuplicate(argNames);
-      if (duplicate >= 0) {
-        throw validator.newValidationError(call,
-            RESOURCE.duplicateArgumentName(argNames.get(duplicate)));
-      }
-      args = argBuilder.build();
-    }
-
-    return args;
+    return argBuilder.build();
   }
 
   protected List<RelDataType> constructArgTypeList(
@@ -593,8 +585,7 @@ public abstract class SqlOperator {
       argTypeBuilder.add(nodeType);
     }
 
-    final List<RelDataType> argTypes = argTypeBuilder.build();
-    return argTypes;
+    return argTypeBuilder.build();
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java b/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
index 738add1..8bf4721 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlRankFunction.java
@@ -25,16 +25,9 @@ import org.apache.calcite.sql.type.ReturnTypes;
 public class SqlRankFunction extends SqlAggFunction {
   //~ Constructors -----------------------------------------------------------
 
-  public SqlRankFunction(String name, boolean requiresOrder) {
-    super(
-        name,
-        null,
-        SqlKind.OTHER_FUNCTION,
-        ReturnTypes.INTEGER,
-        null,
-        OperandTypes.NILADIC,
-        SqlFunctionCategory.NUMERIC,
-        requiresOrder,
+  public SqlRankFunction(boolean requiresOrder, SqlKind kind) {
+    super(kind.name(), null, kind, ReturnTypes.INTEGER, null,
+        OperandTypes.NILADIC, SqlFunctionCategory.NUMERIC, requiresOrder,
         true);
   }
 

http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
index 2ba78aa..40e1255 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
@@ -38,7 +38,10 @@ import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
 import com.google.common.base.Predicate;
+import com.google.common.base.Predicates;
 import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Iterables;
+import com.google.common.collect.Iterators;
 import com.google.common.collect.Lists;
 
 import java.nio.charset.Charset;
@@ -325,41 +328,35 @@ public abstract class SqlUtil {
    * @return matching routine, or null if none found
    * @sql.99 Part 2 Section 10.4
    */
-  public static SqlOperator lookupRoutine(
-      SqlOperatorTable opTab,
-      SqlIdentifier funcName,
-      List<RelDataType> argTypes,
-      List<String> argNames,
-      SqlSyntax sqlSyntax,
-      SqlKind sqlKind,
-      SqlFunctionCategory category) {
-    List<SqlOperator> list =
+  public static SqlOperator lookupRoutine(SqlOperatorTable opTab,
+      SqlIdentifier funcName, List<RelDataType> argTypes,
+      List<String> argNames, SqlFunctionCategory category,
+      SqlSyntax syntax, SqlKind sqlKind) {
+    Iterator<SqlOperator> list =
         lookupSubjectRoutines(
             opTab,
             funcName,
             argTypes,
             argNames,
-            sqlSyntax,
+            syntax,
             sqlKind,
             category);
-    if (list.isEmpty()) {
-      return null;
-    } else {
+    if (list.hasNext()) {
       // return first on schema path
-      return list.get(0);
+      return list.next();
     }
+    return null;
   }
 
-  private static void filterOperatorRoutinesByKind(
-      List<SqlOperator> routines,
-      SqlKind sqlKind) {
-    Iterator<SqlOperator> iter = routines.iterator();
-    while (iter.hasNext()) {
-      SqlOperator sqlOperator = iter.next();
-      if (sqlKind != sqlOperator.getKind()) {
-        iter.remove();
-      }
-    }
+  private static Iterator<SqlOperator>
+  filterOperatorRoutinesByKind(Iterator<SqlOperator> routines,
+      final SqlKind sqlKind) {
+    return Iterators.filter(routines,
+        new Predicate<SqlOperator>() {
+          public boolean apply(SqlOperator input) {
+            return input.getKind() == sqlKind;
+          }
+        });
   }
 
   /**
@@ -375,7 +372,7 @@ public abstract class SqlUtil {
    * @return list of matching routines
    * @sql.99 Part 2 Section 10.4
    */
-  public static List<SqlOperator> lookupSubjectRoutines(
+  public static Iterator<SqlOperator> lookupSubjectRoutines(
       SqlOperatorTable opTab,
       SqlIdentifier funcName,
       List<RelDataType> argTypes,
@@ -384,12 +381,12 @@ public abstract class SqlUtil {
       SqlKind sqlKind,
       SqlFunctionCategory category) {
     // start with all routines matching by name
-    List<SqlOperator> routines =
+    Iterator<SqlOperator> routines =
         lookupSubjectRoutinesByName(opTab, funcName, sqlSyntax, category);
 
     // first pass:  eliminate routines which don't accept the given
     // number of arguments
-    filterRoutinesByParameterCount(routines, argTypes);
+    routines = filterRoutinesByParameterCount(routines, argTypes);
 
     // NOTE: according to SQL99, procedures are NOT overloaded on type,
     // only on number of arguments.
@@ -399,28 +396,29 @@ public abstract class SqlUtil {
 
     // second pass:  eliminate routines which don't accept the given
     // argument types
-    filterRoutinesByParameterType(sqlSyntax, routines, argTypes, argNames);
+    routines = filterRoutinesByParameterType(sqlSyntax, routines, argTypes, argNames);
+
     // see if we can stop now; this is necessary for the case
     // of builtin functions where we don't have param type info
-    if (routines.size() < 2) {
+    final List<SqlOperator> list = Lists.newArrayList(routines);
+    routines = list.iterator();
+    if (list.size() < 2) {
       return routines;
     }
 
     // third pass:  for each parameter from left to right, eliminate
     // all routines except those with the best precedence match for
     // the given arguments
-    filterRoutinesByTypePrecedence(sqlSyntax, routines, argTypes);
+    routines = filterRoutinesByTypePrecedence(sqlSyntax, routines, argTypes);
 
     // fourth pass: eliminate routines which do not have the same
     // SqlKind as requested
-    filterOperatorRoutinesByKind(routines, sqlKind);
-    return routines;
+    return filterOperatorRoutinesByKind(routines, sqlKind);
   }
 
   /**
-   * Determine if there is a routine matching the given name and number of
-   * arguments.
-   *
+   * Determines whether there is a routine matching the given name and number
+   * of arguments.
    *
    * @param opTab    operator table to search
    * @param funcName name of function being invoked
@@ -434,182 +432,172 @@ public abstract class SqlUtil {
       List<RelDataType> argTypes,
       SqlFunctionCategory category) {
     // start with all routines matching by name
-    List<SqlOperator> routines =
+    Iterator<SqlOperator> routines =
         lookupSubjectRoutinesByName(opTab, funcName, SqlSyntax.FUNCTION, category);
 
     // first pass:  eliminate routines which don't accept the given
     // number of arguments
-    filterRoutinesByParameterCount(routines, argTypes);
+    routines = filterRoutinesByParameterCount(routines, argTypes);
 
-    return routines.size() > 0;
+    return routines.hasNext();
   }
 
-  private static List<SqlOperator> lookupSubjectRoutinesByName(
+  private static Iterator<SqlOperator> lookupSubjectRoutinesByName(
       SqlOperatorTable opTab,
       SqlIdentifier funcName,
-      SqlSyntax sqlSyntax,
+      final SqlSyntax syntax,
       SqlFunctionCategory category) {
-    final List<SqlOperator> sqlOperators = Lists.newArrayList();
-    opTab.lookupOperatorOverloads(
-        funcName,
-        category,
-        sqlSyntax,
-        sqlOperators);
-    List<SqlOperator> routines = Lists.newArrayList();
-    for (SqlOperator sqlOperator : sqlOperators) {
-      if (sqlSyntax == SqlSyntax.FUNCTION) {
-        if (sqlOperator instanceof SqlFunction) {
-          routines.add(sqlOperator);
-        }
-      } else if (sqlSyntax == sqlOperator.getSyntax()) {
-        routines.add(sqlOperator);
-      }
-    }
-    return routines;
-  }
-
-  private static void filterRoutinesByParameterCount(
-      List<SqlOperator> routines,
-      List<RelDataType> argTypes) {
-    Iterator<? extends SqlOperator> iter = routines.iterator();
-    while (iter.hasNext()) {
-      SqlOperator operator = iter.next();
-      SqlOperandCountRange od = operator.getOperandCountRange();
-      if (!od.isValidCount(argTypes.size())) {
-        iter.remove();
-      }
-    }
+    final List<SqlOperator> sqlOperators = new ArrayList<>();
+    opTab.lookupOperatorOverloads(funcName, category, syntax, sqlOperators);
+    switch (syntax) {
+    case FUNCTION:
+      return Iterators.filter(sqlOperators.iterator(),
+          Predicates.instanceOf(SqlFunction.class));
+    default:
+      return Iterators.filter(sqlOperators.iterator(),
+          new Predicate<SqlOperator>() {
+            public boolean apply(SqlOperator operator) {
+              return operator.getSyntax() == syntax;
+            }
+          });
+    }
+  }
+
+  private static Iterator<SqlOperator> filterRoutinesByParameterCount(
+      Iterator<SqlOperator> routines,
+      final List<RelDataType> argTypes) {
+    return Iterators.filter(routines,
+        new Predicate<SqlOperator>() {
+          public boolean apply(SqlOperator operator) {
+            SqlOperandCountRange od = operator.getOperandCountRange();
+            return od.isValidCount(argTypes.size());
+          }
+        });
   }
 
   /**
    * @sql.99 Part 2 Section 10.4 Syntax Rule 6.b.iii.2.B
    */
-  private static void filterRoutinesByParameterType(
-      SqlSyntax sqlSyntax,
-      List<SqlOperator> routines,
-      final List<RelDataType> argTypes, List<String> argNames) {
-    if (sqlSyntax != SqlSyntax.FUNCTION) {
-      return;
-    }
-
-    List<SqlFunction> sqlFunctions = Lists.newArrayList();
-    for (SqlOperator sqlOperator : routines) {
-      sqlFunctions.add((SqlFunction) sqlOperator);
+  private static Iterator<SqlOperator> filterRoutinesByParameterType(
+      SqlSyntax syntax,
+      final Iterator<SqlOperator> routines,
+      final List<RelDataType> argTypes, final List<String> argNames) {
+    if (syntax != SqlSyntax.FUNCTION) {
+      return routines;
     }
-    routines.clear();
 
-    Iterator<SqlFunction> iter = sqlFunctions.iterator();
-  loop:
-    while (iter.hasNext()) {
-      SqlFunction function = iter.next();
-      List<RelDataType> paramTypes = function.getParamTypes();
-      if (paramTypes == null) {
-        // no parameter information for builtins; keep for now
-        continue;
-      }
-      final List<RelDataType> permutedArgTypes;
-      if (argNames != null) {
-        // Arguments passed by name. Make sure that the function has parameters
-        // of all of these names.
-        final Map<Integer, Integer> map = new HashMap<>();
-        for (Ord<String> argName : Ord.zip(argNames)) {
-          final int i = function.getParamNames().indexOf(argName.e);
-          if (i < 0) {
-            iter.remove();
-            continue loop;
-          }
-          map.put(i, argName.i);
-        }
-        permutedArgTypes = Functions.generate(paramTypes.size(),
-            new Function1<Integer, RelDataType>() {
-              public RelDataType apply(Integer a0) {
-                if (map.containsKey(a0)) {
-                  return argTypes.get(map.get(a0));
-                } else {
-                  return null;
+    //noinspection unchecked
+    return (Iterator) Iterators.filter(
+        Iterators.filter(routines, SqlFunction.class),
+        new Predicate<SqlFunction>() {
+          public boolean apply(SqlFunction function) {
+            List<RelDataType> paramTypes = function.getParamTypes();
+            if (paramTypes == null) {
+              // no parameter information for builtins; keep for now
+              return true;
+            }
+            final List<RelDataType> permutedArgTypes;
+            if (argNames != null) {
+              // Arguments passed by name. Make sure that the function has
+              // parameters of all of these names.
+              final Map<Integer, Integer> map = new HashMap<>();
+              for (Ord<String> argName : Ord.zip(argNames)) {
+                final int i = function.getParamNames().indexOf(argName.e);
+                if (i < 0) {
+                  return false;
                 }
+                map.put(i, argName.i);
               }
-            });
-      } else {
-        permutedArgTypes = Lists.newArrayList(argTypes);
-        while (permutedArgTypes.size() < argTypes.size()) {
-          paramTypes.add(null);
-        }
-      }
-      for (Pair<RelDataType, RelDataType> p
-          : Pair.zip(paramTypes, permutedArgTypes)) {
-        final RelDataType argType = p.right;
-        final RelDataType paramType = p.left;
-        if (argType != null
-            && !SqlTypeUtil.canCastFrom(paramType, argType, false)) {
-          iter.remove();
-          continue loop;
-        }
-      }
-    }
-
-    routines.addAll(sqlFunctions);
+              permutedArgTypes = Functions.generate(paramTypes.size(),
+                  new Function1<Integer, RelDataType>() {
+                    public RelDataType apply(Integer a0) {
+                      if (map.containsKey(a0)) {
+                        return argTypes.get(map.get(a0));
+                      } else {
+                        return null;
+                      }
+                    }
+                  });
+            } else {
+              permutedArgTypes = Lists.newArrayList(argTypes);
+              while (permutedArgTypes.size() < argTypes.size()) {
+                paramTypes.add(null);
+              }
+            }
+            for (Pair<RelDataType, RelDataType> p
+                : Pair.zip(paramTypes, permutedArgTypes)) {
+              final RelDataType argType = p.right;
+              final RelDataType paramType = p.left;
+              if (argType != null
+                  && !SqlTypeUtil.canCastFrom(paramType, argType, false)) {
+                return false;
+              }
+            }
+            return true;
+          }
+        });
   }
 
   /**
    * @sql.99 Part 2 Section 9.4
    */
-  private static void filterRoutinesByTypePrecedence(
+  private static Iterator<SqlOperator> filterRoutinesByTypePrecedence(
       SqlSyntax sqlSyntax,
-      List<SqlOperator> routines,
+      Iterator<SqlOperator> routines,
       List<RelDataType> argTypes) {
     if (sqlSyntax != SqlSyntax.FUNCTION) {
-      return;
+      return routines;
     }
 
-    List<SqlFunction> sqlFunctions = Lists.newArrayList();
-    for (SqlOperator sqlOperator : routines) {
-      sqlFunctions.add((SqlFunction) sqlOperator);
+    List<SqlFunction> sqlFunctions =
+        Lists.newArrayList(Iterators.filter(routines, SqlFunction.class));
+
+    for (final Ord<RelDataType> argType : Ord.zip(argTypes)) {
+      final RelDataTypePrecedenceList precList =
+          argType.e.getPrecedenceList();
+      final RelDataType bestMatch = bestMatch(sqlFunctions, argType.i, precList);
+      if (bestMatch != null) {
+        sqlFunctions =
+            Lists.newArrayList(
+                Iterables.filter(sqlFunctions,
+                    new Predicate<SqlFunction>() {
+                      public boolean apply(SqlFunction function) {
+                        final List<RelDataType> paramTypes = function.getParamTypes();
+                        if (paramTypes == null) {
+                          return false;
+                        }
+                        final RelDataType paramType = paramTypes.get(argType.i);
+                        return precList.compareTypePrecedence(paramType, bestMatch) >= 0;
+                      }
+                    }));
+      }
     }
-    routines.clear();
+    //noinspection unchecked
+    return (Iterator) sqlFunctions.iterator();
+  }
 
-    for (int i = 0; i < argTypes.size(); ++i) {
-      RelDataTypePrecedenceList precList =
-          argTypes.get(i).getPrecedenceList();
-      RelDataType bestMatch = null;
-      for (SqlFunction function : sqlFunctions) {
-        List<RelDataType> paramTypes = function.getParamTypes();
-        if (paramTypes == null) {
-          continue;
-        }
-        final RelDataType paramType = paramTypes.get(i);
-        if (bestMatch == null) {
-          bestMatch = paramType;
-        } else {
-          int c =
-              precList.compareTypePrecedence(
-                  bestMatch,
-                  paramType);
-          if (c < 0) {
-            bestMatch = paramType;
-          }
-        }
+  private static RelDataType bestMatch(List<SqlFunction> sqlFunctions, int i,
+      RelDataTypePrecedenceList precList) {
+    RelDataType bestMatch = null;
+    for (SqlFunction function : sqlFunctions) {
+      List<RelDataType> paramTypes = function.getParamTypes();
+      if (paramTypes == null) {
+        continue;
       }
-      if (bestMatch != null) {
-        Iterator<SqlFunction> iter = sqlFunctions.iterator();
-        while (iter.hasNext()) {
-          SqlFunction function = iter.next();
-          List<RelDataType> paramTypes = function.getParamTypes();
-          int c;
-          if (paramTypes == null) {
-            c = -1;
-          } else {
-            c = precList.compareTypePrecedence(
-                paramTypes.get(i),
-                bestMatch);
-          }
-          if (c < 0) {
-            iter.remove();
-          }
+      final RelDataType paramType = paramTypes.get(i);
+      if (bestMatch == null) {
+        bestMatch = paramType;
+      } else {
+        int c =
+            precList.compareTypePrecedence(
+                bestMatch,
+                paramType);
+        if (c < 0) {
+          bestMatch = paramType;
         }
       }
     }
-    routines.addAll(sqlFunctions);
+    return bestMatch;
   }
 
   /**

http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index db755a2..dce373f 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -859,33 +859,34 @@ public class SqlStdOperatorTable extends ReflectiveSqlOperatorTable {
   // WINDOW Rank Functions
   //-------------------------------------------------------------
   /**
-   * <code>CUME_DIST</code> Window function.
+   * <code>CUME_DIST</code> window function.
    */
   public static final SqlRankFunction CUME_DIST =
-      new SqlRankFunction("CUME_DIST", true);
+      new SqlRankFunction(true, SqlKind.CUME_DIST);
 
   /**
-   * <code>DENSE_RANK</code> Window function.
+   * <code>DENSE_RANK</code> window function.
    */
   public static final SqlRankFunction DENSE_RANK =
-      new SqlRankFunction("DENSE_RANK", true);
+      new SqlRankFunction(true, SqlKind.DENSE_RANK);
 
   /**
-   * <code>PERCENT_RANK</code> Window function.
+   * <code>PERCENT_RANK</code> window function.
    */
   public static final SqlRankFunction PERCENT_RANK =
-      new SqlRankFunction("PERCENT_RANK", true);
+      new SqlRankFunction(true, SqlKind.PERCENT_RANK);
 
   /**
-   * <code>RANK</code> Window function.
+   * <code>RANK</code> window function.
    */
-  public static final SqlRankFunction RANK = new SqlRankFunction("RANK", true);
+  public static final SqlRankFunction RANK =
+      new SqlRankFunction(true, SqlKind.RANK);
 
   /**
-   * <code>ROW_NUMBER</code> Window function.
+   * <code>ROW_NUMBER</code> window function.
    */
   public static final SqlRankFunction ROW_NUMBER =
-      new SqlRankFunction("ROW_NUMBER", false);
+      new SqlRankFunction(false, SqlKind.ROW_NUMBER);
 
   //-------------------------------------------------------------
   //                   SPECIAL OPERATORS

http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
----------------------------------------------------------------------
diff --git a/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java b/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
index 3291095..494e600 100644
--- a/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/util/ReflectiveSqlOperatorTable.java
@@ -16,30 +16,26 @@
  */
 package org.apache.calcite.sql.util;
 
-import org.apache.calcite.sql.SqlBinaryOperator;
 import org.apache.calcite.sql.SqlFunction;
 import org.apache.calcite.sql.SqlFunctionCategory;
 import org.apache.calcite.sql.SqlIdentifier;
 import org.apache.calcite.sql.SqlOperator;
 import org.apache.calcite.sql.SqlOperatorTable;
-import org.apache.calcite.sql.SqlPostfixOperator;
-import org.apache.calcite.sql.SqlPrefixOperator;
 import org.apache.calcite.sql.SqlSyntax;
 import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Util;
 
+import com.google.common.base.Throwables;
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.Multimap;
 
 import java.lang.reflect.Field;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 
 /**
- * ReflectiveSqlOperatorTable implements the {@link SqlOperatorTable } interface
+ * ReflectiveSqlOperatorTable implements the {@link SqlOperatorTable} interface
  * by reflecting the public fields of a subclass.
  */
 public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
@@ -47,10 +43,7 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
 
   //~ Instance fields --------------------------------------------------------
 
-  private final Multimap<String, SqlOperator> operators = HashMultimap.create();
-
-  private final Map<Pair<String, SqlSyntax>, SqlOperator> mapNameToOp =
-      new HashMap<Pair<String, SqlSyntax>, SqlOperator>();
+  private final Multimap<Key, SqlOperator> operators = HashMultimap.create();
 
   //~ Constructors -----------------------------------------------------------
 
@@ -78,14 +71,8 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
           SqlOperator op = (SqlOperator) field.get(this);
           register(op);
         }
-      } catch (IllegalArgumentException e) {
-        throw Util.newInternal(
-            e,
-            "Error while initializing operator table");
-      } catch (IllegalAccessException e) {
-        throw Util.newInternal(
-            e,
-            "Error while initializing operator table");
+      } catch (IllegalArgumentException | IllegalAccessException e) {
+        throw Throwables.propagate(e);
       }
     }
   }
@@ -112,7 +99,7 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
     // Always look up built-in operators case-insensitively. Even in sessions
     // with unquotedCasing=UNCHANGED and caseSensitive=true.
     final Collection<SqlOperator> list =
-        operators.get(simpleName.toUpperCase());
+        operators.get(new Key(simpleName, syntax));
     if (list.isEmpty()) {
       return;
     }
@@ -133,41 +120,51 @@ public abstract class ReflectiveSqlOperatorTable implements SqlOperatorTable {
     case BINARY:
     case PREFIX:
     case POSTFIX:
-      SqlOperator extra = mapNameToOp.get(Pair.of(simpleName, syntax));
-      // REVIEW: should only search operators added during this method?
-      if (extra != null && !operatorList.contains(extra)) {
-        operatorList.add(extra);
+      for (SqlOperator extra : operators.get(new Key(simpleName, syntax))) {
+        // REVIEW: should only search operators added during this method?
+        if (extra != null && !operatorList.contains(extra)) {
+          operatorList.add(extra);
+        }
       }
       break;
     }
   }
 
-  public void register(SqlOperator op) {
-    operators.put(op.getName().toUpperCase(), op);
-    if (op instanceof SqlBinaryOperator) {
-      mapNameToOp.put(Pair.of(op.getName(), SqlSyntax.BINARY), op);
-    } else if (op instanceof SqlPrefixOperator) {
-      mapNameToOp.put(Pair.of(op.getName(), SqlSyntax.PREFIX), op);
-    } else if (op instanceof SqlPostfixOperator) {
-      mapNameToOp.put(Pair.of(op.getName(), SqlSyntax.POSTFIX), op);
-    }
-  }
-
   /**
-   * Registers a function in the table.
-   *
-   * @param function Function to register
+   * Registers a function or operator in the table.
    */
-  public void register(SqlFunction function) {
-    operators.put(function.getName().toUpperCase(), function);
-    SqlFunctionCategory funcType = function.getFunctionType();
-    assert funcType != null
-        : "Function type for " + function.getName() + " not set";
+  public void register(SqlOperator op) {
+    operators.put(new Key(op.getName(), op.getSyntax()), op);
+    if (op instanceof SqlFunction) {
+      SqlFunction function = (SqlFunction) op;
+      SqlFunctionCategory funcType = function.getFunctionType();
+      assert funcType != null
+          : "Function type for " + function.getName() + " not set";
+    }
   }
 
   public List<SqlOperator> getOperatorList() {
     return ImmutableList.copyOf(operators.values());
   }
+
+  /** Key for looking up operators. The name is stored in upper-case because we
+   * store case-insensitively, even in a case-sensitive session. */
+  private static class Key extends Pair<String, SqlSyntax> {
+    Key(String name, SqlSyntax syntax) {
+      super(name.toUpperCase(), normalize(syntax));
+    }
+
+    private static SqlSyntax normalize(SqlSyntax syntax) {
+      switch (syntax) {
+      case BINARY:
+      case PREFIX:
+      case POSTFIX:
+        return syntax;
+      default:
+        return SqlSyntax.FUNCTION;
+      }
+    }
+  }
 }
 
 // End ReflectiveSqlOperatorTable.java

http://git-wip-us.apache.org/repos/asf/calcite/blob/72b2cfb7/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 31a2b5c..1fe4177 100644
--- a/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
+++ b/core/src/main/java/org/apache/calcite/sql2rel/SqlToRelConverter.java
@@ -1831,17 +1831,9 @@ public class SqlToRelConverter {
     SqlNode windowOrRef = call.operand(1);
     final SqlWindow window =
         validator.resolveWindow(windowOrRef, bb.scope, true);
-    final SqlOperator row_number_function = SqlUtil.lookupRoutine(
-        opTab,
-        SqlStdOperatorTable.ROW_NUMBER.getNameAsId(),
-        ImmutableList.<RelDataType>of(),
-        ImmutableList.<String>of(),
-        SqlStdOperatorTable.ROW_NUMBER.getSyntax(),
-        SqlStdOperatorTable.ROW_NUMBER.getKind(),
-        SqlStdOperatorTable.ROW_NUMBER.getFunctionType());
 
     // ROW_NUMBER() expects specific kind of framing.
-    if (aggCall.getOperator() == row_number_function) {
+    if (aggCall.getKind() == SqlKind.ROW_NUMBER) {
       window.setLowerBound(SqlWindow.createUnboundedPreceding(SqlParserPos.ZERO));
       window.setUpperBound(SqlWindow.createCurrentRow(SqlParserPos.ZERO));
       window.setRows(SqlLiteral.createBoolean(true, SqlParserPos.ZERO));