Skip to content

fix(snowflake): keep constraint, procedure and table actions typed and refuse nameless alters Snowflake refuses - #240

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

kvlonge merged 18 commits into
mainfrom
fix/snowflake-tree-fidelity-3

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 15, 2026

Copy link
Copy Markdown
Contributor

Why

Reviews of Snowflake forms found trees that kept RETURNS TABLE columns, CALL WITH options, constraint options and table policy actions as text, and cases that filled the lower-case part of x86 keywords. Newer receipts also show Snowflake refusing a nameless ALTER ... SET or UNSET for most kinds, which earlier receipts under a retired errno 1003 rule had marked as accepted.

Changes

  • fix(snowflake): RETURNS TABLE columns are fields with their quoting; CALL WITH and anonymous procedure options are properties; a dynamic table's secondary roles are a property.
  • fix(snowflake): constraint options set typed fields; table policy, tag and column actions and MODIFY ( ... ) column lists are structured.
  • fix(snowflake): a nameless ALTER SET or UNSET is refused except where receipts show Snowflake parses it; DATABASE ROLE before SET or UNSET is a nameless database role, except before TAG.
  • fix(format): a call's arguments keep their indent around line comments.
  • fix(syntax-cases): x86 keywords are written, not filled; an option in a one-group branch is written; DEFINE FILE FORMAT options get valid cases.
  • fix(receipts): 3 more reviewed post-parse errnos classify as semantic.
  • chore(syntax-coverage): evidence pinned with batches 34 to 36 and with superseded errno 1003 receipts withdrawn; 28 changed forms reviewed and approved; baseline re-recorded. The x86 fix removes 18 warehouse obligations that filled a keyword's lower-case part.

Still open: inline constraint and ENABLE/VALIDATE options as text, procedure argument-list continuation cases, RETURNS TABLE names without a quoted flag, define-* options only in refused cases, DATE_PART FROM and DMF TABLE() types, and 22 receipt disagreements.

Verification

  • Each fix has parser tests that fail on the previous code.
  • Verified forms 3,087 to 3,114 of 3,351: gross 27, drops 0, net +27.
  • syntax-coverage diff exits 0 with nothing lost or contradicted.
  • make check-ci passes on the final head.

…e first one

A line comment just before a call's first argument left the comment and the
arguments at the call's own indent, joined the arguments on one line and put
the closing parenthesis after them. The group now opens on its own line as it
does when the comment precedes a later argument: the comment lines and the
arguments are indented one level inside the call, one argument per line, and
the parenthesis closes on its own line. Block comments keep their layout.
…erty

EXECUTE AS USER <user> USE SECONDARY ROLES ... put the user and the roles in
one tuple, and CREATE [OR ALTER] DYNAMIC TABLE filed NONE as a role name. The
user is now the EXECUTE AS USER value and USE SECONDARY ROLES is its own
property: ALL or NONE as a keyword, or the list of role names.
…th their quoting

CREATE PROCEDURE ... RETURNS TABLE ( ... ) kept its columns as one custom type
name such as TABLE(v1 Q INT), which lost the quoting. Its columns are now
returns_table fields, as an anonymous procedure's already were, and a quoted
column name keeps its quotes in both.
WITH <name> AS PROCEDURE ... kept RUNTIME_VERSION, PACKAGES, IMPORTS, HANDLER,
the null-input clause and the return type's NULL or NOT NULL as raw strings.
They are now properties, as CREATE PROCEDURE records them: a string value a
literal, a name a name, and a list a tuple. What the procedure accepts is
unchanged.
ALTER TABLE ADD of an out-of-line constraint kept RELY, ENFORCED,
DEFERRABLE, INITIALLY, COMMENT, MATCH and ON UPDATE or DELETE only as
property words, leaving the typed modifier and reference fields empty.
A column's inline REFERENCES did the same for MATCH, ON UPDATE or DELETE
and DEFERRABLE.

Each of those words now sets its field once. Words with no field, such
as ENABLE VALIDATE, and repeats stay in the ordered property list.
ALTER TABLE and ALTER ICEBERG TABLE kept ADD and DROP ROW ACCESS POLICY,
SET and UNSET AGGREGATION or JOIN POLICY, and MODIFY or ALTER of a column's
masking, projection policy or tags as raw action text, which added a
COLUMN the statement may not have had. They now use the governance tree
whenever the shared ALTER TABLE would hold any action as raw text.

