Skip to content

fix: stop naming relations and columns that do not exist - #28

Open
funcpp wants to merge 3 commits into
mainfrom
fix/fabricated-relation-names
Open

funcpp wants to merge 3 commits into
mainfrom
fix/fabricated-relation-names

Conversation

@funcpp

@funcpp funcpp commented Sep 22, 2026

Copy link
Copy Markdown
Owner

Three small changes from the #15 backlog. The first two are the same defect class as #23 — a relation or column name in the output that the rest of the result denies exists. The third settles an API question that #15's remaining work would otherwise reopen.

SELECT base.items_array[1] FROM actual_table AS base

Cherry-picked from #14/#16 (968ed01), authorship preserved; applies to main unchanged.

collect_ancestors handled Expr::CompoundFieldAccess by recursing into root and discarding the access chain. For base.items_array[1] the root is the relation alias, so the alias became the column:

before  Concrete { table: "actual_table", column: "base" }
after   Concrete { table: "actual_table", column: "items_array" }

base is a relation alias, not a column of actual_table. Whether the root is a relation or a struct-valued column is not decidable from the text — payload.items[1] is the second case — so the fix asks the scope:

SELECT base.items_array[1] FROM actual_table AS base   ->  actual_table.items_array
SELECT base.payload.items[1] FROM actual_table AS base ->  actual_table.payload
SELECT payload.items[1] FROM t                         ->  t.payload   (unchanged)

The last one is a struct root with no binding, and already resolved correctly.

SELECT u.* FROM users AS u

Taken from a612e01 in the same backlog; the rest of that commit patches star_arity, which does not exist here, and is left for the set-operation rework.

before  Wildcard { table: "u" }
after   Wildcard { table: "users" }

u is the alias. tables.inputs reports users, so the column graph named a relation the table graph denies. It also blocked expansion: apply_catalog expands a wildcard by calling list_columns on the table it names, and no catalog knows u, so SELECT u.* FROM users AS u stayed unexpanded even with a catalog that has users. expand_star already looked the name up in the scope; it used the binding only to recurse into a CTE or derived table and ignored it when it was a real table.

#[non_exhaustive] on Dialect

Dialect was the one public enum carrying it, added in #18 on the reasoning that sqlparser gains dialects and adding one should not break downstream matches. #23 left ColumnOrigin exhaustive on the opposite reasoning and documented why.

Two rules for two enums is worth maintaining only if the cost avoided is real, and pre-1.0 it is not: a consumer mapping Dialect into its own vocabulary is better served by a compile error naming the new dialect than by a _ arm that routes it somewhere silently. Removing the attribute is permissive for anyone already matching non-exhaustively, so nothing downstream breaks today. ARCHITECTURE.md now states the rule once, for every public enum.

This also settles a conflict ahead of time: 9da186b in #15 marks both Dialect and ColumnOrigin #[non_exhaustive], and that part will be dropped when the rest of it is reconstructed.

Tests

968ed01's six tests come with it. Two added for the alias star — one without a catalog, one checking the catalog now expands it, including through a CTE. Both fail on main.

cargo fmt --all --check                                           exit 0
cargo clippy --workspace --all-targets --all-features -D warnings exit 0
cargo test --workspace --all-features                             exit 0

Compatibility

ColumnOrigin values change for the two shapes above; both were wrong. Dropping #[non_exhaustive] is permissive. A 0.3.0 item alongside #18, #23 and #25.

🤖 Generated with Claude Code

eitsupi and others added 3 commits September 22, 2026 13:18
`SELECT u.* FROM users AS u` produced `Wildcard { table: "u" }`. `u` is
the alias, not a relation: it appears in no catalog and in no
`tables.inputs`, which reports `users`.

Two consequences. The output claimed a relation the table graph says does
not exist, the same defect class as #23. And `apply_catalog` expands a
wildcard by calling `list_columns` on the table it names, so the star
stayed unexpanded even with a catalog that knows `users` perfectly well.

`expand_star` already looks the name up in the scope; it only used the
binding to recurse into a CTE or derived table and ignored it when it was
a real table. It now names the relation the binding points at.

Taken from eitsupi's `a612e01` in #15. The rest of that commit patches
`star_arity`, which does not exist here, and is left for the set-operation
rework.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
`Dialect` was the one public enum carrying it, on the reasoning that
`sqlparser` gains dialects and adding one should not break downstream
matches. `ColumnOrigin` was deliberately left exhaustive on the opposite
reasoning, and #23 documented why.

Two rules for two enums is a distinction worth maintaining only if the
cost it avoids is real. It is not, here: the crate is pre-1.0, and a
consumer that maps `Dialect` into its own vocabulary is better served by
a compile error naming the new dialect than by a `_` arm that routes it
somewhere silently. Removing the attribute is permissive for anyone
already matching non-exhaustively, so nothing downstream breaks today.

ARCHITECTURE.md now states the rule once, for every public enum, rather
than as a property of `ColumnOrigin`.

This also settles a conflict ahead of time: eitsupi's `9da186b` in #15
marks both `Dialect` and `ColumnOrigin` `#[non_exhaustive]`, and that part
will be dropped when the rest of it is reconstructed.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

This branch has not been deployed

No deployments
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