Skip to content

fix(snowflake): keep keywords, pairs and left-out name parts in Snowflake trees - #236

Merged
kvlonge merged 22 commits into
mainfrom
fix/snowflake-tree-fidelity
Nov 15, 2026
Merged

kvlonge merged 22 commits into
mainfrom
fix/snowflake-tree-fidelity

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 15, 2026

Copy link
Copy Markdown
Contributor

Why

Re-reviews of Snowflake forms found trees that lost what the SQL wrote: keywords kept only in a raw action string, KEY = value pairs read as positional tuples, whether a value was a string or a bare word, and quoting. Twelve older forms also disagreed with their Snowflake receipts.

Changes

  • fix(snowflake): keywords land in their own fields: an action's IF [NOT] EXISTS, FOR ALL scopes, PAT, OF TYPE, PATCH, IN RUNTIME/DEPLOYMENT, FROM MODEL/SPECIFICATION, a temporary table's spelling, a sequence's OR ALTER and optional words, MAX_ROWS's return type.
  • fix(snowflake): KEY = v is property_e_q and name => v is named_argument; a multi-word value is one keyword phrase; RUNTIME_VERSION and PACKAGES record bare words; MATCH_RECOGNIZE keeps quoting and AS; a left-out DMF column or replica account is null with an *_omitted flag.
  • fix(snowflake): receipt fixes: ALTER/CREATE ORGANIZATION <name>, AS REPLICA OF a . . b, UNDROP VOLUME, FORCE before FOR ALL refused. 13 disagreements are dropped.
  • chore(syntax-coverage): 74 changed or unreviewed forms were judged again (32 scoped, 42 in full): 63 approved. The baseline is re-recorded.

Still open: function TEMP vs TEMPORARY spelling, keyword values read as table names, MATCH_RECOGNIZE PATTERN as text, options covered only by a case Snowflake refuses, and the ALTER STAGE SET URL = s3:// and ALTER TASK all-options disagreements.

Verification

  • Each fix has parser tests that fail on the previous code.
  • Verified forms 2,963 to 2,994: gross 31, drops 0, net +31. The rule form dropped in the previous PR is verified again.
  • syntax-coverage diff exits 0 with no receipt contradicted; make check-ci passes on the final head.

ON ( , <argument> ) parses with the column before the first comma left out. The tree now records that with column_omitted instead of dropping the slot.
MAX_ROWS AS ( ) RETURNS <type> -> <expression> read the type and dropped it. The MAX_ROWS property now keeps it in returns, in CREATE and ALTER DATA MOVEMENT RULE alike.
CREATE OR ALTER SEQUENCE gave the same tree as CREATE SEQUENCE, and the optional WITH, START WITH, INCREMENT BY and = were read and dropped. The tree now records or_alter, with and the spelling of START and INCREMENT.
AFTER MATCH SKIP TO [ FIRST | LAST ] <symbol>, DEFINE names and measure aliases written after AS lost their quoting, and a measure alias did not record its AS. They now keep both.
…n as strings

RUNTIME_VERSION = m1 and PACKAGES = ( m1 ) gave the same tree as the quoted spellings. A function now records runtime_version_bare, and packages_bare by position, when the value was written as a name or a number.
Parenthesised ALTER values such as WORKLOAD_IDENTITY = ( ANOMALY_DETECTION = TRUE ), SECRETS = ( 'm' = v1 ) and STORAGE_LOCATION = ( NAME = 'm' ... ) kept each pair as an unlabelled two-item tuple, the shape of a row. A KEY = value pair is now a property_e_q, as in the create paths. A <name> => <value> pair, as in USING, is a named argument.
ADD SCORING PROFILE IF NOT EXISTS, ADD VERSION IF NOT EXISTS, CREATE VERSION_TAG IF NOT EXISTS and their DROP ... IF EXISTS counterparts kept the words only in the action string. They now set operand_if_exists or operand_if_not_exists, as ALTER USER's token actions already did, and the action keeps only its keywords.
SET and UNSET of an account policy kept FOR ALL PERSON USERS and its siblings only in the action string, while FORCE was its own property. The scope is now a property too, in written order with FORCE, and the action names only the policy.
ALTER USER and ALTER EXTERNAL CONSUMER wrote PAT as PROGRAMMATIC ACCESS TOKEN in the action, so the spelling taken could not be told apart. The action now keeps the spelling that was written.
STOP ALL OF TYPE kept OF TYPE in the action string and the workload types as unlabelled operands. The types are now an OF TYPE property, and the action is STOP ALL.
UPGRADE USING VERSION <version> PATCH <n> kept PATCH only in the action string and the patch number as an unlabelled second operand. The patch is now a PATCH property, as CREATE APPLICATION ... USING VERSION already records it.
CREATE MODEL ... FROM MODEL and CREATE { EXPERIMENT | GATEWAY } ... FROM SPECIFICATION recorded their source as MODEL and SPECIFICATION, while other creates record FROM SPECIFICATION, FROM SERVICE and FROM EXPERIMENT. Both now keep FROM.
… deployment

CREATE OPENFLOW RUNTIME ... IN DEPLOYMENT <name> and CREATE OPENFLOW CONNECTOR ... IN RUNTIME <name> kept the name as an unlabelled operand and dropped IN DEPLOYMENT and IN RUNTIME. Each is now a property named by its words.
ALLOWED_INTEGRATION_TYPES = SECURITY INTEGRATIONS gave one unquoted name with a blank in it and the span of its first word. A value of several plain words is now a keyword phrase, as Openflow keyword values are, and a one-word value stays a name.
CREATE { TEMP | VOLATILE | LOCAL TEMP | GLOBAL TEMPORARY } TABLE gave the same tree as CREATE TEMPORARY TABLE, and a read-only temporary clone kept READ ONLY inside its modifier string. A table now records temporary_spelling when the words were not TEMPORARY, and a read-only clone keeps its temporary words as the modifier and READ ONLY as a property.
Snowflake refuses ALTER ACCOUNT SET MAINTENANCE POLICY <name> FORCE FOR ALL APPLICATIONS with a syntax error, although the page prints [ FORCE ] before the scope. It parses FORCE after the scope and FORCE alone, for every policy kind recorded. The parser now accepts only those orders.
@kvlonge
kvlonge enabled auto-merge November 15, 2026 04:57
@kvlonge
kvlonge added this pull request to the merge queue Nov 15, 2026
Merged via the queue into main with commit 892ef31 Nov 15, 2026
9 checks passed
@kvlonge
kvlonge deleted the fix/snowflake-tree-fidelity branch November 15, 2026 06:07
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