diff --git a/README.md b/README.md
index e7a8db452..7272abda2 100644
--- a/README.md
+++ b/README.md
@@ -155,6 +155,7 @@ and missing syntax gets added on demand — [open an issue](https://github.com/J
| **PostgreSQL RLS** | `CREATE POLICY` · `ALTER TABLE … ENABLE`/`DISABLE`/`FORCE`/`NO FORCE ROW LEVEL SECURITY` |
| **Routine changes** | `ALTER FUNCTION` · `ALTER PROCEDURE` · `ALTER ROUTINE` · PostgreSQL `ALTER TRIGGER` |
| **MySQL metadata statements** | `SHOW [FULL] COLUMNS`/`FIELDS` · `SHOW TABLE STATUS` · `SHOW CREATE TABLE`/`VIEW`/`PROCEDURE`/`FUNCTION`/`TRIGGER`/`EVENT`/`DATABASE`/`USER` |
+| **MySQL utility statements** | `EXPLAIN`/`DESCRIBE [ANALYZE] FORMAT = …` · `EXPLAIN FOR CONNECTION` · `DESCRIBE t col` · `PREPARE … FROM` · `EXECUTE … USING` · `DROP PREPARE` · `DO` |
| **PostgreSQL administration** | `CREATE`/`ALTER EVENT TRIGGER` · `REINDEX` · `SECURITY LABEL` |
| **Informix constraints** | `ALTER TABLE … ADD CONSTRAINT` with trailing constraint names for primary, unique, foreign and check constraints; enable with `parser.withDialect(Dialect.INFORMIX)` |
| **Salesforce SOQL** | `INCLUDES` · `EXCLUDES` |
diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java
index 447245f4a..2b7bc6ea9 100644
--- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java
+++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java
@@ -537,6 +537,11 @@ public enum Feature {
*/
executeStatementImmediate,
+ /**
+ * MySQL "EXECUTE name USING @variable, ..." of a prepared statement is allowed
+ *
+ * @see Execute#getUsingVariables()
+ */
executeUsing,
/**
* "PREPARE" and "DEALLOCATE" of a prepared statement are allowed
diff --git a/src/main/java/net/sf/jsqlparser/statement/DeallocateStatement.java b/src/main/java/net/sf/jsqlparser/statement/DeallocateStatement.java
index 58b0fe34c..e4624f7f8 100644
--- a/src/main/java/net/sf/jsqlparser/statement/DeallocateStatement.java
+++ b/src/main/java/net/sf/jsqlparser/statement/DeallocateStatement.java
@@ -12,9 +12,14 @@
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
/**
- * {@code DEALLOCATE [PREPARE] name}, which drops a statement prepared by {@link PrepareStatement}.
+ * {@code DEALLOCATE [PREPARE] name}, or MySQL's {@code DROP PREPARE name}, which drops a statement
+ * prepared by {@link PrepareStatement}.
+ *
+ * @see MySQL DEALLOCATE
+ * PREPARE
*/
public class DeallocateStatement extends ASTNodeAccessImpl implements Statement {
+ private Keyword keyword = Keyword.DEALLOCATE;
private String name;
private boolean usingPrepareKeyword;
@@ -37,8 +42,23 @@ public DeallocateStatement withName(String name) {
return this;
}
+ /** The leading keyword, {@code DEALLOCATE} unless MySQL's {@code DROP} was written. */
+ public Keyword getKeyword() {
+ return keyword;
+ }
+
+ public void setKeyword(Keyword keyword) {
+ this.keyword = keyword == null ? Keyword.DEALLOCATE : keyword;
+ }
+
+ public DeallocateStatement withKeyword(Keyword keyword) {
+ setKeyword(keyword);
+ return this;
+ }
+
+ /** Whether {@code PREPARE} follows the keyword; {@code DROP} always takes it. */
public boolean isUsingPrepareKeyword() {
- return usingPrepareKeyword;
+ return usingPrepareKeyword || keyword == Keyword.DROP;
}
public void setUsingPrepareKeyword(boolean usingPrepareKeyword) {
@@ -51,8 +71,8 @@ public DeallocateStatement withUsingPrepareKeyword(boolean usingPrepareKeyword)
}
public StringBuilder appendTo(StringBuilder builder) {
- builder.append("DEALLOCATE ");
- if (usingPrepareKeyword) {
+ builder.append(keyword).append(' ');
+ if (isUsingPrepareKeyword()) {
builder.append("PREPARE ");
}
builder.append(name);
@@ -68,4 +88,9 @@ public String toString() {
public T accept(StatementVisitor statementVisitor, S context) {
return statementVisitor.visit(this, context);
}
+
+ /** The keyword that starts the statement. */
+ public enum Keyword {
+ DEALLOCATE, DROP
+ }
}
diff --git a/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java b/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java
index 2efedba2d..ad0cadd54 100644
--- a/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java
+++ b/src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java
@@ -9,15 +9,23 @@
*/
package net.sf.jsqlparser.statement;
+import java.util.function.Consumer;
+import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.select.Select;
+/**
+ * {@code DESCRIBE} or {@code DESC} of a table, or, in DuckDB, of a query's result.
+ *
+ * @see MySQL DESCRIBE
+ */
public class DescribeStatement extends ASTNodeAccessImpl implements Statement {
private Table table;
private Select select;
private String describeType;
+ private Expression columnPattern;
public DescribeStatement() {
// empty constructor
@@ -49,10 +57,43 @@ public DescribeStatement withSelect(Select select) {
return this;
}
+ /**
+ * The MySQL column name ({@link net.sf.jsqlparser.schema.Column}) or wildcard string that
+ * limits the described columns to those it matches, or null.
+ */
+ public Expression getColumnPattern() {
+ return columnPattern;
+ }
+
+ public void setColumnPattern(Expression columnPattern) {
+ this.columnPattern = columnPattern;
+ }
+
+ public DescribeStatement withColumnPattern(Expression columnPattern) {
+ setColumnPattern(columnPattern);
+ return this;
+ }
+
@Override
public String toString() {
- return this.describeType + " "
- + (select != null ? select.toString() : table.getFullyQualifiedName());
+ StringBuilder builder = new StringBuilder();
+ return appendTo(builder, builder::append, builder::append).toString();
+ }
+
+ /** Shared by SQL rendering and statement deparsers. */
+ public StringBuilder appendTo(StringBuilder builder, Consumer