Skip to content

Commit 84e7f9f

Browse files
committed
Keep ALTER key accessors connected to structured index state
1 parent 0ecf096 commit 84e7f9f

2 files changed

Lines changed: 179 additions & 4 deletions

File tree

src/main/java/net/sf/jsqlparser/statement/alter/AlterExpression.java

Lines changed: 83 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import java.io.Serializable;
1313
import java.util.ArrayList;
14+
import java.util.AbstractList;
1415
import java.util.Arrays;
1516
import java.util.Collection;
1617
import java.util.Collections;
@@ -505,20 +506,98 @@ public void setUsingIfExists(boolean usingIfExists) {
505506
this.usingIfExists = usingIfExists;
506507
}
507508

509+
/** Returns a live view when this action has a structured PRIMARY_KEY definition. */
508510
public List<String> getPkColumns() {
509-
return pkColumns;
511+
return hasKeyIndex(Index.Kind.PRIMARY_KEY) ? new KeyColumnNames(index) : pkColumns;
510512
}
511513

512514
public void setPkColumns(List<String> pkColumns) {
513-
this.pkColumns = pkColumns;
515+
if (hasKeyIndex(Index.Kind.PRIMARY_KEY)) {
516+
replaceKeyColumns(pkColumns);
517+
this.pkColumns = null;
518+
} else {
519+
this.pkColumns = pkColumns;
520+
}
514521
}
515522

523+
/** Returns a live view when this action has a structured UNIQUE definition. */
516524
public List<String> getUkColumns() {
517-
return ukColumns;
525+
return hasKeyIndex(Index.Kind.UNIQUE) ? new KeyColumnNames(index) : ukColumns;
518526
}
519527

520528
public void setUkColumns(List<String> ukColumns) {
521-
this.ukColumns = ukColumns;
529+
if (hasKeyIndex(Index.Kind.UNIQUE)) {
530+
replaceKeyColumns(ukColumns);
531+
this.ukColumns = null;
532+
} else {
533+
this.ukColumns = ukColumns;
534+
}
535+
}
536+
537+
private boolean hasKeyIndex(Index.Kind kind) {
538+
return index != null && index.getKind() == kind;
539+
}
540+
541+
private void replaceKeyColumns(List<String> names) {
542+
List<Index.ColumnParams> replacement = new ArrayList<>();
543+
if (names != null) {
544+
List<Index.ColumnParams> previous = index.getColumns();
545+
for (int i = 0; i < names.size(); i++) {
546+
String name = names.get(i);
547+
replacement.add(previous != null && i < previous.size()
548+
&& previous.get(i).toString().equals(name) ? previous.get(i)
549+
: new Index.ColumnParams(name));
550+
}
551+
}
552+
index.setColumns(replacement);
553+
}
554+
555+
/** Adapts the legacy mutable name list without copying structured expressions to strings. */
556+
private static class KeyColumnNames extends AbstractList<String> {
557+
private final Index index;
558+
559+
KeyColumnNames(Index index) {
560+
this.index = index;
561+
}
562+
563+
@Override
564+
public String get(int position) {
565+
return index.getColumns().get(position).toString();
566+
}
567+
568+
@Override
569+
public int size() {
570+
return index.getColumns() == null ? 0 : index.getColumns().size();
571+
}
572+
573+
@Override
574+
public String set(int position, String name) {
575+
String previous = get(position);
576+
if (!previous.equals(name)) {
577+
List<Index.ColumnParams> columns = new ArrayList<>(index.getColumns());
578+
columns.set(position, new Index.ColumnParams(name));
579+
index.setColumns(columns);
580+
}
581+
return previous;
582+
}
583+
584+
@Override
585+
public void add(int position, String name) {
586+
List<Index.ColumnParams> columns = index.getColumns() == null ? new ArrayList<>()
587+
: new ArrayList<>(index.getColumns());
588+
columns.add(position, new Index.ColumnParams(name));
589+
index.setColumns(columns);
590+
modCount++;
591+
}
592+
593+
@Override
594+
public String remove(int position) {
595+
List<Index.ColumnParams> columns = new ArrayList<>(index.getColumns());
596+
String previous = columns.remove(position).toString();
597+
index.setColumns(columns);
598+
modCount++;
599+
return previous;
600+
}
522601
}
523602

