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