@@ -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