From 57004f15cf760a4e3fbf52def98a1a47c0e83cfa Mon Sep 17 00:00:00 2001 From: Martin Garton Date: Sun, 21 Sep 2025 10:48:31 +0100 Subject: [PATCH 1/2] Rewrite version result to fix column name When `select version()` is run, return a column named `version` instead of `version()` so we are more compatible with postgresql behaviour. This is relied upon by some clients, including pgadmin4. --- datafusion-postgres/src/sql/parser.rs | 3 ++ datafusion-postgres/src/sql/rules.rs | 56 +++++++++++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/datafusion-postgres/src/sql/parser.rs b/datafusion-postgres/src/sql/parser.rs index 9b8d44c..862c830 100644 --- a/datafusion-postgres/src/sql/parser.rs +++ b/datafusion-postgres/src/sql/parser.rs @@ -7,6 +7,8 @@ use datafusion::sql::sqlparser::parser::ParserError; use datafusion::sql::sqlparser::tokenizer::Token; use datafusion::sql::sqlparser::tokenizer::TokenWithSpan; +use crate::sql::rules::FixVersionColumnName; + use super::rules::AliasDuplicatedProjectionRewrite; use super::rules::CurrentUserVariableToSessionUserFunctionCall; use super::rules::FixArrayLiteral; @@ -212,6 +214,7 @@ impl PostgresCompatibilityParser { Arc::new(CurrentUserVariableToSessionUserFunctionCall), Arc::new(FixCollate), Arc::new(RemoveSubqueryFromProjection), + Arc::new(FixVersionColumnName), ], } } diff --git a/datafusion-postgres/src/sql/rules.rs b/datafusion-postgres/src/sql/rules.rs index 837cd00..19b881d 100644 --- a/datafusion-postgres/src/sql/rules.rs +++ b/datafusion-postgres/src/sql/rules.rs @@ -770,6 +770,50 @@ impl SqlStatementRewriteRule for RemoveSubqueryFromProjection { } } +/// `select version()` should return column named `version` not `version()` +#[derive(Debug)] +pub struct FixVersionColumnName; + +struct FixVersionColumnNameVisitor; + +impl VisitorMut for FixVersionColumnNameVisitor { + type Break = (); + + fn pre_visit_query(&mut self, query: &mut Query) -> ControlFlow { + if let SetExpr::Select(select) = query.body.as_mut() { + for projection in &mut select.projection { + if let SelectItem::UnnamedExpr(Expr::Function(f)) = projection { + if f.name.0.len() == 1 { + if let ObjectNamePart::Identifier(part) = &f.name.0[0] { + if part.value == "version" { + if let FunctionArguments::List(args) = &f.args { + if args.args.len() == 0 { + *projection = SelectItem::ExprWithAlias { + expr: Expr::Function(f.clone()), + alias: Ident::new("version"), + } + } + } + } + } + } + } + } + } + + ControlFlow::Continue(()) + } +} + +impl SqlStatementRewriteRule for FixVersionColumnName { + fn rewrite(&self, mut s: Statement) -> Statement { + let mut visitor = FixVersionColumnNameVisitor; + let _ = s.visit(&mut visitor); + + s + } +} + #[cfg(test)] mod tests { use super::*; @@ -1021,4 +1065,16 @@ mod tests { "SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), (SELECT pg_catalog.pg_get_expr(d.adbin, d.adrelid, true) FROM pg_catalog.pg_attrdef d WHERE d.adrelid = a.attrelid AND d.adnum = a.attnum AND a.atthasdef), a.attnotnull, (SELECT c.collname FROM pg_catalog.pg_collation c, pg_catalog.pg_type t WHERE c.oid = a.attcollation AND t.oid = a.atttypid AND a.attcollation <> t.typcollation LIMIT 1) AS attcollation, a.attidentity, a.attgenerated FROM pg_catalog.pg_attribute a WHERE a.attrelid = '16384' AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum;", "SELECT a.attname, pg_catalog.format_type(a.atttypid, a.atttypmod), NULL, a.attnotnull, NULL AS attcollation, a.attidentity, a.attgenerated FROM pg_catalog.pg_attribute AS a WHERE a.attrelid = '16384' AND a.attnum > 0 AND NOT a.attisdropped ORDER BY a.attnum"); } + + #[test] + fn test_version_rewrite() { + let rules: Vec> = vec![Arc::new(FixVersionColumnName)]; + + assert_rewrite!(&rules, "SELECT version()", "SELECT version() AS version"); + + // Make sure we don't rewrite things we should leave alone + assert_rewrite!(&rules, "SELECT version() as foo", "SELECT version() AS foo"); + assert_rewrite!(&rules, "SELECT version(foo)", "SELECT version(foo)"); + assert_rewrite!(&rules, "SELECT foo.version()", "SELECT foo.version()"); + } } From 93103a45b8fcd4ef16f14aaee12c28bc1600b2d3 Mon Sep 17 00:00:00 2001 From: Martin Garton Date: Sun, 21 Sep 2025 11:09:47 +0100 Subject: [PATCH 2/2] Fix clippy warning --- datafusion-postgres/src/sql/rules.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datafusion-postgres/src/sql/rules.rs b/datafusion-postgres/src/sql/rules.rs index 19b881d..18523cf 100644 --- a/datafusion-postgres/src/sql/rules.rs +++ b/datafusion-postgres/src/sql/rules.rs @@ -787,7 +787,7 @@ impl VisitorMut for FixVersionColumnNameVisitor { if let ObjectNamePart::Identifier(part) = &f.name.0[0] { if part.value == "version" { if let FunctionArguments::List(args) = &f.args { - if args.args.len() == 0 { + if args.args.is_empty() { *projection = SelectItem::ExprWithAlias { expr: Expr::Function(f.clone()), alias: Ident::new("version"),