quwin opened a new pull request, #25039:
URL: https://github.com/apache/datafusion/pull/25039

   ## Which issue does this PR close?
   
   - Closes #25038
   
   ## Rationale for this change
   
   A `CREATE FUNCTION` with a SQL body is accepted even when its `RETURN` 
expression references a positional placeholder that does not match a declared 
argument:
   
   ```sql
   CREATE FUNCTION better_add(DOUBLE, DOUBLE)
       RETURNS DOUBLE
       RETURN $1 + $3   -- only two arguments are declared
   ```
   
   The invalid definition is registered successfully, and the error only 
surfaces when the function is invoked:
   
   ```
   Optimizer rule 'simplify_expressions' failed
   caused by
   Execution error: Invalid placeholder, out of range: $3
   ```
   
   A definition error like this should be reported at `CREATE FUNCTION` time, 
not deferred to every invocation. This is acknowledged in code by two FIXMEs 
(see #25038):
   
   - `datafusion/sql/src/expr/value.rs` — "In the CREATE FUNCTION branch, 
param_type = None should raise an error"
   - `datafusion/core/tests/user_defined/user_defined_scalar_functions.rs` — 
"Definitions with invalid placeholders are allowed, fail at runtime"
   
   ## What changes are included in this PR?
   
   - Validate placeholders at planning time in the `Statement::CreateFunction` 
arm of the SQL planner (`datafusion/sql/src/statement.rs`): after the `RETURN` 
body is planned, walk it for `Expr::Placeholder` nodes and reject any 
positional `$N` outside `1..=declared_arg_count` with `Invalid placeholder, out 
of range: $N`, and any named placeholder (which can only survive parsing when 
zero arguments were declared) with `Unknown placeholder: $N`.
   - The check uses the **declared** argument count, so functions with 
defaulted arguments remain callable with fewer arguments than declared.
   - Doing this in the planner (rather than in `value.rs` or in the factories) 
means it applies to every `FunctionFactory` implementation, and it cannot 
change `PREPARE` semantics, where an empty/unknown parameter list must stay 
permissive for deferred type inference. Runtime guards in the factories remain 
as a defensive backstop.
   - Replaced the now-superseded FIXME comment in 
`datafusion/sql/src/expr/value.rs`.
   
   ## What is the testing strategy for this PR?
   
   - Flipped the FIXME regression test in 
`create_scalar_function_from_sql_statement()`: the invalid `CREATE FUNCTION` 
must now fail with `Error during planning: Invalid placeholder, out of range: 
$3`.
   - Added `create_scalar_function_from_sql_statement_invalid_placeholders()` 
covering: out-of-range positional with positional declared args; out-of-range 
positional with named declared args (`RETURN $a + $3`); a zero-argument 
function referencing `$1`; a zero-argument function referencing a named `$a`; 
and a positive case (`RETURN $1 + $2`) that must still be accepted.
   - Verified: pre-fix the new tests fail (CREATE succeeded), post-fix all 
pass. `cargo test -p datafusion --test user_defined_integration`, `cargo test 
-p datafusion-sql`, `cargo fmt --check`, and clippy (`-D warnings`) on the 
touched crates are all green. (Three `user_defined_integration` tests fail on 
this machine only due to uninitialized `testing`/`parquet-testing` git 
submodules — unrelated, pre-existing.)
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to