Skip to content

fix: resolve qualified table names against the schema - #110

Merged
kvlonge merged 2 commits into
mainfrom
fix/qualified-tables
Nov 6, 2026
Merged

kvlonge merged 2 commits into
mainfrom
fix/qualified-tables

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 6, 2026

Copy link
Copy Markdown
Contributor

Why

dbt's compiled SQL always names relations as database.schema.table. Every qualified name was refused with SQ0002 node:table, so sqlquack census target/compiled/..., the census example in the docs, reported nearly every real model as refused.

Changes

  • A relation may be declared in the schema as TABLE, SCHEMA.TABLE or DATABASE.SCHEMA.TABLE. A written name, resolved as Snowflake does (unquoted parts upper-case, quoted parts keep their case), reads the declared relation whose parts agree with it, read backwards from the table name. The longest agreement wins. The converted SQL names the relation as declared, so it binds in a DuckDB database attached under that name.
  • The session's DATABASE and SCHEMA (--session, or the Python session=) complete names written without them.
  • These refuse with SQ0004, naming the candidates: a name that matches several declared relations with no default to settle it; a qualified name whose relation a same-named CTE hides; two differently written names reading one declared relation.
  • The DuckDB check creates qualified tables in their schema and attached catalog.
  • census --chain-models and its blocker graph link a qualified reference to the model file named by its last part.
  • Docs: schema naming, session parameters, census.

Verification

  • CLI tests: qualified, mixed-case and quoted names run on DuckDB over attached catalogs; session SCHEMA/DATABASE defaults; ambiguous, unknown, quoted-case, double-read and CTE-capture refusals.
  • A census test over a dbt-compiled model pair: 2 of 2 convert with chaining, 1 without.
  • make check-ci, make test-rust, make verify-recorded.

A relation may be declared as TABLE, SCHEMA.TABLE or DATABASE.SCHEMA.TABLE,
and a written name reads the declared relation whose parts agree with it,
completed by the session's DATABASE and SCHEMA. The converted SQL names the
relation as declared. Ambiguous, CTE-captured and doubly read names refuse
with SQ0004 naming the candidates. census links a qualified reference to the
model file named by its last part.

kvlonge commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

Local D94 gate on head be64daa (base main 9ad7d1c):

  • make check-ci: exit 0 (fmt, clippy, fensu 0 faults, ruff, syntax coverage, evidence and polyglot guards, generated and referee cases, Python API).
  • make test-rust: passed.
  • make verify-recorded: 8,470 cases, 0 failed; 220 of 220 equivalences and rules verified; syntax coverage 0 regressions.
  • Hygiene scan: clean.

Main has since moved to e9f002d, which merges cleanly. I'll merge main again and re-gate before landing, after slice 2.

kvlonge commented Nov 6, 2026

Copy link
Copy Markdown
Contributor Author

D94 gate on c3555dd (main 464e7bb merged in, clean merge):

  • make check-ci: exit 0
  • make test-rust: passed, every suite exit 0
  • make verify-recorded: 11,774 cases, 7,755 passed, 1,031 diverged as expected, 2,952 refused, 0 pending, 0 unproven, 0 failed; 220 of 220 equivalences and rules verified. translation-results: 0 regressions, 0 other changes, so the results baseline is unchanged.
  • Hygiene scan: clean.
    GitHub Actions jobs aren't starting (billing), so this gate is the landing check.

@kvlonge
kvlonge merged commit c3555dd into main Nov 6, 2026
1 check failed
@kvlonge
kvlonge deleted the fix/qualified-tables branch November 9, 2026 21:32
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.

1 participant