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 @@ -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` |
Expand Down
5 changes: 5 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 @@ -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
Expand Down
33 changes: 29 additions & 4 deletions src/main/java/net/sf/jsqlparser/statement/DeallocateStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 <a href="https://dev.mysql.com/doc/refman/8.4/en/deallocate-prepare.html">MySQL DEALLOCATE
* PREPARE</a>
*/
public class DeallocateStatement extends ASTNodeAccessImpl implements Statement {
private Keyword keyword = Keyword.DEALLOCATE;
private String name;
private boolean usingPrepareKeyword;

Expand All @@ -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) {
Expand All @@ -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);
Expand All @@ -68,4 +88,9 @@ public String toString() {
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
return statementVisitor.visit(this, context);
}

/** The keyword that starts the statement. */
public enum Keyword {
DEALLOCATE, DROP
}
}
45 changes: 43 additions & 2 deletions src/main/java/net/sf/jsqlparser/statement/DescribeStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 <a href="https://dev.mysql.com/doc/refman/8.4/en/explain.html">MySQL DESCRIBE</a>
*/
public class DescribeStatement extends ASTNodeAccessImpl implements Statement {

private Table table;
private Select select;
private String describeType;
private Expression columnPattern;

public DescribeStatement() {
// empty constructor
Expand Down Expand Up @@ -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<Select> selectPrinter,
Consumer<Expression> expressionPrinter) {
builder.append(describeType).append(" ");
if (select != null) {
selectPrinter.accept(select);
} else {
builder.append(table);
if (columnPattern != null) {
builder.append(" ");
expressionPrinter.accept(columnPattern);
}
}
return builder;
}

@Override
Expand Down
53 changes: 52 additions & 1 deletion src/main/java/net/sf/jsqlparser/statement/DoStatement.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,26 @@
*/
package net.sf.jsqlparser.statement;

import java.util.List;
import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.StringValue;
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
import net.sf.jsqlparser.statement.select.SelectItem;

/** A PostgreSQL anonymous routine. The language-specific body remains a string literal. */
/**
* A {@code DO} statement: a PostgreSQL anonymous routine, whose language-specific body remains a
* string literal, or MySQL's {@code DO expr [, expr] ...}, which evaluates expressions without
* returning a result. MySQL reads the expressions as a select list, so they can carry aliases.
*
* @see <a href="https://www.postgresql.org/docs/18/sql-do.html">PostgreSQL DO</a>
* @see <a href="https://dev.mysql.com/doc/refman/8.4/en/do.html">MySQL DO</a>
*/
public class DoStatement extends ASTNodeAccessImpl implements Statement {
private StringValue code;
private String language;
private boolean languageBeforeCode;
private List<SelectItem<?>> selectItems;

public StringValue getCode() {
return code;
Expand Down Expand Up @@ -54,8 +65,48 @@ public void setLanguageBeforeCode(boolean languageBeforeCode) {
this.languageBeforeCode = languageBeforeCode;
}

/** The expressions of MySQL's form, or null for a PostgreSQL code block. */
public List<SelectItem<?>> getSelectItems() {
return selectItems;
}

public void setSelectItems(List<SelectItem<?>> selectItems) {
this.selectItems = selectItems;
}

public DoStatement withSelectItems(List<SelectItem<?>> selectItems) {
setSelectItems(selectItems);
return this;
}

/** Visits the code block, or the expression of every select item. */
public void visitExpressions(Consumer<Expression> visitor) {
if (selectItems != null) {
for (SelectItem<?> item : selectItems) {
visitor.accept(item.getExpression());
}
} else if (code != null) {
visitor.accept(code);
}
}

public StringBuilder appendTo(StringBuilder builder, Consumer<StringValue> codePrinter) {
return appendTo(builder, codePrinter, builder::append);
}

/** Renders the code block or the select items through the caller's writers. */
public StringBuilder appendTo(StringBuilder builder, Consumer<StringValue> codePrinter,
Consumer<SelectItem<?>> itemPrinter) {
builder.append("DO ");
if (selectItems != null) {
for (int i = 0; i < selectItems.size(); i++) {
if (i > 0) {
builder.append(", ");
}
itemPrinter.accept(selectItems.get(i));
}
return builder;
}
if (languageBeforeCode && language != null) {
builder.append("LANGUAGE ").append(language).append(' ');
}
Expand Down
Loading
Loading