Skip to content

Commit f029697

Browse files
committed
feat: enhance ALTER TABLE support with UNIQUE KEY and INVISIBLE index options
1 parent 98e03d4 commit f029697

File tree

3 files changed

+173
-87
lines changed

3 files changed

+173
-87
lines changed

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

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,17 @@
99
*/
1010
package net.sf.jsqlparser.statement.alter;
1111

12+
import java.io.Serializable;
13+
import java.util.ArrayList;
14+
import java.util.Arrays;
15+
import java.util.Collection;
16+
import java.util.Collections;
17+
import java.util.LinkedHashSet;
18+
import java.util.List;
19+
import java.util.Optional;
20+
import java.util.Set;
1221
import java.util.stream.Collectors;
22+
1323
import net.sf.jsqlparser.expression.Expression;
1424
import net.sf.jsqlparser.statement.ReferentialAction;
1525
import net.sf.jsqlparser.statement.ReferentialAction.Action;
@@ -20,9 +30,6 @@
2030
import net.sf.jsqlparser.statement.create.table.PartitionDefinition;
2131
import net.sf.jsqlparser.statement.select.PlainSelect;
2232

23-
import java.io.Serializable;
24-
import java.util.*;
25-
2633
@SuppressWarnings({"PMD.CyclomaticComplexity"})
2734
public class AlterExpression implements Serializable {
2835

@@ -94,6 +101,7 @@ public class AlterExpression implements Serializable {
94101
private String constraintSymbol;
95102
private boolean enforced;
96103
private String constraintType;
104+
private boolean invisible;
97105

98106
public Index getOldIndex() {
99107
return oldIndex;
@@ -628,6 +636,14 @@ public void setConstraintType(String constraintType) {
628636
this.constraintType = constraintType;
629637
}
630638

639+
public boolean isInvisible() {
640+
return invisible;
641+
}
642+
643+
public void setInvisible(boolean invisible) {
644+
this.invisible = invisible;
645+
}
646+
631647
@Override
632648
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity",
633649
"PMD.ExcessiveMethodLength", "PMD.SwitchStmtsShouldHaveDefault"})
@@ -637,17 +653,27 @@ public String toString() {
637653

638654
if (operation == AlterOperation.UNSPECIFIC) {
639655
b.append(optionalSpecifier);
640-
} else if (operation == AlterOperation.ALTER && constraintType != null) {
641-
b.append("ALTER");
642-
b.append(" ").append(constraintType);
643-
644-
if (constraintSymbol != null) {
645-
b.append(" ").append(constraintSymbol);
656+
} else if (operation == AlterOperation.ALTER && constraintType != null
657+
&& constraintSymbol != null) {
658+
// This is for ALTER INDEX ... INVISIBLE
659+
b.append("ALTER ").append(constraintType).append(" ").append(constraintSymbol);
660+
661+
if (invisible) {
662+
b.append(" INVISIBLE");
663+
} else if (!isEnforced()) {
664+
b.append(" NOT ENFORCED");
665+
} else if (enforced) {
666+
b.append(" ENFORCED");
646667
}
647-
if (!isEnforced()) {
648-
b.append(" NOT ");
668+
} else if (operation == AlterOperation.ADD && constraintType != null
669+
&& constraintSymbol != null) {
670+
b.append("ADD CONSTRAINT ").append(constraintType).append(" ").append(constraintSymbol)
671+
.append(" ");
672+
673+
if (index != null && index.getColumnsNames() != null) {
674+
b.append(" ")
675+
.append(PlainSelect.getStringList(index.getColumnsNames(), true, true));
649676
}
650-
b.append(" ENFORCED");
651677
} else if (operation == AlterOperation.ALTER
652678
&& columnDropDefaultList != null && !columnDropDefaultList.isEmpty()) {
653679
b.append("ALTER ");

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 93 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -8034,89 +8034,107 @@ AlterExpression AlterExpression():
80348034
)
80358035
|
80368036
(
8037-
<K_CONSTRAINT> sk3=RelObjectName()
8037+
<K_CONSTRAINT>
80388038
(
8039-
( tk=<K_FOREIGN> tk2=<K_KEY>
8040-
columnNames=ColumnsNamesList()
8041-
{
8042-
fkIndex = new ForeignKeyIndex()
8043-
.withName(sk3)
8044-
.withType(tk.image + " " + tk2.image)
8045-
.withColumnsNames(columnNames);
8046-
columnNames = null;
8047-
}
8048-
<K_REFERENCES> fkTable=Table() [ LOOKAHEAD(2) columnNames=ColumnsNamesList() ]
8049-
{
8050-
fkIndex.withTable(fkTable).withReferencedColumnNames(columnNames);
8051-
alterExp.setIndex(fkIndex);
8052-
}
8053-
8054-
[LOOKAHEAD(2) (<K_ON> (tk=<K_DELETE> | tk=<K_UPDATE>) action = Action()
8055-
{ fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); }
8056-
)]
8057-
[LOOKAHEAD(2) (<K_ON> (tk=<K_DELETE> | tk=<K_UPDATE>) action = Action()
8058-
{ fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); }
8059-
)]
8060-
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
8061-
)
8062-
|
8063-
( tk=<K_PRIMARY> tk2=<K_KEY>
8064-
columnNames=ColumnsNamesList()
8065-
{
8066-
index = new NamedConstraint()
8067-
.withName(sk3)
8068-
.withType(tk.image + " " + tk2.image)
8069-
.withColumnsNames(columnNames);
8070-
alterExp.setIndex(index);
8071-
}
8072-
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
8073-
[ <K_USING> sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }]
8074-
[ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ]
8075-
)
8076-
|
8077-
LOOKAHEAD(2) (
8078-
{ boolean enforced = true; }
8079-
[ tk = <K_NOT> { enforced = false; } ]
8080-
<K_ENFORCED> {
8081-
alterExp.setEnforced(enforced);
8082-
alterExp.setConstraintType("CONSTRAINT");
8083-
alterExp.setConstraintSymbol(sk3);
8084-
}
8085-
)
8086-
|
8039+
LOOKAHEAD(2)
80878040
(
8088-
<K_CHECK> {Expression exp = null;} (LOOKAHEAD(2) "(" exp = Expression() ")")* {
8089-
CheckConstraint checkCs = new CheckConstraint().withName(sk3).withExpression(exp);
8090-
alterExp.setIndex(checkCs);
8041+
<K_UNIQUE> (<K_KEY> { alterExp.setConstraintType("UNIQUE KEY"); }
8042+
| <K_INDEX> { alterExp.setConstraintType("UNIQUE INDEX"); }
8043+
| { alterExp.setConstraintType("UNIQUE"); } )
8044+
sk3=RelObjectName() {
8045+
alterExp.setConstraintSymbol(sk3);
8046+
index = new Index();
8047+
}
8048+
columnNames=ColumnsNamesList() {
8049+
index.setColumnsNames(columnNames);
8050+
alterExp.setIndex(index);
80918051
}
80928052
)
80938053
|
8054+
sk3=RelObjectName()
80948055
(
8095-
tk=<K_UNIQUE> (tk2=<K_KEY> { alterExp.setUk(true); } | tk2=<K_INDEX>)?
8096-
columnNames=ColumnsNamesList()
8097-
{
8098-
index = new NamedConstraint()
8056+
( tk=<K_FOREIGN> tk2=<K_KEY>
8057+
columnNames=ColumnsNamesList()
8058+
{
8059+
fkIndex = new ForeignKeyIndex()
80998060
.withName(sk3)
8100-
.withType(tk.image + (tk2!=null?" " + tk2.image:""))
8061+
.withType(tk.image + " " + tk2.image)
81018062
.withColumnsNames(columnNames);
8102-
alterExp.setIndex(index);
8103-
}
8104-
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
8105-
[ <K_USING> sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }]
8106-
[ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ]
8107-
)
8108-
|
8109-
(
8110-
tk=<K_KEY>
8111-
columnNames=ColumnsNamesList()
8112-
{
8113-
index = new NamedConstraint()
8114-
.withName(sk3)
8115-
.withType(tk.image)
8116-
.withColumnsNames(columnNames);
8117-
alterExp.setIndex(index);
8118-
}
8119-
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
8063+
columnNames = null;
8064+
}
8065+
<K_REFERENCES> fkTable=Table() [ LOOKAHEAD(2) columnNames=ColumnsNamesList() ]
8066+
{
8067+
fkIndex.withTable(fkTable).withReferencedColumnNames(columnNames);
8068+
alterExp.setIndex(fkIndex);
8069+
}
8070+
8071+
[LOOKAHEAD(2) (<K_ON> (tk=<K_DELETE> | tk=<K_UPDATE>) action = Action()
8072+
{ fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); }
8073+
)]
8074+
[LOOKAHEAD(2) (<K_ON> (tk=<K_DELETE> | tk=<K_UPDATE>) action = Action()
8075+
{ fkIndex.setReferentialAction(ReferentialAction.Type.from(tk.image), action); }
8076+
)]
8077+
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
8078+
)
8079+
|
8080+
( tk=<K_PRIMARY> tk2=<K_KEY>
8081+
columnNames=ColumnsNamesList()
8082+
{
8083+
index = new NamedConstraint()
8084+
.withName(sk3)
8085+
.withType(tk.image + " " + tk2.image)
8086+
.withColumnsNames(columnNames);
8087+
alterExp.setIndex(index);
8088+
}
8089+
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
8090+
[ <K_USING> sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }]
8091+
[ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ]
8092+
)
8093+
|
8094+
LOOKAHEAD(2) (
8095+
{ boolean enforced = true; }
8096+
[ tk = <K_NOT> { enforced = false; } ]
8097+
<K_ENFORCED> {
8098+
alterExp.setEnforced(enforced);
8099+
alterExp.setConstraintType("CONSTRAINT");
8100+
alterExp.setConstraintSymbol(sk3);
8101+
}
8102+
)
8103+
|
8104+
(
8105+
<K_CHECK> {Expression exp = null;} (LOOKAHEAD(2) "(" exp = Expression() ")")* {
8106+
CheckConstraint checkCs = new CheckConstraint().withName(sk3).withExpression(exp);
8107+
alterExp.setIndex(checkCs);
8108+
}
8109+
)
8110+
|
8111+
(
8112+
tk=<K_UNIQUE> (tk2=<K_KEY> { alterExp.setUk(true); } | tk2=<K_INDEX>)?
8113+
columnNames=ColumnsNamesList()
8114+
{
8115+
index = new NamedConstraint()
8116+
.withName(sk3)
8117+
.withType(tk.image + (tk2!=null?" " + tk2.image:""))
8118+
.withColumnsNames(columnNames);
8119+
alterExp.setIndex(index);
8120+
}
8121+
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
8122+
[ <K_USING> sk4=RelObjectName() { alterExp.addParameters("USING", sk4); }]
8123+
[ LOOKAHEAD(2) index = IndexWithComment(index) { alterExp.setIndex(index); } ]
8124+
)
8125+
|
8126+
(
8127+
tk=<K_KEY>
8128+
columnNames=ColumnsNamesList()
8129+
{
8130+
index = new NamedConstraint()
8131+
.withName(sk3)
8132+
.withType(tk.image)
8133+
.withColumnsNames(columnNames);
8134+
alterExp.setIndex(index);
8135+
}
8136+
constraints=AlterExpressionConstraintState() { alterExp.setConstraints(constraints); }
8137+
)
81208138
)
81218139
)
81228140
)

