Skip to content

fix: SELECT * EXCLUDE(...) silently returns empty rows when all columns are excluded#21259

Open
xiedeyantu wants to merge 3 commits intoapache:mainfrom
xiedeyantu:fix-exclude
Open

fix: SELECT * EXCLUDE(...) silently returns empty rows when all columns are excluded#21259
xiedeyantu wants to merge 3 commits intoapache:mainfrom
xiedeyantu:fix-exclude

Conversation

@xiedeyantu
Copy link
Copy Markdown
Member

Which issue does this PR close?

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

@github-actions github-actions bot added logical-expr Logical plan and expressions sqllogictest SQL Logic Tests (.slt) labels Mar 30, 2026
@xiedeyantu xiedeyantu marked this pull request as draft March 30, 2026 16:28
@xiedeyantu xiedeyantu marked this pull request as ready for review March 30, 2026 23:57
@xiedeyantu
Copy link
Copy Markdown
Member Author

@alamb Sorry to bother you. Could someone please help me review this PR?

Copy link
Copy Markdown
Contributor

@alamb alamb left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is an improvement, but I am also confused about EXCEPT vs EXCLUDE in duckdb itself 🤔

Thank you @xiedeyantu


# if EXCEPT all the columns, query should still succeed but return empty
statement ok
# if EXCEPT all the columns, query should return an error
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For the record, postgres rejects this syntax

postgres=# CREATE TABLE table1 (
  a int,
  b int,
  c int,
  d int
) ;
CREATE TABLE
postgres=# SELECT * EXCEPT(a, b, c, d)
FROM table1;
ERROR:  syntax error at or near "a"
LINE 1: SELECT * EXCEPT(a, b, c, d)
                        ^

Thus I agree we should be following the duckdb behavior

memory D CREATE TABLE table1 (
           a int,
           b int,
           c int,
           d int
         );

However, duckdb seems to reject this syntax entirely

How did

memory D SELECT * EXCEPT a, b, c, d FROM table1;
Parser Error:
syntax error at or near "a"

LINE 1: SELECT * EXCEPT a, b, c, d FROM table1;
                        ^
memory D SELECT * EXCEPT(a, b, c, d) FROM table1;
Parser Error:
syntax error at or near "a"

LINE 1: SELECT * EXCEPT(a, b, c, d) FROM table1;
                        ^

It looks like the actual syntax is EXCLUDE rather than EXCEPT...

memory D SELECT * EXCLUDE(a, b, c, d) FROM table1;
Binder Error:
SELECT list is empty after resolving * expressions!

🤔

@github-actions github-actions bot removed the logical-expr Logical plan and expressions label Mar 31, 2026
@alamb
Copy link
Copy Markdown
Contributor

alamb commented Mar 31, 2026

(sorry I accidentally pushed to this branch -- i reverted the change)

@github-actions github-actions bot added the logical-expr Logical plan and expressions label Mar 31, 2026
@xiedeyantu
Copy link
Copy Markdown
Member Author

@alamb Thank you for the review! Is there anything else I need to do?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

logical-expr Logical plan and expressions sqllogictest SQL Logic Tests (.slt)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SELECT * EXCLUDE(...) silently returns empty rows when all columns are excluded

2 participants