Skip to content
Merged
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,11 @@
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.schema.Table;

/** A structured option following a {@code CREATE TABLE} definition. */
/**
* A shared CREATE/ALTER TABLE option with either opaque tokens or structured properties. Setting
* non-null tokens discards all structured properties. A structured setter discards the tokens;
* their contents are never parsed or restored by a later setter.
*/
public class TableOption implements Serializable {

private ForeignTableOptions foreignTableOptions;
Expand All @@ -38,21 +42,39 @@ public ForeignTableOptions getForeignTableOptions() {
return foreignTableOptions;
}

/** Replaces the current contents with a structured PostgreSQL SERVER clause. */
public void setForeignTableOptions(ForeignTableOptions options) {
clearContents();
kind = Kind.FOREIGN_SERVER;
name = "SERVER";
foreignTableOptions = options;
}

public static TableOption foreignServer(ForeignTableOptions options) {
TableOption option = new TableOption(Kind.FOREIGN_SERVER, "SERVER", null, false);
option.foreignTableOptions = options;
TableOption option = new TableOption();
option.setForeignTableOptions(options);
return option;
}

public ColumnOption.Storage getTablespaceStorage() {
return tablespaceStorage;
}

/**
* Sets the TABLESPACE storage modifier. A non-null modifier selects TABLESPACE and discards
* another option's contents; an existing TABLESPACE keeps its name, value and equals spelling.
*/
public void setTablespaceStorage(ColumnOption.Storage storage) {
if (storage != null && storage != ColumnOption.Storage.DISK
&& storage != ColumnOption.Storage.MEMORY) {
throw new IllegalArgumentException("TABLESPACE storage must be DISK or MEMORY");
}
if (storage != null && kind != Kind.TABLESPACE) {
clearContents();
kind = Kind.TABLESPACE;
name = "TABLESPACE";
}
tokens = null;
tablespaceStorage = storage;
}

Expand All @@ -61,22 +83,18 @@ public List<IndexOption> getStorageParameters() {
}

public void setStorageParameters(List<IndexOption> storageParameters) {
clearContents();
this.storageParameters = storageParameters;
foreignTableOptions = null;
tablespaceStorage = null;
kind = Kind.STORAGE_PARAMETERS;
name = "WITH";
value = null;
tokens = null;
unionTables = null;
}

public void appendTo(StringBuilder builder,
java.util.function.Consumer<net.sf.jsqlparser.expression.Expression> expressionPrinter) {
if (foreignTableOptions != null) {
foreignTableOptions.appendTo(builder, expressionPrinter);
} else if (storageParameters != null) {
builder.append("WITH ");
builder.append(name).append(useEquals ? " = " : " ");
IndexOption.appendListTo(builder, storageParameters, expressionPrinter);
} else {
builder.append(toString());
Expand Down Expand Up @@ -108,6 +126,7 @@ public Kind getKind() {
}

public void setKind(Kind kind) {
tokens = null;
this.kind = kind;
if (kind != Kind.TABLESPACE) {
tablespaceStorage = null;
Expand All @@ -128,6 +147,7 @@ public String getName() {
}

public void setName(String name) {
tokens = null;
this.name = name;
}

Expand All @@ -142,6 +162,7 @@ public String getValue() {
}

public void setValue(String value) {
tokens = null;
this.value = value;
foreignTableOptions = null;
unionTables = null;
Expand All @@ -155,14 +176,12 @@ public List<Table> getUnionTables() {

/** Replaces raw option contents with structured UNION table references. */
public void setUnionTables(List<Table> unionTables) {
boolean equals = useEquals;
clearContents();
this.unionTables = unionTables;
foreignTableOptions = null;
tablespaceStorage = null;
kind = Kind.UNION;
name = "UNION";
value = null;
tokens = null;
storageParameters = null;
useEquals = equals;
}

public TableOption withUnionTables(List<Table> unionTables) {
Expand All @@ -175,10 +194,14 @@ public boolean isUseEquals() {
}

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

/** Returns the original token groups used by the legacy table-options API. */
/**
* Returns the original, mutable token list for an opaque option, or an unmodifiable snapshot of
* the current structured properties. Editing tokens does not classify or parse them.
*/
public List<String> getTokens() {
if (tokens != null) {
return tokens;
Expand All @@ -201,14 +224,27 @@ public List<String> getTokens() {
return Collections.unmodifiableList(result);
}

/**
* Replaces all structured properties with opaque tokens and {@link Kind#OTHER}. Null clears
* opaque tokens without restoring discarded properties; it leaves structured options alone.
*/
public void setTokens(List<String> tokens) {
this.tokens = tokens;
if (tokens != null) {
tablespaceStorage = null;
foreignTableOptions = null;
unionTables = null;
storageParameters = null;
clearContents();
}
this.tokens = tokens;
}

private void clearContents() {
kind = Kind.OTHER;
name = null;
value = null;
useEquals = false;
tokens = null;
tablespaceStorage = null;
foreignTableOptions = null;
unionTables = null;
storageParameters = null;
}

public TableOption withKind(Kind kind) {
Expand Down
35 changes: 35 additions & 0 deletions src/site/sphinx/usage.rst
Original file line number Diff line number Diff line change
Expand Up @@ -337,6 +337,41 @@ The existing getter and setter names remain, but their return and parameter type
have changed, so clients must recompile. ``Truncate.setCascade(false)`` still
clears the clause. Foreign-key referential actions retain their separate enum.

Edit shared table options
-------------------------

``CreateTable.getTableOptions()`` and
``AlterExpressionTableOption.getStructuredTableOption()`` use the same mutable
``TableOption`` model. Structured values and opaque tokens are alternative
representations. ``setTokens(nonNullList)`` discards the previous kind, name,
value and child nodes: the option becomes ``Kind.OTHER`` without parsing the
tokens. Raw token lists remain mutable; ``getTokens()`` on a structured option
returns an unmodifiable snapshot.

.. code-block:: java

CreateTable table = (CreateTable) CCJSqlParserUtil.parse(
"CREATE TABLE t (id INT) ENGINE=InnoDB");
TableOption option = table.getTableOption(TableOption.Kind.ENGINE).orElseThrow();
option.setTokens(List.of("ROW_FORMAT", "=", "DYNAMIC"));
table.getTableOption(TableOption.Kind.ENGINE).isEmpty(); // true

// Supply structured properties explicitly; the old tokens are discarded.
option.withKind(TableOption.Kind.COMMENT).withName("COMMENT")
.withValue("'new'").withUseEquals(true);
// CREATE TABLE t (id INT) COMMENT = 'new'

Any structured setter leaves the opaque representation; it never recovers
previous values from those tokens. ``setTokens(null)`` clears opaque tokens
without restoring discarded properties, and leaves structured options alone.
``setUnionTables``, ``setStorageParameters`` and ``setForeignTableOptions``
replace the current contents with their respective structured payloads. Their
lists and child nodes remain editable. An empty UNION list means ``UNION ()``;
a null payload omits its value. A non-null ``setTablespaceStorage`` also selects
TABLESPACE; supply its tablespace name with ``setValue``. Choose the new kind and spelling explicitly
when using the scalar setters. These methods edit the AST rather than checking
database-specific DDL validity.

Inspect PostgreSQL schema statements
------------------------------------

Expand Down
Loading
Loading