src/test/java/net/sf/jsqlparser/statement/alter/AlterTest.java

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2138,4 +2138,46 @@ public void testAlterTableAlterCheckNotEnforced() throws JSQLParserException {
21382138

21392139
assertSqlCanBeParsedAndDeparsed(sql);
21402140
}
2141+
2142+
@Test
2143+
public void testAlterTableAddConstraintUniqueKey() throws JSQLParserException {
2144+
String sql = "ALTER TABLE sbtest1 ADD CONSTRAINT UNIQUE KEY ux_c3 (c3)";
2145+
Statement stmt = CCJSqlParserUtil.parse(sql);
2146+
assertInstanceOf(Alter.class, stmt);
2147+
2148+
Alter alter = (Alter) stmt;
2149+
assertEquals("sbtest1", alter.getTable().getFullyQualifiedName());
2150+
2151+
List<AlterExpression> alterExpressions = alter.getAlterExpressions();
2152+
assertNotNull(alterExpressions);
2153+
assertEquals(1, alterExpressions.size());
2154+
2155+
AlterExpression alterExp = alterExpressions.get(0);
2156+
assertEquals(AlterOperation.ADD, alterExp.getOperation());
2157+
assertEquals("UNIQUE KEY", alterExp.getConstraintType());
2158+
assertEquals("ux_c3", alterExp.getConstraintSymbol());
2159+
2160+
assertSqlCanBeParsedAndDeparsed(sql);
2161+
}
2162+
2163+
@Test
2164+
public void testAlterTableAlterIndexInvisible() throws JSQLParserException {
2165+
String sql = "ALTER TABLE sbtest1 ALTER INDEX c4 INVISIBLE";
2166+
Statement stmt = CCJSqlParserUtil.parse(sql);
2167+
assertInstanceOf(Alter.class, stmt);
2168+
2169+
Alter alter = (Alter) stmt;
2170+
assertEquals("sbtest1", alter.getTable().getFullyQualifiedName());
2171+
2172+
List<AlterExpression> alterExpressions = alter.getAlterExpressions();
2173+
assertNotNull(alterExpressions);
2174+
assertEquals(1, alterExpressions.size());
2175+
2176+
AlterExpression alterExp = alterExpressions.get(0);
2177+
assertEquals(AlterOperation.ALTER, alterExp.getOperation());
2178+
assertEquals("c4", alterExp.getIndex().getName());
2179+
assertEquals("INVISIBLE", alterExp.getIndex().getIndexSpec().get(0));
2180+
2181+
assertSqlCanBeParsedAndDeparsed(sql);
2182+
}
21412183
}

0 commit comments

Comments
 (0)