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 @@ -4661,9 +4661,11 @@ private void checkRollUp(@Nullable SqlNode grandParent, @Nullable SqlNode parent
checkRollUp(grandParent, parent, stripDot, scope, contextClause);
} else if (stripDot.getKind() == SqlKind.CONVERT
|| stripDot.getKind() == SqlKind.TRANSLATE
|| stripDot.getKind() == SqlKind.CONVERT_ORACLE) {
|| stripDot.getKind() == SqlKind.CONVERT_ORACLE
|| stripDot.getKind() == SqlKind.ARGUMENT_ASSIGNMENT) {
// only need to check operand[0] for
// CONVERT, TRANSLATE or CONVERT_ORACLE
// 1. CONVERT, TRANSLATE or CONVERT_ORACLE
// 2. for a named argument "value => name"; operand[1] is the parameter name, not a column
SqlNode child = ((SqlCall) stripDot).getOperandList().get(0);
checkRollUp(parent, current, child, scope, contextClause);
} else if (stripDot.getKind() == SqlKind.LAMBDA) {
Expand Down
14 changes: 13 additions & 1 deletion core/src/main/java/org/apache/calcite/sql2rel/AggConverter.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import org.apache.calcite.runtime.PairList;
import org.apache.calcite.sql.SqlAggFunction;
import org.apache.calcite.sql.SqlCall;
import org.apache.calcite.sql.SqlCallBinding;
import org.apache.calcite.sql.SqlDataTypeSpec;
import org.apache.calcite.sql.SqlDynamicParam;
import org.apache.calcite.sql.SqlIdentifier;
Expand Down Expand Up @@ -457,7 +458,18 @@ private void translateAgg(SqlCall call, @Nullable SqlNode filter,
try {
// switch out of agg mode
bb.agg = null;
for (SqlNode operand : call.getOperandList()) {
// Permute named arguments ("name => value") into formal parameter order
// and strip the ARGUMENT_ASSIGNMENT wrappers, so that the parameter name
// identifiers are not converted as column references.
final boolean hasNamedArgument =
call.getOperandList().stream()
.anyMatch(node -> node.getKind() == SqlKind.ARGUMENT_ASSIGNMENT);
final List<SqlNode> aggOperands =
hasNamedArgument
? new SqlCallBinding(bb.getValidator(), bb.scope, call)
.permutedCall().getOperandList()
: call.getOperandList();
for (SqlNode operand : aggOperands) {

// special case for COUNT(*): delete the *
if (operand instanceof SqlIdentifier) {
Expand Down
63 changes: 63 additions & 0 deletions core/src/test/java/org/apache/calcite/test/UdfTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,26 @@ private CalciteAssert.AssertThat withUdf() {
.returns("EXPR$0=0\n");
}

/** Test case for
* <a href="https://issues.apache.org/jira/browse/CALCITE-7686">[CALCITE-7686]
* Named argument should not be resolved as a column</a>.
*
* <p>The parameter name of a {@code name => value} argument must not be
* resolved as a column reference by the roll-up check. */
@Test void testUdfArgumentNameInSelectFromTable() {
final CalciteAssert.AssertThat with = withUdf();
// Named-arg call as a SELECT item over a table scope (unlike VALUES, this
// routes through checkRollUpInSelectList). The parameter names "s" and "n"
// must not be resolved as columns of the FROM source.
with.query("select \"adhoc\".my_left(\"s\" => 'hello', \"n\" => 3) as c\n"
+ "from \"adhoc\".\"EMPLOYEES\"")
.returnsCount(4);
// reverse order
with.query("select \"adhoc\".my_left(\"n\" => 3, \"s\" => 'hello') as c\n"
+ "from \"adhoc\".\"EMPLOYEES\"")
.returnsCount(4);
}

/** Tests calling a user-defined function some of whose parameters are
* optional. */
@Test void testUdfArgumentOptional() {
Expand Down Expand Up @@ -740,6 +760,49 @@ private CalciteAssert.AssertThat withUdf() {
.returns("P=560\n");
}

/**
* Test case for <a href="https://issues.apache.org/jira/browse/CALCITE-7686">[CALCITE-7686]
* Named argument should not be resolved as a column</a>.
*
* <p>Tests calling a user-defined aggregate function by named arguments over a
* table scope. The parameter names must not be resolved as columns during
* sql-to-rel conversion. */
@Test void testUserDefinedAggregateFunctionWithNamedArguments() {
final String empDept = JdbcTest.EmpDeptTableFactory.class.getName();
final String namedSum = Smalls.MyNamedSumFunction.class.getName();
final CalciteAssert.AssertThat with = CalciteAssert.model("{\n"
+ " version: '1.0',\n"
+ " schemas: [\n"
+ " {\n"
+ " name: 'adhoc',\n"
+ " tables: [\n"
+ " {\n"
+ " name: 'EMPLOYEES',\n"
+ " type: 'custom',\n"
+ " factory: '" + empDept + "',\n"
+ " operand: {'foo': true, 'bar': 345}\n"
+ " }\n"
+ " ],\n"
+ " functions: [\n"
+ " {\n"
+ " name: 'MY_NAMED_SUM',\n"
+ " className: '" + namedSum + "'\n"
+ " }\n"
+ " ]\n"
+ " }\n"
+ " ]\n"
+ "}")
.withDefaultSchema("adhoc");
// named arguments in physical order
with.query("select \"adhoc\".my_named_sum(\"v1\" => \"commission\", \"v2\" => 250) as p\n"
+ "from \"adhoc\".EMPLOYEES\n")
.returns("P=1500\n");
// named arguments in reverse order
with.query("select \"adhoc\".my_named_sum(\"v2\" => 250, \"v1\" => \"commission\") as p\n"
+ "from \"adhoc\".EMPLOYEES\n")
.returns("P=1500\n");
}

/** Test for
* {@link org.apache.calcite.runtime.CalciteResource#firstParameterOfAdd(String)}. */
@Test void testUserDefinedAggregateFunction3() {
Expand Down
25 changes: 25 additions & 0 deletions testkit/src/main/java/org/apache/calcite/util/Smalls.java
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,31 @@
}
}

/** Example of a UDAF with two named parameters (via {@code @Parameter}),
* so it can be called using named-argument notation. It sums {@code v1}
* for rows where {@code v1 > v2}. */
public static class MyNamedSumFunction {
public MyNamedSumFunction() {

Check failure on line 916 in testkit/src/main/java/org/apache/calcite/util/Smalls.java

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Add a nested comment explaining why this method is empty, throw an UnsupportedOperationException or complete the implementation.

See more on https://sonarcloud.io/project/issues?id=apache_calcite&issues=AZ_EcVmZ1vMCp7SkJkby&open=AZ_EcVmZ1vMCp7SkJkby&pullRequest=5143
}
public int init() {
return 0;
}
public int add(int accumulator,
@Parameter(name = "v1") int v1,
@Parameter(name = "v2") int v2) {
if (v1 > v2) {
return accumulator + v1;
}
return accumulator;
}
public int merge(int accumulator0, int accumulator1) {
return accumulator0 + accumulator1;
}
public int result(int accumulator) {
return accumulator;
}
}

/** Example of a user-defined aggregate function (UDAF) with two parameters.
* The constructor has an initialization parameter. */
public static class MyTwoParamsSumFunctionFilter1 {
Expand Down
Loading