This is an automated email from the ASF dual-hosted git repository.
gustavodemorais pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/flink.git
The following commit(s) were added to refs/heads/master by this push:
new d6b7fad86b5 [FLINK-39915][table] Reject mixing positional and named
function arguments
d6b7fad86b5 is described below
commit d6b7fad86b50d88843898adfc3dfc6c0bb52c291
Author: Gustavo de Morais <[email protected]>
AuthorDate: Sat Jun 13 13:48:12 2026 +0200
[FLINK-39915][table] Reject mixing positional and named function arguments
This closes #28399.
---
.../planner/calcite/FlinkCalciteSqlValidator.java | 22 +++++++++++++++
.../calcite/FlinkCalciteSqlValidatorTest.java | 32 ++++++++++++++++++++++
.../plan/stream/sql/ProcessTableFunctionTest.java | 5 ++++
3 files changed, 59 insertions(+)
diff --git
a/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/calcite/FlinkCalciteSqlValidator.java
b/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/calcite/FlinkCalciteSqlValidator.java
index 77a1634fa0b..6d8ad8d2591 100644
---
a/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/calcite/FlinkCalciteSqlValidator.java
+++
b/flink-table/flink-table-planner/src/main/java/org/apache/flink/table/planner/calcite/FlinkCalciteSqlValidator.java
@@ -380,6 +380,7 @@ public final class FlinkCalciteSqlValidator extends
FlinkSqlParsingValidator {
}
final SqlBasicCall call = (SqlBasicCall) node;
+ checkNoNamedAndPositionalMixedArgs(call);
// Special case for MODEL
if (node instanceof SqlExplicitModelCall) {
@@ -432,6 +433,27 @@ public final class FlinkCalciteSqlValidator extends
FlinkSqlParsingValidator {
return rewritten;
}
+ /** Mixing positional and named arguments is not supported and crashes
operand permutation. */
+ private static void checkNoNamedAndPositionalMixedArgs(SqlBasicCall call) {
+ if (!(call.getOperator() instanceof SqlFunction)) {
+ return;
+ }
+ final List<SqlNode> operands = call.getOperandList();
+ final boolean anyNamed =
+ operands.stream()
+ .anyMatch(op -> op != null && op.getKind() ==
SqlKind.ARGUMENT_ASSIGNMENT);
+ final boolean anyPositional =
+ operands.stream()
+ .anyMatch(op -> op != null && op.getKind() !=
SqlKind.ARGUMENT_ASSIGNMENT);
+ if (anyNamed && anyPositional) {
+ throw new ValidationException(
+ "Cannot mix positional and named arguments when calling
function '"
+ + call.getOperator().getName()
+ + "'. Use either all positional arguments or all
named arguments "
+ + "(e.g. arg => value).");
+ }
+ }
+
@Override
public SqlNode maybeCast(SqlNode node, RelDataType currentType,
RelDataType desiredType) {
return super.maybeCast(node, currentType, desiredType);
diff --git
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/calcite/FlinkCalciteSqlValidatorTest.java
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/calcite/FlinkCalciteSqlValidatorTest.java
index 7da22c97d5e..831b3b6ecc4 100644
---
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/calcite/FlinkCalciteSqlValidatorTest.java
+++
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/calcite/FlinkCalciteSqlValidatorTest.java
@@ -18,9 +18,13 @@
package org.apache.flink.table.planner.calcite;
+import org.apache.flink.table.annotation.ArgumentHint;
+import org.apache.flink.table.annotation.DataTypeHint;
+import org.apache.flink.table.annotation.FunctionHint;
import org.apache.flink.table.api.DataTypes;
import org.apache.flink.table.api.Schema;
import org.apache.flink.table.api.ValidationException;
+import org.apache.flink.table.functions.ScalarFunction;
import org.apache.flink.table.planner.utils.PlannerMocks;
import org.junit.jupiter.api.Test;
@@ -138,4 +142,32 @@ class FlinkCalciteSqlValidatorTest {
.hasMessageContaining(
"UPSERT INTO statement is not supported. Please use
INSERT INTO instead.");
}
+
+ @Test
+ void testMixedPositionalAndNamedArguments() {
+ plannerMocks
+ .getFunctionCatalog()
+ .registerTemporarySystemFunction("myFunc", new
NamedArgsScalarFunction(), false);
+
+ assertDoesNotThrow(() -> plannerMocks.getParser().parse("SELECT
myFunc(1, 2) FROM t1"));
+ assertDoesNotThrow(
+ () -> plannerMocks.getParser().parse("SELECT myFunc(in1 => 1,
in2 => 2) FROM t1"));
+ assertThatThrownBy(
+ () -> plannerMocks.getParser().parse("SELECT myFunc(1,
in2 => 2) FROM t1"))
+ .isInstanceOf(ValidationException.class)
+ .hasMessageContaining("Cannot mix positional and named
arguments");
+ }
+
+ /** Scalar function with named arguments for the mixed-argument validation
test. */
+ public static class NamedArgsScalarFunction extends ScalarFunction {
+ @FunctionHint(
+ output = @DataTypeHint("INT"),
+ arguments = {
+ @ArgumentHint(name = "in1", type = @DataTypeHint("INT")),
+ @ArgumentHint(name = "in2", type = @DataTypeHint("INT"))
+ })
+ public Integer eval(Integer in1, Integer in2) {
+ return null;
+ }
+ }
}
diff --git
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/stream/sql/ProcessTableFunctionTest.java
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/stream/sql/ProcessTableFunctionTest.java
index 411b6fc2b75..d0d150759ae 100644
---
a/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/stream/sql/ProcessTableFunctionTest.java
+++
b/flink-table/flink-table-planner/src/test/java/org/apache/flink/table/planner/plan/stream/sql/ProcessTableFunctionTest.java
@@ -349,6 +349,11 @@ class ProcessTableFunctionTest extends TableTestBase {
private static Stream<ErrorSpec> errorSpecs() {
return Stream.of(
+ ErrorSpec.ofSelect(
+ "mixed positional and named arguments",
+ ScalarArgsFunction.class,
+ "SELECT * FROM f(1, b => true)",
+ "Cannot mix positional and named arguments when
calling function 'f'"),
ErrorSpec.ofSelect(
"invalid uid",
ScalarArgsFunction.class,