Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,7 @@ and missing syntax gets added on demand — [open an issue](https://github.com/J
| **MySQL table maintenance** | `ANALYZE` · `CHECK` · `CHECKSUM` · `OPTIMIZE` · `REPAIR TABLE` |
| **PostgreSQL maintenance** | `VACUUM` · `ANALYZE` · `CLUSTER` · `CHECKPOINT` |
| **MySQL locks** | `LOCK TABLES` · `UNLOCK TABLES` · `LOCK INSTANCE FOR BACKUP` · `UNLOCK INSTANCE` |
| **MySQL server administration** | `FLUSH` · `KILL` · `RESET PERSIST` · `HANDLER … OPEN`/`READ`/`CLOSE` |
| **MySQL account management** | `CREATE`/`ALTER`/`RENAME USER` · `CREATE ROLE` · `SET ROLE` · `SET DEFAULT ROLE` · `SET PASSWORD` |
| **Tablespaces** | MySQL and PostgreSQL `CREATE TABLESPACE` · `ALTER TABLESPACE` |
| **PostgreSQL RLS** | `CREATE POLICY` · `ALTER TABLE … ENABLE`/`DISABLE`/`FORCE`/`NO FORCE ROW LEVEL SECURITY` |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ private void acceptStatementToken(Token token, Token next) {
if (statementStart) {
statementKind = kind;
}
if (statementKind == K_DECLARE && keyword(token, "HANDLER")) {
if (statementKind == K_DECLARE && token.kind == K_HANDLER) {
handlerAction = true;
}
statementStart = false;
Expand Down
30 changes: 30 additions & 0 deletions src/main/java/net/sf/jsqlparser/parser/feature/Feature.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
import net.sf.jsqlparser.statement.ShowStatement;
import net.sf.jsqlparser.statement.TableMaintenanceStatement;
import net.sf.jsqlparser.statement.UseStatement;
import net.sf.jsqlparser.statement.admin.FlushStatement;
import net.sf.jsqlparser.statement.admin.KillStatement;
import net.sf.jsqlparser.statement.alter.Alter;
import net.sf.jsqlparser.statement.alter.AlterEventTrigger;
import net.sf.jsqlparser.statement.alter.sequence.AlterSequence;
Expand All @@ -51,6 +53,7 @@
import net.sf.jsqlparser.statement.drop.Drop;
import net.sf.jsqlparser.statement.execute.Execute;
import net.sf.jsqlparser.statement.grant.Grant;
import net.sf.jsqlparser.statement.handler.HandlerStatement;
import net.sf.jsqlparser.statement.lock.BackupLockStatement;
import net.sf.jsqlparser.statement.lock.UnlockStatement;
import net.sf.jsqlparser.statement.merge.Merge;
Expand Down Expand Up @@ -490,6 +493,27 @@ public enum Feature {
*/
tableMaintenance,

/**
* MySQL "FLUSH" statement is allowed
*
* @see FlushStatement
*/
flush,

/**
* MySQL "KILL" statement is allowed
*
* @see KillStatement
*/
kill,

/**
* MySQL "HANDLER ... OPEN", "HANDLER ... READ" and "HANDLER ... CLOSE" statements are allowed
*
* @see HandlerStatement
*/
handler,

/**
* PostgreSQL "VACUUM" statement is allowed
*
Expand Down Expand Up @@ -930,6 +954,12 @@ public enum Feature {
* @see ResetStatement
*/
reset,
/**
* MySQL "RESET PERSIST" statement is allowed
*
* @see ResetStatement#isPersist()
*/
resetPersist,
/**
* @see Pivot
*/
Expand Down
59 changes: 57 additions & 2 deletions src/main/java/net/sf/jsqlparser/statement/ResetStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,18 @@

import net.sf.jsqlparser.parser.ASTNodeAccessImpl;

/**
* PostgreSQL {@code RESET configuration_parameter}, {@code RESET ALL} and {@code RESET TIME ZONE},
* and MySQL {@code RESET PERSIST [[IF EXISTS] system_var_name]}, which {@link #isPersist()} marks.
*
* @see <a href="https://www.postgresql.org/docs/current/sql-reset.html">PostgreSQL RESET</a>
* @see <a href="https://dev.mysql.com/doc/refman/8.4/en/reset-persist.html">MySQL RESET PERSIST</a>
*/
public final class ResetStatement extends ASTNodeAccessImpl implements Statement {

private String name = "";
private boolean persist;
private boolean ifExists;

public ResetStatement() {
// empty constructor
Expand All @@ -27,6 +36,10 @@ public void add(String name) {
this.name = name;
}

/**
* Returns the parameter or, for RESET PERSIST, the system variable; null when RESET PERSIST
* names none and removes every persisted variable.
*/
public String getName() {
return name;
}
Expand All @@ -35,10 +48,52 @@ public void setName(String name) {
this.name = name;
}

/** Whether this is MySQL RESET PERSIST, which removes persisted global system variables. */
public boolean isPersist() {
return persist;
}

public void setPersist(boolean persist) {
this.persist = persist;
}

public ResetStatement withPersist(boolean persist) {
setPersist(persist);
return this;
}

/** Whether RESET PERSIST has IF EXISTS before the variable name. */
public boolean isIfExists() {
return ifExists;
}

public void setIfExists(boolean ifExists) {
this.ifExists = ifExists;
}

public ResetStatement withIfExists(boolean ifExists) {
setIfExists(ifExists);
return this;
}

public StringBuilder appendTo(StringBuilder builder) {
builder.append("RESET ");
if (!persist) {
return builder.append(name);
}
builder.append("PERSIST");
if (ifExists) {
builder.append(" IF EXISTS");
}
if (name != null && !name.isEmpty()) {
builder.append(' ').append(name);
}
return builder;
}

@Override
public String toString() {
StringBuilder b = new StringBuilder("RESET ").append(name);
return b.toString();
return appendTo(new StringBuilder()).toString();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,9 @@
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.insert.InsertBulk;
import net.sf.jsqlparser.statement.load.LoadDataStatement;
import net.sf.jsqlparser.statement.admin.FlushStatement;
import net.sf.jsqlparser.statement.admin.KillStatement;
import net.sf.jsqlparser.statement.handler.HandlerStatement;
import net.sf.jsqlparser.statement.lock.BackupLockStatement;
import net.sf.jsqlparser.statement.lock.LockStatement;
import net.sf.jsqlparser.statement.lock.UnlockStatement;
Expand Down Expand Up @@ -783,6 +786,40 @@ public <S> Void visit(TableMaintenanceStatement statement, S context) {
return null;
}

@Override
public <S> Void visit(FlushStatement flush, S context) {
// a server operation like ALTER SYSTEM FLUSH; WITH READ LOCK and FOR EXPORT also lock
analysis.claimTopLevel();
analysis.certain(StmtFeature.MODIFIES_SESSION);
if (flush.getTableLock() != null) {
analysis.certain(StmtFeature.MODIFIES_TRANSACTION);
}
return null;
}

@Override
public <S> Void visit(KillStatement kill, S context) {
// ends another session or its statement, like ALTER SYSTEM KILL SESSION
analysis.claimTopLevel();
analysis.certain(StmtFeature.MODIFIES_SESSION);
return null;
}

@Override
public <S> Void visit(HandlerStatement handler, S context) {
if (handler.getAction() != HandlerStatement.Action.READ) {
// OPEN and CLOSE change the handlers of the session
analysis.claimTopLevel();
analysis.certain(StmtFeature.MODIFIES_SESSION);
return null;
}
if (analysis.claimTopLevel()) {
analysis.certain(StmtFeature.RETURNS_RESULT_SET);
}
analysis.certain(StmtFeature.READS_DATA);
return super.visit(handler, context);
}

@Override
public <S> Void visit(VacuumStatement vacuum, S context) {
// reclaims storage and, with ANALYZE, rewrites statistics; FULL rewrites the tables
Expand Down
27 changes: 27 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.insert.InsertBulk;
import net.sf.jsqlparser.statement.insert.ParenthesedInsert;
import net.sf.jsqlparser.statement.admin.FlushStatement;
import net.sf.jsqlparser.statement.admin.KillStatement;
import net.sf.jsqlparser.statement.handler.HandlerStatement;
import net.sf.jsqlparser.statement.lock.BackupLockStatement;
import net.sf.jsqlparser.statement.lock.LockStatement;
import net.sf.jsqlparser.statement.lock.UnlockStatement;
Expand Down Expand Up @@ -376,6 +379,30 @@ default void visit(TableMaintenanceStatement statement) {
this.visit(statement, null);
}

default <S> T visit(FlushStatement flush, S context) {
return null;
}

default void visit(FlushStatement flush) {
this.visit(flush, null);
}

default <S> T visit(KillStatement kill, S context) {
return null;
}

default void visit(KillStatement kill) {
this.visit(kill, null);
}

default <S> T visit(HandlerStatement handler, S context) {
return null;
}

default void visit(HandlerStatement handler) {
this.visit(handler, null);
}

default <S> T visit(VacuumStatement vacuum, S context) {
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@
import net.sf.jsqlparser.statement.insert.InsertBulk;
import net.sf.jsqlparser.statement.insert.InsertConflictAction;
import net.sf.jsqlparser.statement.insert.ParenthesedInsert;
import net.sf.jsqlparser.statement.admin.FlushStatement;
import net.sf.jsqlparser.statement.admin.KillStatement;
import net.sf.jsqlparser.statement.handler.HandlerStatement;
import net.sf.jsqlparser.statement.lock.BackupLockStatement;
import net.sf.jsqlparser.statement.lock.LockStatement;
import net.sf.jsqlparser.statement.lock.UnlockStatement;
Expand Down Expand Up @@ -723,6 +726,24 @@ public <S> T visit(TableMaintenanceStatement statement, S context) {
return null;
}

@Override
public <S> T visit(FlushStatement flush, S context) {
return null;
}

@Override
public <S> T visit(KillStatement kill, S context) {
expressionVisitor.visitExpression(kill.getProcesslistId(), context);
return null;
}

@Override
public <S> T visit(HandlerStatement handler, S context) {
expressionVisitor.visitExpression(handler.getKeyValues(), context);
expressionVisitor.visitExpression(handler.getWhere(), context);
return null;
}

@Override
public <S> T visit(VacuumStatement vacuum, S context) {
return null;
Expand Down
97 changes: 97 additions & 0 deletions src/main/java/net/sf/jsqlparser/statement/admin/FlushOption.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2026 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.admin;

import java.util.Locale;
import java.util.Objects;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;

/**
* One flush option of MySQL {@code FLUSH}, such as {@code BINARY LOGS} or
* {@code RELAY LOGS FOR CHANNEL 'c1'}.
*
* @see <a href="https://dev.mysql.com/doc/refman/8.4/en/flush.html">MySQL FLUSH</a>
*/
public class FlushOption extends ASTNodeAccessImpl {
private Kind kind;
private StringValue channel;

/** The flush options of MySQL 8.4. */
public enum Kind {
BINARY_LOGS, ENGINE_LOGS, ERROR_LOGS, GENERAL_LOGS, LOGS, OPTIMIZER_COSTS, PRIVILEGES, RELAY_LOGS, SLOW_LOGS, STATUS, USER_RESOURCES;

/** Returns the SQL spelling, for example {@code BINARY LOGS}. */
public String getKeyword() {
return this == OPTIMIZER_COSTS || this == USER_RESOURCES ? name()
: name().replace('_', ' ');
}

/**
* Returns the option spelled by the keyword, ignoring case, or null.
*
* @param keyword the words of the option separated by one space, such as
* {@code binary logs}
*/
public static Kind fromKeyword(String keyword) {
String upper = keyword == null ? null : keyword.toUpperCase(Locale.ROOT);
for (Kind kind : values()) {
if (kind.getKeyword().equals(upper)) {
return kind;
}
}
return null;
}
}

public FlushOption(Kind kind) {
setKind(kind);
}

public Kind getKind() {
return kind;
}

public void setKind(Kind kind) {
this.kind = Objects.requireNonNull(kind);
}

public FlushOption withKind(Kind kind) {
setKind(kind);
return this;
}

/** Returns the channel of {@code RELAY LOGS FOR CHANNEL 'name'}, or null. */
public StringValue getChannel() {
return channel;
}

public void setChannel(StringValue channel) {
this.channel = channel;
}

public FlushOption withChannel(StringValue channel) {
setChannel(channel);
return this;
}

public StringBuilder appendTo(StringBuilder builder) {
builder.append(kind.getKeyword());
if (channel != null) {
builder.append(" FOR CHANNEL ").append(channel);
}
return builder;
}

@Override
public String toString() {
return appendTo(new StringBuilder()).toString();
}
}
Loading
Loading