Skip to content

Commit 6b67189

Browse files
authored
Make table option state transitions explicit (#2765)
Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 49c1d52 commit 6b67189

3 files changed

Lines changed: 322 additions & 20 deletions

File tree

‎src/main/java/net/sf/jsqlparser/statement/create/table/TableOption.java‎

Lines changed: 56 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,11 @@
1717
import net.sf.jsqlparser.statement.select.PlainSelect;
1818
import net.sf.jsqlparser.schema.Table;
1919

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

2327
private ForeignTableOptions foreignTableOptions;
@@ -38,21 +42,39 @@ public ForeignTableOptions getForeignTableOptions() {
3842
return foreignTableOptions;
3943
}
4044

45+
/** Replaces the current contents with a structured PostgreSQL SERVER clause. */
46+
public void setForeignTableOptions(ForeignTableOptions options) {
47+
clearContents();
48+
kind = Kind.FOREIGN_SERVER;
49+
name = "SERVER";
50+
foreignTableOptions = options;
51+
}
52+
4153
public static TableOption foreignServer(ForeignTableOptions options) {
42-
TableOption option = new TableOption(Kind.FOREIGN_SERVER, "SERVER", null, false);
43-
option.foreignTableOptions = options;
54+
TableOption option = new TableOption();
55+
option.setForeignTableOptions(options);
4456
return option;
4557
}
4658

4759
public ColumnOption.Storage getTablespaceStorage() {
4860
return tablespaceStorage;
4961
}
5062

63+
/**
64+
* Sets the TABLESPACE storage modifier. A non-null modifier selects TABLESPACE and discards
65+
* another option's contents; an existing TABLESPACE keeps its name, value and equals spelling.
66+
*/
5167
public void setTablespaceStorage(ColumnOption.Storage storage) {
5268
if (storage != null && storage != ColumnOption.Storage.DISK
5369
&& storage != ColumnOption.Storage.MEMORY) {
5470
throw new IllegalArgumentException("TABLESPACE storage must be DISK or MEMORY");
5571
}
72+
if (storage != null && kind != Kind.TABLESPACE) {
73+
clearContents();
74+
kind = Kind.TABLESPACE;
75+
name = "TABLESPACE";
76+
}
77+
tokens = null;
5678
tablespaceStorage = storage;
5779
}
5880

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

6385
public void setStorageParameters(List<IndexOption> storageParameters) {
86+
clearContents();
6487
this.storageParameters = storageParameters;
65-
foreignTableOptions = null;
66-
tablespaceStorage = null;
6788
kind = Kind.STORAGE_PARAMETERS;
6889
name = "WITH";
69-
value = null;
70-
tokens = null;
71-
unionTables = null;
7290
}
7391

7492
public void appendTo(StringBuilder builder,
7593
java.util.function.Consumer<net.sf.jsqlparser.expression.Expression> expressionPrinter) {
7694
if (foreignTableOptions != null) {
7795
foreignTableOptions.appendTo(builder, expressionPrinter);
7896
} else if (storageParameters != null) {
79-
builder.append("WITH ");
97+
builder.append(name).append(useEquals ? " = " : " ");
8098
IndexOption.appendListTo(builder, storageParameters, expressionPrinter);
8199
} else {
82100
builder.append(toString());
@@ -108,6 +126,7 @@ public Kind getKind() {
108126
}
109127

110128
public void setKind(Kind kind) {
129+
tokens = null;
111130
this.kind = kind;
112131
if (kind != Kind.TABLESPACE) {
113132
tablespaceStorage = null;
@@ -128,6 +147,7 @@ public String getName() {
128147
}
129148

130149
public void setName(String name) {
150+
tokens = null;
131151
this.name = name;
132152
}
133153

@@ -142,6 +162,7 @@ public String getValue() {
142162
}
143163

144164
public void setValue(String value) {
165+
tokens = null;
145166
this.value = value;
146167
foreignTableOptions = null;
147168
unionTables = null;
@@ -155,14 +176,12 @@ public List<Table> getUnionTables() {
155176

156177
/** Replaces raw option contents with structured UNION table references. */
157178
public void setUnionTables(List<Table> unionTables) {
179+
boolean equals = useEquals;
180+
clearContents();
158181
this.unionTables = unionTables;
159-
foreignTableOptions = null;
160-
tablespaceStorage = null;
161182
kind = Kind.UNION;
162183
name = "UNION";
163-
value = null;
164-
tokens = null;
165-
storageParameters = null;
184+
useEquals = equals;
166185
}
167186

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

177196
public void setUseEquals(boolean useEquals) {
197+
tokens = null;
178198
this.useEquals = useEquals;
179199
}
180200

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

227+
/**
228+
* Replaces all structured properties with opaque tokens and {@link Kind#OTHER}. Null clears
229+
* opaque tokens without restoring discarded properties; it leaves structured options alone.
230+
*/
204231
public void setTokens(List<String> tokens) {
205-
this.tokens = tokens;
206232
if (tokens != null) {
207-
tablespaceStorage = null;
208-
foreignTableOptions = null;
209-
unionTables = null;
210-
storageParameters = null;
233+
clearContents();
211234
}
235+
this.tokens = tokens;
236+
}
237+
238+
private void clearContents() {
239+
kind = Kind.OTHER;
240+
name = null;
241+
value = null;
242+
useEquals = false;
243+
tokens = null;
244+
tablespaceStorage = null;
245+
foreignTableOptions = null;
246+
unionTables = null;
247+
storageParameters = null;
212248
}
213249

214250
public TableOption withKind(Kind kind) {

‎src/site/sphinx/usage.rst‎

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -337,6 +337,41 @@ The existing getter and setter names remain, but their return and parameter type
337337
have changed, so clients must recompile. ``Truncate.setCascade(false)`` still
338338
clears the clause. Foreign-key referential actions retain their separate enum.
339339

340+
Edit shared table options
341+
-------------------------
342+
343+
``CreateTable.getTableOptions()`` and
344+
``AlterExpressionTableOption.getStructuredTableOption()`` use the same mutable
345+
``TableOption`` model. Structured values and opaque tokens are alternative
346+
representations. ``setTokens(nonNullList)`` discards the previous kind, name,
347+
value and child nodes: the option becomes ``Kind.OTHER`` without parsing the
348+
tokens. Raw token lists remain mutable; ``getTokens()`` on a structured option
349+
returns an unmodifiable snapshot.
350+
351+
.. code-block:: java
352+
353+
CreateTable table = (CreateTable) CCJSqlParserUtil.parse(
354+
"CREATE TABLE t (id INT) ENGINE=InnoDB");
355+
TableOption option = table.getTableOption(TableOption.Kind.ENGINE).orElseThrow();
356+
option.setTokens(List.of("ROW_FORMAT", "=", "DYNAMIC"));
357+
table.getTableOption(TableOption.Kind.ENGINE).isEmpty(); // true
358+
359+
// Supply structured properties explicitly; the old tokens are discarded.
360+
option.withKind(TableOption.Kind.COMMENT).withName("COMMENT")
361+
.withValue("'new'").withUseEquals(true);
362+
// CREATE TABLE t (id INT) COMMENT = 'new'
363+
364+
Any structured setter leaves the opaque representation; it never recovers
365+
previous values from those tokens. ``setTokens(null)`` clears opaque tokens
366+
without restoring discarded properties, and leaves structured options alone.
367+
``setUnionTables``, ``setStorageParameters`` and ``setForeignTableOptions``
368+
replace the current contents with their respective structured payloads. Their
369+
lists and child nodes remain editable. An empty UNION list means ``UNION ()``;
370+
a null payload omits its value. A non-null ``setTablespaceStorage`` also selects
371+
TABLESPACE; supply its tablespace name with ``setValue``. Choose the new kind and spelling explicitly
372+
when using the scalar setters. These methods edit the AST rather than checking
373+
database-specific DDL validity.
374+
340375
Inspect PostgreSQL schema statements
341376
------------------------------------
342377

0 commit comments

Comments
 (0)