Skip to content

fix(optimizer): retain set-returning projections in pushdown_projections#7686

Merged
georgesittas merged 1 commit into
mainfrom
retain-set-returning-projections
May 28, 2026
Merged

fix(optimizer): retain set-returning projections in pushdown_projections#7686
georgesittas merged 1 commit into
mainfrom
retain-set-returning-projections

Conversation

@tobymao
Copy link
Copy Markdown
Owner

@tobymao tobymao commented May 28, 2026

Problem

pushdown_projections removes any projection that the outer query doesn't reference. But a projection whose expression is a set-returning / table function (EXPLODE, POSEXPLODE, INLINE, UNNEST) multiplies the rows of the entire query, so dropping it because it's otherwise unused silently changes the result's row cardinality:

-- before this PR: slicing to `d` drops EXPLODE(e) and loses the row multiplication
SELECT d FROM (SELECT EXPLODE(e) AS col, d FROM w)
-- becomes
SELECT d FROM (SELECT d FROM w)   -- WRONG: different row count

Fix

Retain any otherwise-unused projection whose expression contains a set-returning function. Posexplode and the *Outer variants subclass Explode, so matching Explode covers them. Window functions are not set-returning and remain prunable; LATERAL VIEW is already retained.

Tests

Added fixtures to tests/fixtures/optimizer/pushdown_projections.sql covering EXPLODE / POSEXPLODE / INLINE retention and ROW_NUMBER pruning. The full optimizer suite passes.

A projection containing a set-returning (table) function such as
EXPLODE/POSEXPLODE/INLINE/UNNEST multiplies the rows of the entire
query, so it affects the cardinality of every output column. Pruning
such a projection because it is otherwise unreferenced silently changes
the result's row multiset, which is a correctness bug.

Keep any unused projection whose expression contains a set-returning
function. Window functions (e.g. ROW_NUMBER() OVER (...)) do not change
cardinality and remain prunable; LATERAL VIEW is already retained.
@github-actions
Copy link
Copy Markdown
Contributor

SQLGlot Integration Test Results

Comparing:

  • this branch (sqlglot:retain-set-returning-projections @ sqlglot ca72692)
  • baseline (main @ sqlglot 07faa10)

By Dialect

dialect main feature branch transitions links
bigquery -> bigquery 24647/24652 passed (100.0%) 23497/23497 passed (100.0%) No change full result / delta
bigquery -> duckdb 870/1154 passed (75.4%) 0/0 passed (0.0%) Results not found full result / delta
duckdb -> duckdb 5823/5823 passed (100.0%) 0/0 passed (0.0%) Results not found full result / delta
snowflake -> duckdb 1125/1857 passed (60.6%) 0/0 passed (0.0%) Results not found full result / delta
snowflake -> snowflake 65203/65232 passed (100.0%) 63027/63027 passed (100.0%) No change full result / delta

Overall

main: 113231 total, 112181 passed (pass rate: 99.1%)

sqlglot:retain-set-returning-projections: 101037 total, 101037 passed (pass rate: 100.0%)

Transitions:
No change

Dialect pair changes: 0 previous results not found, 3 current results not found

✅ 64 test(s) passed

@georgesittas georgesittas merged commit 5c916ee into main May 28, 2026
8 checks passed
@georgesittas georgesittas deleted the retain-set-returning-projections branch May 28, 2026 12:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants