Skip to content

Commit a209258

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

7 files changed

Lines changed: 592 additions & 105 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
@@ -57,9 +57,7 @@ public enum TableRenameKeyword {
5757
private List<ColumnSetDefault> columnSetDefaultList;
5858
private List<ColumnSetVisibility> columnSetVisibilityList;
5959

60-
private List<String> pkColumns;
61-
private List<String> ukColumns;
62-
private String ukName;
60+
private List<String> dropColumns;
6361
private Index index = null;
6462
private Index oldIndex = null;
6563
private NamedConstraint constraint;
@@ -94,8 +92,6 @@ public enum TableRenameKeyword {
9492
*/
9593
@Deprecated
9694
private List<String> fkSourceColumns;
97-
private boolean uk;
98-
private boolean ukTypeSpecified;
9995
private boolean useEqual;
10096

10197
private List<String> partitions;
@@ -551,75 +547,144 @@ public void setUsingIfExists(boolean usingIfExists) {
551547
}
552548

553549
/**
554-
* Returns a snapshot of the rendered key elements for a structured PRIMARY_KEY, or the legacy
555-
* list otherwise. Changing the snapshot does not change the constraint; use
556-
* {@link #setPkColumns(List)} to replace its keys, or {@link KeyConstraint#getColumns()} for
557-
* structured edits.
550+
* Returns the stored key definition, or null for another definition. The returned object is
551+
* shared with {@link #getConstraint()} and can be edited directly.
552+
*/
553+
public KeyConstraint getKeyConstraint() {
554+
return constraint instanceof KeyConstraint ? (KeyConstraint) constraint : null;
555+
}
556+
557+
/**
558+
* Returns the owned mutable column targets for parenthesized DROP, DROP UNIQUE or DROP FOREIGN
559+
* KEY syntax, or null when omitted. Stored targets are independent of any ADD definition.
560+
*/
561+
public List<String> getDropColumns() {
562+
return dropColumns;
563+
}
564+
565+
/** Copies the supplied targets without changing the operation or any stored definition. */
566+
public void setDropColumns(List<String> dropColumns) {
567+
this.dropColumns = dropColumns == null ? null : new ArrayList<>(dropColumns);
568+
}
569+
570+
public AlterExpression withDropColumns(List<String> dropColumns) {
571+
setDropColumns(dropColumns);
572+
return this;
573+
}
574+
575+
public AlterExpression addDropColumns(String... columns) {
576+
return addDropColumns(Arrays.asList(columns));
577+
}
578+
579+
public AlterExpression addDropColumns(Collection<String> columns) {
580+
if (dropColumns == null) {
581+
dropColumns = new ArrayList<>();
582+
}
583+
dropColumns.addAll(columns);
584+
return this;
585+
}
586+
587+
/**
588+
* Returns a rendered snapshot of the stored PRIMARY KEY's elements, or null when absent. For
589+
* DROP, DROP UNIQUE and DROP FOREIGN KEY operations this legacy accessor instead returns a
590+
* snapshot of {@link #getDropColumns()}. Snapshot edits never change the AST. New code should
591+
* use {@link #getKeyConstraint()} or {@link #getDropColumns()} explicitly.
558592
*/
559593
public List<String> getPkColumns() {
594+
if (usesLegacyDropColumns()) {
595+
return dropColumns == null ? null : new ArrayList<>(dropColumns);
596+
}
560597
return hasKeyConstraint(ConstraintKind.PRIMARY_KEY)
561598
? ((KeyConstraint) constraint).getColumnsNames()
562-
: pkColumns;
599+
: null;
563600
}
564601

565602
/**
566-
* Replaces a structured PRIMARY_KEY's elements using
567-
* {@link KeyConstraint#setColumnsNames(List)}. The strings are not parsed and existing element
568-
* attributes are not retained, even when the rendered SQL is unchanged. Use
569-
* {@link KeyConstraint#setColumns(List)} to preserve structured elements. Without a matching
570-
* constraint, stores the legacy list.
603+
* Replaces PRIMARY KEY elements with opaque names, without parsing or retaining element
604+
* attributes. A non-null list creates a definition when none exists; a competing definition
605+
* must be replaced explicitly using {@link #setConstraint(NamedConstraint)}. Null clears only
606+
* an existing PRIMARY KEY's elements and does not create a definition. With DROP, DROP UNIQUE
607+
* or DROP FOREIGN KEY already selected, delegates to {@link #setDropColumns(List)} instead. Set
608+
* the operation first for this legacy DROP alias; new builders should use setDropColumns.
609+
*
610+
* @throws IllegalStateException if a non-null list would replace another definition
571611
*/
572612
public void setPkColumns(List<String> pkColumns) {
573-
if (hasKeyConstraint(ConstraintKind.PRIMARY_KEY)) {
574-
((KeyConstraint) constraint).setColumnsNames(pkColumns);
575-
this.pkColumns = null;
576-
} else {
577-
this.pkColumns = pkColumns;
613+
if (usesLegacyDropColumns()) {
614+
setDropColumns(pkColumns);
615+
return;
616+
}
617+
KeyConstraint key = keyForUpdate(ConstraintKind.PRIMARY_KEY, pkColumns != null);
618+
if (key != null) {
619+
key.setColumnsNames(pkColumns);
578620
}
579621
}
580622

581623
/**
582-
* Returns a snapshot of the rendered key elements for a structured UNIQUE, or the legacy list
583-
* otherwise. Changing the snapshot does not change the constraint; use
584-
* {@link #setUkColumns(List)} to replace its keys, or {@link KeyConstraint#getColumns()} for
585-
* structured edits.
624+
* Returns a snapshot of the stored UNIQUE's elements, or null when absent. Changing the
625+
* snapshot does not change the constraint; use {@link #setUkColumns(List)} to replace its keys,
626+
* or {@link KeyConstraint#getColumns()} for structured edits.
586627
*/
587628
public List<String> getUkColumns() {
588629
return hasKeyConstraint(ConstraintKind.UNIQUE)
589630
? ((KeyConstraint) constraint).getColumnsNames()
590-
: ukColumns;
631+
: null;
591632
}
592633

593634
/**
594635
* Replaces a structured UNIQUE's elements using {@link KeyConstraint#setColumnsNames(List)}.
595636
* The strings are not parsed and existing element attributes are not retained, even when the
596637
* rendered SQL is unchanged. Use {@link KeyConstraint#setColumns(List)} to preserve structured
597-
* elements. Without a matching constraint, stores the legacy list.
638+
* elements. A non-null list creates a UNIQUE definition only when none exists; a competing
639+
* definition must be replaced explicitly. Null clears only an existing UNIQUE's elements.
640+
*
641+
* @throws IllegalStateException if a non-null list would replace another definition
598642
*/
599643
public void setUkColumns(List<String> ukColumns) {
600-
if (hasKeyConstraint(ConstraintKind.UNIQUE)) {
601-
((KeyConstraint) constraint).setColumnsNames(ukColumns);
602-
this.ukColumns = null;
603-
} else {
604-
this.ukColumns = ukColumns;
644+
KeyConstraint key = keyForUpdate(ConstraintKind.UNIQUE, ukColumns != null);
645+
if (key != null) {
646+
key.setColumnsNames(ukColumns);
605647
}
606648
}
607649

650+
private boolean usesLegacyDropColumns() {
651+
return operation == AlterOperation.DROP || operation == AlterOperation.DROP_UNIQUE
652+
|| operation == AlterOperation.DROP_FOREIGN_KEY;
653+
}
654+
608655
private boolean hasKeyConstraint(ConstraintKind kind) {
609656
return constraint instanceof KeyConstraint && constraint.getKind() == kind;
610657
}
611658

659+
private KeyConstraint keyForUpdate(ConstraintKind kind, boolean create) {
660+
if (hasKeyConstraint(kind)) {
661+
return (KeyConstraint) constraint;
662+
}
663+
if (!create) {
664+
return null;
665+
}
666+
if (constraint != null || index != null || getFkColumns() != null) {
667+
throw new IllegalStateException(
668+
"Key setters cannot replace an existing definition; use setConstraint");
669+
}
670+
KeyConstraint key = new KeyConstraint()
671+
.withType(kind == ConstraintKind.PRIMARY_KEY ? "PRIMARY KEY" : "UNIQUE");
672+
setConstraint(key);
673+
return key;
674+
}
675+
612676
public String getUkName() {
613677
return hasKeyConstraint(ConstraintKind.UNIQUE)
614678
? ((KeyConstraint) constraint).getIndexName()
615-
: ukName;
679+
: null;
616680
}
617681

682+
/** Uses the creation and replacement policy of {@link #setUkColumns(List)}. */
618683
public void setUkName(String ukName) {
619-
if (hasKeyConstraint(ConstraintKind.UNIQUE)) {
620-
((KeyConstraint) constraint).setIndexName(ukName);
684+
KeyConstraint key = keyForUpdate(ConstraintKind.UNIQUE, ukName != null);
685+
if (key != null) {
686+
key.setIndexName(ukName);
621687
}
622-
this.ukName = ukName;
623688
}
624689

625690
public Index getIndex() {
@@ -671,12 +736,6 @@ private ConstraintKind getAddedConstraintKind() {
671736
if (index != null) {
672737
return ConstraintKind.OTHER;
673738
}
674-
if (pkColumns != null) {
675-
return ConstraintKind.PRIMARY_KEY;
676-
}
677-
if (ukColumns != null) {
678-
return ConstraintKind.UNIQUE;
679-
}
680739
return fkColumns != null ? ConstraintKind.FOREIGN_KEY : ConstraintKind.OTHER;
681740
}
682741

@@ -838,20 +897,53 @@ public void setUseEqual(boolean useEqual) {
838897
}
839898

840899
public boolean getUk() {
841-
return uk;
900+
return "KEY".equalsIgnoreCase(getUniqueIndexKeyword());
842901
}
843902

903+
/** Selects KEY when true or INDEX when false on the stored UNIQUE definition. */
844904
public void setUk(boolean uk) {
845-
this.uk = uk;
846-
this.ukTypeSpecified = true;
905+
setUniqueIndexKeyword(keyForUpdate(ConstraintKind.UNIQUE, true), uk ? "KEY" : "INDEX");
847906
}
848907

849908
public boolean isUkTypeSpecified() {
850-
return ukTypeSpecified;
909+
return getUniqueIndexKeyword() != null;
851910
}
852911

912+
/**
913+
* Removes the explicit KEY/INDEX spelling when false. When true, retains an existing spelling
914+
* or selects INDEX. Clearing an absent UNIQUE definition does not create one.
915+
*/
853916
public void setUkTypeSpecified(boolean ukTypeSpecified) {
854-
this.ukTypeSpecified = ukTypeSpecified;
917+
KeyConstraint key = keyForUpdate(ConstraintKind.UNIQUE, ukTypeSpecified);
918+
if (key != null) {
919+
String keyword = getUniqueIndexKeyword();
920+
setUniqueIndexKeyword(key,
921+
ukTypeSpecified ? keyword == null ? "INDEX" : keyword : null);
922+
}
923+
}
924+
925+
private String getUniqueIndexKeyword() {
926+
KeyConstraint key = keyForUpdate(ConstraintKind.UNIQUE, false);
927+
if (key == null) {
928+
return null;
929+
}
930+
if (key.getIndexKeyword() != null) {
931+
return key.getIndexKeyword();
932+
}
933+
if ("UNIQUE KEY".equalsIgnoreCase(key.getType())) {
934+
return "KEY";
935+
}
936+
return "UNIQUE INDEX".equalsIgnoreCase(key.getType()) ? "INDEX" : null;
937+
}
938+
939+
private void setUniqueIndexKeyword(KeyConstraint key, String keyword) {
940+
if (hasLegacyKeyConstraint() || "UNIQUE KEY".equalsIgnoreCase(key.getType())
941+
|| "UNIQUE INDEX".equalsIgnoreCase(key.getType())) {
942+
key.setType("UNIQUE" + (keyword == null ? "" : " " + keyword));
943+
key.setIndexKeyword(null);
944+
} else {
945+
key.setIndexKeyword(keyword);
946+
}
855947
}
856948

857949
public boolean isUseIfNotExists() {
@@ -1059,7 +1151,7 @@ protected boolean isDropSpecialOperation() {
10591151
case DROP_CHECK:
10601152
return true;
10611153
case DROP:
1062-
return columnName == null && pkColumns != null && !pkColumns.isEmpty();
1154+
return columnName == null && dropColumns != null && !dropColumns.isEmpty();
10631155
default:
10641156
return false;
10651157
}
@@ -1220,22 +1312,23 @@ protected void toStringDropSpecial(StringBuilder b) {
12201312
b.append("DROP PRIMARY KEY ");
12211313
break;
12221314
case DROP_UNIQUE:
1223-
b.append("DROP UNIQUE (").append(PlainSelect.getStringList(pkColumns)).append(')');
1315+
b.append("DROP UNIQUE (").append(PlainSelect.getStringList(dropColumns))
1316+
.append(')');
12241317
break;
12251318
case DROP_FOREIGN_KEY:
12261319
b.append("DROP FOREIGN KEY ");
12271320
if (constraintName != null) {
12281321
b.append(constraintName);
12291322
} else {
1230-
b.append('(').append(PlainSelect.getStringList(pkColumns)).append(')');
1323+
b.append('(').append(PlainSelect.getStringList(dropColumns)).append(')');
12311324
}
12321325
break;
12331326
case DROP_CHECK:
12341327
b.append("DROP CHECK ").append(constraintName);
12351328
break;
12361329
default:
12371330
// Oracle Multi Column Drop
1238-
b.append("DROP (").append(PlainSelect.getStringList(pkColumns)).append(')');
1331+
b.append("DROP (").append(PlainSelect.getStringList(dropColumns)).append(')');
12391332
break;
12401333
}
12411334
}
@@ -1451,26 +1544,7 @@ private void toStringGeneral(StringBuilder b, Consumer<ColumnDataType> columnPri
14511544
} else if (constraint != null) {
14521545
b.append(constraint);
14531546
} else if (index != null) {
1454-
// The structured index is canonical. Legacy PK/UK/FK fields may also be populated for
1455-
// source compatibility, but cannot represent names, expressions, or index options.
14561547
b.append(index);
1457-
} else if (pkColumns != null) {
1458-
b.append("PRIMARY KEY (").append(PlainSelect.getStringList(pkColumns)).append(')');
1459-
} else if (ukColumns != null) {
1460-
b.append("UNIQUE");
1461-
if (ukName != null) {
1462-
if (isUkTypeSpecified()) {
1463-
if (getUk()) {
1464-
b.append(" KEY ");
1465-
} else {
1466-
b.append(" INDEX ");
1467-
}
1468-
} else {
1469-
b.append(" ");
1470-
}
1471-
b.append(ukName);
1472-
}
1473-
b.append(" (").append(PlainSelect.getStringList(ukColumns)).append(")");
14741548
} else if (fkColumns != null) {
14751549
// @deprecated path - kept for backward compatibility when ForeignKeyConstraint is not
14761550
// set

0 commit comments

Comments
 (0)