Skip to content

fix(semantics): give every select item its range through each dialect's strict parser - #203

Merged
kvlonge merged 1 commit into
mainfrom
fix/strict-expression-ranges
Nov 12, 2026
Merged

kvlonge merged 1 commit into
mainfrom
fix/strict-expression-ranges

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

Why

Lineage gives each output column its select item's byte range (expression_range), but only query_lineage's located parse recorded every item's range. Through each dialect's parse_strict, most items had none or a short one. On SELECT w.window_id, UPPER(w.sku) AS loud FROM orders AS w, Snowflake gave loud no range, and DuckDB gave w.window_id the range window_id.

Changes

  • A strict Snowflake parse records each select item's range, as a located one does. The plain parse still records none, so no tree the syntax reviews fingerprint changes.
  • Lineage runs a column's range from its qualifier; six native parsers' column spans cover only the name.
  • SQL Server ranges aliased items and stars, and ClickHouse aliased items.

Through parse_strict, before → after:

aliased qualified star
Snowflake none → full full none → full
DuckDB, BigQuery, Databricks full name → full full
SQLite full name → full none
SQL Server none → full name → full none → full
ClickHouse none → full name → full full
Postgres full full full

SQLite stars have no range yet: recording one changes the parse trees of 15 reviewed SQLite forms, which would need re-review.

Verification

  • Each of the eight dialects' lineage tests parses a statement with its parse_strict and asserts every output's exact byte range: a literal with AS after a two-byte character, a qualified column, a call with a bare label, a bare column and, except SQLite, a qualified star. Seven fail on the previous code; Postgres already passed.
  • check-syntax loses no form in any dialect.
  • make instruction-counts passes. Once each on one machine, base main 9b9070d → this head: parse 253,208,648 → 252,880,943 (−0.13%), analysis 240,240,857 → 240,389,961 (+0.06%); repeat runs of one build differ by up to 0.02%. The baseline is unchanged.
  • make check-ci passes.

…'s strict parser

Lineage reports a projection item's source range as its output's
expression_range, but through parse_strict most items had none or a
short one:

- Snowflake recorded item ranges only in a located parse, so an aliased
  item, a call, an expression or a star had no range; only a column
  reference did.
- DuckDB, BigQuery, SQLite, SQL Server, Databricks and ClickHouse give a
  qualified column its name's range, so w.status read as status.
- SQL Server and ClickHouse gave an aliased item no range, and SQL
  Server none to a star.

A strict Snowflake parse now records each select item's range, as a
located one does; the plain parse still records none, so no serialised
tree the syntax reviews fingerprint changes. Lineage runs a column's
range from its qualifier. SQL Server ranges aliased items and stars,
and ClickHouse aliased items.

SQLite stars still have no range: recording one changes the parse
trees of 15 reviewed SQLite forms.
@kvlonge
kvlonge added this pull request to the merge queue Nov 12, 2026
Merged via the queue into main with commit 8e7bfdc Nov 12, 2026
14 checks passed
@kvlonge
kvlonge deleted the fix/strict-expression-ranges branch November 12, 2026 13:29
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