@@ -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 ;
@@ -633,75 +629,144 @@ public void setUsingIfExists(boolean usingIfExists) {
633629 }
634630
635631 /**
636- * Returns a snapshot of the rendered key elements for a structured PRIMARY_KEY, or the legacy
637- * list otherwise. Changing the snapshot does not change the constraint; use
638- * {@link #setPkColumns(List)} to replace its keys, or {@link KeyConstraint#getColumns()} for
639- * structured edits.
632+ * Returns the stored key definition, or null for another definition. The returned object is
633+ * shared with {@link #getConstraint()} and can be edited directly.
634+ */
635+ public KeyConstraint getKeyConstraint () {
636+ return constraint instanceof KeyConstraint ? (KeyConstraint ) constraint : null ;
637+ }
638+
639+ /**
640+ * Returns the owned mutable column targets for parenthesized DROP, DROP UNIQUE or DROP FOREIGN
641+ * KEY syntax, or null when omitted. Stored targets are independent of any ADD definition.
642+ */
643+ public List <String > getDropColumns () {
644+ return dropColumns ;
645+ }
646+
647+ /** Copies the supplied targets without changing the operation or any stored definition. */
648+ public void setDropColumns (List <String > dropColumns ) {
649+ this .dropColumns = dropColumns == null ? null : new ArrayList <>(dropColumns );
650+ }
651+
652+ public AlterExpression withDropColumns (List <String > dropColumns ) {
653+ setDropColumns (dropColumns );
654+ return this ;
655+ }
656+
657+ public AlterExpression addDropColumns (String ... columns ) {
658+ return addDropColumns (Arrays .asList (columns ));
659+ }
660+
661+ public AlterExpression addDropColumns (Collection <String > columns ) {
662+ if (dropColumns == null ) {
663+ dropColumns = new ArrayList <>();
664+ }
665+ dropColumns .addAll (columns );
666+ return this ;
667+ }
668+
669+ /**
670+ * Returns a rendered snapshot of the stored PRIMARY KEY's elements, or null when absent. For
671+ * DROP, DROP UNIQUE and DROP FOREIGN KEY operations this legacy accessor instead returns a
672+ * snapshot of {@link #getDropColumns()}. Snapshot edits never change the AST. New code should
673+ * use {@link #getKeyConstraint()} or {@link #getDropColumns()} explicitly.
640674 */
641675 public List <String > getPkColumns () {
676+ if (usesLegacyDropColumns ()) {
677+ return dropColumns == null ? null : new ArrayList <>(dropColumns );
678+ }
642679 return hasKeyConstraint (ConstraintKind .PRIMARY_KEY )
643680 ? ((KeyConstraint ) constraint ).getColumnsNames ()
644- : pkColumns ;
681+ : null ;
645682 }
646683
647684 /**
648- * Replaces a structured PRIMARY_KEY's elements using
649- * {@link KeyConstraint#setColumnsNames(List)}. The strings are not parsed and existing element
650- * attributes are not retained, even when the rendered SQL is unchanged. Use
651- * {@link KeyConstraint#setColumns(List)} to preserve structured elements. Without a matching
652- * constraint, stores the legacy list.
685+ * Replaces PRIMARY KEY elements with opaque names, without parsing or retaining element
686+ * attributes. A non-null list creates a definition when none exists; a competing definition
687+ * must be replaced explicitly using {@link #setConstraint(NamedConstraint)}. Null clears only
688+ * an existing PRIMARY KEY's elements and does not create a definition. With DROP, DROP UNIQUE
689+ * or DROP FOREIGN KEY already selected, delegates to {@link #setDropColumns(List)} instead. Set
690+ * the operation first for this legacy DROP alias; new builders should use setDropColumns.
691+ *
692+ * @throws IllegalStateException if a non-null list would replace another definition
653693 */
654694 public void setPkColumns (List <String > pkColumns ) {
655- if (hasKeyConstraint (ConstraintKind .PRIMARY_KEY )) {
656- ((KeyConstraint ) constraint ).setColumnsNames (pkColumns );
657- this .pkColumns = null ;
658- } else {
659- this .pkColumns = pkColumns ;
695+ if (usesLegacyDropColumns ()) {
696+ setDropColumns (pkColumns );
697+ return ;
698+ }
699+ KeyConstraint key = keyForUpdate (ConstraintKind .PRIMARY_KEY , pkColumns != null );
700+ if (key != null ) {
701+ key .setColumnsNames (pkColumns );
660702 }
661703 }
662704
663705 /**
664- * Returns a snapshot of the rendered key elements for a structured UNIQUE, or the legacy list
665- * otherwise. Changing the snapshot does not change the constraint; use
666- * {@link #setUkColumns(List)} to replace its keys, or {@link KeyConstraint#getColumns()} for
667- * structured edits.
706+ * Returns a snapshot of the stored UNIQUE's elements, or null when absent. Changing the
707+ * snapshot does not change the constraint; use {@link #setUkColumns(List)} to replace its keys,
708+ * or {@link KeyConstraint#getColumns()} for structured edits.
668709 */
669710 public List <String > getUkColumns () {
670711 return hasKeyConstraint (ConstraintKind .UNIQUE )
671712 ? ((KeyConstraint ) constraint ).getColumnsNames ()
672- : ukColumns ;
713+ : null ;
673714 }
674715
675716 /**
676717 * Replaces a structured UNIQUE's elements using {@link KeyConstraint#setColumnsNames(List)}.
677718 * The strings are not parsed and existing element attributes are not retained, even when the
678719 * rendered SQL is unchanged. Use {@link KeyConstraint#setColumns(List)} to preserve structured
679- * elements. Without a matching constraint, stores the legacy list.
720+ * elements. A non-null list creates a UNIQUE definition only when none exists; a competing
721+ * definition must be replaced explicitly. Null clears only an existing UNIQUE's elements.
722+ *
723+ * @throws IllegalStateException if a non-null list would replace another definition
680724 */
681725 public void setUkColumns (List <String > ukColumns ) {
682- if (hasKeyConstraint (ConstraintKind .UNIQUE )) {
683- ((KeyConstraint ) constraint ).setColumnsNames (ukColumns );
684- this .ukColumns = null ;
685- } else {
686- this .ukColumns = ukColumns ;
726+ KeyConstraint key = keyForUpdate (ConstraintKind .UNIQUE , ukColumns != null );
727+ if (key != null ) {
728+ key .setColumnsNames (ukColumns );
687729 }
688730 }
689731
732+ private boolean usesLegacyDropColumns () {
733+ return operation == AlterOperation .DROP || operation == AlterOperation .DROP_UNIQUE
734+ || operation == AlterOperation .DROP_FOREIGN_KEY ;
735+ }
736+
690737 private boolean hasKeyConstraint (ConstraintKind kind ) {
691738 return constraint instanceof KeyConstraint && constraint .getKind () == kind ;
692739 }
693740
741+ private KeyConstraint keyForUpdate (ConstraintKind kind , boolean create ) {
742+ if (hasKeyConstraint (kind )) {
743+ return (KeyConstraint ) constraint ;
744+ }
745+ if (!create ) {
746+ return null ;
747+ }
748+ if (constraint != null || index != null || getFkColumns () != null ) {
749+ throw new IllegalStateException (
750+ "Key setters cannot replace an existing definition; use setConstraint" );
751+ }
752+ KeyConstraint key = new KeyConstraint ()
753+ .withType (kind == ConstraintKind .PRIMARY_KEY ? "PRIMARY KEY" : "UNIQUE" );
754+ setConstraint (key );
755+ return key ;
756+ }
757+
694758 public String getUkName () {
695759 return hasKeyConstraint (ConstraintKind .UNIQUE )
696760 ? ((KeyConstraint ) constraint ).getIndexName ()
697- : ukName ;
761+ : null ;
698762 }
699763
764+ /** Uses the creation and replacement policy of {@link #setUkColumns(List)}. */
700765 public void setUkName (String ukName ) {
701- if (hasKeyConstraint (ConstraintKind .UNIQUE )) {
702- ((KeyConstraint ) constraint ).setIndexName (ukName );
766+ KeyConstraint key = keyForUpdate (ConstraintKind .UNIQUE , ukName != null );
767+ if (key != null ) {
768+ key .setIndexName (ukName );
703769 }
704- this .ukName = ukName ;
705770 }
706771
707772 public Index getIndex () {
@@ -753,12 +818,6 @@ private ConstraintKind getAddedConstraintKind() {
753818 if (index != null ) {
754819 return ConstraintKind .OTHER ;
755820 }
756- if (pkColumns != null ) {
757- return ConstraintKind .PRIMARY_KEY ;
758- }
759- if (ukColumns != null ) {
760- return ConstraintKind .UNIQUE ;
761- }
762821 return ConstraintKind .OTHER ;
763822 }
764823
@@ -920,20 +979,53 @@ public void setUseEqual(boolean useEqual) {
920979 }
921980
922981 public boolean getUk () {
923- return uk ;
982+ return "KEY" . equalsIgnoreCase ( getUniqueIndexKeyword ()) ;
924983 }
925984
985+ /** Selects KEY when true or INDEX when false on the stored UNIQUE definition. */
926986 public void setUk (boolean uk ) {
927- this .uk = uk ;
928- this .ukTypeSpecified = true ;
987+ setUniqueIndexKeyword (keyForUpdate (ConstraintKind .UNIQUE , true ), uk ? "KEY" : "INDEX" );
929988 }
930989
931990 public boolean isUkTypeSpecified () {
932- return ukTypeSpecified ;
991+ return getUniqueIndexKeyword () != null ;
933992 }
934993
994+ /**
995+ * Removes the explicit KEY/INDEX spelling when false. When true, retains an existing spelling
996+ * or selects INDEX. Clearing an absent UNIQUE definition does not create one.
997+ */
935998 public void setUkTypeSpecified (boolean ukTypeSpecified ) {
936- this .ukTypeSpecified = ukTypeSpecified ;
999+ KeyConstraint key = keyForUpdate (ConstraintKind .UNIQUE , ukTypeSpecified );
1000+ if (key != null ) {
1001+ String keyword = getUniqueIndexKeyword ();
1002+ setUniqueIndexKeyword (key ,
1003+ ukTypeSpecified ? keyword == null ? "INDEX" : keyword : null );
1004+ }
1005+ }
1006+
1007+ private String getUniqueIndexKeyword () {
1008+ KeyConstraint key = keyForUpdate (ConstraintKind .UNIQUE , false );
1009+ if (key == null ) {
1010+ return null ;
1011+ }
1012+ if (key .getIndexKeyword () != null ) {
1013+ return key .getIndexKeyword ();
1014+ }
1015+ if ("UNIQUE KEY" .equalsIgnoreCase (key .getType ())) {
1016+ return "KEY" ;
1017+ }
1018+ return "UNIQUE INDEX" .equalsIgnoreCase (key .getType ()) ? "INDEX" : null ;
1019+ }
1020+
1021+ private void setUniqueIndexKeyword (KeyConstraint key , String keyword ) {
1022+ if (hasLegacyKeyConstraint () || "UNIQUE KEY" .equalsIgnoreCase (key .getType ())
1023+ || "UNIQUE INDEX" .equalsIgnoreCase (key .getType ())) {
1024+ key .setType ("UNIQUE" + (keyword == null ? "" : " " + keyword ));
1025+ key .setIndexKeyword (null );
1026+ } else {
1027+ key .setIndexKeyword (keyword );
1028+ }
9371029 }
9381030
9391031 public boolean isUseIfNotExists () {
@@ -1171,7 +1263,7 @@ protected boolean isDropSpecialOperation() {
11711263 case DROP_CHECK :
11721264 return true ;
11731265 case DROP :
1174- return columnName == null && pkColumns != null && !pkColumns .isEmpty ();
1266+ return columnName == null && dropColumns != null && !dropColumns .isEmpty ();
11751267 default :
11761268 return false ;
11771269 }
@@ -1332,22 +1424,23 @@ protected void toStringDropSpecial(StringBuilder b) {
13321424 b .append ("DROP PRIMARY KEY " );
13331425 break ;
13341426 case DROP_UNIQUE :
1335- b .append ("DROP UNIQUE (" ).append (PlainSelect .getStringList (pkColumns )).append (')' );
1427+ b .append ("DROP UNIQUE (" ).append (PlainSelect .getStringList (dropColumns ))
1428+ .append (')' );
13361429 break ;
13371430 case DROP_FOREIGN_KEY :
13381431 b .append ("DROP FOREIGN KEY " );
13391432 if (constraintName != null ) {
13401433 b .append (constraintName );
13411434 } else {
1342- b .append ('(' ).append (PlainSelect .getStringList (pkColumns )).append (')' );
1435+ b .append ('(' ).append (PlainSelect .getStringList (dropColumns )).append (')' );
13431436 }
13441437 break ;
13451438 case DROP_CHECK :
13461439 b .append ("DROP CHECK " ).append (constraintName );
13471440 break ;
13481441 default :
13491442 // Oracle Multi Column Drop
1350- b .append ("DROP (" ).append (PlainSelect .getStringList (pkColumns )).append (')' );
1443+ b .append ("DROP (" ).append (PlainSelect .getStringList (dropColumns )).append (')' );
13511444 break ;
13521445 }
13531446 }
@@ -1563,26 +1656,7 @@ private void toStringGeneral(StringBuilder b, Consumer<ColumnDataType> columnPri
15631656 } else if (constraint != null ) {
15641657 b .append (constraint );
15651658 } else if (index != null ) {
1566- // The structured index is canonical. Legacy PK/UK fields may also be populated for
1567- // source compatibility, but cannot represent names, expressions, or index options.
15681659 b .append (index );
1569- } else if (pkColumns != null ) {
1570- b .append ("PRIMARY KEY (" ).append (PlainSelect .getStringList (pkColumns )).append (')' );
1571- } else if (ukColumns != null ) {
1572- b .append ("UNIQUE" );
1573- if (ukName != null ) {
1574- if (isUkTypeSpecified ()) {
1575- if (getUk ()) {
1576- b .append (" KEY " );
1577- } else {
1578- b .append (" INDEX " );
1579- }
1580- } else {
1581- b .append (" " );
1582- }
1583- b .append (ukName );
1584- }
1585- b .append (" (" ).append (PlainSelect .getStringList (ukColumns )).append (")" );
15861660 }
15871661
15881662 if (getConstraints () != null && !getConstraints ().isEmpty ()) {
0 commit comments