fix: stop inlining SELECT-list aliases that shadow FROM columns (#131)#133
Merged
rampage644 merged 3 commits intomainfrom Apr 23, 2026
Merged
fix: stop inlining SELECT-list aliases that shadow FROM columns (#131)#133rampage644 merged 3 commits intomainfrom
rampage644 merged 3 commits intomainfrom
Conversation
…ations `InlineAliasesInSelect` textually substituted SELECT-list alias references into other projection expressions before the planner ran. When an alias shadowed a real column of the FROM-clause relation, this silently rewrote the query into an incorrect one -- e.g. `start_tstamp = user_start_tstamp` inside `MAX(CASE WHEN ...)` was turned into the tautology `user_start_tstamp = user_start_tstamp`, and `MAX(CASE WHEN TRUE THEN sid END)` degenerated to `MAX(sid)`. Snowflake and ANSI SQL resolve such references against the FROM-clause column, not the alias. For derived subqueries in FROM the visitor already collects the inner column/alias names into `subquery_idents` and skips substitutions that collide. For named tables, CTEs, and table functions we have no schema at the AST level, so we now conservatively skip projection-list alias inlining whenever any such relation appears in FROM. WHERE/QUALIFY inlining is unchanged. Fixes #131.
…le_if) Rust 1.95 promoted two lints from `pedantic` to `correctness`/ `complexity`: - `useless_conversion` — `.into_iter()` on arguments already accepting `IntoIterator` (in `stream::iter`, `Extend::extend`, `Iterator::zip`, `Iterator::chain`, `ScalarValue::iter_to_array`). - `collapsible_if` — `if` inside a match arm that only gates the entire arm; the condition belongs on a `match` guard. The workspace's `[workspace.lints.clippy] all = "deny"` turns both into hard errors, so CI broke on the first clippy run after the toolchain bump. Mechanical, behavior-preserving fixes across `catalog`, `executor`, and `functions`.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes #131 — a SELECT-list alias that shadows a FROM-clause column name was being silently inlined into other projection expressions, producing wrong aggregate results.
InlineAliasesInSelect(crates/functions/src/visitors/inline_aliases_in_query.rs) is a pre-planning SQL-AST rewriter that replaces references to SELECT-list aliases with their underlying expressions. For derived subqueries inFROMit already gathers the inner column/alias names intosubquery_identsand skips substitutions that would collide. But for named tables, CTEs, and table functions it had no schema information and inlined blindly, producing:rewritten into
CASE WHEN user_start_tstamp = user_start_tstamp ...— a tautology — collapsingMAX(CASE ...)toMAX(sid). Per ANSI SQL and Snowflake the reference must resolve to the FROM-clause column.Fix
Skip projection-list alias inlining whenever
FROMcontains any non-derived relation (named table, CTE, table function, or a nested join that leads to one).WHERE/QUALIFYinlining is unchanged. Derived-subquery FROMs continue to rely on the existingsubquery_identspath.Test plan
cargo test -p functions --lib tests::visitors— 9/9 pass, including a new case for the issue reproducer.cargo test -p executor --lib tests::sql::dml::select— 5/5 pass, including a new end-to-end snapshotquery_alias_shadows_column_in_aggregate_casethat runs the exact query from the issue and assertsfirst_sid = S1(the Snowflake-correct answer, vs. theS2that Embucket was returning pre-fix).https://claude.ai/code/session_01RqHxFFaNxKbhGTGWD6A19z
Generated by Claude Code