From 764940eff84973445f4e270ea64c5ecadf8c82a1 Mon Sep 17 00:00:00 2001 From: discord9 <55937128+discord9@users.noreply.github.com> Date: Fri, 9 Oct 2026 17:45:27 +0800 Subject: [PATCH] fix: preserve effective query option SHOW across SQL protocols Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com> --- src/servers/src/mysql/federated.rs | 40 ++++++++++++++++- src/servers/src/postgres/handler.rs | 67 ++++++++++++++++++++++++++++- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/servers/src/mysql/federated.rs b/src/servers/src/mysql/federated.rs index e6c4890df93..520101fb146 100644 --- a/src/servers/src/mysql/federated.rs +++ b/src/servers/src/mysql/federated.rs @@ -44,7 +44,7 @@ static SHOW_LOWER_CASE_PATTERN: Lazy = Lazy::new(|| { }); static SHOW_VARIABLES_LIKE_PATTERN: Lazy = Lazy::new(|| { Regex::new(&format!( - "(?i)^(SHOW {VARIABLES_SCOPE}VARIABLES( LIKE (.*))?)" + "(?i)^\\s*SHOW {VARIABLES_SCOPE}VARIABLES( LIKE (.*))?\\s*;?\\s*$" )) .unwrap() }); @@ -644,6 +644,44 @@ mod test { test(query, expected); } + #[test] + fn test_show_named_variables_reach_query_handler() { + let session = Arc::new(Session::new(None, Channel::Mysql, Default::default(), 0)); + + for query in [ + "SHOW VARIABLES query.parallelism", + "SHOW VARIABLES datafusion.optimizer.prefer_hash_join", + "SHOW VARIABLES query.allow_query_fallback", + "SHOW VARIABLES query.enable_remote_dynamic_filter_pushdown", + "SHOW GLOBAL VARIABLES datafusion.optimizer.prefer_hash_join", + "SHOW SESSION VARIABLES query.parallelism", + "SHOW LOCAL VARIABLES query.allow_query_fallback", + " SHOW VARIABLES query.parallelism ", + "SHOW VARIABLES query.parallelism;", + ] { + assert!( + check(query, QueryContext::arc(), session.clone()).is_none(), + "{query} should reach the query handler" + ); + } + + for query in [ + "SHOW VARIABLES", + "SHOW VARIABLES;", + "SHOW GLOBAL VARIABLES", + "SHOW SESSION VARIABLES", + "SHOW LOCAL VARIABLES", + "SHOW GLOBAL VARIABLES LIKE 'event_scheduler'", + "SHOW SESSION VARIABLES LIKE 'event_scheduler'", + "SHOW LOCAL VARIABLES LIKE 'event_scheduler'", + ] { + assert!( + check(query, QueryContext::arc(), session.clone()).is_some(), + "{query} should retain federated compatibility handling" + ); + } + } + #[test] fn test_show_warnings() { // Test SHOW WARNINGS with no warnings diff --git a/src/servers/src/postgres/handler.rs b/src/servers/src/postgres/handler.rs index 204fa7745a5..06f254da055 100644 --- a/src/servers/src/postgres/handler.rs +++ b/src/servers/src/postgres/handler.rs @@ -84,7 +84,7 @@ impl SimpleQueryHandler for PostgresServerHandlerInner { let query = if let Ok(statements) = &parsed_query { statements .iter() - .map(|s| s.to_string()) + .map(statement_to_query) .collect::>() .join(";") } else { @@ -119,6 +119,24 @@ impl SimpleQueryHandler for PostgresServerHandlerInner { } } +fn statement_to_query(statement: &SqlParserStatement) -> String { + if let SqlParserStatement::ShowVariable { variable } = statement + && variable.len() > 1 + && (variable[0].value.eq_ignore_ascii_case("query") + || variable[0].value.eq_ignore_ascii_case("datafusion")) + { + return format!( + "SHOW {}", + variable + .iter() + .map(ToString::to_string) + .collect::>() + .join(".") + ); + } + statement.to_string() +} + async fn send_warning_opt(client: &mut C, query_context: QueryContextRef) -> PgWireResult<()> where C: Sink + Unpin + Send + Sync, @@ -772,6 +790,53 @@ mod tests { use super::*; + #[test] + fn test_dotted_show_query_options() { + for (sql, expected) in [ + ("SHOW QUERY.PARALLELISM", "SHOW QUERY.PARALLELISM"), + ( + "SHOW query.allow_query_fallback", + "SHOW query.allow_query_fallback", + ), + ( + "SHOW datafusion.optimizer.enable_dynamic_filter_pushdown", + "SHOW datafusion.optimizer.enable_dynamic_filter_pushdown", + ), + ( + "SET query.parallelism = 2; SHOW query.parallelism", + "SET query.parallelism = 2;SHOW query.parallelism", + ), + ( + "/* comment */ SHOW query.parallelism", + "SHOW query.parallelism", + ), + ( + "SHOW \"query\".\"allow_query_fallback\"", + "SHOW \"query\".\"allow_query_fallback\"", + ), + ] { + let actual = PostgresCompatibilityParser::new() + .parse(sql) + .unwrap() + .iter() + .map(statement_to_query) + .collect::>() + .join(";"); + assert_eq!(actual, expected, "for SQL: {sql}"); + } + } + + #[test] + fn test_other_postgres_show_serialization_is_unchanged() { + for sql in ["SHOW ordinary_variable", "SHOW search_path"] { + let statement = PostgresCompatibilityParser::new() + .parse(sql) + .unwrap() + .remove(0); + assert_eq!(statement_to_query(&statement), statement.to_string()); + } + } + fn parse_copy_statement(sql: &str) -> SqlParserStatement { let parser = PostgresCompatibilityParser::new(); let statements = parser.parse(sql).unwrap();