This is an automated email from the ASF dual-hosted git repository.

github-bot pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/datafusion.git


The following commit(s) were added to refs/heads/main by this push:
     new bc2b36cf56 fix: `SELECT * EXCLUDE(...)` silently returns empty rows 
when all columns are excluded (#21259)
bc2b36cf56 is described below

commit bc2b36cf56846e0c697b0f8b98619f346a72a9bf
Author: Zhen Chen <[email protected]>
AuthorDate: Wed Apr 1 14:33:06 2026 +0800

    fix: `SELECT * EXCLUDE(...)` silently returns empty rows when all columns 
are excluded (#21259)
    
    ## Which issue does this PR close?
    
    - Closes #21258.
    
    ## Rationale for this change
    
    When `SELECT * EXCLUDE(...)` or `SELECT * EXCEPT(...)` excludes every
    column in the schema, DataFusion silently produces rows with zero
    columns instead of failing at planning time. This is confusing and
    inconsistent with DuckDB, which raises a clear `Binder Error: SELECT
    list is empty after resolving * expressions!` at planning time.
    
    ## What changes are included in this PR?
    
    - In `project_with_validation` (builder.rs), after expanding all
    `Wildcard` and `QualifiedWildcard` expressions, added a check: if any
    wildcard was present **and** the resulting projection list is empty,
    return a `plan_err!` with the message `SELECT list is empty after
    resolving * expressions, the wildcard expanded to zero columns`.
    - Updated select.slt to change all existing "zero-column wildcard" test
    cases (previously `statement ok`) to `statement error` asserting the new
    error message. Cases updated include bare `SELECT * EXCEPT(all_cols)`,
    with `LIMIT`, `WHERE`, `GROUP BY`, `JOIN`, and window functions.
    
    ## Are these changes tested?
    
    Yes. The existing SQL logic tests in select.slt are updated to assert
    the new planning error for all zero-column wildcard scenarios (`EXCLUDE`
    and `EXCEPT`, with various clauses). This covers:
    - `SELECT * EXCLUDE(a, b)` / `SELECT * EXCEPT(a, b, c, d)` on a plain
    scan
    - Combined with `LIMIT`, `WHERE`, `GROUP BY`, `JOIN`, and window
    functions
    - Qualified wildcards (`SELECT t.* EXCLUDE(...)`)
    
    ## Are there any user-facing changes?
    
    Yes. Queries that previously silently returned empty-column result sets
    via `SELECT * EXCLUDE(...)` or `SELECT * EXCEPT(...)` when all columns
    were excluded will now fail at planning time with:
    
    ```
    DataFusion error: Error during planning: SELECT list is empty after 
resolving * expressions, the wildcard expanded to zero columns
    ```
---
 datafusion/expr/src/logical_plan/builder.rs   |  9 +++++++++
 datafusion/sqllogictest/test_files/select.slt | 28 +++++++++++++--------------
 2 files changed, 23 insertions(+), 14 deletions(-)

diff --git a/datafusion/expr/src/logical_plan/builder.rs 
b/datafusion/expr/src/logical_plan/builder.rs
index 95c6010a34..e9f41670bd 100644
--- a/datafusion/expr/src/logical_plan/builder.rs
+++ b/datafusion/expr/src/logical_plan/builder.rs
@@ -1931,10 +1931,12 @@ fn project_with_validation(
     expr: impl IntoIterator<Item = (impl Into<SelectExpr>, bool)>,
 ) -> Result<LogicalPlan> {
     let mut projected_expr = vec![];
+    let mut has_wildcard = false;
     for (e, validate) in expr {
         let e = e.into();
         match e {
             SelectExpr::Wildcard(opt) => {
+                has_wildcard = true;
                 let expanded = expand_wildcard(plan.schema(), &plan, 
Some(&opt))?;
 
                 // If there is a REPLACE statement, replace that column with 
the given
@@ -1955,6 +1957,7 @@ fn project_with_validation(
                 }
             }
             SelectExpr::QualifiedWildcard(table_ref, opt) => {
+                has_wildcard = true;
                 let expanded =
                     expand_qualified_wildcard(&table_ref, plan.schema(), 
Some(&opt))?;
 
@@ -1984,6 +1987,12 @@ fn project_with_validation(
             }
         }
     }
+    if has_wildcard && projected_expr.is_empty() && 
!plan.schema().fields().is_empty() {
+        return plan_err!(
+            "SELECT list is empty after resolving * expressions, \
+             the wildcard expanded to zero columns"
+        );
+    }
     validate_unique_names("Projections", projected_expr.iter())?;
 
     Projection::try_new(projected_expr, 
Arc::new(plan)).map(LogicalPlan::Projection)
diff --git a/datafusion/sqllogictest/test_files/select.slt 
b/datafusion/sqllogictest/test_files/select.slt
index f37ec2233d..3e97dc4588 100644
--- a/datafusion/sqllogictest/test_files/select.slt
+++ b/datafusion/sqllogictest/test_files/select.slt
@@ -1318,25 +1318,25 @@ statement error
 SELECT * EXCLUDE(a, a)
 FROM table1
 
-# if EXCEPT all the columns, query should still succeed but return empty
-statement ok
+# if EXCEPT all the columns, query should return an error
+statement error DataFusion error: Error during planning: SELECT list is empty 
after resolving \* expressions, the wildcard expanded to zero columns
 SELECT * EXCEPT(a, b, c, d)
 FROM table1
 
-# try zero column with LIMIT, 1 row but empty
-statement ok
+# try zero column with LIMIT, should error
+statement error DataFusion error: Error during planning: SELECT list is empty 
after resolving \* expressions, the wildcard expanded to zero columns
 SELECT * EXCEPT (a, b, c, d)
 FROM table1
 LIMIT 1
 
-# try zero column with GROUP BY, 2 row but empty
-statement ok
+# try zero column with GROUP BY, should error
+statement error DataFusion error: Error during planning: SELECT list is empty 
after resolving \* expressions, the wildcard expanded to zero columns
 SELECT * EXCEPT (a, b, c, d)
 FROM table1
 GROUP BY a
 
-# try zero column with WHERE, 1 row but empty
-statement ok
+# try zero column with WHERE, should error
+statement error DataFusion error: Error during planning: SELECT list is empty 
after resolving \* expressions, the wildcard expanded to zero columns
 SELECT * EXCEPT (a, b, c, d)
 FROM table1
 WHERE a = 1
@@ -1352,15 +1352,15 @@ CREATE TABLE table2 (
   (1, 10, 100, 1000),
   (2, 20, 200, 2000);
 
-# try zero column with inner JOIN, 2 row but empty
-statement ok
+# try zero column with inner JOIN, should error
+statement error DataFusion error: Error during planning: SELECT list is empty 
after resolving \* expressions, the wildcard expanded to zero columns
 WITH t1 AS (SELECT a AS t1_a FROM table1), t2 AS (SELECT a AS t2_a FROM table2)
 SELECT * EXCEPT (t1_a, t2_a)
 FROM t1
 JOIN t2 ON (t1_a = t2_a)
 
-# try zero column with more JOIN, 2 row but empty
-statement ok
+# try zero column with more JOIN, should error
+statement error DataFusion error: Error during planning: SELECT list is empty 
after resolving \* expressions, the wildcard expanded to zero columns
 SELECT * EXCEPT (b1, b2)
 FROM (
   SELECT b AS b1 FROM table1
@@ -1369,8 +1369,8 @@ JOIN (
   SELECT b AS b2 FROM table2
 ) ON b1 = b2
 
-# try zero column with Window, 2 row but empty
-statement ok
+# try zero column with Window, should error
+statement error DataFusion error: Error during planning: SELECT list is empty 
after resolving \* expressions, the wildcard expanded to zero columns
 SELECT * EXCEPT (a, b, row_num)
 FROM (
     SELECT


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

Reply via email to