Skip to content

Commit 583431d

Browse files
committed
Separate ALTER key definitions from column drop targets
Signed-off-by: minleejae <mmj9808@gmail.com>
1 parent 066f581 commit 583431d

7 files changed

Lines changed: 594 additions & 109 deletions

File tree

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

Lines changed: 143 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -55,18 +55,14 @@ public enum TableRenameKeyword {
5555
private List<ColumnSetDefault> columnSetDefaultList;
5656
private List<ColumnSetVisibility> columnSetVisibilityList;
5757

58-
private List<String> pkColumns;
59-
private List<String> ukColumns;
60-
private String ukName;
58+
private List<String> dropColumns;
6159
private Index index = null;
6260
private Index oldIndex = null;
6361
private NamedConstraint constraint;
6462
private String newConstraintName;
6563
private String constraintName;
6664
private boolean usingIfExists;
6765

68-
private boolean uk;
69-
private boolean ukTypeSpecified;
7066
private boolean useEqual;
7167

7268
private List<String> partitions;
@@ -634,75 +630,144 @@ public void setUsingIfExists(boolean usingIfExists) {
634630
}
635631

636632
/**
637-
* Returns a snapshot of the rendered key elements for a structured PRIMARY_KEY, or the legacy
638-
* list otherwise. Changing the snapshot does not change the constraint; use
639-
* {@link #setPkColumns(List)} to replace its keys, or {@link KeyConstraint#getColumns()} for
640-
* structured edits.
633+
* Returns the stored key definition, or null for another definition. The returned object is
634+
* shared with {@link #getConstraint()} and can be edited directly.
635+
*/
636+
public KeyConstraint getKeyConstraint() {
637+
return constraint instanceof KeyConstraint ? (KeyConstraint) constraint : null;
638+
}
639+
640+
/**
641+
* Returns the owned mutable column targets for parenthesized DROP, DROP UNIQUE or DROP FOREIGN
642+
* KEY syntax, or null when omitted. Stored targets are independent of any ADD definition.
643+
*/
644+
public List<String> getDropColumns() {
645+
return dropColumns;
646+
}
647+
648+
/** Copies the supplied targets without changing the operation or any stored definition. */
649+
public void setDropColumns(List<String> dropColumns) {
650+
this.dropColumns = dropColumns == null ? null : new ArrayList<>(dropColumns);
651+
}
652+
653+
public AlterExpression withDropColumns(List<String> dropColumns) {
654+
setDropColumns(dropColumns);
655+
return this;
656+
}
657+
658+
public AlterExpression addDropColumns(String... columns) {
659+
return addDropColumns(Arrays.asList(columns));
660+
}
661+
662+
public AlterExpression addDropColumns(Collection<String> columns) {
663+
if (dropColumns == null) {
664+
dropColumns = new ArrayList<>();
665+
}
666+
dropColumns.addAll(columns);
667+
return this;
668+
}
669+
670+
/**
671+
* Returns a rendered snapshot of the stored PRIMARY KEY's elements, or null when absent. For
672+
* DROP, DROP UNIQUE and DROP FOREIGN KEY operations this legacy accessor instead returns a
673+
* snapshot of {@link #getDropColumns()}. Snapshot edits never change the AST. New code should
674+
* use {@link #getKeyConstraint()} or {@link #getDropColumns()} explicitly.
641675
*/
642676
public List<String> getPkColumns() {
677+
if (usesLegacyDropColumns()) {
678+
return dropColumns == null ? null : new ArrayList<>(dropColumns);
679+
}
643680
return hasKeyConstraint(ConstraintKind.PRIMARY_KEY)
644681
? ((KeyConstraint) constraint).getColumnsNames()
645-
: pkColumns;
682+
: null;
646683
}
647684

648685
/**
649-
* Replaces a structured PRIMARY_KEY's elements using
650-
* {@link KeyConstraint#setColumnsNames(List)}. The strings are not parsed and existing element
651-
* attributes are not retained, even when the rendered SQL is unchanged. Use
652-
* {@link KeyConstraint#setColumns(List)} to preserve structured elements. Without a matching
653-
* constraint, stores the legacy list.
686+
* Replaces PRIMARY KEY elements with opaque names, without parsing or retaining element
687+
* attributes. A non-null list creates a definition when none exists; a competing definition
688+
* must be replaced explicitly using {@link #setConstraint(NamedConstraint)}. Null clears only
689+
* an existing PRIMARY KEY's elements and does not create a definition. With DROP, DROP UNIQUE
690+
* or DROP FOREIGN KEY already selected, delegates to {@link #setDropColumns(List)} instead. Set
691+
* the operation first for this legacy DROP alias; new builders should use setDropColumns.
692+
*
693+
* @throws IllegalStateException if a non-null list would replace another definition
654694
*/
655695
public void setPkColumns(List<String> pkColumns) {
656-
if (hasKeyConstraint(ConstraintKind.PRIMARY_KEY)) {
657-
((KeyConstraint) constraint).setColumnsNames(pkColumns);
658-
this.pkColumns = null;
659-
} else {
660-
this.pkColumns = pkColumns;
696+
if (usesLegacyDropColumns()) {
697+
setDropColumns(pkColumns);
698+
return;
699+
}
700+
KeyConstraint key = keyForUpdate(ConstraintKind.PRIMARY_KEY, pkColumns != null);
701+
if (key != null) {
702+
key.setColumnsNames(pkColumns);
661703
}
662704
}
663705

664706
/**
665-
* Returns a snapshot of the rendered key elements for a structured UNIQUE, or the legacy list
666-
* otherwise. Changing the snapshot does not change the constraint; use
667-
* {@link #setUkColumns(List)} to replace its keys, or {@link KeyConstraint#getColumns()} for
668-
* structured edits.
707+
* Returns a snapshot of the stored UNIQUE's elements, or null when absent. Changing the
708+
* snapshot does not change the constraint; use {@link #setUkColumns(List)} to replace its keys,
709+
* or {@link KeyConstraint#getColumns()} for structured edits.
669710
*/
670711
public List<String> getUkColumns() {
671712
return hasKeyConstraint(ConstraintKind.UNIQUE)
672713
? ((KeyConstraint) constraint).getColumnsNames()
673-
: ukColumns;
714+
: null;
674715
}
675716

676717
/**
677718
* Replaces a structured UNIQUE's elements using {@link KeyConstraint#setColumnsNames(List)}.
678719
* The strings are not parsed and existing element attributes are not retained, even when the
679720
* rendered SQL is unchanged. Use {@link KeyConstraint#setColumns(List)} to preserve structured
680-
* elements. Without a matching constraint, stores the legacy list.
721+
* elements. A non-null list creates a UNIQUE definition only when none exists; a competing
722+
* definition must be replaced explicitly. Null clears only an existing UNIQUE's elements.
723+
*
724+
* @throws IllegalStateException if a non-null list would replace another definition
681725
*/
682726
public void setUkColumns(List<String> ukColumns) {
683-
if (hasKeyConstraint(ConstraintKind.UNIQUE)) {
684-
((KeyConstraint) constraint).setColumnsNames(ukColumns);
685-
this.ukColumns = null;
686-
} else {
687-
this.ukColumns = ukColumns;
727+
KeyConstraint key = keyForUpdate(ConstraintKind.UNIQUE, ukColumns != null);
728+
if (key != null) {
729+
key.setColumnsNames(ukColumns);
688730
}
689731
}
690732

733+
private boolean usesLegacyDropColumns() {
734+
return operation == AlterOperation.DROP || operation == AlterOperation.DROP_UNIQUE
735+
|| operation == AlterOperation.DROP_FOREIGN_KEY;
736+
}
737+
691738
private boolean hasKeyConstraint(ConstraintKind kind) {
692739
return constraint instanceof KeyConstraint && constraint.getKind() == kind;
693740
}
694741

742+
private KeyConstraint keyForUpdate(ConstraintKind kind, boolean create) {
743+
if (hasKeyConstraint(kind)) {
744+
return (KeyConstraint) constraint;
745+
}
746+
if (!create) {
747+
return null;
748+
}
749+
if (constraint != null || index != null || getFkColumns() != null) {
750+
throw new IllegalStateException(
751+
"Key setters cannot replace an existing definition; use setConstraint");
752+
}
753+
KeyConstraint key = new KeyConstraint()
754+
.withType(kind == ConstraintKind.PRIMARY_KEY ? "PRIMARY KEY" : "UNIQUE");
755+
setConstraint(key);
756+
return key;
757+
}
758+
695759
public String getUkName() {
696760
return hasKeyConstraint(ConstraintKind.UNIQUE)
697761
? ((KeyConstraint) constraint).getIndexName()
698-
: ukName;
762+
: null;
699763
}
700764

765+
/** Uses the creation and replacement policy of {@link #setUkColumns(List)}. */
701766
public void setUkName(String ukName) {
702-
if (hasKeyConstraint(ConstraintKind.UNIQUE)) {
703-
((KeyConstraint) constraint).setIndexName(ukName);
767+
KeyConstraint key = keyForUpdate(ConstraintKind.UNIQUE, ukName != null);
768+
if (key != null) {
769+
key.setIndexName(ukName);
704770
}
705-
this.ukName = ukName;
706771
}
707772

708773
public Index getIndex() {
@@ -754,12 +819,6 @@ private ConstraintKind getAddedConstraintKind() {
754819
if (index != null) {
755820
return ConstraintKind.OTHER;
756821
}
757-
if (pkColumns != null) {
758-
return ConstraintKind.PRIMARY_KEY;
759-
}
760-
if (ukColumns != null) {
761-
return ConstraintKind.UNIQUE;
762-
}
763822
return ConstraintKind.OTHER;
764823
}
765824

@@ -921,20 +980,53 @@ public void setUseEqual(boolean useEqual) {
921980
}
922981

923982
public boolean getUk() {
924-
return uk;
983+
return "KEY".equalsIgnoreCase(getUniqueIndexKeyword());
925984
}
926985

986+
/** Selects KEY when true or INDEX when false on the stored UNIQUE definition. */
927987
public void setUk(boolean uk) {
928-
this.uk = uk;
929-
this.ukTypeSpecified = true;
988+
setUniqueIndexKeyword(keyForUpdate(ConstraintKind.UNIQUE, true), uk ? "KEY" : "INDEX");
930989
}
931990

932991
public boolean isUkTypeSpecified() {
933-
return ukTypeSpecified;
992+
return getUniqueIndexKeyword() != null;
934993
}
935994

995+
/**
996+
* Removes the explicit KEY/INDEX spelling when false. When true, retains an existing spelling
997+
* or selects INDEX. Clearing an absent UNIQUE definition does not create one.
998+
*/
936999
public void setUkTypeSpecified(boolean ukTypeSpecified) {
937-
this.ukTypeSpecified = ukTypeSpecified;
1000+
KeyConstraint key = keyForUpdate(ConstraintKind.UNIQUE, ukTypeSpecified);
1001+
if (key != null) {
1002+
String keyword = getUniqueIndexKeyword();
1003+
setUniqueIndexKeyword(key,
1004+
ukTypeSpecified ? keyword == null ? "INDEX" : keyword : null);
1005+
}
1006+
}
1007+
1008+
private String getUniqueIndexKeyword() {
1009+
KeyConstraint key = keyForUpdate(ConstraintKind.UNIQUE, false);
1010+
if (key == null) {
1011+
return null;
1012+
}
1013+
if (key.getIndexKeyword() != null) {
1014+
return key.getIndexKeyword();
1015+
}
1016+
if ("UNIQUE KEY".equalsIgnoreCase(key.getType())) {
1017+
return "KEY";
1018+
}
1019+
return "UNIQUE INDEX".equalsIgnoreCase(key.getType()) ? "INDEX" : null;
1020+
}
1021+
1022+
private void setUniqueIndexKeyword(KeyConstraint key, String keyword) {
1023+
if (hasLegacyKeyConstraint() || "UNIQUE KEY".equalsIgnoreCase(key.getType())
1024+
|| "UNIQUE INDEX".equalsIgnoreCase(key.getType())) {
1025+
key.setType("UNIQUE" + (keyword == null ? "" : " " + keyword));
1026+
key.setIndexKeyword(null);
1027+
} else {
1028+
key.setIndexKeyword(keyword);
1029+
}
9381030
}
9391031

9401032
public boolean isUseIfNotExists() {
@@ -1146,7 +1238,7 @@ protected boolean isDropSpecialOperation() {
11461238
case DROP_CHECK:
11471239
return true;
11481240
case DROP:
1149-
return columnName == null && pkColumns != null && !pkColumns.isEmpty();
1241+
return columnName == null && dropColumns != null && !dropColumns.isEmpty();
11501242
default:
11511243
return false;
11521244
}
@@ -1307,22 +1399,23 @@ protected void toStringDropSpecial(StringBuilder b) {
13071399
b.append("DROP PRIMARY KEY ");
13081400
break;
13091401
case DROP_UNIQUE:
1310-
b.append("DROP UNIQUE (").append(PlainSelect.getStringList(pkColumns)).append(')');
1402+
b.append("DROP UNIQUE (").append(PlainSelect.getStringList(dropColumns))
1403+
.append(')');
13111404
break;
13121405
case DROP_FOREIGN_KEY:
13131406
b.append("DROP FOREIGN KEY ");
13141407
if (constraintName != null) {
13151408
b.append(constraintName);
13161409
} else {
1317-
b.append('(').append(PlainSelect.getStringList(pkColumns)).append(')');
1410+
b.append('(').append(PlainSelect.getStringList(dropColumns)).append(')');
13181411
}
13191412
break;
13201413
case DROP_CHECK:
13211414
b.append("DROP CHECK ").append(constraintName);
13221415
break;
13231416
default:
13241417
// Oracle Multi Column Drop
1325-
b.append("DROP (").append(PlainSelect.getStringList(pkColumns)).append(')');
1418+
b.append("DROP (").append(PlainSelect.getStringList(dropColumns)).append(')');
13261419
break;
13271420
}
13281421
}
@@ -1538,26 +1631,7 @@ private void toStringGeneral(StringBuilder b, Consumer<ColumnDataType> columnPri
15381631
} else if (constraint != null) {
15391632
b.append(constraint);
15401633
} else if (index != null) {
1541-
// The structured index is canonical. Legacy PK/UK fields may also be populated for
1542-
// source compatibility, but cannot represent names, expressions, or index options.
15431634
b.append(index);
1544-
} else if (pkColumns != null) {
1545-
b.append("PRIMARY KEY (").append(PlainSelect.getStringList(pkColumns)).append(')');
1546-
} else if (ukColumns != null) {
1547-
b.append("UNIQUE");
1548-
if (ukName != null) {
1549-
if (isUkTypeSpecified()) {
1550-
if (getUk()) {
1551-
b.append(" KEY ");
1552-
} else {
1553-
b.append(" INDEX ");
1554-
}
1555-
} else {
1556-
b.append(" ");
1557-
}
1558-
b.append(ukName);
1559-
}
1560-
b.append(" (").append(PlainSelect.getStringList(ukColumns)).append(")");
15611635
}
15621636

15631637
if (getConstraints() != null && !getConstraints().isEmpty()) {

0 commit comments

Comments
 (0)