In that tree a written COLUMN is kept on each column's property; FORCE and
an aggregation policy's ENTITY KEY are their own properties instead of
entries in the policy tuple; and UNSET JOIN without POLICY keeps its
spelling. A column's WITH TAG and WITH PROJECTION POLICY keep their WITH.
…ions

ALTER TABLE <name> MODIFY ( <column> <action> , ... ) was one raw action string with an invented COLUMN. It now reads like ALTER ( ... ): one AlterColumn per entry, marked as written with MODIFY.
…nstead of filling it

A bare grammar word with any lower-case letter was read as a placeholder,
so the warehouse RESOURCE_CONSTRAINT alternatives MEMORY_1X_x86,
MEMORY_16X_x86 and MEMORY_64X_x86 were written as v1 and never tested.
For Snowflake, a word whose first underscore-separated part is upper case
is now a keyword. Other dialects keep the old reading.

This removes the 24 class and wrong-kind obligations those three words
had only as placeholders, in four warehouse forms; no other obligation
changes.
…s semantic

Errno 1647 refuses a temporary object in a DCM definition file, 90214 names
a RETURNS TABLE column missing its name or type after the type is
resolved, and 90216 refuses a well-formed quoted function name. Each is
checked after parsing. Errno 926, an empty external table name, may be
refused while parsing and stays unestablished.
…e without TEMP

SKIP_HEADER, FILE_EXTENSION and COMMENT had a valid value only in the
refused DEFINE TEMP case that sets every option, so no accepted case
showed them. Eight observe limits write each one on its own.
…ptions

A choice branch written as a brace group of optional parts rendered with
none of them, so ALTER STAGE SET's GCS and Azure branches were covered
only by the refused "SET ;". The branch now writes its first option, and
an absent option leaves the group's next option written. Only those 11
ALTER STAGE obligations change case.
…guments

When a call broke across lines, the argument after a comment between two
arguments was not put at the argument indent: after a trailing line
comment it landed one space left, and an own-line block comment and the
argument after it stayed at the call's indent, or at column 0 inside an
expression body. The comment's continuation line and the next argument
now start at the argument indent; lines inside a block comment keep their
text.
… definition-file receipts

The new receipts settle 64 more DDL cases, mostly DEFINE statements whose
definition-file failures are now classified after parsing. The ALTER STAGE
storage branches and the DEFINE FILE FORMAT options get their valid cases.
…awn errno 1003 receipts

53 cases whose receipts disagreed, semantic under a retired errno 1003 rule
and syntax under the current one, now settle as rejections. Batch 36 adds
receipts for the DEFINE FILE FORMAT and ALTER WAREHOUSE cases of this
train.
…fuses

Receipts recorded under the current errno 1003 rule show Snowflake
refusing an omitted name as a syntax error for the policies, the
integrations' SET and UNSET, and VIEW, so only DATABASE, SCHEMA,
ONLINE FEATURE TABLE, SNAPSHOT POLICY's SET, INTEGRATION's REFRESH and
MATERIALIZED VIEW's SET still parse without a name.

DATABASE ROLE before SET or UNSET is now a database role with no name,
which is refused, except before TAG, where ROLE stays the database's
name as the recorded semantic errors show.
…ts at their cases

The three RESOURCE_CONSTRAINT x86 alternatives now have their own cases, which the capture guard held when the batch 36 packets were built.
…baseline

Records the approved reviews of the forms whose trees, cases or receipts
this train changed, and re-records the baseline on the head. The x86
RESOURCE_CONSTRAINT keywords no longer give the warehouse forms operand
and negative-neighbour obligations for their lower-case part, so those
18 obligations leave the baseline; CREATE WAREHOUSE's three x86
alternatives now cite their own cases, which have no receipts yet.
…the train's changes

Constraint modifiers match each spelling on its own arm, the foreign key reference is passed by value, CREATE PROCEDURE's WITH options and body parse in their own methods, and the new comments and docstrings fit the repository's one-line rules. Behaviour is unchanged.
@kvlonge
kvlonge enabled auto-merge November 15, 2026 14:59
@kvlonge
kvlonge added this pull request to the merge queue Nov 15, 2026
Merged via the queue into main with commit b4767dd Nov 15, 2026
9 checks passed
@kvlonge
kvlonge deleted the fix/snowflake-tree-fidelity-3 branch November 15, 2026 16:13
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