Skip to content

fix(snowflake): PIVOT/UNPIVOT — chained-clause parse, deparse, and lineage soundness#300

Merged
h3n4l merged 1 commit into
mainfrom
feat/snowflake/pivot-ast
Jun 10, 2026
Merged

fix(snowflake): PIVOT/UNPIVOT — chained-clause parse, deparse, and lineage soundness#300
h3n4l merged 1 commit into
mainfrom
feat/snowflake/pivot-ast

Conversation

@h3n4l

@h3n4l h3n4l commented Jun 10, 2026

Copy link
Copy Markdown
Member

Fix

PIVOT/UNPIVOT soundness (found by bytebase cutover P1 review): the AST nodes existed (#261) but (1) chained t PIVOT(...) PIVOT(...) mis-parsed (2nd keyword eaten as implicit alias, clause dropped), (2) deparse emitted nothing for Pivot/Unpivot, (3) analysis resolved pivoted refs as the bare base table, fabricating source columns like T."2023_Q1" (under-attribution leak).

New TableRef.Nested for chains; alias guard refuses PIVOT/UNPIVOT clause heads; deparse round-trips all forms; analysis attributes every column through a pivoted relation to whole-relation sources (masking-sound over-attribution, matching the catalog-less convention). 23 new tests; full suite + corpus green; walker regenerated (guard green). Verified on fresh checkout of aeadf5d.

Residual chips filed: parser-wide trailing-token drop; MATCH_RECOGNIZE same-class.

🤖 Generated with Claude Code

…ard) — lineage soundness

The T5.3 node already parsed PIVOT/UNPIVOT into TableRef.Pivot/.Unpivot,
but three downstream gaps still silently treated 'FROM t PIVOT(...)' as
bare 'FROM t':

- parser: a chained 'PIVOT(...) PIVOT(...)' (official docs, corpus
  example_20) mis-parsed — the second PIVOT keyword was eaten as the
  first clause's implicit alias and the second clause body silently
  discarded. parseTableSuffix now loops, re-rooting the ref in place
  with the prior pivoted source on the new TableRef.Nested field, and
  the clause trailing alias refuses a PIVOT/UNPIVOT-plus-'(' head.
- deparse: writeTableRef dropped Pivot/Unpivot entirely, so any rewrite
  consumer would emit the unpivoted relation. Both clauses (and Nested
  chains) now round-trip.
- analysis/query_span: pivoted relations resolved as their base table,
  fabricating per-column attributions for output columns that do not
  exist on the base (e.g. T."2023_Q1" for SUM(T.AMOUNT) data) — an
  under-attribution leak for masking consumers. Pivoted refs now
  resolve as opaque-derived entries: every column resolved through
  them (star, bare, or alias-qualified) attributes to the source
  relation's whole-relation ('*') sources, deliberately conservative.

Walker regenerated for Nested (genwalker guard green); ast.Inspect
reaches both clauses of a chain and the IN-list values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@h3n4l h3n4l merged commit dac10f3 into main Jun 10, 2026
2 checks passed
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