Skip to content

Snowflake DESCRIBE/SHOW, audit withholds, coverage-diff regression line, DuckShop functions - #49

Merged
kvlonge merged 12 commits into
mainfrom
fix/parser-gaps-d
Nov 5, 2026
Merged

kvlonge merged 12 commits into
mainfrom
fix/parser-gaps-d

Conversation

@kvlonge

@kvlonge kvlonge commented Nov 5, 2026 •

Copy link
Copy Markdown
Contributor

Batch fix/parser-gaps-d (D122/D122a). It has typed Snowflake DESCRIBE and SHOW, parser fixes from the omission audit, the DuckShop driver change, and the coverage-diff regression line (D122 decision after #45/#48).

Coverage against main 2f0c38a (head b323a31, which contains main 5cfdde2; #50 does not touch the syntax crate) (both sides on the same combined tree: catalogue + evidence + audit): forms +69 −1, obligations +1,095 −0. The D122a floor is 67 forms (2% of 3,348), so this clears it by 2.

  • The one form shown as lost, sf.functions.approx-count-distinct.approx-count-distinct-over, is a stale review, not a lost obligation: all 17 of its obligations stay satisfied. The auditor approved it when APPROX_COUNT_DISTINCT ( DISTINCT 1 , 1 ) dropped DISTINCT. Withhold (3) below fixes that tree, so the fingerprint changed and the form needs re-review.
  • New regression line: Snowflake-parsed receipted cases that main accepts and this head rejects: 0.

Parser (Snowflake only):

  • DESCRIBE reads every documented kind and keeps the name. Before, DESC WAREHOUSE v1 took WAREHOUSE as the target and dropped v1, DESC DATABASE and DESC SCHEMA did the same, and multi-word kinds didn't parse. It also keeps TYPE, REVISION, IN APPLICATION and AS RESOURCE.
  • SHOW reads a documented kind, then LIKE, IN with the containers that kind takes, the kind's follow-ups (FOR PACKAGE, RUN, FOR METRIC…), STARTS WITH and LIMIT … FROM as strings, and WITH PRIVILEGES as a list. A reserved word is now refused in any dotted part of an object name.
  • PIVOT/UNPIVOT; a join's FIRST|LAST ( alias ); TRUNCATE ERROR_TABLE; a failover account's <org>.<account> kept apart with its quoting (auditor withhold).
  • Auditor withholds after Snowflake parser fixes from syntax coverage, DuckShop driver and translation measure #46/fix(syntax): parse Snowflake ALTER APPLICATION ROLE and DATABASE ROLE by their grammar #48: SELECT ALL (select.all), DISTINCT on a multi-argument aggregate, TIMESTAMP WITHOUT TIME ZONE → TIMESTAMP_NTZ, START TRANSACTION NAME as the name, and USE SECONDARY ROLES as a list (use.roles). The INSERT DEFAULT withhold was withdrawn; that tree is unchanged.

Coverage checker: snapshots list the receipted cases Snowflake parsed, split into accepted and rejected. diff fails on base acceptances, opaque or not, that the head rejects. That is the #45 role regression's blind spot. I checked it on the 42 role cases: it reports all 42 and exits 1.

DuckShop driver (coordinator ruling a–c): schema --functions writes the functions section. snowflake --functions --schema converts each SQL function with sqlquack function and creates it as a DuckDB macro before models run. Models that call a Python function report python_udf_not_measured and are not scored. sqlquack function now resolves __ref(…) the way census does, so DuckShop's two table functions convert. All 3 SQL functions convert, create and run.

Exact-check fixes after the first gate (accaaa3, exit 2, only the runs binary failed): SHOW PRIMARY/UNIQUE/IMPORTED/EXPORTED KEYS goes back to the shared SHOW, which already read them. SELECT ALL and the DESCRIBE property stop now apply to Snowflake only, so PostgreSQL EXPLAIN options and SQLite trees are unchanged. 12 statements now refused in Snowflake are reviewed [[rejection]] entries: DESCRIBE without a kind, plus MySQL/Hive SHOW and DESCRIBE forms. A new [[kept_field]] kind (documented in docs/syntax.md, with a matching test) covers the secondary-role list, the container kind of SHOW … IN a.b that polyglot infers as SCHEMA, and the TIMESTAMP_NTZ target of TIMESTAMP WITHOUT TIME ZONE.

From the parser-only disagreements, each checked against receipts:
- a PIVOT aggregate is a call of a column: a parenthesised column or a
  string argument is a syntax error, as is a string alias;
- a PIVOT IN list is not empty, and ANY ORDER needs BY;
- PIVOT and UNPIVOT IN values take an alias without AS;
- an UNPIVOT IN list holds columns, not strings, and its name column is
  no reserved keyword.
Snowflake documents [ { FIRST | LAST } ( <alias> ) ] after a join's ON
or USING. The join keeps it as first_last and first_last_alias, left
out of the tree when absent; the alias refuses a reserved keyword, as
recorded. The classifier names it join_first_last, and conversion,
which accepts only the join fields it understands, refuses it.
ALTER FAILOVER GROUP / REPLICATION GROUP ADD|REMOVE accounts and ALTER
CONNECTION ENABLE|DISABLE FAILOVER TO ACCOUNTS read <org_name>.<account_name>
as a table reference: the account as its name, the organization as its
schema, each keeping its own quoting. The joined string lost both the
split and the quoting. Verdicts do not change.
…ame )

TRUNCATE [ TABLE ] [ IF EXISTS ] ERROR_TABLE ( <table> ) parses, with
error_table on the tree (left out when false). In SQLQuack's own modes
TRUNCATE ( name ) is a bare call, not a statement, as Snowflake refuses
it; the exact check's modes still read it as polyglot does.
…n-UDF models unmeasured

- `schema --functions` writes the compiled functions beside the relations.
- `snowflake --functions --schema` converts each SQL function with
  `sqlquack function` and creates it as a DuckDB macro before models run.
  A function that is refused or cannot be created makes the models calling
  it input_unloadable, never a mismatch.
- Models calling a Python function report python_udf_not_measured and are
  not compared or scored.
- `sqlquack function` resolves sqlbuild references (`__ref(...)` and kin)
  in the body to the census placeholder relations, as census does for
  models; DuckShop's two table functions read models through `__ref`.
…d and now rejects

A snapshot now lists the receipted cases Snowflake parsed, split into those
the parser accepts (opaque or not) and those it rejects. diff reports base
acceptances the head rejects as a regression, by case. An opaque acceptance
satisfies no obligation, so a move from it to a rejection changed no form or
obligation and passed unseen.
DESC WAREHOUSE v1 parsed WAREHOUSE as the target and dropped v1; DESC
DATABASE and DESC SCHEMA did the same, and multi-word kinds such as COMPUTE
POOL or FILE FORMAT did not parse. Snowflake DESCRIBE now reads every kind
the catalogue documents, then the name and that kind's options (TYPE,
REVISION, IN APPLICATION, AS RESOURCE), and refuses an unknown kind or a
bare name. The shared DESCRIBE no longer drops a word that is not a
property.
The shared SHOW folded every word up to a clause keyword into the kind, so
SHOW DATABASES WITH USAGE, SHOW POOLS or SHOW OFFERS IN LISTING v1 parsed
with the clauses swallowed or dropped. Snowflake SHOW now reads a
documented kind, then LIKE, IN with the containers that kind takes (some
kinds need one), the follow-up a kind takes (FOR PACKAGE, RUN, FOR
METRIC...), STARTS WITH and LIMIT ... FROM with strings, and WITH
PRIVILEGES as a list. GRANTS, PARAMETERS, USER and a few others keep the
shared reading. An object name now refuses a reserved word in any dotted
part, not only the first.
…on names and role lists

