Repository navigation
Fix parser gaps: empty arguments, type parameters, reserved names, anonymous procedures, tree findings - #38
Merged
Merged
Conversation
Snowflake rejects calls such as TO_DECIMAL(1, ) and F(a, , b) with a syntax error; the parser skipped the empty argument and accepted them.
Snowflake rejects TIME(), VARBINARY(), NUMBER(), NUMBER(9,) and PERIOD() with a syntax error. CHAR(), VARCHAR() and STRING() stay accepted, as does RETURNS TABLE ().
Snowflake rejects DROP TABLE SELECT, DROP INDEX v1.SELECT, UNDROP ... RENAME TO SELECT, TRUNCATE SELECT, USE SELECT, DECLARE SELECT RESULTSET and CAST(x AS SELECT); quoted names such as "SELECT" stay accepted. The check applies to the names these statements parse, not to every table reference, so FROM TABLE(...) and RETURNS TABLE (...) are unaffected. Adds parser tests for the rejected statements and their accepted neighbours, including the empty-argument and type-parameter fixes.
WITH <name> AS PROCEDURE (...) RETURNS ... LANGUAGE ... [options] [AS body] followed by CALL <name>(...) [INTO :var] now parses to a structured Call that keeps its WITH clause, instead of failing. The procedure is a CreateProcedure CTE; RETURNS TABLE columns, handler options and the body are kept, and a LANGUAGE SQL body is parsed as Snowflake Scripting so a broken body fails. Snowflake CTEs also need AS and an unreserved name. All 280 recorded WITH ... AS PROCEDURE cases now agree with Snowflake's phase.
…tree A faithful Snowflake parse now records what was written: - an unquoted date part in DATEDIFF, TIMEDIFF, TIMESTAMPDIFF, EXTRACT(part, x) and TRUNC(x, part) is a date part, not a column; TRUNC(x, c1) stays a column; - ORDER BY ALL is an OrderBy.all node with its direction, not a sort key; - unary + is a Pos node instead of being dropped; - CURRENT_ORGANIZATION_USER without parentheses is a no_parens call. Lineage checks and typing treat Pos like Neg and read OrderBy.all. The WITH clause's trailing statement moves to its own module to keep entry.rs within its size limits.
An [[unobservable]] entry may set cause = "not_submitted" for cases that were never sent to Snowflake, such as side-effecting calls a capture guard holds. It has no runs or probes, and its obligation reports unverifiable_not_submitted instead of unverifiable_internal_error, kept in the denominator and never satisfied. An absent cause keeps today's 603 meaning; any other value is refused.
…nt state A form's definition hash now covers its [[reading]] from limits.toml, so editing a reading stales that form's per-form review and no other. Forms without a reading keep their hash. limits.toml is required; a duplicate reading or one naming an uncatalogued form is refused. Receipts may carry an optional account_state (D120): account parameters by name, each with a value (or null) and a basis. It is validated, shown on each case result, and changes no verdict.
A reading's grammar_sha256 may be a prose heading, as its form's is, and a lexical form's reading may have no grammar lines when its reason explains it. 54 readings in the catalogue have one or both.
Unary plus is now a kept_node entry: the trees must match once SQLQuack's pos wrappers are removed. Snowflake-only rejections cover a CTE without AS, a reserved CTE or TRUNCATE name, an empty named argument, and the reserved NOT in a typed-expression type, each pinned by a parser test.
# Conflicts: # crates/sqlquack-syntax/tests/parser/test_fixes.rs
Contributor
Author
|
Merged as a2c64d6 (parents 4a8656b, 736cf93) after a local gate (D94): D122a floor: 67 forms (2% of 3,348). This batch gains +84 forms and +456 obligations, with 0 forms and 0 obligations lost (coverage diff against main be4dfac), so it clears the floor by 17. It also carries #39's checker changes: the |
kvlonge
added a commit
that referenced
this pull request
Nov 4, 2026
Basis: main 00e831a (PR #38, #39, #40), catalogue 5f35885, evidence 469edde, parser tree 08415e1. - 68 rebinds (ddl 1, expressions 6, functions 59, query 2): #39 put [[reading]] grammars into the definition hash; each fingerprint equals one an earlier full-read review approved. - 149 newly approved forms (ddl 71, functions 56, scripting 14, expressions 5, query 2, transaction_session 1), read against their pinned pages and raw parser trees. - Not approved: 37 forms with catalogue findings and 1 withhold (sf.ddl.drop-sequence: RESTRICT is dropped from the tree). Checker at 00e831a: valid, 3476 forms; 1239 of 3348 verified.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Parser fixes from the ranked parser-gap list (#1, #3, #4, #12) and the auditor's D118 parser-tree findings.
Syntax (Snowflake agrees by receipt):
TO_DECIMAL(1, ),F(a, , b)).TIME(),VARBINARY(),NUMBER(),NUMBER(9,),PERIOD()).CHAR(),VARCHAR(),STRING()andRETURNS TABLE ()stay accepted.FROM TABLE(...)is unaffected.WITH <name> AS PROCEDURE ... CALL <name>(...) [INTO :v]into a structuredCallthat keeps its WITH clause. A LANGUAGE SQL body is parsed as Snowflake Scripting, so a broken body fails. Snowflake CTEs also need AS and an unreserved name. All 280 recordedWITH ... AS PROCEDUREcases agree with Snowflake's phase.Tree (auditor D118 withholds):
ORDER BY ALLisOrderBy.allwith its direction.+is kept as aPosnode.CURRENT_ORGANIZATION_USERis a no_parens call.PoslikeNegand readOrderBy.all. No recorded case uses unary + or ORDER BY ALL, and the converter refused both shapes before.Coverage diff (
syntax-coverage family <f> --jsonfor each family, base parser 4391b71 vs this head; catalogue 7522b4e, evidence b326079, reviews wip/syntax-omission-audit e24f3c7):forms completed +84, -0; obligations satisfied +456, -0.
ddl +16, dml +1, expressions +4, functions +45, query +1, scripting +15, transaction_session +2; utility obligations +229.
Forms gained
Batched with #39 (D122)
This branch now also carries #39 (feat/unobservable-cause, head 75a66c7):
cause = "not_submitted", readings in definition hashes, and receiptaccount_state. See #39 for details. Both are gated once, at this head; merging this PR lands #39's commits too.Polyglot exact check
The parser fixes changed polyglot comparisons, which are now explained in
corpora/polyglot-check/expected_differences.toml:[[kept_node]]category, with one entry,unary_plus: the trees must be equal once SQLQuack'sposwrappers are removed;NOTas a typed-expression type (DuckDB keeps the original error).Each of these is pinned by a parser test.
Coverage against the D122a floor
On main be4dfac: +84 forms, 0 lost, against a floor of 67 (2% of 3,348); +456 obligations, 0 lost.