Skip to content

feat!: compute query fingerprints from SQLQuack tokens - #1348

Merged
kvlonge merged 6 commits into
mainfrom
feat/sqlquack-query-fingerprints
Nov 7, 2026
Merged

kvlonge merged 6 commits into
mainfrom
feat/sqlquack-query-fingerprints

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 7, 2026 •

Copy link
Copy Markdown
Contributor

Why

Query fingerprints decide whether a model's SQL changed. They came from Polyglot's tokenizer, which SQLBuild is removing. SQLQuack now tokenizes DuckDB, PostgreSQL, Snowflake and SQLite, so those dialects and the generic stream move now; the rest switch as their SQLQuack tokenizers land.

Changes

  • Add sqlquack-syntax and sqlquack-syntax-postgres at a pinned git revision. Generic, DuckDB, Snowflake and SQLite read sqlquack-syntax's lossless tokens; PostgreSQL reads the native PostgreSQL scanner, so a later Postgres move does not change hashes again.
  • Upper-case reserved keywords and unquoted called names outside name positions. Quoted names, __ placeholders and CTE or INTO/TABLE column-list names keep their case.
  • Matching parentheses are found in one pass, so deep or unbalanced nesting stays linear.
  • BigQuery, Databricks, SQL Server and ClickHouse keep the Polyglot stream for now.
  • The hash format is unchanged. On a compiled corpus of 8,617 models, 24 hash differently: unquoted user-defined or unknown function names (DuckDB 4, Snowflake 3, SQLite 1) and SQLite built-ins Polyglot left unfolded (16). PostgreSQL: 0 of 669.

Verification

  • Golden hashes for the switched dialects are unchanged; a new one covers lower-case keywords with __ref.
  • Unit cases: comments and case per dialect, quoted call names, placeholders, CTE column lists, a PostgreSQL multi-character operator, and time limits for 32,000-deep nesting and unclosed calls.
  • E2E: an unedited project plans no_change after a build; an identifier-case edit is a query change.
  • cargo test -p sqlbuild-analysis, the fingerprint, planner and format-case suites (1,825) and make check-ci pass locally.

DuckShop: no new project shape; the change was measured on DuckShop's compiled queries (411 of 412 unchanged).

Query fingerprints for generic, DuckDB, PostgreSQL, Snowflake and SQLite
SQL now come from SQLQuack's lossless tokenizer instead of Polyglot's.
Reserved keywords and called names fold case outside name positions;
SQLBuild placeholders such as __ref keep their case. BigQuery, Databricks,
SQL Server and ClickHouse keep the previous token stream until SQLQuack
tokenizes them.

BREAKING CHANGE: the first run after upgrading can plan some models as
query_changed even though their SQL did not change. On the switched dialects
this affects models that call user-defined functions, whose name case now
folds like built-in function names. Plan that run: affected incremental and
microbatch models whose replay_on_change is bounded or full replay or
rebuild, and sqb build --changed reruns them. Models on the default forward
policy only warn.
Fold call names after JOIN again; only INTO, TABLE and CTE column lists keep a called name's case.
Check the word before looking for a column list and find each call's closing parenthesis with one stack pass, so deep or unbalanced nesting stays linear.
@kvlonge
kvlonge enabled auto-merge (squash) November 7, 2026 16:53
@kvlonge
kvlonge disabled auto-merge November 7, 2026 16:54
@kvlonge
kvlonge enabled auto-merge (squash) November 7, 2026 16:54
@kvlonge
kvlonge merged commit 1ee7c8f into main Nov 7, 2026
49 checks passed
@kvlonge
kvlonge deleted the feat/sqlquack-query-fingerprints branch November 7, 2026 21:26
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