524603
public String getUkName() {
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2019 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement.alter;
11+
12+
import static org.junit.jupiter.api.Assertions.*;
13+
import java.util.ArrayList;
14+
import java.util.List;
15+
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
16+
import net.sf.jsqlparser.statement.create.table.Index;
17+
import net.sf.jsqlparser.util.deparser.StatementDeParser;
18+
import org.junit.jupiter.api.Test;
19+
import org.junit.jupiter.params.ParameterizedTest;
20+
import org.junit.jupiter.params.provider.ValueSource;
21+
22+
class AlterKeyAccessorsTest {
23+
private List<String> columns(AlterExpression action, boolean primary) {
24+
return primary ? action.getPkColumns() : action.getUkColumns();
25+
}
26+
27+
@ParameterizedTest
28+
@ValueSource(booleans = {false, true})
29+
void keepsGettersSettersAndMutableListsConnectedToTheIndex(boolean primary) throws Exception {
30+
String prefix = "ALTER TABLE t ADD " + (primary ? "PRIMARY KEY" : "UNIQUE");
31+
Alter statement = (Alter) CCJSqlParserUtil.parse(prefix + " (a)");
32+
AlterExpression action = statement.getAlterExpressions().get(0);
33+
Index originalIndex = action.getIndex();
34+
action.getIndex().setColumnsNames(List.of("b"));
35+
assertEquals(List.of("b"), columns(action, primary));
36+
if (primary) {
37+
action.setPkColumns(List.of("c"));
38+
} else {
39+
action.setUkColumns(List.of("c"));
40+
}
41+
assertEquals(prefix + " (c)", statement.toString());
42+
columns(action, primary).add("d");
43+
columns(action, primary).set(0, "e");
44+
assertEquals(List.of("e", "d"), action.getIndex().getColumnsNames());
45+
assertEquals("e", columns(action, primary).remove(0));
46+
if (primary) {
47+
action.addPkColumns("f");
48+
} else {
49+
action.addUkColumns("f");
50+
}
51+
assertEquals(prefix + " (d, f)", statement.toString());
52+
assertSame(originalIndex, action.getIndex());
53+
StringBuilder output = new StringBuilder();
54+
statement.accept(new StatementDeParser(output), null);
55+
assertEquals(statement.toString(), output.toString());
56+
columns(action, primary).clear();
57+
assertTrue(action.getIndex().getColumns().isEmpty());
58+
}
59+
60+
@Test
61+
void preservesStructuredElementsAndIndexMetadataForUnchangedKeys() throws Exception {
62+
Alter statement = (Alter) CCJSqlParserUtil.parse(
63+
"ALTER TABLE t ADD UNIQUE (a, b) DEFERRABLE",
64+
parser -> parser.withDialect(
65+
net.sf.jsqlparser.parser.AbstractJSqlParser.Dialect.POSTGRESQL));
66+
AlterExpression action = statement.getAlterExpressions().get(0);
67+
Index index = action.getIndex();
68+
index.setName("uq");
69+
Index.ColumnParams expression =
70+
new Index.ColumnParams(new net.sf.jsqlparser.schema.Column("a"))
71+
.withExpressionParenthesized(false);
72+
index.getColumns().set(0, expression);
73+
String original = statement.toString();
74+
action.setUkColumns(new ArrayList<>(action.getUkColumns()));
75+
assertSame(expression, index.getColumns().get(0));
76+
assertEquals(original, statement.toString());
77+
action.addUkColumns("c");
78+
assertSame(expression, index.getColumns().get(0));
79+
assertEquals("uq", index.getName());
80+
assertEquals(original.replace("(a, b)", "(a, b, c)"), statement.toString());
81+
assertTrue(statement.toString().endsWith("DEFERRABLE"));
82+
assertEquals(List.of("a", "b", "c"), action.getUkColumns());
83+
}
84+
85+
@Test
86+
void retainsLegacyOnlyConstructionAndAllowsClearingStructuredKeys() {
87+
AlterExpression action = new AlterExpression().withOperation(AlterOperation.ADD)
88+
.withPkColumns(new ArrayList<>(List.of("a")));
89+
action.addPkColumns("b");
90+
assertEquals("ADD PRIMARY KEY (a, b)", action.toString());
91+
action.setIndex(new Index().withType("PRIMARY KEY").withColumnsNames(List.of("c")));
92+
assertEquals(List.of("c"), action.getPkColumns());
93+
action.setPkColumns(null);
94+
assertTrue(action.getPkColumns().isEmpty());
95+
}
96+
}

0 commit comments

Comments
 (0)