Support the unsupported features from the clause-level MySQL 26.7 sweep - #44
Merged
Merged
Conversation
…lists, and LOCK TABLES aliases Implement the mysql_unsupported_txn coverage group (MySQL 26.7 §15.3.1, §15.3.6): its error goldens turn into Restore() goldens. - BEGIN WORK, COMMIT WORK, and ROLLBACK WORK accept the optional WORK keyword; Restore() drops it, matching the existing BEGIN -> START TRANSACTION canonicalization. - START TRANSACTION now parses a comma-separated transaction characteristic list (WITH CONSISTENT SNAPSHOT | READ WRITE | READ ONLY), keeping the TiDB READ ONLY AS OF and WITH CAUSAL CONSISTENCY ONLY extensions. - LOCK TABLES accepts [[AS] alias] per table (new TableLock.Alias field, restored with AS) and the deprecated LOW_PRIORITY WRITE lock type (new TableLockWriteLowPriority appended to the TableLockType enum). Keyword tables: WORK becomes an unreserved keyword; TestKeywordsLength count updated. testdata/errors.json is unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
…and REPLICA STATUS FOR CHANNEL Implement the mysql_unsupported_show coverage group (MySQL 26.7 §15.7.7): its error goldens turn into Restore() goldens. - SHOW STORAGE ENGINES parses; Restore() canonicalizes to SHOW ENGINES. - SHOW WARNINGS and SHOW ERRORS accept SelectStmtLimitOpt, stored in the existing ShowStmt.Limit field and restored after the keyword. - SHOW EXTENDED INDEX/INDEXES/KEYS FROM|IN parses, reusing ShowStmt.Extended; ShowIndex Restore() now writes the EXTENDED prefix. - SHOW REPLICA STATUS accepts FOR CHANNEL, stored in the existing ShowStmt.ChannelName field and restored after the keyword. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
…ATTRIBUTE, ALTER DATABASE READ ONLY, and bare WITH CHECK OPTION
Implement the mysql_unsupported_ddl coverage group (MySQL 26.7 §15.1):
its error goldens turn into Restore() goldens.
- The AUTOEXTEND_SIZE table option now also accepts an integer literal
value (previously only StringName forms like '4M' parsed).
- CREATE TABLE ... START TRANSACTION parses as a new
TableOptionStartTransaction table option (parsed and carried through
Restore; like AUTOEXTEND_SIZE it has no storage-engine effect here).
- ENGINE_ATTRIBUTE joins SECONDARY_ENGINE_ATTRIBUTE as an index option
(new IndexOption.EngineAttr field).
- ALTER DATABASE ... READ ONLY = {DEFAULT | 0 | 1} parses as a new
DatabaseOptionReadOnly database option.
- CREATE VIEW and ALTER VIEW accept WITH CHECK OPTION without a
CASCADED/LOCAL qualifier, meaning CASCADED as in MySQL.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
… BINARY LOGS AND GTIDS TO Implement the mysql_unsupported_replication coverage group (MySQL 26.7 §15.4.2.1, §15.4.1.2): its error goldens turn into Restore() goldens. ReplicationSourceOption gains three value forms beyond literals, each a new backwards-compatible field selected by the option name: - IGNORE_SERVER_IDS = (n, ...) parses into ServerIDs (non-nil but empty for an empty list, so () round-trips). - PRIVILEGE_CHECKS_USER takes an account name (User) or NULL. - REQUIRE_TABLE_PRIMARY_KEY_CHECK and ASSIGN_GTIDS_TO_ANONYMOUS_TRANSACTIONS take bare keyword values (STREAM, GENERATE, ON, OFF, LOCAL), stored uppercase in KeywordValue; the ASSIGN_GTIDS uuid string form stays a literal Value. ChangeReplicationSourceStmt.Accept now skips options without a literal Value instead of dereferencing nil. RESET BINARY LOGS AND GTIDS accepts the TO binary_log_file_index_number clause (new ResetBinaryLogsAndGtidsStmt.To field, zero when absent). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
…ble wildcards Implement the mysql_unsupported_utility coverage group (MySQL 26.7 §15.8.2): its error goldens turn into Restore() goldens. - The FORMAT = value of EXPLAIN [ANALYZE] now also accepts a bare identifier (e.g. TREE), yielding its spelling like the keyword alternatives; Restore() writes formats as quoted strings, unchanged. - EXPLAIN FORMAT = ... INTO @var parses into the new ExplainStmt.IntoVar field, restored between the format and the explained statement. - DESCRIBE tbl 'wildcard' parses the column wildcard into the inner ShowStmt's existing Pattern field (a LIKE pattern, as SHOW COLUMNS does); the DESC form of ExplainStmt Restore() writes it as a plain string since DESC does not accept a charset-prefixed literal. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
…nsions, FLUSH variants, and SET PERSIST Implement the mysql_unsupported_admin coverage group (MySQL 26.7 §15.7): its error goldens turn into Restore() goldens. - ANALYZE TABLE ... UPDATE HISTOGRAM gains USING DATA 'json' (new AnalyzeTableStmt.HistogramData field) and the AUTO/MANUAL UPDATE clause (new HistogramUpdate field with HistogramUpdateType), composing with WITH n BUCKETS. - INSTALL COMPONENT ... SET now works with PERSIST-scoped assignments (see below). - DROP RESOURCE GROUP accepts FORCE (new field); SET RESOURCE GROUP accepts FOR thread_id, ... (new ThreadIDs field). - FLUSH gains OPTIMIZER_COSTS and USER_RESOURCES option types, RELAY LOGS [FOR CHANNEL ch] (new LogTypeRelay and Channel field), TABLES ... FOR EXPORT (new ForExport field), and comma-separated option lists (new MoreOptions field; the option rendering split into restoreOption). - SET PERSIST / PERSIST_ONLY parse as new VariableAssignment IsPersist/IsPersistOnly flags (also implying IsGlobal), restored as @@persist./@@PERSIST_ONLY. system variables; the lexer's @@ prefix list learns those spellings so the restored form round-trips. Scopes mix freely in one SET list. Keyword tables: AUTO, EXPORT, OPTIMIZER_COSTS, PERSIST_ONLY, RELAY, and USER_RESOURCES become unreserved keywords; TestKeywordsLength counts updated. testdata/errors.json is unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
…T (expr) with operators
Implement the mysql_unsupported_types coverage group (MySQL 26.7
§13.1.20, §15.1.9): its error goldens turn into Restore() goldens.
- VISIBLE and INVISIBLE parse as column attributes (new
ColumnOptionVisible/ColumnOptionInvisible), covering CREATE TABLE,
ADD/MODIFY COLUMN, and the GIPK SHOW CREATE TABLE round-trip through
the /*!80023 ... */ versioned comment.
- ALTER TABLE ... ALTER COLUMN col SET {VISIBLE|INVISIBLE} parses as a
new AlterTableAlterColumnVisibility spec, reusing the existing
AlterTableSpec.Visibility field.
- ENGINE_ATTRIBUTE joins SECONDARY_ENGINE_ATTRIBUTE as a column
attribute (new ColumnOptionEngineAttribute), with and without =.
- DEFAULT (expr): when the goyacc-shaped '('-led DefaultValueExpr
alternatives do not span the parentheses, the content reparses as a
full parenthesized expression, so operators and INTERVAL arithmetic
parse. BinaryOperationExpr defaults restore inside parentheses, which
MySQL requires; other shapes keep their existing Restore() output.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
Implement the mysql_unsupported_compound coverage group (MySQL 26.7
§15.6.5, §15.6.7.1): its error goldens turn into Restore() goldens.
- DECLARE name CONDITION FOR {SQLSTATE [VALUE] 'x' | mysql_error_code}
parses as a new ProcedureConditionDecl declaration, and handler
condition lists accept a declared condition name (new
ProcedureErrorName ErrNode).
- [label:] LOOP ... END LOOP [label] parses as a new ProcedureLoopStmt,
joining WHILE/REPEAT in the unlabeled and labeled loop productions.
Keyword tables: CONDITION and LOOP become reserved words, matching
their MySQL 26.7 classification; GET DIAGNOSTICS ... CONDITION now
matches the token instead of an identifier spelling.
TestKeywordsLength counts updated. testdata/errors.json is unaffected.
ProcedureJump (LEAVE/ITERATE) restored its label as a quoted string
literal, which does not re-parse; it now restores as an identifier.
The test-only nodeTextCleaner also learns to clean the statements of a
ProcedureBlock, whose Accept deliberately does not traverse them, so
procedure bodies compare deep-equal in the round-trip harness.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
…nt, derived-table column lists, and LOAD DATA options Implement the mysql_unsupported_dml coverage group (MySQL 26.7 §15.2.13, §15.2.9): its error goldens turn into Restore() goldens. - SELECT ... INTO OUTFILE accepts CHARACTER SET (new SelectIntoOption.Charset field), in both the mid-statement and trailing INTO positions. - A SELECT may carry several locking clauses (FOR SHARE OF t1 NOWAIT FOR UPDATE OF t2 SKIP LOCKED): the first stays in SelectStmt.LockInfo and the rest land in the new MoreLockInfos field; the lock rendering moved into a restoreSelectLockInfo helper shared by both. - The SelectStmtIntoOption also parses between the limit and locking clauses (SELECT ... INTO @A FOR UPDATE); Restore() keeps the trailing position, which MySQL also accepts. - Derived tables accept the column alias list ((VALUES ...) AS v (c1, c2)), filling the existing TableSource.ColumnNames field that only LATERAL tables populated. - LOAD DATA gains CONCURRENT (new field, mirroring LoadXMLStmt), PARTITION (p, ...) (new Partitions field), and IGNORE n ROWS (canonicalized to LINES like LOAD XML). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
…and SOUNDS LIKE Implement the mysql_unsupported_functions coverage group (MySQL 26.7 §14.17.6, §14.17.3, §14.10): its error goldens turn into Restore() goldens. - JSON_TABLE(expr, path COLUMNS (...)) parses as a table factor: new JSONTableExpr ResultSetNode (ast/mysql_json.go) with JSONTableColumn covering FOR ORDINALITY, typed PATH columns with ON EMPTY/ON ERROR responses, EXISTS PATH, and NESTED PATH sub-columns. The shared JSONOnResponse node models NULL/ERROR/DEFAULT v ON EMPTY|ERROR. - JSON_VALUE with RETURNING and/or ON EMPTY/ON ERROR parses as a new JSONValueExpr; the plain two-argument call stays a generic FuncCallExpr, selected by speculation. - CAST accepts AT TIME ZONE 'tz' between the expression and AS (new FuncCastExpr.AtTimeZone field) and NCHAR[(n)] as a cast type (canonicalized to CHAR in the national character set). - expr SOUNDS LIKE expr parses, desugaring to SOUNDEX(l) = SOUNDEX(r) as MySQL defines the operator. Keyword tables: NESTED, ORDINALITY, PATH, RETURNING, SOUNDS, and ZONE become unreserved keywords, and EMPTY (whose token existed unused) joins the tables; TestKeywordsLength counts updated. testdata/errors.json is unaffected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
…ollar quoting, and the USING clause Implement the mysql_unsupported_routines coverage group (MySQL 26.7 §15.1.17, §11.1.1, §15.1.19): its error goldens turn into Restore() goldens. - CREATE PROCEDURE now accepts the full routine characteristic list (COMMENT, LANGUAGE, [NOT] DETERMINISTIC, CONTAINS/NO SQL, READS/MODIFIES SQL DATA, SQL SECURITY), reusing the RoutineCharacteristics machinery CREATE FUNCTION already had (new ProcedureInfo.Characteristics field). - Dollar-quoted strings ($$...$$ and $tag$...$tag$) lex as string literals; an opening tag without a matching closing tag falls back to the '$'-led identifier reading. Restore() writes them as ordinary quoted strings. - LANGUAGE JAVASCRIPT bodies: CREATE PROCEDURE and CREATE FUNCTION accept AS 'code' (string or dollar-quoted) via the new CodeBody fields, plus the USING (library [AS alias], ...) imports clause (new RoutineImport node and Imports fields). CREATE LIBRARY $$-bodies now parse through the same lexer change. - ProcedureInfo.Accept no longer dereferences a nil body. Restore() prints procedure parameter types via CompactStr, which substitutes default display widths; the round-trip harness canonicalizes parsed parameter types the same way and clears the recorded parameter source text (test-only nodeTextCleaner cases). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
…OLE, GRANT AS, and the REVOKE variants
Implement the mysql_unsupported_account coverage group (MySQL 26.7
§15.7.1): its error goldens turn into Restore() goldens.
- IDENTIFIED [WITH plugin] BY RANDOM PASSWORD parses (new
AuthOption.ByRandomPassword), and every auth option accepts the
dual-password clauses REPLACE 'current' and RETAIN CURRENT PASSWORD
(new ReplacePassword/RetainCurrentPassword fields). ALTER USER ...
DISCARD OLD PASSWORD parses as an AuthOption carrying only the new
DiscardOldPassword flag.
- Multi-factor authentication: user specs chain AND IDENTIFIED ...
factors (new UserSpec.MoreAuthOpts), and ALTER USER gains
ADD/MODIFY/DROP n FACTOR plus the n FACTOR INITIATE/FINISH
REGISTRATION and UNREGISTER steps (new AlterUserFactor clause and
AlterUserStmt.Factors field).
- CREATE USER and ALTER USER accept DEFAULT ROLE {NONE | ALL | roles}
(new UserDefaultRoles clause), and the PASSWORD REQUIRE CURRENT
[OPTIONAL] account policies join the existing DEFAULT form (whose
Restore case was missing).
- GRANT role TO user accepts WITH ADMIN OPTION (new
GrantRoleStmt.AdminOption), and GRANT ... accepts AS user [WITH ROLE
DEFAULT|NONE|ALL|ALL EXCEPT r...|r...] (new GrantAs clause reusing
SetRoleStmtType).
- REVOKE gains IF EXISTS and IGNORE UNKNOWN USER on both the privilege
and role forms, and REVOKE PROXY ON user FROM users parses as a new
RevokeProxyStmt mirroring GrantProxyStmt.
- SET PASSWORD gains TO RANDOM, REPLACE 'old', and RETAIN CURRENT
PASSWORD (new SetPwdStmt fields).
Keyword tables: CHALLENGE_RESPONSE, FACTOR, FINISH, INITIATE, OLD,
RANDOM, REGISTRATION, RETAIN, and UNREGISTER become unreserved
keywords; TestKeywordsLength counts updated. testdata/errors.json is
unaffected.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
With every case now supported, the mysql_unsupported_* names no longer describe their contents. Following the #39-#41 precedent of renaming an implemented group, the seven groups whose mysql_* counterpart already exists (txn, dml, ddl, admin, show, replication, compound) have their cases appended to it, and the five without one (types, functions, routines, account, utility) are renamed to mysql_<name>. No case or golden changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg
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.
Summary
#43 recorded 148 parse gaps from the clause-level MySQL 26.7 sweep as error goldens across twelve
mysql_unsupported_*test groups. This PR implements all of them: every-- errorsegment in those groups became aRestore()golden, one commit per group.With nothing left unsupported, a final commit folds the
mysql_unsupported_*groups away, following the #39–#41 renaming precedent: the seven groups whosemysql_*counterpart already exists (txn, dml, ddl, admin, show, replication, compound) have their cases appended to it, and the five without one are renamed tomysql_types,mysql_functions,mysql_routines,mysql_account, andmysql_utility. No case or golden changes in that commit.Per the repo's rules, every AST change is additive (new node types and fields; enum values appended so existing values keep their numbers), the public parser API is unchanged, and
testdata/errors.jsonis unaffected.What each group gained
mysql_txnBEGIN/COMMIT/ROLLBACK WORK,START TRANSACTIONcharacteristic lists,LOCK TABLESaliases (newTableLock.Alias) andLOW_PRIORITY WRITEmysql_showSHOW STORAGE ENGINES,SHOW WARNINGS/ERRORS LIMIT,SHOW EXTENDED INDEX,SHOW REPLICA STATUS FOR CHANNEL(reusing existingShowStmtfields)mysql_ddlAUTOEXTEND_SIZE,CREATE TABLE ... START TRANSACTION, index-levelENGINE_ATTRIBUTE,ALTER DATABASE ... READ ONLY, bareWITH CHECK OPTIONon CREATE/ALTER VIEWmysql_replicationIGNORE_SERVER_IDS = (...),PRIVILEGE_CHECKS_USER = user|NULL, bare-keyword option values (STREAM,GENERATE,ON,OFF,LOCAL),RESET BINARY LOGS AND GTIDS TO nmysql_utilityEXPLAIN FORMAT = TREE,EXPLAIN ... INTO @var,DESCRIBE tbl 'wildcard'mysql_adminUSING DATAandAUTO/MANUAL UPDATE,INSTALL COMPONENT ... SET PERSIST,DROP RESOURCE GROUP FORCE,SET RESOURCE GROUP ... FOR ids,FLUSHmulti-option lists plusOPTIMIZER_COSTS/RELAY LOGS [FOR CHANNEL]/USER_RESOURCES/TABLES ... FOR EXPORT,SET PERSIST/PERSIST_ONLY(with@@PERSIST.lexing so restores round-trip)mysql_typesINVISIBLE/VISIBLE(incl. the GIPK versioned-comment round-trip andALTER ... SET VISIBLE), column-levelENGINE_ATTRIBUTE,DEFAULT (expr)with operators andINTERVALarithmeticmysql_compoundDECLARE ... CONDITIONwith named conditions in handler lists, and[label:] LOOP ... END LOOP [label];CONDITIONandLOOPbecome reserved wordsmysql_dmlINTO OUTFILE ... CHARACTER SET, multiple locking clauses,INTObefore locking, derived-table column lists on(VALUES ...),LOAD DATA CONCURRENT/PARTITION/IGNORE n ROWSmysql_functionsJSON_TABLE(ordinality, typedPATHcolumns withON EMPTY/ON ERROR,EXISTS,NESTED),JSON_VALUE RETURNING/ON EMPTY/ON ERROR,CAST ... AT TIME ZONE,CAST AS NCHAR,SOUNDS LIKE(desugared toSOUNDEX(a) = SOUNDEX(b), MySQL's definition)mysql_routinesCREATE PROCEDUREcharacteristic list (reusing theRoutineCharacteristicsmachinery from #41), dollar-quoted strings in the lexer ($$...$$,$tag$...$tag$),LANGUAGE JAVASCRIPTAS-string bodies for procedures/functions/libraries, and theUSING (lib [AS alias], ...)imports clausemysql_accountBY RANDOM PASSWORD, multi-factor auth (AND IDENTIFIED,ADD/MODIFY/DROP n FACTOR, registration flow), dual passwords (REPLACE/RETAIN CURRENT PASSWORD/DISCARD OLD PASSWORD),DEFAULT ROLEon CREATE/ALTER USER,PASSWORD REQUIRE CURRENT [OPTIONAL],GRANT ... AS user WITH ROLE,GRANT role WITH ADMIN OPTION,REVOKE IF EXISTS/IGNORE UNKNOWN USER/PROXY,SET PASSWORD TO RANDOM/REPLACE/RETAINNotable decisions
JSONTableExpr/JSONTableColumn/JSONOnResponse/JSONValueExpr(ast/mysql_json.go),ProcedureLoopStmt,ProcedureConditionDecl,ProcedureErrorName,RoutineImport,AlterUserFactor,UserDefaultRoles,GrantAs,RevokeProxyStmt— everything else extends existing nodes with new fields.CONDITIONandLOOPreserved, matching MySQL 26.7);GET DIAGNOSTICS ... CONDITIONnow matches the token instead of an identifier spelling.TestKeywordsLengthcounts updated.'$'-led identifier reading when no closing tag matches, so$foo-style identifiers keep working.LEAVE/ITERATErestored their label as a quoted string (unparseable), andPASSWORD REQUIRE CURRENT DEFAULThad no Restore case.nodeTextCleanerlearns to cleanProcedureBlockstatement lists (whoseAcceptdeliberately skips them) and to canonicalize procedure parameter types the wayCompactStrdisplays them.Closes #14, closes #15, closes #17, closes #18, closes #19, closes #20, closes #21, closes #23, closes #28, closes #29, closes #30 — #43 noted the new goldens covered every parse gap tracked by those issues, and all of those goldens now parse.
Test plan
go test ./... -count=1 -timeout 120spasses, before and after the test-group reorganizationRestore()goldens (grep -r '^-- error' parser/testdata/parser/*/output.sqlfinds none in the touched groups); every passing case is round-tripped by the harnessgo vet ./...is clean🤖 Generated with Claude Code
https://claude.ai/code/session_01GBD2pnzaVgeXtHgWwUqxUg