Skip to content

Commit 14d8fff

Browse files
committed
Preserve detached CREATE INDEX option isolation and traversal
Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 09e7250 commit 14d8fff

3 files changed

Lines changed: 78 additions & 2 deletions

File tree

‎src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java‎

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ public List<String> getIncludeColumns() {
8181
return options == null ? null : options.getIncludeColumns();
8282
}
8383

84+
/**
85+
* Copies the supplied list as {@link Index#setIncludeColumns(List)} does; null clears it.
86+
* {@link #getIncludeColumns()} returns the live, mutable list held by the index options.
87+
*/
8488
public void setIncludeColumns(List<String> includeColumns) {
8589
getOrCreateOptions().setIncludeColumns(includeColumns);
8690
}
@@ -99,6 +103,11 @@ public List<Index.Option> getStorageParameters() {
99103
return options == null ? null : options.getStorageParameters();
100104
}
101105

106+
/**
107+
* Copies the list container as {@link Index#setStorageParameters(List)} does, retaining the
108+
* option objects; null clears it. {@link #getStorageParameters()} returns the live, mutable
109+
* list held by the index options.
110+
*/
102111
public void setStorageParameters(List<Index.Option> storageParameters) {
103112
getOrCreateOptions().setStorageParameters(storageParameters);
104113
}
@@ -146,13 +155,20 @@ public Index getIndex() {
146155
/**
147156
* Replaces the index definition. Options supplied by the new index take precedence; omitted
148157
* options inherit the current statement options, including those set before an index was
149-
* attached. Passing null detaches the definition without discarding its options. Use the option
158+
* attached. Passing null detaches the definition without discarding its options. The detached
159+
* option lists have independent containers, with their elements retained. Use the option
150160
* setters with null to clear individual options.
151161
*/
152162
public void setIndex(Index index) {
153163
Index previousOptions = getOptions();
154164
if (index == null) {
155-
detachedOptions = previousOptions;
165+
if (this.index != null) {
166+
detachedOptions = new Index();
167+
detachedOptions.setIncludeColumns(previousOptions.getIncludeColumns());
168+
detachedOptions.setNullsDistinct(previousOptions.getNullsDistinct());
169+
detachedOptions.setStorageParameters(previousOptions.getStorageParameters());
170+
detachedOptions.setTableSpace(previousOptions.getTableSpace());
171+
}
156172
} else {
157173
if (previousOptions != null && previousOptions != index) {
158174
if (index.getIncludeColumns() == null) {

‎src/main/java/net/sf/jsqlparser/util/TableDefinitionTraversal.java‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ public static void visit(CreateIndex createIndex, Consumer<Expression> expressio
4343
accept(createIndex.getTable(), tables);
4444
if (createIndex.getIndex() != null) {
4545
visit(createIndex.getIndex(), expressions, tables);
46+
} else {
47+
visitOptions(createIndex.getStorageParameters(), expressions);
4648
}
4749
accept(createIndex.getWhere(), expressions);
4850
}

‎src/test/java/net/sf/jsqlparser/statement/create/CreateIndexOptionStateTest.java‎

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package net.sf.jsqlparser.statement.create;
1111

1212
import static org.junit.jupiter.api.Assertions.assertEquals;
13+
import static org.junit.jupiter.api.Assertions.assertNotSame;
1314
import static org.junit.jupiter.api.Assertions.assertNull;
1415
import static org.junit.jupiter.api.Assertions.assertSame;
1516

@@ -128,6 +129,63 @@ void replacementOptionsTakePrecedenceAndMissingOptionsSurviveDetachment() throws
128129
+ "NULLS NOT DISTINCT WITH (fillfactor = 90)", statement);
129130
}
130131

132+
@Test
133+
void detachedOptionSettersDoNotMutateTheRemovedIndex() throws Exception {
134+
CreateIndex statement = parse(SQL);
135+
Index removed = statement.getIndex();
136+
statement.setIndex(null);
137+
138+
assertNotSame(removed.getIncludeColumns(), statement.getIncludeColumns());
139+
assertNotSame(removed.getStorageParameters(), statement.getStorageParameters());
140+
assertSame(removed.getStorageParameters().get(0), statement.getStorageParameters().get(0));
141+
List<String> detachedColumns = statement.getIncludeColumns();
142+
List<Index.Option> detachedParameters = statement.getStorageParameters();
143+
statement.setIndex(null);
144+
assertSame(detachedColumns, statement.getIncludeColumns());
145+
assertSame(detachedParameters, statement.getStorageParameters());
146+
statement.getIncludeColumns().add("extra");
147+
assertEquals(List.of("payload", "extra"), statement.getIncludeColumns());
148+
assertEquals(List.of("payload"), removed.getIncludeColumns());
149+
150+
statement.setTableSpace("detached_space");
151+
statement.setNullsDistinct(true);
152+
statement.setIncludeColumns(List.of("detached_payload"));
153+
statement.setStorageParameters(List.of(option(90)));
154+
assertEquals("fast_space", removed.getTableSpace());
155+
assertEquals(Boolean.FALSE, removed.getNullsDistinct());
156+
assertEquals(List.of("payload"), removed.getIncludeColumns());
157+
assertEquals("80", removed.getStorageParameters().get(0).getValue().toString());
158+
159+
removed.setTableSpace("external_space");
160+
removed.setNullsDistinct(null);
161+
assertEquals("detached_space", statement.getTableSpace());
162+
assertEquals(Boolean.TRUE, statement.getNullsDistinct());
163+
statement.setIndex(new Index().withType("UNIQUE").withName("reattached")
164+
.withColumnsNames(List.of("id")));
165+
assertRoundTrip("CREATE UNIQUE INDEX reattached ON t (id) INCLUDE (detached_payload) "
166+
+ "NULLS DISTINCT WITH (fillfactor = 90) TABLESPACE detached_space", statement);
167+
}
168+
169+
@Test
170+
void optionsAreVisitedBeforeAttachmentAndAfterDetachment() throws Exception {
171+
for (CreateIndex statement : List.of(new CreateIndex(), parse(SQL))) {
172+
statement.setIndex(null);
173+
statement.setStorageParameters(List.of(option(80)));
174+
List<Long> values = new ArrayList<>();
175+
ExpressionVisitorAdapter<Void> expressions = new ExpressionVisitorAdapter<Void>() {
176+
@Override
177+
public <S> Void visit(LongValue value, S context) {
178+
assertEquals("context", context);
179+
values.add(value.getValue());
180+
return null;
181+
}
182+
};
183+
statement.accept(new StatementVisitorAdapter<>(new SelectVisitorAdapter<>(expressions)),
184+
"context");
185+
assertEquals(List.of(80L), values);
186+
}
187+
}
188+
131189
@Test
132190
void indexOptionEditsAreVisitedOnceAndCanBeDeparsedThroughCustomVisitors() throws Exception {
133191
CreateIndex statement = parse(SQL);

0 commit comments

Comments
 (0)