Feature Request: parse the CREATE TABLE source forms the grammar only partially accepts (parenthesized SELECT, AS TABLE, EXCEPT/INTERSECT)
Overview of the Issue
The SQL parser accepts several CREATE TABLE forms only partially. When the grammar hits syntax it does not know after CREATE TABLE <name>, Parse2 (go/vt/sqlparser/parser.go) keeps the *CreateTable node with just the name and marks it FullyParsed=false; TableSpec, OptLike and Select are all nil. vttablet then forwards the client's raw text to MySQL.
These MySQL-valid forms are among them, and each copies rows from a source table the AST never records:
create table ct (select id from src) -- parenthesized query as the body
create table ct as table src -- TABLE statement as the source
create table ct as select id from a except select id from b -- EXCEPT / INTERSECT source
create table ct as select * from (table src) d -- TABLE inside a derived table(EXCEPT is worse than the others: the parser keeps a truncated Select covering only the first arm, so a consumer that trusted it would see a and miss b.)
Under strict table ACL, #21139 (stacked on #21053) treats every partially parsed CREATE TABLE as having an undetermined table set and fails closed on it for callers outside the exempt ACL, because the planner cannot tell a row-copying form from a valid statement in syntax the grammar simply lacks — create table t (id int) start transaction arrives with the same empty node. That is correct but coarse: it denies legitimate CREATE TABLE syntax the grammar does not cover, and it depends on the fallback behaving the same way forever.
The better end state is for the grammar to parse these sources so they become ordinary CreateTable.Select values that the permission walker, the schema tracker and Online DDL can all see. Concretely:
create_table_prefix ... '(' select_statement ')'andcreate_table_prefix ... table_spec? '(' select_statement ')'AS/opt_asTABLE table_nameas aSelect-like source (MySQL'sTABLEstatement)EXCEPTandINTERSECTinquery_expression(MySQL 8.0.31+), which also fixes the truncatedSelectTABLE table_nameas a derived-table body
Once these parse fully, the !IsFullyParsed() guard in planbuilder.BuildPermissions stops firing for them and the over-denial narrows to genuinely unknown syntax. The create table t golden in planbuilder/testdata/ddl_cases.txt and the partial-parse cases in TestBuildPermissions document the current classification.
Reproduction Steps
- Parse any of the four statements above with
sqlparser.NewTestParser().Parse(...). - Observe a
*sqlparser.CreateTablewithIsFullyParsed() == falseandSelect == nil(or a one-armSelectfor theEXCEPTform), while MySQL 8.0.46 accepts the statement and copies the rows. - With
--queryserver-config-strict-table-acl, a non-exempt caller is denied withDDL command denied to user '...' for a table set that cannot be determined (ACL check error), even with full grants on every table involved.
Binary Version
vttablet --version
Version: 25.0.0-SNAPSHOT (Git revision 1cf37324b4 branch 'main')Operating System and Environment details
Any. Verified against the parser and MySQL 8.0.46 on macOS arm64.Log Fragments
WRN sqlparser/parser.go:84 ignoring error parsing DDL 'create table ct (select id from src)': syntax error at position 24 near 'select'
WRN sqlparser/parser.go:84 ignoring error parsing DDL 'create table ct as table src': syntax error at position 25 near 'table'Related
This is one of a set of changes that came out of one investigation into what a stored procedure, or any statement whose tables the planner never sees, can do on a vttablet. They reference each other so the whole picture is reachable from any one of them.
Table ACL — GHSA-w6mx-2f8x-pqf4
- #21053 — fail closed under strict table ACL for statements whose tables the parser discards (
DO,CALL,REPAIR,OPTIMIZE,LOAD DATA) - #21139 — stacked on #21053: check the reads embedded in statements the planner does parse (
CREATE TABLE ... AS SELECT,EXPLAIN ANALYZE,SHOW ... WHERE,SET), reject connection settings that carry a subquery, and have a targeted vtgate session store aSET's value rather than its expression - #21134 — still open: a stored function invoked inside an expression runs its body outside the table ACL
- #21138 — (this issue) still open: parse the
CREATE TABLEsource forms the grammar only partially accepts, which #21139 has to deny outright today - #21140 — still open:
ALTER/REVERT VITESS_MIGRATIONderive no permissions, so any authenticated caller can control Online DDL migrations; split out of #21053's review
Stored-procedure session residue
- #21046 — procedure-body session state (
SET SESSION, temp tables) persists on pooled connections afterCALL - #21062 — fixes #21046 by discarding the pooled connection after
CALL - #21063 — still open: the same residue on a transaction connection recycled at commit
- #21066 — still open: the pooled-connection baseline differs between fresh and settings-reset connections on servers using
init_connect
Source: vitessio/vitess