From f05ec59424321cab1a1af7921758293a18c99c7d Mon Sep 17 00:00:00 2001 From: osipovartem Date: Wed, 2 Sep 2026 01:09:32 +0300 Subject: [PATCH 1/2] Plan qualified wildcard function options --- Cargo.lock | 26 ++++++------ Cargo.toml | 2 +- datafusion/sql/src/expr/function.rs | 53 ++++++++++++++++++------- datafusion/sql/tests/sql_integration.rs | 22 ++++++++++ 4 files changed, 73 insertions(+), 30 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 62c04d332b98e..943fd94e80a35 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -112,7 +112,7 @@ version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -123,7 +123,7 @@ checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -2801,7 +2801,7 @@ dependencies = [ "libc", "option-ext", "redox_users", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -2940,7 +2940,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -4212,7 +4212,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -5373,7 +5373,7 @@ dependencies = [ "errno", "libc", "linux-raw-sys", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -5845,7 +5845,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -5876,8 +5876,7 @@ dependencies = [ [[package]] name = "sqlparser" version = "0.62.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13c6d1b651dc4edf07eead2a0c6c78016ce971bc2c10da5266861b13f25e7cec" +source = "git+https://github.com/Embucket/datafusion-sqlparser-rs.git?rev=1a3f48f60802d0f135a968a27c89a3351e78b159#1a3f48f60802d0f135a968a27c89a3351e78b159" dependencies = [ "log", "recursive", @@ -5887,8 +5886,7 @@ dependencies = [ [[package]] name = "sqlparser_derive" version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6dd45d8fc1c79299bfbb7190e42ccbbdf6a5f52e4a6ad98d92357ea965bd289" +source = "git+https://github.com/Embucket/datafusion-sqlparser-rs.git?rev=1a3f48f60802d0f135a968a27c89a3351e78b159#1a3f48f60802d0f135a968a27c89a3351e78b159" dependencies = [ "proc-macro2", "quote", @@ -5945,7 +5943,7 @@ dependencies = [ "cfg-if", "libc", "psm", - "windows-sys 0.61.2", + "windows-sys 0.60.2", ] [[package]] @@ -6125,7 +6123,7 @@ dependencies = [ "getrandom 0.4.2", "once_cell", "rustix", - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] @@ -7066,7 +7064,7 @@ version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.61.2", + "windows-sys 0.52.0", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 4526fa0c58934..13e26dafdc4ee 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -196,7 +196,7 @@ regex = "1.12" rstest = "0.26.1" serde_json = "1" sha2 = "^0.11.0" -sqlparser = { version = "0.62.0", default-features = false, features = ["std", "visitor"] } +sqlparser = { git = "https://github.com/Embucket/datafusion-sqlparser-rs.git", rev = "1a3f48f60802d0f135a968a27c89a3351e78b159", default-features = false, features = ["std", "visitor"] } stacker = "0.1.24" strum = "0.28.0" strum_macros = "0.28.0" diff --git a/datafusion/sql/src/expr/function.rs b/datafusion/sql/src/expr/function.rs index 0b340ff9001dc..7b1b88424594e 100644 --- a/datafusion/sql/src/expr/function.rs +++ b/datafusion/sql/src/expr/function.rs @@ -36,9 +36,29 @@ use datafusion_expr::{ use sqlparser::ast::{ DuplicateTreatment, Expr as SQLExpr, Function as SQLFunction, FunctionArg, FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList, FunctionArguments, - LambdaFunction, ObjectName, OrderByExpr, Spanned, WindowType, + LambdaFunction, ObjectName, OrderByExpr, Spanned, WildcardAdditionalOptions, + WindowType, }; +fn function_wildcard_options( + options: WildcardAdditionalOptions, +) -> Result> { + if options.opt_alias.is_some() { + return not_impl_err!("wildcard function argument with AS alias"); + } + if options.opt_replace.is_some() { + return not_impl_err!("wildcard function argument with REPLACE"); + } + + Ok(Box::new(WildcardOptions { + ilike: options.opt_ilike, + exclude: options.opt_exclude, + except: options.opt_except, + replace: None, + rename: options.opt_rename, + })) +} + /// Suggest a valid function based on an invalid input function name /// /// Returns `None` if no valid matches are found. This happens when there are no @@ -1076,23 +1096,10 @@ impl SqlToRel<'_, S> { Ok((expr, None)) } FunctionArg::Unnamed(FunctionArgExpr::WildcardWithOptions(options)) => { - if options.opt_alias.is_some() { - return not_impl_err!("wildcard function argument with AS alias"); - } - if options.opt_replace.is_some() { - return not_impl_err!("wildcard function argument with REPLACE"); - } - #[expect(deprecated)] let expr = Expr::Wildcard { qualifier: None, - options: Box::new(WildcardOptions { - ilike: options.opt_ilike, - exclude: options.opt_exclude, - except: options.opt_except, - replace: None, - rename: options.opt_rename, - }), + options: function_wildcard_options(options)?, }; Ok((expr, None)) } @@ -1111,6 +1118,22 @@ impl SqlToRel<'_, S> { }; Ok((expr, None)) } + FunctionArg::Unnamed(FunctionArgExpr::QualifiedWildcardWithOptions( + object_name, + options, + )) => { + let qualifier = self.object_name_to_table_reference(object_name)?; + if schema.fields_indices_with_qualified(&qualifier).is_empty() { + return plan_err!("Invalid qualifier {qualifier}"); + } + + #[expect(deprecated)] + let expr = Expr::Wildcard { + qualifier: qualifier.into(), + options: function_wildcard_options(options)?, + }; + Ok((expr, None)) + } // PostgreSQL dialect uses ExprNamed variant with expression for name FunctionArg::ExprNamed { name: SQLExpr::Identifier(name), diff --git a/datafusion/sql/tests/sql_integration.rs b/datafusion/sql/tests/sql_integration.rs index 71e7ee7ad9bdf..7855e755e1a7d 100644 --- a/datafusion/sql/tests/sql_integration.rs +++ b/datafusion/sql/tests/sql_integration.rs @@ -61,6 +61,7 @@ use insta::{allow_duplicates, assert_snapshot}; use rstest::rstest; use sqlparser::dialect::{ DatabricksDialect, Dialect, GenericDialect, HiveDialect, MySqlDialect, + SnowflakeDialect, }; use sqlparser::parser::Parser; @@ -2244,6 +2245,27 @@ fn scalar_expr_planner_applies_wildcard_ilike() { ); } +#[test] +fn scalar_expr_planner_applies_qualified_wildcard_options() { + let state = mock_session_state().with_expr_planner(Arc::new(ScalarWildcardPlanner)); + let plan = logical_plan_from_state( + "SELECT concat((p.* ILIKE '%name')) FROM person AS p", + &SnowflakeDialect {}, + ParserOptions::default(), + state, + ) + .unwrap(); + + assert_snapshot!( + plan, + @r" + Projection: concat(p.first_name, p.last_name) + SubqueryAlias: p + TableScan: person + " + ); +} + #[test] fn select_approx_median() { let sql = "SELECT approx_median(age) FROM person"; From 57636801afb3da72e698b3b0bdeea090f12f334d Mon Sep 17 00:00:00 2001 From: osipovartem Date: Wed, 2 Sep 2026 02:22:46 +0300 Subject: [PATCH 2/2] Format SQLParser workspace dependency --- Cargo.toml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 13e26dafdc4ee..39735db249480 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -196,7 +196,10 @@ regex = "1.12" rstest = "0.26.1" serde_json = "1" sha2 = "^0.11.0" -sqlparser = { git = "https://github.com/Embucket/datafusion-sqlparser-rs.git", rev = "1a3f48f60802d0f135a968a27c89a3351e78b159", default-features = false, features = ["std", "visitor"] } +sqlparser = { git = "https://github.com/Embucket/datafusion-sqlparser-rs.git", rev = "1a3f48f60802d0f135a968a27c89a3351e78b159", default-features = false, features = [ + "std", + "visitor", +] } stacker = "0.1.24" strum = "0.28.0" strum_macros = "0.28.0"