From the omission audit after #46 and #48:
- SELECT ALL sets select.all; it was consumed and dropped.
- An aggregate of several arguments, such as APPROX_COUNT_DISTINCT
  ( DISTINCT a , b ), keeps distinct; the generic call dropped it.
- TIMESTAMP [ ( p ) ] WITHOUT TIME ZONE is TIMESTAMP_NTZ, as its synonyms
  are, not bare TIMESTAMP (whose meaning follows TIMESTAMP_TYPE_MAPPING).
- START TRANSACTION NAME n keeps n as the name, quoting kept, apart from NAME.
- USE SECONDARY ROLES lists each role with its quoting in use.roles.
… kept fields

The gate's exact check found the batch's Snowflake trees and refusals
unreviewed. SHOW of PRIMARY, UNIQUE, IMPORTED and EXPORTED KEYS goes back to
the shared SHOW, which read them before; SELECT ALL and the DESCRIBE property
stop apply to Snowflake only, so other dialects keep their trees.

The 12 statements now refused in Snowflake (a DESCRIBE without a kind, MySQL
and Hive SHOW and DESCRIBE forms) are reviewed rejections. A new kept_field
entry covers a field SQLQuack keeps as written where polyglot drops or infers
it: the secondary role list, the container kind of SHOW ... IN a.b, and the
TIMESTAMP_NTZ target of TIMESTAMP WITHOUT TIME ZONE.
@kvlonge
kvlonge merged commit b323a31 into main Nov 5, 2026

kvlonge commented Nov 5, 2026

Copy link
Copy Markdown
Contributor Author

Landed as a fast-forward of main (D122d): git push github b323a31e:main, 5cfdde2..b323a31. Main is now b323a31.

  • Gate (local, D94): make check-merge RECORDER=0 on the exact head b323a31 (main 5cfdde2 merged in) exited 0. The first gate, on accaaa3, exited 2. Only the polyglot exact check (runs) failed; the fixes are in 174f4f1 and are listed in the PR body.
  • Trees: main's tree is a89362b7, the same as the gated head's tree (a89362b7). There is no merge commit: main is the gated commit.
  • Coverage against main 2f0c38a (same combined tree on both sides; feat: DuckShop batch 3, PIVOT in FROM and TIMESTAMP_TZ refusal guidance #50 does not touch the syntax crate): forms +69 −1, obligations +1,095 −0. The D122a floor is 67 forms, so this clears it by 2.
    • The −1 is sf.functions.approx-count-distinct.approx-count-distinct-over, which is now a stale review. All 17 of its obligations stay satisfied. Its tree changed because withhold (3) now keeps DISTINCT, so it needs re-review.
  • Snowflake-parsed cases the parser now rejects: 0.

kvlonge added a commit that referenced this pull request Nov 5, 2026
Basis: main b323a31 (PR #49), catalogue f61d213, evidence b22649e,
parser tree 8067a98.

- 117 forms approved (ddl 69, security_admin 33, functions 6, query 4,
  expressions 2, transaction_session 2, dml 1): typed DESCRIBE and SHOW,
  the cleared withholds (APPROX_COUNT_DISTINCT DISTINCT and -over,
  TIMESTAMP WITHOUT TIME ZONE, START TRANSACTION NAME, USE SECONDARY
  ROLES, the <org>.<account> forms) and re-reads of stale reviews.
- Not approved: 7 catalogue findings (insert, unpivot, reduce,
  show-classes, show-databases, show-models, show-replication-databases)
  and 2 parser withholds (SELECT RENAME alias quoting, PIVOT alias
  quoting).

Checker at b323a31: valid, 3476 forms, 0 problems; 1575 of 3348 verified.
@kvlonge
kvlonge deleted the fix/parser-gaps-d 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