Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,9 @@ public SqlUnresolvedFunction(
return typeFactory.createTypeWithNullability(
typeFactory.createSqlType(SqlTypeName.ANY), true);
}

@Override public boolean argumentMustBeScalar(final int ordinal) {
// We don't know whether the argument is scalar or not for an unresolved function
return false;
}
}
25 changes: 25 additions & 0 deletions core/src/main/java/org/apache/calcite/sql/SqlUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -626,6 +626,31 @@ public static Iterator<SqlOperator> lookupSubjectRoutines(
return filterOperatorRoutinesByKind(routines, sqlKind);
}

/**
* Finding operators matching the given name and number of arguments.
*
* @param opTab operator table to search
* @param funcName name of function being invoked
* @param argNumber number of arguments
* @param category category of routine to look up
* @param nameMatcher Whether to look up the function case-sensitively
* @return list of matching routines
*/
public static List<SqlOperator> lookupOperatorsByParameterCount(
SqlOperatorTable opTab,
SqlFunctionCategory category,
SqlSyntax syntax,
SqlIdentifier funcName,
SqlNameMatcher nameMatcher,
int argNumber) {
final List<SqlOperator> sqlOperators = new ArrayList<>();
opTab.lookupOperatorOverloads(funcName, category, syntax, sqlOperators,
nameMatcher);
return sqlOperators.stream()
.filter(sqlOperator -> sqlOperator.getOperandCountRange().isValidCount(argNumber))
.collect(Collectors.toList());
}

/**
* Determines whether there is a routine matching the given name and number
* of arguments.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,12 +23,12 @@
import org.apache.calcite.sql.SqlOperator;
import org.apache.calcite.sql.SqlOperatorTable;
import org.apache.calcite.sql.SqlSyntax;
import org.apache.calcite.sql.SqlUtil;
import org.apache.calcite.sql.fun.SqlAbstractGroupFunction;
import org.apache.calcite.sql.util.SqlBasicVisitor;

import org.checkerframework.checker.nullness.qual.Nullable;

import java.util.ArrayList;
import java.util.List;

import static java.util.Objects.requireNonNull;
Expand Down Expand Up @@ -89,12 +89,12 @@ abstract class AggVisitor extends SqlBasicVisitor<Void> {
if (operator instanceof SqlFunction) {
final SqlFunction sqlFunction = (SqlFunction) operator;
if (sqlFunction.getFunctionType().isUserDefinedNotSpecificFunction()) {
final List<SqlOperator> list = new ArrayList<>();
final SqlIdentifier identifier = sqlFunction.getSqlIdentifier();
if (identifier != null) {
opTab.lookupOperatorOverloads(identifier,
sqlFunction.getFunctionType(), SqlSyntax.FUNCTION, list,
nameMatcher);
final List<SqlOperator> list =
SqlUtil.lookupOperatorsByParameterCount(opTab,
sqlFunction.getFunctionType(), SqlSyntax.FUNCTION,
identifier, nameMatcher, call.operandCount());
for (SqlOperator operator2 : list) {
if (operator2.isAggregator() && !operator2.requiresOver()) {
// If nested aggregates disallowed or found aggregate at invalid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1824,10 +1824,11 @@ private void handleOffsetFetch(@Nullable SqlNode offset, @Nullable SqlNode fetch
// a half-hearted resolution now in case it's a
// builtin function requiring special casing. If it's
// not, we'll handle it later during overload resolution.
final List<SqlOperator> overloads = new ArrayList<>();
opTab.lookupOperatorOverloads(function.getNameAsId(),
function.getFunctionType(), SqlSyntax.FUNCTION, overloads,
catalogReader.nameMatcher());
final List<SqlOperator> overloads =
SqlUtil.lookupOperatorsByParameterCount(opTab,
function.getFunctionType(), SqlSyntax.FUNCTION,
function.getNameAsId(), catalogReader.nameMatcher(),
call.operandCount());
if (overloads.size() == 1) {
((SqlBasicCall) call).setOperator(overloads.get(0));
}
Expand Down
33 changes: 30 additions & 3 deletions core/src/test/java/org/apache/calcite/test/SqlValidatorTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -5751,24 +5751,51 @@ private ImmutableList<ImmutableBitSet> cube(ImmutableBitSet... sets) {
.fails("GROUPING_ID operator may only occur in SELECT, HAVING or ORDER BY clause");
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-7685">[CALCITE-7685]
* Filter unresolved function overloads by argument count during early
* resolution</a>.
*/
@Test void testAggregateFunctionWrongNumberOfArguments() {
final String invalidArgCount =
"Invalid number of arguments to function 'MYAGG'. Was expecting 2 arguments";
sql("select myagg(sal, comm) from emp").ok();
sql("select deptno from emp order by ^myagg(sal, comm)^")
.fails("Aggregate expression is illegal in ORDER BY clause of "
+ "non-aggregating SELECT");
// Before CALCITE-7685 the error was "Aggregate expression is illegal in
// ORDER BY clause of non-aggregating SELECT".
sql("select deptno from emp order by ^myagg(deptno)^")
.fails(invalidArgCount);
// Before CALCITE-7685 the error was "Aggregate expression is illegal in
// WHERE clause".
sql("select deptno from emp where ^myagg(deptno)^ = 1")
.fails(invalidArgCount);
sql("select ^myagg(deptno)^ from emp")
.fails(invalidArgCount);
}

@Test void testGroupId() {
final String groupIdOnlyInAggregate =
"GROUP_ID operator may only occur in an aggregate query";
final String groupIdWrongClause =
"GROUP_ID operator may only occur in SELECT, HAVING or ORDER BY clause";
final String groupIdInvalidArgumentNumber =
"Invalid number of arguments to function 'GROUP_ID'. Was expecting 0 arguments";

sql("select deptno, group_id() from emp group by deptno").ok();
sql("select deptno, ^group_id^ as x from emp group by deptno")
.fails("Column 'GROUP_ID' not found in any table");
sql("select deptno, ^group_id(deptno)^ from emp group by deptno")
.fails("Invalid number of arguments to function 'GROUP_ID'\\. "
+ "Was expecting 0 arguments");
.fails(groupIdInvalidArgumentNumber);
// Oracle throws "GROUPING function only supported with GROUP BY CUBE or
// ROLLUP"
sql("select ^group_id()^ from emp")
.fails(groupIdOnlyInAggregate);
sql("select deptno from emp order by ^group_id(deptno)^")
sql("select deptno from emp order by ^group_id()^")
.fails(groupIdOnlyInAggregate);
sql("select deptno from emp order by ^group_id(deptno)^")
.fails(groupIdInvalidArgumentNumber);
// Oracle throws "GROUPING function only supported with GROUP BY CUBE or
// ROLLUP"
sql("select 1 from emp order by ^group_id()^")
Expand Down
Loading