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
6 changes: 6 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 @@ -509,6 +509,12 @@ public enum Feature {
* @see CreateDatabase
*/
createDatabase,
/**
* SQL "ALTER DATABASE" statement is allowed
*
* @see net.sf.jsqlparser.statement.alter.database.AlterDatabase
*/
alterDatabase,
/**
* SQL "CREATE SCHEMA" statement is allowed
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
/*-
* #%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;

import java.io.Serializable;
import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.expression.operators.relational.ExpressionList;

/**
* A PostgreSQL {@code SET} or {@code RESET} of a configuration parameter, shared by statements that
* store parameter defaults, such as {@code ALTER ROLE} and {@code ALTER DATABASE}:
*
* <pre>
* SET parameter { TO | = } { value [, ...] | DEFAULT }
* SET parameter FROM CURRENT
* RESET { parameter | ALL }
* </pre>
*
* Parameter names keep their SQL spelling, including qualifiers and identifier quotes.
* {@code RESET ALL} uses the parameter name {@code ALL}.
*/
public class ConfigurationParameterChange implements Serializable {

public enum Action {
SET, RESET
}

/** What a {@code SET} assigns. Only the selected kind is rendered. */
public enum ValueKind {
/** The explicit values of {@link #getValues()}. */
VALUES,
/** {@code TO DEFAULT} or {@code = DEFAULT}. */
DEFAULT,
/** {@code FROM CURRENT}. */
FROM_CURRENT
}

private Action action = Action.SET;
private String parameter;
private ValueKind valueKind = ValueKind.VALUES;
private boolean useEquals;
private ExpressionList<Expression> values;

public ConfigurationParameterChange() {}

public ConfigurationParameterChange(Action action, String parameter) {
this.action = action;
this.parameter = parameter;
}

public Action getAction() {
return action;
}

public void setAction(Action action) {
this.action = action;
}

public String getParameter() {
return parameter;
}

public void setParameter(String parameter) {
this.parameter = parameter;
}

public ValueKind getValueKind() {
return valueKind;
}

/**
* Selects what a {@code SET} assigns. The values are retained when another kind is selected.
*
* @param valueKind the assigned value kind
*/
public void setValueKind(ValueKind valueKind) {
this.valueKind = valueKind;
}

/**
* Whether {@code =} rather than {@code TO} precedes the value.
*
* @return {@code true} for {@code =}
*/
public boolean isUseEquals() {
return useEquals;
}

public void setUseEquals(boolean useEquals) {
this.useEquals = useEquals;
}

/**
* The values assigned by {@link ValueKind#VALUES}, as a mutable list.
*
* @return the values, or {@code null} if none were set
*/
public ExpressionList<Expression> getValues() {
return values;
}

public void setValues(ExpressionList<Expression> values) {
this.values = values;
}

public ConfigurationParameterChange withAction(Action action) {
setAction(action);
return this;
}

public ConfigurationParameterChange withParameter(String parameter) {
setParameter(parameter);
return this;
}

public ConfigurationParameterChange withValueKind(ValueKind valueKind) {
setValueKind(valueKind);
return this;
}

public ConfigurationParameterChange withUseEquals(boolean useEquals) {
setUseEquals(useEquals);
return this;
}

public ConfigurationParameterChange withValues(ExpressionList<Expression> values) {
setValues(values);
return this;
}

/**
* Appends this clause to a builder.
*
* @param builder the target
* @param valueRenderer appends each value, for example through an expression deparser
* @return the builder
*/
public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> valueRenderer) {
if (action == Action.RESET) {
return builder.append("RESET ").append(parameter);
}
builder.append("SET ").append(parameter);
if (valueKind == ValueKind.FROM_CURRENT) {
return builder.append(" FROM CURRENT");
}
builder.append(useEquals ? " = " : " TO ");
if (valueKind == ValueKind.DEFAULT) {
return builder.append("DEFAULT");
}
if (values != null) {
for (int i = 0; i < values.size(); i++) {
if (i > 0) {
builder.append(", ");
}
valueRenderer.accept(values.get(i));
}
}
return builder;
}

@Override
public String toString() {
StringBuilder builder = new StringBuilder();
return appendTo(builder, builder::append).toString();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,44 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.ConfigurationParameterChange;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
import net.sf.jsqlparser.statement.create.database.DatabaseOption;

/** MySQL ALTER DATABASE (or SCHEMA); a missing name selects the current database. */
/**
* MySQL or PostgreSQL {@code ALTER DATABASE}. MySQL's {@code ALTER SCHEMA} synonym only changes
* options, and a missing name selects the current database. The options use the same
* {@link DatabaseOption} model as {@code CREATE DATABASE}. Names retain SQL identifier quoting.
*/
public class AlterDatabase implements Statement {

public enum Action {
/** MySQL options or PostgreSQL {@code [WITH] option ...}, see {@link #getOptions()}. */
OPTIONS,
/** {@code RENAME TO}, see {@link #getNewName()}. */
RENAME,
/** {@code OWNER TO}, see {@link #getOwner()}. */
OWNER,
/** {@code SET TABLESPACE}, see {@link #getTablespace()}. */
SET_TABLESPACE,
/** {@code REFRESH COLLATION VERSION}. */
REFRESH_COLLATION_VERSION,
/** {@code SET} or {@code RESET}, see {@link #getParameterChange()}. */
CONFIGURATION_PARAMETER
}

private String databaseName;
private boolean useSchemaKeyword;
private Action action = Action.OPTIONS;
private boolean useWith;
private final List<DatabaseOption> options = new ArrayList<>();
private String newName;
private String owner;
private String tablespace;
private ConfigurationParameterChange parameterChange;

public String getDatabaseName() {
return databaseName;
Expand All @@ -38,6 +67,37 @@ public void setUseSchemaKeyword(boolean useSchemaKeyword) {
this.useSchemaKeyword = useSchemaKeyword;
}

/**
* The rendered alteration. Payloads of other actions are retained for a later switch back.
*
* @return the action, {@link Action#OPTIONS} unless changed
*/
public Action getAction() {
return action;
}

public void setAction(Action action) {
this.action = action;
}

/**
* Whether PostgreSQL's optional {@code WITH} precedes the options.
*
* @return {@code true} if {@code WITH} is rendered
*/
public boolean isUseWith() {
return useWith;
}

public void setUseWith(boolean useWith) {
this.useWith = useWith;
}

/**
* The options of {@link Action#OPTIONS}, as a mutable list.
*
* @return the options in source order
*/
public List<DatabaseOption> getOptions() {
return options;
}
Expand All @@ -46,13 +106,81 @@ public Optional<DatabaseOption> getOption(DatabaseOption.Kind kind) {
return options.stream().filter(option -> option.getKind() == kind).findFirst();
}

public String getNewName() {
return newName;
}

public void setNewName(String newName) {
this.newName = newName;
}

/**
* The new owner, a role name or {@code CURRENT_USER}, {@code CURRENT_ROLE} or
* {@code SESSION_USER}.
*
* @return the owner
*/
public String getOwner() {
return owner;
}

public void setOwner(String owner) {
this.owner = owner;
}

public String getTablespace() {
return tablespace;
}

public void setTablespace(String tablespace) {
this.tablespace = tablespace;
}

public ConfigurationParameterChange getParameterChange() {
return parameterChange;
}

public void setParameterChange(ConfigurationParameterChange parameterChange) {
this.parameterChange = parameterChange;
}

public StringBuilder appendTo(StringBuilder builder) {
return appendTo(builder, builder::append);
}

/**
* Appends this statement to a builder.
*
* @param builder the target
* @param valueRenderer appends each configuration parameter value
* @return the builder
*/
public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> valueRenderer) {
builder.append(useSchemaKeyword ? "ALTER SCHEMA" : "ALTER DATABASE");
if (databaseName != null) {
builder.append(' ').append(databaseName);
}
options.forEach(option -> builder.append(' ').append(option));
return builder;
switch (action) {
case RENAME:
return builder.append(" RENAME TO ").append(newName);
case OWNER:
return builder.append(" OWNER TO ").append(owner);
case SET_TABLESPACE:
return builder.append(" SET TABLESPACE ").append(tablespace);
case REFRESH_COLLATION_VERSION:
return builder.append(" REFRESH COLLATION VERSION");
case CONFIGURATION_PARAMETER:
if (parameterChange == null) {
throw new IllegalStateException("Expected a configuration parameter change");
}
return parameterChange.appendTo(builder.append(' '), valueRenderer);
default:
if (useWith) {
builder.append(" WITH");
}
options.forEach(option -> builder.append(' ').append(option));
return builder;
}
}

@Override
Expand Down
Loading
Loading