Skip to content

Commit cb2bde6

Browse files
authored
feat: parse MySQL 8.4 SHOW statements for variables, status, grants, logs and other server metadata (#2916)
MySQL SHOW VARIABLES, STATUS, PROCESSLIST, GRANTS, WARNINGS, ERRORS, PROFILE, ENGINE, BINARY LOGS, BINLOG and RELAYLOG EVENTS, REPLICA STATUS, TRIGGERS, EVENTS, OPEN TABLES, routine STATUS and CODE, CHARACTER SET, COLLATION and DATABASES became UnsupportedStatement, or a ShowStatement for a single word, and SHOW INDEX FROM t FROM db failed to parse. Add MySqlShowStatement for these forms. Its Kind lists the parts each statement allows, and the values follow the MySQL 8.4 grammar: string LIKE patterns, log names and channels, unsigned limits and positions. It is read with Dialect.MYSQL and MARIADB and without a dialect; without a dialect a single word stays a ShowStatement, and the spellings removed in MySQL 8.4 (MASTER, SLAVE) are not read with Dialect.MYSQL. Share the {FROM | IN} db clause and the LIKE | WHERE filter as ShowDbSelection and ShowFilter, each read by one production, in SHOW TABLES, COLUMNS, TABLE STATUS and INDEX; the existing accessors read and write them. Extend ShowIndexStatement with EXTENDED, INDEXES and KEYS, IN, a Table, the trailing database and WHERE, and report its table in TablesNamesFinder. Let the whole-statement lookahead of the typed SHOW forms accept a WHERE filter after its first condition, so conditions with AND or OR no longer fall back to UnsupportedStatement. Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 27396f6 commit cb2bde6

32 files changed

Lines changed: 3401 additions & 194 deletions

‎README.md‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ and missing syntax gets added on demand — [open an issue](https://github.com/J
161161
| **MySQL spatial reference systems and instance** | `CREATE`/`DROP SPATIAL REFERENCE SYSTEM` · `ALTER INSTANCE` |
162162
| **PostgreSQL RLS** | `CREATE POLICY` · `ALTER TABLE … ENABLE`/`DISABLE`/`FORCE`/`NO FORCE ROW LEVEL SECURITY` |
163163
| **Routine changes** | `ALTER FUNCTION` · `ALTER PROCEDURE` · `ALTER ROUTINE` · PostgreSQL `ALTER TRIGGER` |
164-
| **MySQL metadata statements** | `SHOW [FULL] COLUMNS`/`FIELDS` · `SHOW TABLE STATUS` · `SHOW CREATE TABLE`/`VIEW`/`PROCEDURE`/`FUNCTION`/`TRIGGER`/`EVENT`/`DATABASE`/`USER` |
164+
| **MySQL metadata statements** | `SHOW [FULL] COLUMNS`/`FIELDS` · `SHOW INDEX`/`INDEXES`/`KEYS` · `SHOW TABLE STATUS` · `SHOW CREATE TABLE`/`VIEW`/`PROCEDURE`/`FUNCTION`/`TRIGGER`/`EVENT`/`DATABASE`/`USER` · `SHOW [GLOBAL | SESSION] VARIABLES`/`STATUS` · `SHOW [FULL] PROCESSLIST` · `SHOW GRANTS [FOR …]` · `SHOW WARNINGS`/`ERRORS` · `SHOW BINARY LOGS`/`BINLOG EVENTS`/`RELAYLOG EVENTS` · `SHOW ENGINE …` · `SHOW PROFILE` · `SHOW DATABASES`/`TRIGGERS`/`EVENTS`/`OPEN TABLES`/`CHARACTER SET`/`COLLATION` · `SHOW PROCEDURE`/`FUNCTION STATUS`/`CODE` · `SHOW REPLICA STATUS`/`REPLICAS` |
165165
| **MySQL utility statements** | `EXPLAIN`/`DESCRIBE [ANALYZE] FORMAT = …` · `EXPLAIN FOR CONNECTION` · `DESCRIBE t col` · `PREPARE … FROM` · `EXECUTE … USING` · `DROP PREPARE` · `DO` |
166166
| **PostgreSQL administration** | `CREATE`/`ALTER EVENT TRIGGER` · `REINDEX` · `SECURITY LABEL` |
167167
| **PostgreSQL types and rules** | `CREATE TYPE` (shell, composite, enum, range and base types) · `ALTER TYPE` · `CREATE RULE` · `ALTER RULE` |

‎src/main/java/net/sf/jsqlparser/parser/feature/Feature.java‎

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,6 +971,13 @@ public enum Feature {
971971
* @see ShowCreateStatement
972972
*/
973973
showCreate,
974+
/**
975+
* The MySQL/MariaDB "SHOW" statements of server settings, state and object lists, such as "SHOW
976+
* VARIABLES", "SHOW GRANTS" or "SHOW BINLOG EVENTS"
977+
*
978+
* @see MySqlShowStatement
979+
*/
980+
mySqlShow,
974981
/**
975982
* @see UseStatement
976983
*/

‎src/main/java/net/sf/jsqlparser/statement/ShowColumnsStatement.java‎

Lines changed: 69 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,12 @@
99
*/
1010
package net.sf.jsqlparser.statement;
1111

12+
import java.util.function.Consumer;
1213
import net.sf.jsqlparser.expression.Expression;
1314
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
1415
import net.sf.jsqlparser.schema.Table;
16+
import net.sf.jsqlparser.statement.show.ShowDbSelection;
17+
import net.sf.jsqlparser.statement.show.ShowFilter;
1518
import net.sf.jsqlparser.statement.show.ShowTablesStatement.SelectionMode;
1619

1720
/**
@@ -27,10 +30,8 @@ public class ShowColumnsStatement extends ASTNodeAccessImpl implements Statement
2730
private boolean fieldsKeyword;
2831
private SelectionMode tableSelectionMode = SelectionMode.FROM;
2932
private Table table;
30-
private SelectionMode dbSelectionMode = SelectionMode.FROM;
31-
private String dbName;
32-
private Expression likeExpression;
33-
private Expression whereCondition;
33+
private ShowDbSelection dbSelection;
34+
private ShowFilter filter;
3435

3536
public ShowColumnsStatement() {
3637
// empty constructor
@@ -97,41 +98,73 @@ public void setTableName(String tableName) {
9798

9899
/** The keyword before the database name, {@code FROM} unless {@code IN} was written. */
99100
public SelectionMode getDbSelectionMode() {
100-
return dbSelectionMode;
101+
return dbSelection == null ? SelectionMode.FROM : dbSelection.getSelectionMode();
101102
}
102103

104+
/** Sets the keyword before the database name, which is kept until the name is set. */
103105
public void setDbSelectionMode(SelectionMode dbSelectionMode) {
104-
this.dbSelectionMode = dbSelectionMode;
106+
dbSelection = ShowDbSelection.updateSelectionMode(dbSelection, dbSelectionMode);
105107
}
106108

107109
/** The database of the trailing {@code FROM db} or {@code IN db} clause, or null. */
108110
public String getDbName() {
109-
return dbName;
111+
return ShowDbSelection.name(dbSelection);
110112
}
111113

112114
public void setDbName(String dbName) {
113-
this.dbName = dbName;
115+
dbSelection = ShowDbSelection.updateName(dbSelection, dbName);
116+
}
117+
118+
/** The trailing {@code {FROM | IN} db} clause, or null. */
119+
public ShowDbSelection getDbSelection() {
120+
return dbSelection;
121+
}
122+
123+
public void setDbSelection(ShowDbSelection dbSelection) {
124+
this.dbSelection = dbSelection;
125+
}
126+
127+
/** The {@code LIKE} or {@code WHERE} filter, or null. */
128+
public ShowFilter getFilter() {
129+
return filter;
130+
}
131+
132+
public void setFilter(ShowFilter filter) {
133+
this.filter = filter;
114134
}
115135

116136
public Expression getLikeExpression() {
117-
return likeExpression;
137+
return ShowFilter.likeExpression(filter);
118138
}
119139

140+
/** Sets a {@code LIKE} filter, which replaces a {@code WHERE} filter; null removes it. */
120141
public void setLikeExpression(Expression likeExpression) {
121-
this.likeExpression = likeExpression;
142+
filter = ShowFilter.replace(filter, ShowFilter.Kind.LIKE, likeExpression);
122143
}
123144

124145
public Expression getWhereCondition() {
125-
return whereCondition;
146+
return ShowFilter.whereCondition(filter);
126147
}
127148

149+
/** Sets a {@code WHERE} filter, which replaces a {@code LIKE} filter; null removes it. */
128150
public void setWhereCondition(Expression whereCondition) {
129-
this.whereCondition = whereCondition;
151+
filter = ShowFilter.replace(filter, ShowFilter.Kind.WHERE, whereCondition);
130152
}
131153

132-
@Override
133-
public String toString() {
134-
StringBuilder builder = new StringBuilder("SHOW");
154+
/**
155+
* The table the statement reads: {@link #getTable()}, or the table in the database of the
156+
* trailing {@code FROM db} clause, which MySQL reads as {@code db.table}.
157+
*/
158+
public Table getQualifiedTable() {
159+
if (table == null || !ShowDbSelection.isPresent(dbSelection)) {
160+
return table;
161+
}
162+
return new Table(dbSelection.getName(), table.getName());
163+
}
164+
165+
/** Appends the statement, printing the filter expression with the given printer. */
166+
public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> printer) {
167+
builder.append("SHOW");
135168
if (extended) {
136169
builder.append(" EXTENDED");
137170
}
@@ -141,17 +174,19 @@ public String toString() {
141174
builder.append(fieldsKeyword ? " FIELDS " : " COLUMNS ")
142175
.append(tableSelectionMode == null ? SelectionMode.FROM : tableSelectionMode)
143176
.append(' ').append(table);
144-
if (dbName != null) {
145-
builder.append(' ')
146-
.append(dbSelectionMode == null ? SelectionMode.FROM : dbSelectionMode)
147-
.append(' ').append(dbName);
177+
if (ShowDbSelection.isPresent(dbSelection)) {
178+
builder.append(' ').append(dbSelection);
148179
}
149-
if (likeExpression != null) {
150-
builder.append(" LIKE ").append(likeExpression);
151-
} else if (whereCondition != null) {
152-
builder.append(" WHERE ").append(whereCondition);
180+
if (filter != null) {
181+
filter.appendTo(builder.append(' '), printer);
153182
}
154-
return builder.toString();
183+
return builder;
184+
}
185+
186+
@Override
187+
public String toString() {
188+
StringBuilder builder = new StringBuilder();
189+
return appendTo(builder, builder::append).toString();
155190
}
156191

157192
@Override
@@ -208,4 +243,14 @@ public ShowColumnsStatement withWhereCondition(Expression whereCondition) {
208243
this.setWhereCondition(whereCondition);
209244
return this;
210245
}
246+
247+
public ShowColumnsStatement withDbSelection(ShowDbSelection dbSelection) {
248+
this.setDbSelection(dbSelection);
249+
return this;
250+
}
251+
252+
public ShowColumnsStatement withFilter(ShowFilter filter) {
253+
this.setFilter(filter);
254+
return this;
255+
}
211256
}

‎src/main/java/net/sf/jsqlparser/statement/StatementFeatureVisitor.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,7 @@
141141
import net.sf.jsqlparser.statement.select.SelectVisitorAdapter;
142142
import net.sf.jsqlparser.statement.select.TableStatement;
143143
import net.sf.jsqlparser.statement.select.WithItem;
144+
import net.sf.jsqlparser.statement.show.MySqlShowStatement;
144145
import net.sf.jsqlparser.statement.show.ShowCreateStatement;
145146
import net.sf.jsqlparser.statement.show.ShowIndexStatement;
146147
import net.sf.jsqlparser.statement.show.ShowTableStatusStatement;
@@ -1169,6 +1170,11 @@ public <S> Void visit(ShowCreateStatement showCreate, S context) {
11691170
return metadataOnly();
11701171
}
11711172

1173+
@Override
1174+
public <S> Void visit(MySqlShowStatement mySqlShow, S context) {
1175+
return metadataOnly();
1176+
}
1177+
11721178
@Override
11731179
public <S> Void visit(DescribeStatement describe, S context) {
11741180
return metadataOnly();

‎src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java‎

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@
111111
import net.sf.jsqlparser.statement.resourcegroup.SetResourceGroup;
112112
import net.sf.jsqlparser.statement.securitylabel.SecurityLabel;
113113
import net.sf.jsqlparser.statement.select.Select;
114+
import net.sf.jsqlparser.statement.show.MySqlShowStatement;
114115
import net.sf.jsqlparser.statement.show.ShowCreateStatement;
115116
import net.sf.jsqlparser.statement.show.ShowIndexStatement;
116117
import net.sf.jsqlparser.statement.show.ShowTableStatusStatement;
@@ -551,6 +552,14 @@ default void visit(ShowCreateStatement showCreate) {
551552
this.visit(showCreate, null);
552553
}
553554

555+
default <S> T visit(MySqlShowStatement mySqlShow, S context) {
556+
return null;
557+
}
558+
559+
default void visit(MySqlShowStatement mySqlShow) {
560+
this.visit(mySqlShow, null);
561+
}
562+
554563
<S> T visit(Merge merge, S context);
555564

556565
default void visit(Merge merge) {

‎src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@
126126
import net.sf.jsqlparser.statement.select.SelectVisitor;
127127
import net.sf.jsqlparser.statement.select.SelectVisitorAdapter;
128128
import net.sf.jsqlparser.statement.select.WithItem;
129+
import net.sf.jsqlparser.statement.show.MySqlShowStatement;
129130
import net.sf.jsqlparser.statement.show.ShowCreateStatement;
130131
import net.sf.jsqlparser.statement.show.ShowIndexStatement;
131132
import net.sf.jsqlparser.statement.show.ShowTableStatusStatement;
@@ -742,6 +743,11 @@ public <S> T visit(ShowCreateStatement showCreate, S context) {
742743
return null;
743744
}
744745

746+
@Override
747+
public <S> T visit(MySqlShowStatement mySqlShow, S context) {
748+
return null;
749+
}
750+
745751
@Override
746752
public <S> T visit(DeclareStatement declareStatement, S context) {
747753
return null;

0 commit comments

Comments
 (0)