Repository navigation
fix(core): know an unaliased table by its name - #14
Merged
Merged
Conversation
A table read without an alias registered nothing in its scope, so a
qualifier naming it was looked up in the enclosing scopes first, and
an outer alias of the same name won:
SELECT reviews.id FROM events AS reviews
WHERE EXISTS (SELECT 1 FROM raw.reviews WHERE reviews.book_id = 1)
put the subquery's filter on events. Since the twelfth patch a
select-list subquery is analysed too, and did the same. Where no alias
competed, the qualifier fell through to the bare name taken as a
table, without its schema, so `SELECT orders.id FROM db.sch.orders`
read no column at all.
A table or CTE read without an alias now registers its bare name in
its scope, normalized as qualifiers are, and the alias and instance
lookups check, innermost scope first, the aliases, the bare names,
then the names with no table behind them. A bare name two different
relations of one scope share resolves to neither and stops the
search. A LATERAL VIEW's name, and the aliases of table functions,
PIVOT, UNPIVOT and UNNEST, are registered normalized in the scope, so
they shadow an outer alias of the same name too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018LDZwk297SKdJXXLpTFZEh
IL-William
force-pushed
the
fix/unaliased-table-scope-master
branch
from
October 30, 2026 21:31
ed2d0cd to
34116bb
Compare
IL-William
added a commit
to IL-William/dbt-collin
that referenced
this pull request
Oct 30, 2026
It drops the nineteen marks the engine side of two Snowflake shapes left after #48: `book_ratings` (a scalar subquery in a select list), `loan_titles` and `shelf_tags` (a table without an alias whose columns are qualified with its own name). **The pin.** `rev` moves to `b904397`, tagged `collin-engine-8`: the fork's `master` with - **patch 12** (IL-William/flowscope#12, #13): a scalar subquery in a select list is analysed against a node of its own, and its column feeds the item. It was never analysed, so its column was drawn from the `FROM` table with the subquery's text, and `engine.rs` read the outer side of a correlation out of that text as the value; - **patch 13** (IL-William/flowscope#14, #15): a table or CTE read without an alias is known by its bare name in its scope. With patch 12 alone (`collin-engine-7`, never pinned), two tests of 0049 failed: the engine now placed a subquery's filter, and an unaliased inner table did not shadow an outer alias of its name. It also reads a column qualified with an unaliased table's bare name, which fell to a name without its schema. **What moves.** | | Before | After | | --- | --- | --- | | lineage-library facts given | 192 of 221 | 203 of 221 | | Snowflake shapes marked | 5 | 3: `TABLE(FLATTEN(...))`, a star inside a call, a lambda's argument | | wrong lines given | 6 | 5 | | Jaffle Shop cache and totals, with and without `--indirect` | | identical | | Shopify cache and totals, with and without `--indirect` | | identical | One test, `a_column_a_child_reads_and_its_parent_s_list_lacks_is_the_parent_s_finding`, held a CTE named like the alias inside it, where the engine raised a false alarm that stayed on the child; the engine now reads it right and the child has no entry, so the case asserts that. The rule it covered, a column the parent lacks with no edge behind the child's read, which then stays on the child, has a new case: `quiet_kid` reads `amount` only in a `WHERE`; it fails with the rule removed. **Docs.** 0028 lists the eleventh to thirteenth patches and records the move; `docs/next-steps.md` item 2 and the README's known limits name the three shapes left, and item 3 counts thirteen patches. No version bump. 246 tests pass with `cargo test --release`. 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 13 of the engine fork that collin pins (dbt-collin decision 0028). A table or CTE read without an alias is now known by its bare name in its own scope.
Until now it registered nothing there, so a qualifier naming it was looked up in the enclosing scopes first:
put the subquery's filter on
events, quoted table or not; withFROM raw.reviews AS reviewsit landed right. Since patch 12 (#12) a select-list subquery is analysed too, and collin's tests for correlated subqueries caught it there. Where no alias competed, the qualifier fell through to the bare name taken as a table, without its schema, soSELECT orders.id FROM db.sch.ordersread no column at all.The change
TableFactor::Tablewithout an alias, table or CTE, registers its bare name in its scope (Scope::bare_tables), normalized as qualifiers are (normalize_identifier), mapping to its canonical.resolve_table_aliasandresolve_alias_instancecheck, innermost scope first: the aliases, the bare names, then the names with no table behind them; the first scope that knows the qualifier answers.LATERAL VIEW's name, and the aliases of table functions,PIVOT,UNPIVOTandUNNEST, are registered normalized in the scope (register_subquery_alias), so they shadow an outer alias of their name too. The global alias set keeps them as written, as before.Left as it is:
FROM events AS "Reviews" WHERE EXISTS (SELECT 1 FROM raw.reviews WHERE "Reviews".kind = 'x')puts the filter onreviews, with a warning that it has nokind, wheremasterplaced none;masteralready fails a quoted alias in the outer select;UNNEST(...) AS U(id)under an outeru), as before this patch.Tests
EXISTSand in a select-list subquery, quoted and not, on Snowflake and DuckDB;LATERAL VIEWname (eandE), aTABLE(GENERATOR(...))alias and an upper-caseUNNESTalias shadow an outer alias.Each fails without its part of the patch.
cargo test -p flowscope-core,cargo fmt --all -- --checkand CI'scargo clippy --workspace --locked -- -D warningspass. The same commit applies unchanged tocollinandmaster.Measured through collin
With a local
[patch]on this branch, collin'smain:book_ratings(with patch 12),loan_titlesandshelf_tagsgive their lineage as written: nineteen marks go, nothing else moves--indirecttoo--indirecttoo🤖 Generated with Claude Code
https://claude.ai/code/session_018LDZwk297SKdJXXLpTFZEh