You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Commit 0425c84
Browse filesBrowse the repository at this point in the historyBrowse files
feat: support MySQL CTE-prefixed updates and deletes with strict DML syntax
Allow top-level WITH and WITH RECURSIVE to wrap native MySQL UPDATE and
DELETE ASTs. Keep CTE definitions and nested query contexts query-only,
reject WITH INSERT, classify the main statement correctly, and retain
single-target routing metadata. The existing emitter preserves the CTE
and main DML together; local execution and unsupported parameterization
remain guarded.
Validate required UPDATE SET clauses, one-/two-/three-part assignment
names, = and := assignment operators, complete values, WHERE and ORDER BY
operands, and unsigned/identifier/placeholder LIMIT counts. Share value
and LIMIT syntax checks with query expressions. Preserve MySQL's fixed
LOW_PRIORITY/IGNORE UPDATE order and repeated DELETE options. Handle both
multi-table DELETE forms with table.* and schema.table.* targets without
mistaking the wildcard for routing metadata or accepting missing FROM or
USING clauses. Require complete JOIN/ON/USING components and retain quoted
USING column names.
Add 28 focused regression tests and register them in the default suite.
Correct the older ORDER BY/LIMIT fixture to quote its reserved RANK column:
MySQL 8.4.8 rejects the unquoted original with 1064. Extend the independently
specified compatibility corpus by 24 cases and promote the two CTE DML
gaps. Document the 137-case baseline, source provenance and native limits.
Validation:
- Forced full rebuild and corpus-test build, followed by full make all and
make test after the fixture correction: 1,580 passed, 37 external DB tests
skipped. Initial full run exposed only the invalid RANK fixture above.
- ASan/UBSan with leak detection: 64 focused MySQL regression tests passed.
- MySQL harness: 11 tests; all 137 expected outcomes match, with 72 CHECKED,
50 REJECTED and 15 explicitly retained gaps. Verify 134 source anchors
per pinned release. Native 8.4.8 and 9.7.2 show zero validity mismatches;
server errors and three skipped DDL cases stay separately reported.
- PostgreSQL harness: 87 tests; full pinned baseline and 5,122 committed CI
cases unchanged.
- Seven parser/emitter benchmark smoke cases passed; no new speed claim.
- Independent review verified routing metadata, test registration, query
boundaries, emission and execution guards; no unresolved blockers.
Keep PR #67 a work in progress. Benchmark code, reports and benchmark-only
README/.gitignore edits are intentionally excluded from this commit.
Copy file name to clipboardExpand all lines: docs/mysql-compatibility.md
+5-3Lines changed: 5 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -8,6 +8,8 @@ ParserSQL also preserves partition lists, `USE`/`FORCE`/`IGNORE INDEX` or `KEY`,
8
8
9
9
MySQL query expressions also preserve explicit `TABLE name` and `VALUES ROW(...)` constructors in standalone, compound, derived, LATERAL, scalar, IN, EXISTS, and query-only CTE contexts. `INTERSECT` binds more tightly than `UNION` and `EXCEPT`; explicit parentheses and branch-local ordering/limits are retained. Recursive CTEs retain their keyword and optional column lists. Query locking clauses, including `LOCK IN SHARE MODE`, remain structured. This is parser/AST coverage; the local engine rejects unsupported query forms.
10
10
11
+
Top-level MySQL `WITH` and `WITH RECURSIVE` also retain structured UPDATE and DELETE main statements, including join/comma UPDATEs, both multi-table DELETE target-list forms, quoted CTE names, partitions, statement options, and single-table ordering/limits. CTE bodies and subqueries remain query-only; DML inside them and a leading `WITH ... INSERT` are rejected. UPDATE assignments require one-, two-, or three-part column names and accept both `=` and `:=` (emitted as `=`), including `DEFAULT` values. UPDATE options follow `LOW_PRIORITY` then `IGNORE`; DELETE options may appear in any order and repeat. The [8.4.8 UPDATE/DELETE productions](https://github.com/mysql/mysql-server/blob/0896fcd61dec11a0904166911a0126f59daaa1bf/sql/sql_yacc.yy#L13389) and [9.7.2 UPDATE/DELETE productions](https://github.com/mysql/mysql-server/blob/008e09c2834b98143a8c067d4d225c90953050cf/sql/sql_yacc.yy#L13945) attach an optional WITH clause to each main statement. Routing metadata identifies the main DML target, including wildcard DELETE targets. JOIN conditions require complete ON/USING operands and retain quoted USING column names. These are parser/AST guarantees; the local engine rejects CTE-prefixed DML.
12
+
11
13
The native grammar permits empty `VALUES ROW()`, `VALUES ROW(DEFAULT)`, and repeated locking clauses. Both pinned servers return semantic errors 3942, 3943, and 3569 respectively for the curated standalone or overlapping-lock witnesses. These remain `SERVER_ERROR` observations, not syntax rejections, while ParserSQL preserves the grammar-valid ASTs. `TABLE` takes a table identifier and query-level tails; aliases, partitions, index hints, and WHERE clauses directly after its table name are malformed controls. The [8.4.8 query-primary productions](https://github.com/mysql/mysql-server/blob/0896fcd61dec11a0904166911a0126f59daaa1bf/sql/sql_yacc.yy#L9831) and [9.7.2 query-primary productions](https://github.com/mysql/mysql-server/blob/008e09c2834b98143a8c067d4d225c90953050cf/sql/sql_yacc.yy#L10145) include both constructors. The corpus records exact anchors for their rows, subquery contexts, locking, CTEs, and malformed controls.
12
14
13
15
Table identifiers and aliases use the common 259-word reserved baseline observed in the pinned 8.4.8 and 9.7.2 releases. ParserSQL has no MySQL version setting, so the five 9.7-only reserved additions (`CUBE`, `EXTERNAL`, `LIBRARY`, `QUALIFY`, and `TABLESAMPLE`) remain accepted as names. Strict version-specific identifier rules remain a gap.
@@ -46,7 +48,7 @@ Malformed controls are handled separately: a complete AST is `MALFORMED_ACCEPTED
46
48
47
49
Every fixture freezes one exact expected outcome. Known gaps do not make arbitrary failures acceptable. Both regression and unexpected improvement cause exit status 1, so a fixed gap must be reviewed and explicitly promoted in the corpus. When promoting, add an independently derived `expected_sql`, set `known_gap=false`, and require `CHECKED`. Harness/transport/source errors return 2. Exit status 0 means the expected baseline matched, including its documented known gaps.
48
50
49
-
The 113-case baseline has 62`CHECKED` witnesses and 34`REJECTED` negative controls. Its remaining known gaps are ten `TRAILING_INPUT`, three `NO_AST`, two `ERROR`, one `PARTIAL`, and one `EMISSION_MISMATCH`. The two `ERROR` witnesses are CTE-prefixed UPDATE/DELETE: the query-only WITH parser now rejects these unsupported main statements directly. Source verification checks 110 exact grammar anchors per pinned release. These counts describe this corpus only.
51
+
The 137-case baseline has 72`CHECKED` witnesses and 50`REJECTED` negative controls. Its 15 remaining known gaps are ten `TRAILING_INPUT`, three `NO_AST`, one `PARTIAL`, and one `EMISSION_MISMATCH`. CTE-prefixed UPDATE/DELETE now pass complete parse, exact emission, and stable reparse checks. Source verification checks 134 exact grammar anchors per pinned release. These counts describe this corpus only.
50
52
51
53
The JSON report includes all original and reparsed records, source verification counts, pinned revisions, SQL-mode metadata, and SHA-256 hashes of the corpus and probe. Counts apply only to these witnesses. The probe uses hex-line input and hex fields in its TSV response, preserving tabs, newlines and embedded NUL bytes. It emits while both the input string and parser arena are alive; Python reparses owned copies in a second probe invocation.
52
54
@@ -65,9 +67,9 @@ Each curated case explicitly chooses direct query execution, `EXPLAIN` for DML (
65
67
66
68
Native results are stored separately in `native_oracle`: `ACCEPTED`, `SYNTAX_REJECTED` (1064/1149), `SERVER_ERROR`, `CLIENT_ERROR`, or **NOT VERIFIED**. For example, a derived table missing its required alias returns error 1248; this remains a server error, even though the corpus requires ParserSQL to reject that input. Accepted invalid controls and syntax-rejected valid controls count as expectation mismatches, using per-version validity when specified. Server errors remain explicitly unresolved; client errors return status 2. Thus exit status 0 still does not mean all native cases were verified. The default corpus metadata remains **NOT VERIFIED**, while the optional report describes the actual native observations.
67
69
68
-
A native check of all 113 witnesses under `ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION` found no native expectation mismatches. MySQL 8.4.8 accepted 69, syntax-rejected 36, and returned five server errors (two 1248 missing-alias errors, 3942, 3943, and 3569); MySQL 9.7.2 accepted 71, syntax-rejected 32, and returned seven server errors (the same five plus 1235 and 3889). Both runs skipped the three DDL/procedure witnesses and cleaned up their owned schemas. All shared positive query/DML witnesses except the three explicitly grammar-valid semantic-error controls were accepted, including partition selection, index hints, query constructors, and recursive CTEs. Re-run the command on each isolated socket to reproduce current observations; reports are intentionally not committed.
70
+
A native check of all 137 witnesses under `ONLY_FULL_GROUP_BY,STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION` found no native expectation mismatches. MySQL 8.4.8 accepted 77, syntax-rejected 52, and returned five server errors (two 1248 missing-alias errors, 3942, 3943, and 3569); MySQL 9.7.2 accepted 79, syntax-rejected 48, and returned seven server errors (the same five plus 1235 and 3889). Both runs skipped the three DDL/procedure witnesses and cleaned up their owned schemas. All shared positive query/DML witnesses except the three explicitly grammar-valid semantic-error controls were accepted, including partition selection, index hints, query constructors, recursive CTEs, and CTE-prefixed UPDATE/DELETE. Re-run the command on each isolated socket to reproduce current observations; reports are intentionally not committed.
69
71
70
-
The corpus is deliberately selected and is not a representative workload. It contains 109 shared witnesses and four version-specific query witnesses; this does not imply identical dialects in 8.4.8 and 9.7.2. The version-specific entries record `applicability`, source productions for both versions, `native_validity` per version, and observed native outcomes. Their generic `validity=valid` denotes the 9.7.2 grammar target. The native helper selects the intended validity using the actual server version, so an expected 8.4.8 syntax rejection is not treated as a corpus error. Stored native observations are context, not substitutes for a current run. These additions remain ParserSQL gaps. The following differences include those four query witnesses and two separate DDL spot checks:
72
+
The corpus is deliberately selected and is not a representative workload. It contains 133 shared witnesses and four version-specific query witnesses; this does not imply identical dialects in 8.4.8 and 9.7.2. The version-specific entries record `applicability`, source productions for both versions, `native_validity` per version, and observed native outcomes. Their generic `validity=valid` denotes the 9.7.2 grammar target. The native helper selects the intended validity using the actual server version, so an expected 8.4.8 syntax rejection is not treated as a corpus error. Stored native observations are context, not substitutes for a current run. These additions remain ParserSQL gaps. The following differences include those four query witnesses and two separate DDL spot checks:
71
73
72
74
| Reduced feature | MySQL 8.4.8 observation | MySQL 9.7.2 observation |
0 commit comments