Skip to content

fix(syntax): parse Snowflake ALTER of policies and account-level objects - #43

Merged
kvlonge merged 3 commits into
mainfrom
fix/snowflake-alter-policies
Nov 4, 2026
Merged

kvlonge merged 3 commits into
mainfrom
fix/snowflake-alter-policies

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor

Parses Snowflake ALTER of policies and account-level objects into the typed AlterObject statement. Until now they went through the opaque Command fallback, which accepted their documented negatives. It also refuses an unquoted reserved keyword as a Snowflake DROP object name.

  • Policies: AGGREGATION, AUTHENTICATION, BACKUP, DATA MOVEMENT, FEATURE, INGRESS, JOIN, MAINTENANCE, MASKING, MULTI PARTY APPROVAL, NETWORK, PACKAGES, PASSWORD, SESSION and SNAPSHOT policies, and NETWORK RULE. This covers BODY -> <expr>, AS bodies and ADD/REMOVE lists. ALTER SESSION POLICY no longer falls into ALTER SESSION, which is otherwise unchanged.
  • FAILOVER / REPLICATION GROUP: ADD/REMOVE on the allowed lists, MOVE, PRIMARY (failover only), REFRESH, RESUME, SUSPEND [IMMEDIATE], RENAME, SET/UNSET and TAG.
  • CONNECTION, [ ] INTEGRATION and ACCOUNT (current or named): properties, TAG, CONTACT, policies with FOR ALL … and FORCE, RENAME TO [ SAVE_OLD_URL ], DROP OLD [ ORGANIZATION ] URL, and REFRESH of integration secrets and keys.
  • ORGANIZATION: properties and the event routing table, plus ORGANIZATION ACCOUNT, PROFILE, USER and USER GROUP.
  • Layout: the account-level kinds are in a new parser/_helpers/ddl/snowflake_alter_account.rs. The policies extend snowflake_alter_resources.rs.
  • Behaviour taken from the receipts, not the pages:
    • A SET of an AS body alone is refused.
    • Organization-qualified account names refuse a reserved keyword in either part.
    • Incomplete kinds are syntax errors. Examples: MASKING v1, DATA POLICY, FAILOVER v1, GROUP, PROFILE, EXTERNAL ACCESS v1.
  • DROP (second commit): DROP AGENT SELECT ; and the same for every Snowflake DROP kind now fail as Snowflake does (errno 1003). The name follows ALTER's object-name rule; "SELECT" is still a name.
  • Tests: these extend tests/parser/test_snowflake_alter.rs and test_fixes.rs.
  • No catalogue changes. main 5581fa5 (fix(syntax): typed Snowflake ALTER of application, backup, Cortex Search, database, semantic view and Streamlit kinds #45) is merged in. The only conflicts were the module list and two parse_account_list helpers, so this PR's is renamed parse_account_names.

Receipt harness: every form in the batch agrees with its receipts, except 6 cases in the ALTER USER [ GROUP ] path, which this PR doesn't touch. By group:

The only other mismatches are unscored observe rows.

Coverage diff: family <f> --json for all ten families. It compares the gate-profile checker of main 5581fa5 with this branch's (c12439e), over catalogue 3296ca1 plus evidence b56cd49:

ddl                  forms +33 -0   obligations +49 -0
security_admin       forms +51 -0   obligations +4159 -0
forms completed: +84 -0; obligations satisfied: +4208 -0

D122 floor: +84 forms against a floor of 67, so this PR gates on form count. The gain by kind:

  • DROP: 33, one per kind.
  • FAILOVER GROUP: 20.
  • ORGANIZATION PROFILE: 3.
  • 2 each: ORGANIZATION, CONNECTION, and the AGGREGATION, BACKUP, DATA MOVEMENT, JOIN, MAINTENANCE, MASKING and SNAPSHOT policies.
  • 1 each: the other policies, NETWORK RULE, and ORGANIZATION SET/UNSET EVENT ROUTING TABLE.

Most of the remaining forms in these kinds already agree with every receipt, but still wait on observe rows or receipts.

Snowflake ALTER of these kinds used to fall back to an opaque statement, which
accepted their documented negatives. They now parse into AlterObject:
- Policies: the AGGREGATION, AUTHENTICATION, BACKUP, DATA MOVEMENT, FEATURE,
  INGRESS, JOIN, MAINTENANCE, MASKING, MULTI PARTY APPROVAL, NETWORK, PACKAGES,
  PASSWORD, SESSION and SNAPSHOT policies, and NETWORK RULE. ALTER SESSION
  POLICY no longer falls into ALTER SESSION. That covers BODY -> <expr>, AS bodies
  and ADD/REMOVE lists. A SET of an AS body alone is refused, as the receipts
  show.
- FAILOVER and REPLICATION GROUP: ADD/REMOVE to the allowed lists, MOVE to a
  group of the same kind, PRIMARY (failover only), REFRESH, RESUME,
  SUSPEND [IMMEDIATE], RENAME, SET/UNSET and TAG. A SET list value runs to the
  next `<name> =`, and an integration type may be two words.
- CONNECTION: PRIMARY, ENABLE/DISABLE FAILOVER, SET/UNSET COMMENT.
- [ <type> ] INTEGRATION (API, CATALOG, EXTERNAL ACCESS, NOTIFICATION,
  SECURITY, STORAGE): SET properties with parenthesized lists and key/value
  pairs, UNSET, TAG, and REFRESH of its secrets and keys.
- ACCOUNT, current or named: properties, TAG, CONTACT, policies with
  FOR ALL ... and FORCE, RENAME TO [ SAVE_OLD_URL ], DROP OLD [ ORGANIZATION ]
  URL, and ADD/REMOVE ORGANIZATION USER GROUP.
- ORGANIZATION: SET/UNSET properties and the event routing table, ORGANIZATION
  ACCOUNT, PROFILE, USER and USER GROUP.
Organization-qualified account names refuse a reserved keyword as either part.
Incomplete kinds, such as MASKING v1, DATA POLICY, FAILOVER v1, GROUP,
PROFILE and EXTERNAL ACCESS v1, are syntax errors.
DROP of the Snowflake object kinds took any table reference as the name, so
`DROP AGENT SELECT ;` parsed although Snowflake refuses it with errno 1003.
The name now goes through the same object-name rule as ALTER: an identifier,
never a string or an unquoted reserved keyword. A quoted `"SELECT"` is still
a name.
…olicies

# Conflicts:
#	crates/sqlquack-syntax/src/parser/_helpers/ddl/mod.rs

kvlonge commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

D94 gate for this PR:

  • Head c12439e, tree 5fa7938ce8b158fa4abe2f43ae186f6b89e17783. main 5581fa5 is its ancestor, so the merge tree is this gated tree.
  • CARGO_BUILD_JOBS=2 RUST_TEST_JOBS=1 RUST_TEST_THREADS=2 make check-merge RECORDER=0: exit 0. All 23 Rust test binaries passed.
  • Coverage diff against main 5581fa5 (catalogue 3296ca1, evidence b56cd49): forms +84 −0, obligations +4,208 −0.
  • Hygiene scan of the outgoing diff: 0 hits. Commit identities are the noreply address only, with no trailers.

@kvlonge
kvlonge merged commit deaa882 into main Nov 4, 2026

kvlonge commented Nov 4, 2026

Copy link
Copy Markdown
Contributor Author

Re-gate of the merge result (D94 remedy, D122d): main deaa882ea17d615caa7dafc9ffd7e8a6e7a4381c, tree d4208862cea0d0b67dfae93515526ad2e2652272 (the merge tree, which differed from the gated tree c12439e because #47 landed first).

CARGO_BUILD_JOBS=2 RUST_TEST_JOBS=1 RUST_TEST_THREADS=2 make check-merge RECORDER=0 → exit 0. All test results report 0 failed. No revert needed.

kvlonge added a commit that referenced this pull request Nov 4, 2026
Basis: main deaa882 (PR #43), catalogue 97db46c, evidence a1c9e0f,
parser tree a4401f7.

- 81 newly approved forms (security_admin 47, ddl 34), read against their
  pinned pages and raw parser trees; M2 agrees on every case.
- Not approved: alter-maintenance-policy.unset (catalogue: all-optional
  UNSET positive), and alter-connection.disable-failover plus
  alter-failover-group add/remove allowed accounts (parser: the
  <org>.<account> operand collapses into one unquoted name).
- 8 earlier reviews are stale on re-rendered cases that still await
  receipts; drop-sequence stays withheld until PR #46.

Checker at deaa882: valid, 3476 forms; 1384 of 3348 verified.
@kvlonge
kvlonge deleted the fix/snowflake-alter-policies branch November 9, 2026 21:31
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