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 <[email protected]> Authored: Tue Feb 9 15:16:11 2016 -0800 Committer: Julian Hyde <[email protected]> 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));
