Repository navigation
Give each CTE its own node when a nested WITH reuses its name - #5
Merged
Merged
Conversation
A CTE's node was keyed by statement and name, and its output columns were
kept in one map per statement keyed by name. Two CTEs of one statement
sharing a name in different WITH blocks, as dbt writes when it inlines
ephemeral models that each name a CTE `final`, therefore shared one node
and one column list, and each reader received both lineages:
WITH a AS (
WITH final AS (SELECT k, ts FROM sat_a) SELECT k, ts FROM final
),
b AS (
WITH final AS (SELECT k, ts FROM sat_b) SELECT k, ts FROM final
)
SELECT a.ts AS a_ts, b.ts AS b_ts FROM a JOIN b ON a.k = b.k
a_ts came out derived from sat_a.ts and sat_b.ts both, and so did b_ts,
with no issue raised.
Count the CTEs of each name per statement, as derived tables already are.
The first keeps the key it always had, so nothing changes for a statement
that does not repeat a name, and each later one is keyed `name#n`, with a
node and column nodes of its own and the name as its label. A WITH that
defines a name an earlier CTE has hides that CTE's definition and columns
until its query ends, then puts them back, so a name read after a nested
WITH is the one in scope there.
Backward inference through `SELECT *` grouped wildcards by the target's
name and chained them by the source's. It now keys them by node, so two
CTEs of one name with no schema infer their own columns; a derived table
reusing an alias, which the earlier fix left to inference by name, is
covered too.
Tests: the query above; the same inside two derived tables; an outer CTE
shadowed in a nested WITH and read after it; the same with no schema; a
filter on one of two CTEs of one name; an unqualified column of an outer
CTE beside an inner namesake. All six fail without the change. Two more
pass either way and guard it: stars expanded per CTE, and dbt's shape, an
outer `final` over an inlined model holding its own `final`.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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.
Patch 7 of the engine fork that collin pins (dbt-collin decision 0028): two CTEs of one name in nested
WITHblocks get a node and a column list of their own, instead of sharing the first one's. dbt writes this whenever it inlines ephemeral models that each name a CTEfinal,ordersorranked.Without the patch, every reader of either CTE gets both lineages, and the engine raises no issue. collin works around it by setting such compiles aside (dbt-collin decision 0018). This patch lets it read them.
The change
name#nfrom its second occurrence in a statement, as patch 4 already does for derived tables. The first occurrence keeps its key, so a statement that never repeats a name is analysed as before.WITHthat redefines a name hides the earlier definition and its columns until its query ends, then puts them back.SELECT *without a schema. Wildcards are now keyed by node, not by name. This also covers derived tables that reuse an alias.There are 8 new tests. 6 fail without the patch; 2 pass either way and serve as guards. 2620 tests pass.
cargo fmt --checkis clean.Measured through collin
Each project was run with and without
--indirect.Nothing goes to pondpilot/flowscope.
🤖 Generated with Claude Code
https://claude.ai/code/session_017VTEw2dNNL9Pn57Hkeeirn