GeezerVison is showing github.com — feat: parse MySQL FLUSH, KILL, RESET PERSIST and HANDLER · JSQLParser/JSqlParser@49fac8e
File treeExpand file treeCollapse file tree Open diff view settings jjtree/net/sf/jsqlparser/parser
test/java/net/sf/jsqlparser util/validation/validator
Expand file treeCollapse file tree Open diff view settings Collapse file Copy file name to clipboardExpand all lines: README.md +1Lines changed: 1 addition & 0 deletions - Display the source diff
- Display the rich diff
| Original file line number | Diff line number | Diff line change |
|---|
@@ -152,6 +152,7 @@ and missing syntax gets added on demand — [open an issue](https://github.com/J | 152 | 152 | | **PostgreSQL maintenance** | `VACUUM` · `ANALYZE` · `CLUSTER` · `CHECKPOINT` | | 153 | 153 | | **MySQL locks** | `LOCK TABLES` · `UNLOCK TABLES` · `LOCK INSTANCE FOR BACKUP` · `UNLOCK INSTANCE` | | 154 | 154 | | **PostgreSQL session statements** | `DISCARD` · `LISTEN` · `UNLISTEN` · `SHOW`/`RESET TIME ZONE`/`TRANSACTION ISOLATION LEVEL`/`SESSION AUTHORIZATION` · `COPY` options from before 9.0 | | | 155 | +| **MySQL server administration** | `FLUSH` · `KILL` · `RESET PERSIST` · `HANDLER … OPEN`/`READ`/`CLOSE` | | 155 | 156 | | **MySQL account management** | `CREATE`/`ALTER`/`RENAME USER` · `CREATE ROLE` · `SET ROLE` · `SET DEFAULT ROLE` · `SET PASSWORD` | | 156 | 157 | | **Tablespaces** | MySQL and PostgreSQL `CREATE TABLESPACE` · `ALTER TABLESPACE` | | 157 | 158 | | **PostgreSQL RLS** | `CREATE POLICY` · `ALTER TABLE … ENABLE`/`DISABLE`/`FORCE`/`NO FORCE ROW LEVEL SECURITY` | | |
Collapse file Copy file name to clipboardExpand all lines: src/main/java/net/sf/jsqlparser/parser/RoutineBodyBoundary.java +1-1Lines changed: 1 addition & 1 deletion | Original file line number | Diff line number | Diff line change |
|---|
@@ -248,7 +248,7 @@ private void acceptStatementToken(Token token, Token next) { | 248 | 248 | if (statementStart) { | 249 | 249 | statementKind = kind; | 250 | 250 | } | 251 | | - if (statementKind == K_DECLARE && keyword(token, "HANDLER")) { | | 251 | + if (statementKind == K_DECLARE && token.kind == K_HANDLER) { | 252 | 252 | handlerAction = true; | 253 | 253 | } | 254 | 254 | statementStart = false; | |
Collapse file Copy file name to clipboardExpand all lines: src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +30Lines changed: 30 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 32 | 32 | import net.sf.jsqlparser.statement.TableMaintenanceStatement; | 33 | 33 | import net.sf.jsqlparser.statement.UseStatement; | 34 | 34 | import net.sf.jsqlparser.statement.XaStatement; | | 35 | +import net.sf.jsqlparser.statement.admin.FlushStatement; | | 36 | +import net.sf.jsqlparser.statement.admin.KillStatement; | 35 | 37 | import net.sf.jsqlparser.statement.alter.Alter; | 36 | 38 | import net.sf.jsqlparser.statement.alter.AlterEventTrigger; | 37 | 39 | import net.sf.jsqlparser.statement.alter.sequence.AlterSequence; | | 55 | 57 | import net.sf.jsqlparser.statement.drop.Drop; | 56 | 58 | import net.sf.jsqlparser.statement.execute.Execute; | 57 | 59 | import net.sf.jsqlparser.statement.grant.Grant; | | 60 | +import net.sf.jsqlparser.statement.handler.HandlerStatement; | 58 | 61 | import net.sf.jsqlparser.statement.lock.BackupLockStatement; | 59 | 62 | import net.sf.jsqlparser.statement.lock.UnlockStatement; | 60 | 63 | import net.sf.jsqlparser.statement.merge.Merge; | @@ -494,6 +497,27 @@ public enum Feature { | 494 | 497 | */ | 495 | 498 | tableMaintenance, | 496 | 499 |
| | 500 | + /** | | 501 | + * MySQL "FLUSH" statement is allowed | | 502 | + * | | 503 | + * @see FlushStatement | | 504 | + */ | | 505 | + flush, | | 506 | + | | 507 | + /** | | 508 | + * MySQL "KILL" statement is allowed | | 509 | + * | | 510 | + * @see KillStatement | | 511 | + */ | | 512 | + kill, | | 513 | + | | 514 | + /** | | 515 | + * MySQL "HANDLER ... OPEN", "HANDLER ... READ" and "HANDLER ... CLOSE" statements are allowed | | 516 | + * | | 517 | + * @see HandlerStatement | | 518 | + */ | | 519 | + handler, | | 520 | + | 497 | 521 | /** | 498 | 522 | * PostgreSQL "VACUUM" statement is allowed | 499 | 523 | * | @@ -982,6 +1006,12 @@ public enum Feature { | 982 | 1006 | * @see net.sf.jsqlparser.statement.notify.ListenStatement | 983 | 1007 | */ | 984 | 1008 | listen, | | 1009 | + /** | | 1010 | + * MySQL "RESET PERSIST" statement is allowed | | 1011 | + * | | 1012 | + * @see ResetStatement#isPersist() | | 1013 | + */ | | 1014 | + resetPersist, | 985 | 1015 | /** | 986 | 1016 | * @see Pivot | 987 | 1017 | */ | |
Collapse file Copy file name to clipboardExpand all lines: src/main/java/net/sf/jsqlparser/statement/ResetStatement.java +57-2Lines changed: 57 additions & 2 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 11 | 11 |
| 12 | 12 | import net.sf.jsqlparser.parser.ASTNodeAccessImpl; | 13 | 13 |
| | 14 | +/** | | 15 | + * PostgreSQL {@code RESET configuration_parameter}, {@code RESET ALL} and {@code RESET TIME ZONE}, | | 16 | + * and MySQL {@code RESET PERSIST [[IF EXISTS] system_var_name]}, which {@link #isPersist()} marks. | | 17 | + * | | 18 | + * @see <a href="https://www.postgresql.org/docs/current/sql-reset.html">PostgreSQL RESET</a> | | 19 | + * @see <a href="https://dev.mysql.com/doc/refman/8.4/en/reset-persist.html">MySQL RESET PERSIST</a> | | 20 | + */ | 14 | 21 | public final class ResetStatement extends ASTNodeAccessImpl implements Statement { | 15 | 22 |
| 16 | 23 | private String name = ""; | | 24 | + private boolean persist; | | 25 | + private boolean ifExists; | 17 | 26 |
| 18 | 27 | public ResetStatement() { | 19 | 28 | // empty constructor | @@ -27,6 +36,10 @@ public void add(String name) { | 27 | 36 | this.name = name; | 28 | 37 | } | 29 | 38 |
| | 39 | + /** | | 40 | + * Returns the parameter or, for RESET PERSIST, the system variable; null when RESET PERSIST | | 41 | + * names none and removes every persisted variable. | | 42 | + */ | 30 | 43 | public String getName() { | 31 | 44 | return name; | 32 | 45 | } | @@ -35,10 +48,52 @@ public void setName(String name) { | 35 | 48 | this.name = name; | 36 | 49 | } | 37 | 50 |
| | 51 | + /** Whether this is MySQL RESET PERSIST, which removes persisted global system variables. */ | | 52 | + public boolean isPersist() { | | 53 | + return persist; | | 54 | + } | | 55 | + | | 56 | + public void setPersist(boolean persist) { | | 57 | + this.persist = persist; | | 58 | + } | | 59 | + | | 60 | + public ResetStatement withPersist(boolean persist) { | | 61 | + setPersist(persist); | | 62 | + return this; | | 63 | + } | | 64 | + | | 65 | + /** Whether RESET PERSIST has IF EXISTS before the variable name. */ | | 66 | + public boolean isIfExists() { | | 67 | + return ifExists; | | 68 | + } | | 69 | + | | 70 | + public void setIfExists(boolean ifExists) { | | 71 | + this.ifExists = ifExists; | | 72 | + } | | 73 | + | | 74 | + public ResetStatement withIfExists(boolean ifExists) { | | 75 | + setIfExists(ifExists); | | 76 | + return this; | | 77 | + } | | 78 | + | | 79 | + public StringBuilder appendTo(StringBuilder builder) { | | 80 | + builder.append("RESET "); | | 81 | + if (!persist) { | | 82 | + return builder.append(name); | | 83 | + } | | 84 | + builder.append("PERSIST"); | | 85 | + if (ifExists) { | | 86 | + builder.append(" IF EXISTS"); | | 87 | + } | | 88 | + if (name != null && !name.isEmpty()) { | | 89 | + builder.append(' ').append(name); | | 90 | + } | | 91 | + return builder; | | 92 | + } | | 93 | + | 38 | 94 | @Override | 39 | 95 | public String toString() { | 40 | | - StringBuilder b = new StringBuilder("RESET ").append(name); | 41 | | - return b.toString(); | | 96 | + return appendTo(new StringBuilder()).toString(); | 42 | 97 | } | 43 | 98 |
| 44 | 99 | @Override | |
Collapse file Copy file name to clipboardExpand all lines: src/main/java/net/sf/jsqlparser/statement/StatementFeatureVisitor.java +37Lines changed: 37 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 98 | 98 | import net.sf.jsqlparser.statement.insert.Insert; | 99 | 99 | import net.sf.jsqlparser.statement.insert.InsertBulk; | 100 | 100 | import net.sf.jsqlparser.statement.load.LoadDataStatement; | | 101 | +import net.sf.jsqlparser.statement.admin.FlushStatement; | | 102 | +import net.sf.jsqlparser.statement.admin.KillStatement; | | 103 | +import net.sf.jsqlparser.statement.handler.HandlerStatement; | 101 | 104 | import net.sf.jsqlparser.statement.lock.BackupLockStatement; | 102 | 105 | import net.sf.jsqlparser.statement.lock.LockStatement; | 103 | 106 | import net.sf.jsqlparser.statement.lock.UnlockStatement; | @@ -784,6 +787,40 @@ public <S> Void visit(TableMaintenanceStatement statement, S context) { | 784 | 787 | return null; | 785 | 788 | } | 786 | 789 |
| | 790 | + @Override | | 791 | + public <S> Void visit(FlushStatement flush, S context) { | | 792 | + // a server operation like ALTER SYSTEM FLUSH; WITH READ LOCK and FOR EXPORT also lock | | 793 | + analysis.claimTopLevel(); | | 794 | + analysis.certain(StmtFeature.MODIFIES_SESSION); | | 795 | + if (flush.getTableLock() != null) { | | 796 | + analysis.certain(StmtFeature.MODIFIES_TRANSACTION); | | 797 | + } | | 798 | + return null; | | 799 | + } | | 800 | + | | 801 | + @Override | | 802 | + public <S> Void visit(KillStatement kill, S context) { | | 803 | + // ends another session or its statement, like ALTER SYSTEM KILL SESSION | | 804 | + analysis.claimTopLevel(); | | 805 | + analysis.certain(StmtFeature.MODIFIES_SESSION); | | 806 | + return null; | | 807 | + } | | 808 | + | | 809 | + @Override | | 810 | + public <S> Void visit(HandlerStatement handler, S context) { | | 811 | + if (handler.getAction() != HandlerStatement.Action.READ) { | | 812 | + // OPEN and CLOSE change the handlers of the session | | 813 | + analysis.claimTopLevel(); | | 814 | + analysis.certain(StmtFeature.MODIFIES_SESSION); | | 815 | + return null; | | 816 | + } | | 817 | + if (analysis.claimTopLevel()) { | | 818 | + analysis.certain(StmtFeature.RETURNS_RESULT_SET); | | 819 | + } | | 820 | + analysis.certain(StmtFeature.READS_DATA); | | 821 | + return super.visit(handler, context); | | 822 | + } | | 823 | + | 787 | 824 | @Override | 788 | 825 | public <S> Void visit(VacuumStatement vacuum, S context) { | 789 | 826 | // reclaims storage and, with ANALYZE, rewrites statistics; FULL rewrites the tables | |
Collapse file Copy file name to clipboardExpand all lines: src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java +27Lines changed: 27 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 91 | 91 | import net.sf.jsqlparser.statement.insert.Insert; | 92 | 92 | import net.sf.jsqlparser.statement.insert.InsertBulk; | 93 | 93 | import net.sf.jsqlparser.statement.insert.ParenthesedInsert; | | 94 | +import net.sf.jsqlparser.statement.admin.FlushStatement; | | 95 | +import net.sf.jsqlparser.statement.admin.KillStatement; | | 96 | +import net.sf.jsqlparser.statement.handler.HandlerStatement; | 94 | 97 | import net.sf.jsqlparser.statement.lock.BackupLockStatement; | 95 | 98 | import net.sf.jsqlparser.statement.lock.LockStatement; | 96 | 99 | import net.sf.jsqlparser.statement.lock.UnlockStatement; | @@ -409,6 +412,30 @@ default void visit(TableMaintenanceStatement statement) { | 409 | 412 | this.visit(statement, null); | 410 | 413 | } | 411 | 414 |
| | 415 | + default <S> T visit(FlushStatement flush, S context) { | | 416 | + return null; | | 417 | + } | | 418 | + | | 419 | + default void visit(FlushStatement flush) { | | 420 | + this.visit(flush, null); | | 421 | + } | | 422 | + | | 423 | + default <S> T visit(KillStatement kill, S context) { | | 424 | + return null; | | 425 | + } | | 426 | + | | 427 | + default void visit(KillStatement kill) { | | 428 | + this.visit(kill, null); | | 429 | + } | | 430 | + | | 431 | + default <S> T visit(HandlerStatement handler, S context) { | | 432 | + return null; | | 433 | + } | | 434 | + | | 435 | + default void visit(HandlerStatement handler) { | | 436 | + this.visit(handler, null); | | 437 | + } | | 438 | + | 412 | 439 | default <S> T visit(VacuumStatement vacuum, S context) { | 413 | 440 | return null; | 414 | 441 | } | |
Collapse file Copy file name to clipboardExpand all lines: src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +21Lines changed: 21 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| 94 | 94 | import net.sf.jsqlparser.statement.insert.InsertBulk; | 95 | 95 | import net.sf.jsqlparser.statement.insert.InsertConflictAction; | 96 | 96 | import net.sf.jsqlparser.statement.insert.ParenthesedInsert; | | 97 | +import net.sf.jsqlparser.statement.admin.FlushStatement; | | 98 | +import net.sf.jsqlparser.statement.admin.KillStatement; | | 99 | +import net.sf.jsqlparser.statement.handler.HandlerStatement; | 97 | 100 | import net.sf.jsqlparser.statement.lock.BackupLockStatement; | 98 | 101 | import net.sf.jsqlparser.statement.lock.LockStatement; | 99 | 102 | import net.sf.jsqlparser.statement.lock.UnlockStatement; | @@ -751,6 +754,24 @@ public <S> T visit(TableMaintenanceStatement statement, S context) { | 751 | 754 | return null; | 752 | 755 | } | 753 | 756 |
| | 757 | + @Override | | 758 | + public <S> T visit(FlushStatement flush, S context) { | | 759 | + return null; | | 760 | + } | | 761 | + | | 762 | + @Override | | 763 | + public <S> T visit(KillStatement kill, S context) { | | 764 | + expressionVisitor.visitExpression(kill.getProcesslistId(), context); | | 765 | + return null; | | 766 | + } | | 767 | + | | 768 | + @Override | | 769 | + public <S> T visit(HandlerStatement handler, S context) { | | 770 | + expressionVisitor.visitExpression(handler.getKeyValues(), context); | | 771 | + expressionVisitor.visitExpression(handler.getWhere(), context); | | 772 | + return null; | | 773 | + } | | 774 | + | 754 | 775 | @Override | 755 | 776 | public <S> T visit(VacuumStatement vacuum, S context) { | 756 | 777 | return null; | |
Collapse file Copy file name to clipboard +97Lines changed: 97 additions & 0 deletions | Original file line number | Diff line number | Diff line change |
|---|
| | 1 | +/*- | | 2 | + * #%L | | 3 | + * JSQLParser library | | 4 | + * %% | | 5 | + * Copyright (C) 2004 - 2026 JSQLParser | | 6 | + * %% | | 7 | + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 | | 8 | + * #L% | | 9 | + */ | | 10 | +package net.sf.jsqlparser.statement.admin; | | 11 | + | | 12 | +import java.util.Locale; | | 13 | +import java.util.Objects; | | 14 | +import net.sf.jsqlparser.expression.StringValue; | | 15 | +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; | | 16 | + | | 17 | +/** | | 18 | + * One flush option of MySQL {@code FLUSH}, such as {@code BINARY LOGS} or | | 19 | + * {@code RELAY LOGS FOR CHANNEL 'c1'}. | | 20 | + * | | 21 | + * @see <a href="https://dev.mysql.com/doc/refman/8.4/en/flush.html">MySQL FLUSH</a> | | 22 | + */ | | 23 | +public class FlushOption extends ASTNodeAccessImpl { | | 24 | + private Kind kind; | | 25 | + private StringValue channel; | | 26 | + | | 27 | + /** The flush options of MySQL 8.4. */ | | 28 | + public enum Kind { | | 29 | + BINARY_LOGS, ENGINE_LOGS, ERROR_LOGS, GENERAL_LOGS, LOGS, OPTIMIZER_COSTS, PRIVILEGES, RELAY_LOGS, SLOW_LOGS, STATUS, USER_RESOURCES; | | 30 | + | | 31 | + /** Returns the SQL spelling, for example {@code BINARY LOGS}. */ | | 32 | + public String getKeyword() { | | 33 | + return this == OPTIMIZER_COSTS || this == USER_RESOURCES ? name() | | 34 | + : name().replace('_', ' '); | | 35 | + } | | 36 | + | | 37 | + /** | | 38 | + * Returns the option spelled by the keyword, ignoring case, or null. | | 39 | + * | | 40 | + * @param keyword the words of the option separated by one space, such as | | 41 | + * {@code binary logs} | | 42 | + */ | | 43 | + public static Kind fromKeyword(String keyword) { | | 44 | + String upper = keyword == null ? null : keyword.toUpperCase(Locale.ROOT); | | 45 | + for (Kind kind : values()) { | | 46 | + if (kind.getKeyword().equals(upper)) { | | 47 | + return kind; | | 48 | + } | | 49 | + } | | 50 | + return null; | | 51 | + } | | 52 | + } | | 53 | + | | 54 | + public FlushOption(Kind kind) { | | 55 | + setKind(kind); | | 56 | + } | | 57 | + | | 58 | + public Kind getKind() { | | 59 | + return kind; | | 60 | + } | | 61 | + | | 62 | + public void setKind(Kind kind) { | | 63 | + this.kind = Objects.requireNonNull(kind); | | 64 | + } | | 65 | + | | 66 | + public FlushOption withKind(Kind kind) { | | 67 | + setKind(kind); | | 68 | + return this; | | 69 | + } | | 70 | + | | 71 | + /** Returns the channel of {@code RELAY LOGS FOR CHANNEL 'name'}, or null. */ | | 72 | + public StringValue getChannel() { | | 73 | + return channel; | | 74 | + } | | 75 | + | | 76 | + public void setChannel(StringValue channel) { | | 77 | + this.channel = channel; | | 78 | + } | | 79 | + | | 80 | + public FlushOption withChannel(StringValue channel) { | | 81 | + setChannel(channel); | | 82 | + return this; | | 83 | + } | | 84 | + | | 85 | + public StringBuilder appendTo(StringBuilder builder) { | | 86 | + builder.append(kind.getKeyword()); | | 87 | + if (channel != null) { | | 88 | + builder.append(" FOR CHANNEL ").append(channel); | | 89 | + } | | 90 | + return builder; | | 91 | + } | | 92 | + | | 93 | + @Override | | 94 | + public String toString() { | | 95 | + return appendTo(new StringBuilder()).toString(); | | 96 | + } | | 97 | +} |
|