calcite-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jh...@apache.org
Subject [3/3] calcite git commit: Fix up [CALCITE-1062]
Date Wed, 10 Feb 2016 00:05:45 GMT
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 <jhyde@apache.org>
Authored: Tue Feb 9 15:16:11 2016 -0800
Committer: Julian Hyde <jhyde@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));


Mime
View raw message