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