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:45 UTC
[3/3] calcite git commit: Fix up [CALCITE-1062]
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));