Repository navigation
Conversation
MySQL's EXPLAIN FORMAT = name, EXPLAIN ANALYZE FORMAT = name, EXPLAIN ... INTO @var, EXPLAIN FOR CONNECTION and FOR SCHEMA, their DESCRIBE and DESC spellings, DESCRIBE t col, PREPARE ... FROM, EXECUTE ... USING, DROP PREPARE and DO expr failed to parse. Extend the existing models. ExplainStatement keeps ANALYZE and FORMAT as options, marks FORMAT = name with useEqual and reads it as a Format enum, and gains the INTO variable, the connection id, the schema, a column pattern and a derived TargetKind. DescribeStatement gains the column pattern, PrepareStatement the FROM source, Execute the USING variables, DeallocateStatement a DROP keyword and DoStatement MySQL's select-list items. One ExplainableStatement production reads the explained statement for both EXPLAIN paths, and the user variables reuse MySqlIntoVariable. The forms are read with the MySQL and MariaDB dialects and without a dialect, except DESCRIBE TABLE t, DESCRIBE t col and DO before a string, which other products read differently. Other dialects are unchanged. Wire the deparser, visitors, table finder (EXPLAIN t now reports t, PREPARE ... FROM raises like EXECUTE), validation (prepare, executeExecute, executeUsing and doStatement in the MySQL and MariaDB capabilities) and feature analysis. Signed-off-by: minleejae <mmj9808@gmail.com>
This branch has not been deployed
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.
Purpose
MySQL scripts and tools use
EXPLAINwith an output format, prepared statements andDO. Onmaster(4a970a34e) these fail withDialect.MYSQLand without a dialect, for example:EXPLAIN FORMAT=JSON SELECT * FROM t,EXPLAIN FORMAT=TREE UPDATE t SET a = 1,EXPLAIN ANALYZE FORMAT=TREE SELECT * FROM tEXPLAIN FORMAT=JSON INTO @plan SELECT * FROM tandEXPLAIN FOR CONNECTION 7DESC FORMAT=JSON SELECT …,DESCRIBE UPDATE t SET a = 1,EXPLAIN REPLACE INTO t VALUES (1)DESCRIBE t aandDESCRIBE t 'a%'PREPARE s FROM 'SELECT ?',PREPARE s FROM @sql,EXECUTE s USING @a, @b,DROP PREPARE sDO SLEEP(0),DO 1, @a := 2,DO (SELECT 1)MySQL 8.4 references: EXPLAIN, prepared statements, PREPARE, EXECUTE, DEALLOCATE PREPARE, DO.
Current design (As-is)
ExplainStatementholds a keyword (EXPLAIN,SUMMARIZE), an option list (ANALYZE,FORMAT, … with PostgreSQL's parenthesized form) and either the explained statement or a table. Its unparenthesized options are PostgreSQL's legacy keywords:FORMAT JSONparses,FORMAT = JSONdoes not. There is noINTO,FOR CONNECTIONorFOR SCHEMA, andREPLACEcannot be explained.DescribeStatementdescribes a table or, as in DuckDB, a query.DESC/DESCRIBEcannot take an explain option or a DML statement, and neither statement takes a column after the table.PrepareStatementis thePREPARE name [(types)] AS statementof PostgreSQL and DuckDB.Executeis theEXEC/EXECUTE/CALLof several dialects with an argument list; it has noUSING.DeallocateStatementisDEALLOCATE [PREPARE] name.DoStatementis PostgreSQL'sDO [LANGUAGE l] 'code', read only withDialect.POSTGRESQL; MySQL'sDO expr, …has no reading.TablesNamesFinderreports no table forEXPLAIN t, while it reportstforDESCRIBE t.Target design (To-be)
The existing models are extended; MySQL's forms are read with
Dialect.MYSQL,Dialect.MARIADBand, where noted, without a dialect. Other dialects are unchanged.explain_stmt:{EXPLAIN | DESCRIBE | DESC}thenANALYZE [FORMAT = name]or[FORMAT = name] [INTO @var], thenFOR CONNECTION idor[FOR {SCHEMA | DATABASE} name]and aSELECT,TABLE,VALUES,INSERT,REPLACE,UPDATEorDELETEstatement. They parse toExplainStatement, andgetKeyword()keeps the spelling.ANALYZEandFORMATareExplainStatement.Options, as for PostgreSQL.Option.isUseEqual()marks MySQL'sFORMAT = name, sogetOption(OptionType.FORMAT).getValue()reads the format of both products. The format is a keyword choice:ExplainStatement.Format(TEXT,XML,JSON,YAML,TRADITIONAL,TREE), read withgetFormat().FORMAT = nametakes MySQL'sTRADITIONAL,JSONandTREE; as in MySQL the name is case-insensitive and may be quoted (FORMAT='json'), and it is rendered as the enum name.getIntoVariable()(UserVariable),getConnectionId()(LongValue, orHexValuefor0x1F),getSchemaName()withisSchemaKeyword(), andgetColumnPattern()forEXPLAIN t col.getTargetKind()(STATEMENT,TABLE,CONNECTION) is derived from the target, and the target setters keep them exclusive.EXPLAIN SELECT,EXPLAIN ANALYZE SELECT,EXPLAIN t,DESCRIBE SELECT …andDESCRIBE tkeep their readings and models. The MySQL path is taken only for tokens the generic one does not read (FORMAT =,INTO,FOR,REPLACE, and forDESC/DESCRIBEalsoANALYZE,INSERT,UPDATE,DELETE,TABLE,VALUES), and a single word afterDESC, such asDESC replace, remains a table name.ExplainableStatement()production, shared with the genericEXPLAIN.toString()andStatementDeParsershareappendTo.DescribeStatementdoes too; itstoString()now renders the table as the deparser did (Table.toString(), which keeps a time-travel clause).{DESCRIBE | DESC | EXPLAIN} table {column | 'pattern'}(MySQL'sopt_describe_column) addsgetColumnPattern()toDescribeStatementandExplainStatement: aColumn, aStringValueor a hex string. The column must end the statement, and a statement keyword on the next line, as inDESC t+ newline +COMMIT, still starts the next statement.PREPARE name FROM {'text' | @var}extendsPrepareStatement:getSource()is theStringValueorUserVariable,getStatement()is null, and setting one clears the other. The text is not parsed.EXECUTE name USING @a, @baddsExecute.getUsingVariables()(ExpressionList<UserVariable>, asMySqlSelectIntoClauseholds its variables). OnlyEXECUTEtakes it, and only user variables, as in MySQL.DROP PREPARE nameparses toDeallocateStatementwithgetKeyword()DROP(DeallocateStatement.Keyword);isUsingPrepareKeyword()is true for it.DO expr [, expr] …extendsDoStatementwithgetSelectItems(). MySQL'sdo_stmtisDO select_item_list, so the items reuseSelectItemsList()and may carry aliases (DO 1 AS a);getCode()is null.EXPLAIN … INTO,EXECUTE … USINGandPREPARE … FROMreuseMySqlIntoVariable()ofSELECT … INTO, which now also links the quoted form (@'v') to its source range.DESCRIBE TABLE tandDESCRIBE x yneed the MySQL dialects, because Snowflake'sDESCRIBE TABLE tandDESCRIBE VIEW vname an object kind.DObefore a string orLANGUAGEstays PostgreSQL's code block, which needsDialect.POSTGRESQL;DO SLEEP(0)is MySQL's.StatementDeParseruses the models'appendToforEXPLAIN,DESCRIBE,PREPAREandDO;ExecuteDeParserrendersUSINGthroughExecute.appendTo.StatementVisitorAdaptervisits theUSINGvariables, thePREPAREsource and theDOitems.TablesNamesFinderreports the table ofEXPLAIN t(until now none) and the tables of subqueries in MySQL'sDO.PREPARE … FROMraisesUnsupportedOperationException, likeEXECUTE,CALLand PostgreSQL'sDO, since the tables of the statement text are unknown;EXECUTEkeeps raising it for the same reason.Feature.executeUsingis reported forUSING.MySqlVersionandMariaDbVersionaddprepare,executeExecute,executeUsinganddoStatement.EXPLAIN … INTOreportsMODIFIES_SESSIONinstead ofRETURNS_RESULT_SET; MySQL'sDOanalyses its expressions (a subquery reads data, a function is unresolved) instead of reportingOPAQUE.ASTNodeCoverageTestwalks the new forms.Validation
MySqlExplainTest82,MySqlPreparedStatementTest27 and 20 inDoStatementTest;ASTNodeCoverageTestwalks the new forms. They fail onmaster.toString(),StatementDeParserand reparse withDialect.MYSQLand, where read there, without a dialect and withDialect.MARIADB, plus the AST fields (options,Format,useEqual, target kind,INTOvariable, connection id, schema, column pattern, source,USINGvariables, keyword, select items).FORMAT = XML),ANALYZE … INTO, misplacedINTOandANALYZE,@@v,FOR CONNECTION -1/1.5/@c,FOR SCHEMA s FOR CONNECTION 1, options before a table, two columns,PREPARE s FROM SELECT 1,PREPARE s FROM 'a' 'b',PREPARE s (INT) FROM …,EXECUTE s USING 1,CALL p USING @a,DROP PREPARE,DO,DO 1,,DO 1 FROM t.EXPLAIN ANALYZE SELECT,EXPLAIN t,DESC SELECT …,DESC analyze/replace/formatas tables, the genericEXPLAIN FORMAT JSON, Oracle'sEXPLAIN PLAN FOR, PostgreSQL'sEXPLAIN (FORMAT JSON),PREPARE … AS,DEALLOCATE sandDO $$…$$; PostgreSQL, Oracle, SQL Server and H2 reject the new forms.DoStatementTest.gatesDialectAndRejectsMalformedWrappersasserted that every dialect but PostgreSQL rejectsDO $$BEGIN NULL; END$$. The MySQL dialects now read it asDOof a string, because the lexer reads$$…$$as a string in every dialect; the test asserts that reading for them.Dialect.MYSQLis accepted by the server's grammar, and every form it rejects is rejected while the server parses it; the PostgreSQL results all agree. The exceptions:master, which MySQL rejects:DESC analyze,DESC replaceandEXPLAIN replace(table names), the genericEXPLAIN FORMAT JSON …,DEALLOCATE s,EXECUTE s (1, 2)andPREPARE p AS SELECT 1.DO $$BEGIN NULL; END$$parses withDialect.MYSQLbecause the lexer reads$$…$$as a string in every dialect, asSELECT $$…$$already does onmaster.FORMAT = XML,TEXT,'LONG') with error 1791 rather than 1064 while parsing (EXPLAIN FORMAT = XML FROMalso reports 1791), and so does this parser.EXPLAIN INTO @v FORMAT = JSON …stops at error 6006 before the server readsFORMAT;FORMATafterINTOis a syntax error (EXPLAIN FORMAT=JSON INTO @v FORMAT = JSON SELECT 1gives 1064), and the parser rejects it.PREPARE … FROM @varwas run in one session with the variable set, since an unset variable makes the server prepare the textNULL.spotlessApply cleanTest check jar: 12,768 tests, 12,743 passed, 25 skipped, zero failures/errors. The grammar choice conflict check, Checkstyle, PMD and SpotBugs pass.master(4a970a34e) on a corpus of 188 MySQL 8.4 and 166 PostgreSQL 18 statements other than DDL/DCL, each accepted by the server, with the MySQL or PostgreSQL dialect and without a dialect:Dialect.MYSQL:EXPLAIN FORMAT=JSON SELECT * FROM t,EXPLAIN FORMAT=TREE UPDATE t SET a = 1,EXPLAIN FOR CONNECTION 1,DESCRIBE t a,PREPARE s FROM 'SELECT ?',EXECUTE s USING @a, @b,DROP PREPARE sandDO SLEEP(0); without a dialect all of them butDESCRIBE t a.EXPLAIN tchanges from no table tot.master(4a970a34e) on a corpus of 635 MySQL 8.4 and PostgreSQL 18 DDL/DCL statements, each accepted by the server, plus variants, scripts and the keyword sweeps: 0 regressed, 0 changed.AI assistance: prepared with Claude Code.