From b19e42f83e83262ddaadd76dca935212b0d5f436 Mon Sep 17 00:00:00 2001 From: nuno-faria Date: Thu, 11 Jun 2026 19:55:55 +0100 Subject: [PATCH 1/4] fix: Consider column names' case when aliasing tables --- datafusion/common/src/column.rs | 6 +-- datafusion/sqllogictest/test_files/alias.slt | 47 ++++++++++++++++++++ 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/datafusion/common/src/column.rs b/datafusion/common/src/column.rs index 0332fa3f59f34..8ef7bef15e8c7 100644 --- a/datafusion/common/src/column.rs +++ b/datafusion/common/src/column.rs @@ -329,21 +329,21 @@ impl Column { impl From<&str> for Column { fn from(c: &str) -> Self { - Self::from_qualified_name(c) + Self::from_qualified_name_ignore_case(c) } } /// Create a column, cloning the string impl From<&String> for Column { fn from(c: &String) -> Self { - Self::from_qualified_name(c) + Self::from_qualified_name_ignore_case(c) } } /// Create a column, reusing the existing string impl From for Column { fn from(c: String) -> Self { - Self::from_qualified_name(c) + Self::from_qualified_name_ignore_case(c) } } diff --git a/datafusion/sqllogictest/test_files/alias.slt b/datafusion/sqllogictest/test_files/alias.slt index 5339179db4c43..d761743e6793f 100644 --- a/datafusion/sqllogictest/test_files/alias.slt +++ b/datafusion/sqllogictest/test_files/alias.slt @@ -57,3 +57,50 @@ drop table t1; statement count 0 drop table t2; + + +# Test table-aliasing a subquery with a case sensitive column +# (https://github.com/apache/datafusion/issues/22916) + +statement ok +create table t ("A" int); + +query I +select * from (select * from t) t_(x); +---- + +query TT +explain select * from (select * from t) t_(x); +---- +logical_plan +01)SubqueryAlias: t_ +02)--Projection: t.A AS x +03)----TableScan: t projection=[A] +physical_plan +01)ProjectionExec: expr=[A@0 as x] +02)--DataSourceExec: partitions=1, partition_sizes=[0] + +query TT +explain select * from (select * from t) t_(X); +---- +logical_plan +01)SubqueryAlias: t_ +02)--Projection: t.A AS x +03)----TableScan: t projection=[A] +physical_plan +01)ProjectionExec: expr=[A@0 as x] +02)--DataSourceExec: partitions=1, partition_sizes=[0] + +query TT +explain select * from (select * from t) t_("X"); +---- +logical_plan +01)SubqueryAlias: t_ +02)--Projection: t.A AS X +03)----TableScan: t projection=[A] +physical_plan +01)ProjectionExec: expr=[A@0 as X] +02)--DataSourceExec: partitions=1, partition_sizes=[0] + +statement ok +drop table t; From edf4ef8858fa2cf7fc1d7d17c6596c352ba71184 Mon Sep 17 00:00:00 2001 From: nuno-faria Date: Thu, 11 Jun 2026 20:52:39 +0100 Subject: [PATCH 2/4] Use from_qualified_name_ignore_case directly in apply_expr_alias --- datafusion/common/src/column.rs | 6 +++--- datafusion/sql/src/planner.rs | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/datafusion/common/src/column.rs b/datafusion/common/src/column.rs index 8ef7bef15e8c7..0332fa3f59f34 100644 --- a/datafusion/common/src/column.rs +++ b/datafusion/common/src/column.rs @@ -329,21 +329,21 @@ impl Column { impl From<&str> for Column { fn from(c: &str) -> Self { - Self::from_qualified_name_ignore_case(c) + Self::from_qualified_name(c) } } /// Create a column, cloning the string impl From<&String> for Column { fn from(c: &String) -> Self { - Self::from_qualified_name_ignore_case(c) + Self::from_qualified_name(c) } } /// Create a column, reusing the existing string impl From for Column { fn from(c: String) -> Self { - Self::from_qualified_name_ignore_case(c) + Self::from_qualified_name(c) } } diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs index 01215ae3434cf..f3722e989f87b 100644 --- a/datafusion/sql/src/planner.rs +++ b/datafusion/sql/src/planner.rs @@ -23,19 +23,19 @@ use std::vec; use crate::utils::make_decimal_type; use arrow::datatypes::*; -use datafusion_common::TableReference; use datafusion_common::config::SqlParserOptions; use datafusion_common::datatype::{DataTypeExt, FieldExt}; use datafusion_common::error::add_possible_columns_to_diag; +use datafusion_common::{Column, TableReference}; use datafusion_common::{DFSchema, DataFusionError, Result, not_impl_err, plan_err}; use datafusion_common::{ DFSchemaRef, Diagnostic, SchemaError, field_not_found, internal_err, plan_datafusion_err, }; +use datafusion_expr::Expr; use datafusion_expr::logical_plan::{LogicalPlan, LogicalPlanBuilder}; pub use datafusion_expr::planner::ContextProvider; use datafusion_expr::utils::find_column_exprs; -use datafusion_expr::{Expr, col}; use sqlparser::ast::{ArrayElemTypeDef, ExactNumberInfo, TimezoneInfo}; use sqlparser::ast::{ColumnDef as SQLColumnDef, ColumnOption}; use sqlparser::ast::{DataType as SQLDataType, Ident, ObjectName, TableAlias}; @@ -575,7 +575,8 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { let fields = plan.schema().fields().clone(); LogicalPlanBuilder::from(plan) .project(fields.iter().zip(idents).map(|(field, ident)| { - col(field.name()).alias(self.ident_normalizer.normalize(ident)) + Expr::Column(Column::from_qualified_name_ignore_case(field.name())) + .alias(self.ident_normalizer.normalize(ident)) }))? .build() } From 02eebf469b58c9b4408f929df29992ec86f8a418 Mon Sep 17 00:00:00 2001 From: nuno-faria Date: Thu, 18 Jun 2026 20:24:51 +0100 Subject: [PATCH 3/4] Alias the existing columns instead --- datafusion/sql/src/planner.rs | 7 ++--- datafusion/sqllogictest/test_files/alias.slt | 32 ++++++++++---------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs index f3722e989f87b..ade939ef37517 100644 --- a/datafusion/sql/src/planner.rs +++ b/datafusion/sql/src/planner.rs @@ -572,11 +572,10 @@ impl<'a, S: ContextProvider> SqlToRel<'a, S> { idents.len() ) } else { - let fields = plan.schema().fields().clone(); + let columns = plan.schema().columns().clone(); LogicalPlanBuilder::from(plan) - .project(fields.iter().zip(idents).map(|(field, ident)| { - Expr::Column(Column::from_qualified_name_ignore_case(field.name())) - .alias(self.ident_normalizer.normalize(ident)) + .project(columns.into_iter().zip(idents).map(|(col, ident)| { + Expr::Column(col).alias(self.ident_normalizer.normalize(ident)) }))? .build() } diff --git a/datafusion/sqllogictest/test_files/alias.slt b/datafusion/sqllogictest/test_files/alias.slt index d761743e6793f..ae993c6e79b4c 100644 --- a/datafusion/sqllogictest/test_files/alias.slt +++ b/datafusion/sqllogictest/test_files/alias.slt @@ -59,47 +59,47 @@ statement count 0 drop table t2; -# Test table-aliasing a subquery with a case sensitive column +# Test table-aliasing a subquery with case sensitive columns # (https://github.com/apache/datafusion/issues/22916) statement ok -create table t ("A" int); +create table t ("A" int, "B.C" int); -query I -select * from (select * from t) t_(x); +query II +select * from (select * from t) t_(x, y); ---- query TT -explain select * from (select * from t) t_(x); +explain select * from (select * from t) t_(x, y); ---- logical_plan 01)SubqueryAlias: t_ -02)--Projection: t.A AS x -03)----TableScan: t projection=[A] +02)--Projection: t.A AS x, t.B.C AS y +03)----TableScan: t projection=[A, B.C] physical_plan -01)ProjectionExec: expr=[A@0 as x] +01)ProjectionExec: expr=[A@0 as x, B.C@1 as y] 02)--DataSourceExec: partitions=1, partition_sizes=[0] query TT -explain select * from (select * from t) t_(X); +explain select * from (select * from t) t_(X, Y); ---- logical_plan 01)SubqueryAlias: t_ -02)--Projection: t.A AS x -03)----TableScan: t projection=[A] +02)--Projection: t.A AS x, t.B.C AS y +03)----TableScan: t projection=[A, B.C] physical_plan -01)ProjectionExec: expr=[A@0 as x] +01)ProjectionExec: expr=[A@0 as x, B.C@1 as y] 02)--DataSourceExec: partitions=1, partition_sizes=[0] query TT -explain select * from (select * from t) t_("X"); +explain select * from (select * from t) t_("X", "Y"); ---- logical_plan 01)SubqueryAlias: t_ -02)--Projection: t.A AS X -03)----TableScan: t projection=[A] +02)--Projection: t.A AS X, t.B.C AS Y +03)----TableScan: t projection=[A, B.C] physical_plan -01)ProjectionExec: expr=[A@0 as X] +01)ProjectionExec: expr=[A@0 as X, B.C@1 as Y] 02)--DataSourceExec: partitions=1, partition_sizes=[0] statement ok From 4934e8a1607bd1661e42860259671249b8430bc5 Mon Sep 17 00:00:00 2001 From: nuno-faria Date: Thu, 18 Jun 2026 21:27:28 +0100 Subject: [PATCH 4/4] Fix fmt --- datafusion/sql/src/planner.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/datafusion/sql/src/planner.rs b/datafusion/sql/src/planner.rs index ade939ef37517..a61444a8267ce 100644 --- a/datafusion/sql/src/planner.rs +++ b/datafusion/sql/src/planner.rs @@ -23,10 +23,10 @@ use std::vec; use crate::utils::make_decimal_type; use arrow::datatypes::*; +use datafusion_common::TableReference; use datafusion_common::config::SqlParserOptions; use datafusion_common::datatype::{DataTypeExt, FieldExt}; use datafusion_common::error::add_possible_columns_to_diag; -use datafusion_common::{Column, TableReference}; use datafusion_common::{DFSchema, DataFusionError, Result, not_impl_err, plan_err}; use datafusion_common::{ DFSchemaRef, Diagnostic, SchemaError, field_not_found, internal_err,