GeezerVison is showing github.com — feat: parse MySQL server option values and INSTALL/UNINSTALL PLUGIN and COMPONENT by minleejae · Pull Request #2908 · JSQLParser/JSqlParser
Conversation
Purpose
Parse the MySQL statements that manage federated servers, plugins and components, following the MySQL 8.4 grammar:
CREATE SERVER s FOREIGN DATA WRAPPER mysql OPTIONS (USER 'u', HOST 'h', DATABASE 'd', PORT 3306);
CREATE SERVER `s-1` FOREIGN DATA WRAPPER 'mysql' OPTIONS (USER 'u');
ALTER SERVER s OPTIONS (USER 'u2', PORT 3307);
INSTALL PLUGIN myplugin SONAME 'somelib.so';
UNINSTALL PLUGIN myplugin;
INSTALL COMPONENT 'file://component1', 'file://component2'
SET GLOBAL component1.var1 = 12 + 3, PERSIST component1.var3 = 'x';
UNINSTALL COMPONENT 'file://component1';
Current design (As-is)
CreateServer and AlterServer exist for PostgreSQL. ForeignDataOption holds a StringValue, and the option production reads a string literal only, so OPTIONS (PORT 3306) fails at the number. Server and wrapper names are identifiers only, so FOREIGN DATA WRAPPER 'mysql' fails.
- With
Dialect.MYSQL the PostgreSQL-only clauses (IF NOT EXISTS, TYPE, VERSION, ADD/SET/DROP options, arbitrary option names, RENAME TO, OWNER TO, no OPTIONS) are accepted although MySQL reports a syntax error for them.
INSTALL starts only DuckDB's [FORCE] INSTALL extension [FROM repository] (ExtensionStatement). INSTALL PLUGIN name SONAME 'lib' and INSTALL COMPONENT 'urn' fail, and UNINSTALL starts no statement.
Target design (To-be)
Server options
ForeignDataOption keeps one value as an Expression: getValueExpression() returns the StringValue, or the number of a MySQL server option as written (LongValue, DoubleValue, HexValue, MySQL's ulong_num). getValue() keeps its signature and derives the string from it (null for a number).
- A new
ServerOptions production shares the option list with the other foreign-data statements and is used only by CREATE SERVER and ALTER SERVER. Numbers and string-literal names (ident_or_text, kept as written) are read with the MySQL and MariaDB dialects and without a dialect. PostgreSQL, the other dialects and every other option list (CREATE USER MAPPING, foreign tables, foreign-data wrappers) keep requiring string constants.
Dialect.MYSQL follows the server grammar: USER, HOST, DATABASE, OWNER, PASSWORD and SOCKET take a string, PORT a number, OPTIONS is required, and the PostgreSQL-only clauses are rejected. This is a behaviour change for input that MySQL itself rejects. MariaDB and the default configuration keep the generic option names and clauses.
DROP SERVER [IF EXISTS] name stays the generic Drop.
Plugins and components
- One
PluginStatement with an Action (INSTALL, UNINSTALL) and an ObjectType (PLUGIN, COMPONENT): plugin name and SONAME library, or the component URNs and the SET assignments.
- Each assignment is a
ComponentVariable: SetScope (NONE, GLOBAL, PERSIST), the name as written (variable, component.variable, DEFAULT.variable), = or := (SetStatement.AssignmentOperator) and the value expression; the word ON is read as a column. As in MySQL, the scope keywords are not variable names, GLOBAL./LOCAL./SESSION. are not qualifiers, and a value is neither DEFAULT nor a subquery.
- No new token and no reserved word:
UNINSTALL, PLUGIN, COMPONENT and SONAME stay identifiers and a lookahead routes the statement.
- With the MySQL and MariaDB dialects every
INSTALL is this statement (the DuckDB form is rejected there, as the server does). MariaDB has no components.
- Without a dialect DuckDB's
INSTALL plugin / INSTALL component [FROM …] keep producing an ExtensionStatement; SONAME after the plugin name or a component URN selects the MySQL statement.
- Other dialects are unchanged.
- Wired into
StatementVisitor (default method), StatementVisitorAdapter, StatementDeParser, TablesNamesFinder, StatementFeatureVisitor (MODIFIES_SESSION) and StatementValidator with the new features installPlugin (MySQL, MariaDB) and installComponent (MySQL). createServer and alterServer are added to the MySQL and MariaDB capabilities. README, index.rst and usage.rst describe the statements.
Validation
-
New tests: PluginStatementTest (120 cases) and MySqlServerTest (81 cases), plus entries in ASTNodeCoverageTest and StatementValidatorTest. They cover each form with and without the dialect, toString, the deparser, reparse, AST fields and node spans, rejected forms, readings kept in other dialects, statement boundaries in scripts, visitors, TablesNamesFinder and validation features.
-
./gradlew spotlessApply cleanTest check jar on Java 17: 13,542 tests, 0 failures, 25 skipped; checkGrammarAmbiguity, Checkstyle, PMD, SpotBugs and JaCoCo pass.
-
Compared with master (e27929f76) on the MySQL and PostgreSQL DDL/DCL and non-DDL statement corpora (parsed with the dialect and without): no regression and no changed result.
-
MySQL 8.4.11 accepts 62 of the checked statements; the branch parses 60 of them, 45 of which master rejects. They fail only when run, for example Can't open shared library or an unknown server. The two it does not parse are values that the shared expression grammar does not read on master either (SET v = BINARY 'x' and the adjacent string literals 'a' 'b'). MySQL reports a syntax error (1064) for 96 statements; the branch rejects 94 of them, including PORT '3306', USER 1, an unknown option name, IF NOT EXISTS, OPTIONS (), INSTALL PLUGIN without SONAME, SET SESSION v = 1, SET v = DEFAULT and a subquery value. The two it still accepts are DROP SERVER IF EXISTS a, b and DROP SERVER db.s, which the generic Drop reads for every object type, as on master.
AI assistance: prepared with Claude Code.
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
…nd COMPONENT
MySQL CREATE SERVER and ALTER SERVER failed on a numeric option value
such as PORT 3306 and on a server or wrapper name written as a string,
and INSTALL/UNINSTALL PLUGIN and COMPONENT did not parse.
ForeignDataOption keeps its value as an expression: a string, or the
number of a MySQL server option; getValue() derives the string from it.
Numbers and quoted names are read in CREATE SERVER and ALTER SERVER with
the MySQL and MariaDB dialects or none. The MySQL dialect follows the
server grammar: USER, HOST, DATABASE, OWNER, PASSWORD and SOCKET take a
string, PORT a number, and the PostgreSQL clauses are rejected.
The plugin and component statements are one PluginStatement with an
Action and an ObjectType; INSTALL COMPONENT ... SET assignments are
ComponentVariable items with a SetScope. They are read with the MySQL
and MariaDB dialects or none; MariaDB has no components. DuckDB INSTALL
extension keeps its reading outside those dialects, and UNINSTALL,
PLUGIN, COMPONENT and SONAME stay usable as names. Wire the statement
into the deparser, visitors, table finder, feature analysis and
validation, with new installPlugin and installComponent features.
Signed-off-by: minleejae <[email protected]>
This branch has not been deployed
No deployments
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
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.
|