Visitar URL original
Separate index and constraint ASTs (breaking API change) by minleejae · Pull Request #2747 · JSQLParser/JSqlParser · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Next Next commit
feat: expose unified table constraint inspection
Signed-off-by: minleejae <mmj9808@gmail.com>
  • Loading branch information
minleejae committed Oct 1, 2026
commit 1d66332e042e285978eea9ffdeba0dcea26c3e49
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

import java.util.Objects;
import net.sf.jsqlparser.statement.create.table.ConstraintAttributes;
import net.sf.jsqlparser.statement.create.table.Index;

/** Changes an existing constraint using the attributes shared with CREATE and ADD. */
public class AlterConstraintAttributes extends AlterExpression {
Expand Down Expand Up @@ -49,6 +50,11 @@ public void setEnforced(boolean enforced) {
attributes.setEnforced(enforced);
}

@Override
public Index.Kind getConstraintKind() {
return Index.Kind.OTHER;
}

@Override
protected void appendBody(StringBuilder builder) {
builder.append("ALTER CONSTRAINT ").append(getConstraintSymbol());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -590,6 +590,56 @@ public Index getIndex() {
return index;
}

/**
* Returns the constraint kind explicitly declared or targeted by the active action. Named
* DROP/ALTER CONSTRAINT actions return OTHER because their SQL does not identify the kind; no
* catalogue lookup or inference from an inactive Index field is performed. Column actions
* return OTHER: inspect their ColumnOption nodes for inline constraints.
*/
public Index.Kind getConstraintKind() {
if (operation == null) {
return Index.Kind.OTHER;
}
switch (operation) {
case DROP_PRIMARY_KEY:
case ALTER_PRIMARY_KEY:
return Index.Kind.PRIMARY_KEY;
case DROP_UNIQUE:
return Index.Kind.UNIQUE;
case DROP_FOREIGN_KEY:
return Index.Kind.FOREIGN_KEY;
case DROP_CHECK:
return Index.Kind.CHECK;
case ADD:
case ALTER:
if (constraintType != null && constraintSymbol != null) {
Index.Kind declared = new Index().withType(constraintType).getKind();
return declared.canDescribeConstraint() ? declared : Index.Kind.OTHER;
}
if (operation != AlterOperation.ADD || columnName != null
|| colDataTypeList != null || constraintName != null || oldIndex != null
|| commentText != null || columnSetNotNullList != null
|| columnDropNotNullList != null
|| columnDropDefaultList != null && !columnDropDefaultList.isEmpty()) {
return Index.Kind.OTHER;
}
if (index != null) {
return index.getKind() != null && index.getKind().canDescribeConstraint()
? index.getKind()
: Index.Kind.OTHER;
}
if (pkColumns != null) {
return Index.Kind.PRIMARY_KEY;
}
if (ukColumns != null) {
return Index.Kind.UNIQUE;
}
return fkColumns != null ? Index.Kind.FOREIGN_KEY : Index.Kind.OTHER;
default:
return Index.Kind.OTHER;
}
}

public void setIndex(Index index) {
this.index = index;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@
*/
package net.sf.jsqlparser.statement.alter;

import net.sf.jsqlparser.statement.create.table.Index;

/**
* Internal subclass for character set and collation operations within ALTER TABLE. Handles CONVERT
* TO CHARACTER SET, DEFAULT CHARACTER SET, CHARACTER SET, and COLLATE.
*/
public class AlterExpressionCharset extends AlterExpression {

@Override
public Index.Kind getConstraintKind() {
return Index.Kind.OTHER;
}

@Override
protected void appendBody(StringBuilder b) {
toStringConvert(b);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,30 @@
*/
package net.sf.jsqlparser.statement.alter;


import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.create.table.Index;

/**
* Internal subclass for DROP operations within ALTER TABLE. Handles DROP column, DROP CONSTRAINT,
* DROP INDEX/KEY, DROP PRIMARY KEY, DROP UNIQUE, DROP FOREIGN KEY, and DROP PARTITION.
*/
public class AlterExpressionDrop extends AlterExpression {
@Override
public Index.Kind getConstraintKind() {
if (getOperation() == null) {
return Index.Kind.OTHER;
}
switch (getOperation()) {
case DROP_PRIMARY_KEY:
case DROP_UNIQUE:
case DROP_FOREIGN_KEY:
case DROP_CHECK:
return super.getConstraintKind();
default:
return Index.Kind.OTHER;
}
}

@Override
protected void appendBody(StringBuilder b) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.select.OrderByElement;
import net.sf.jsqlparser.statement.create.table.Index;

/** MySQL ALTER TABLE ORDER BY, using the same mutable order elements as query ordering. */
public class AlterExpressionOrderBy extends AlterExpression {
Expand All @@ -27,6 +28,11 @@ public List<OrderByElement> getOrderByElements() {
return orderByElements;
}

@Override
public Index.Kind getConstraintKind() {
return Index.Kind.OTHER;
}

@Override
protected void appendBody(StringBuilder builder) {
appendOrderBy(builder, builder::append);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import net.sf.jsqlparser.statement.create.table.PartitionDefinition;
import net.sf.jsqlparser.statement.create.table.TablePartitioning;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.create.table.Index;

/**
* Structured model for partition operations within {@code ALTER TABLE}.
Expand Down Expand Up @@ -292,6 +293,11 @@ public AlterExpressionPartition addPartitionDefinitions(
return withPartitionDefinitions(collection);
}

@Override
public Index.Kind getConstraintKind() {
return Index.Kind.OTHER;
}

@Override
protected void appendBody(StringBuilder b) {
appendBody(b, b::append);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ public void setBucketCount(Expression bucketCount) {
this.bucketCount = bucketCount;
}

@Override
public Index.Kind getConstraintKind() {
return Index.Kind.PRIMARY_KEY;
}

@Override
protected void appendBody(StringBuilder builder) {
appendDefinition(builder, expression -> builder.append(expression));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,19 @@
*/
package net.sf.jsqlparser.statement.alter;

import net.sf.jsqlparser.statement.create.table.Index;

/**
* Internal subclass for RENAME operations within ALTER TABLE. Handles RENAME COLUMN, RENAME TO
* (table), RENAME INDEX/KEY/CONSTRAINT.
*/
public class AlterExpressionRename extends AlterExpression {

@Override
public Index.Kind getConstraintKind() {
return Index.Kind.OTHER;
}

@Override
protected void appendBody(StringBuilder b) {
switch (getOperation()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package net.sf.jsqlparser.statement.alter;

import net.sf.jsqlparser.statement.create.table.TableOption;
import net.sf.jsqlparser.statement.create.table.Index;

/**
* Internal subclass for table-level option operations within ALTER TABLE. Handles ENGINE,
Expand Down Expand Up @@ -128,6 +129,11 @@ public void setUseEqual(boolean useEqual) {
super.setUseEqual(useEqual);
}

@Override
public Index.Kind getConstraintKind() {
return Index.Kind.OTHER;
}

@Override
protected void appendBody(StringBuilder b) {
if (structuredTableOption != null) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import java.util.function.Consumer;
import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.statement.create.table.ForeignDataOption;
import net.sf.jsqlparser.statement.create.table.Index;

/** Foreign table OPTIONS, optionally applied to one column. */
public class AlterForeignDataOptions extends AlterExpression {
Expand All @@ -39,6 +40,11 @@ public StringBuilder appendTo(StringBuilder builder, Consumer<Expression> expres
return builder;
}

@Override
public Index.Kind getConstraintKind() {
return Index.Kind.OTHER;
}

@Override
protected void appendBody(StringBuilder builder) {
appendTo(builder, builder::append);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,11 @@ public void setResetOptions(List<String> resetOptions) {
this.resetOptions = resetOptions;
}

@Override
public Index.Kind getConstraintKind() {
return Index.Kind.OTHER;
}

@Override
protected void appendBody(StringBuilder builder) {
appendDefinition(builder, builder::append);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,29 @@ public Index getConstraint() {
return constraint;
}

/**
* Returns the constraint kind explicitly represented by this option, including REFERENCES,
* DEFAULT and NOT NULL. Returns OTHER for NULL, unrelated or raw options, and options without a
* recognized constraint kind. The result is computed from the current AST; it does not infer
* constraints implied by other options, such as NOT NULL implied by a primary key.
*/
public Index.Kind getConstraintKind() {
switch (kind) {
case CONSTRAINT:
return constraint != null && constraint.getKind() != null
&& constraint.getKind().canDescribeConstraint() ? constraint.getKind()
: Index.Kind.OTHER;
case REFERENCE:
return foreignKeyReference == null ? Index.Kind.OTHER : Index.Kind.FOREIGN_KEY;
case DEFAULT:
return defaultExpression == null ? Index.Kind.OTHER : Index.Kind.DEFAULT;
case NULLABILITY:
return Boolean.FALSE.equals(nullable) ? Index.Kind.NOT_NULL : Index.Kind.OTHER;
default:
return Index.Kind.OTHER;
}
}

public static ColumnOption raw(List<String> tokens) {
ColumnOption option = new ColumnOption();
option.tokens = tokens;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2026 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.create.table;

/**
* A view of a constraint declared in a CREATE TABLE definition. Its source nodes remain editable;
* no constraint data is copied. A column declaration retains its owning column rather than
* manufacturing a table constraint or a key-column list.
*
* @see CreateTable#getConstraints()
*/
public final class ConstraintDeclaration {
private final ColumnDefinition column;
private final ColumnOption columnOption;
private final Index index;

ConstraintDeclaration(ColumnDefinition column, ColumnOption columnOption) {
this.column = column;
this.columnOption = columnOption;
this.index = null;
}

ConstraintDeclaration(Index index) {
this.column = null;
this.columnOption = null;
this.index = index;
}

/** Returns the current kind, or OTHER if an edit no longer represents a constraint. */
public Index.Kind getKind() {
if (columnOption != null) {
return columnOption.getConstraintKind();
}
return index.getKind() != null && index.getKind().canDescribeConstraint() ? index.getKind()
: Index.Kind.OTHER;
}

/** Returns the original owning column, or null for a table-level declaration. */
public ColumnDefinition getColumn() {
return column;
}

/** Returns the original column option, or null for a table-level declaration. */
public ColumnOption getColumnOption() {
return columnOption;
}

/**
* Returns the original constraint node, including a column's nested constraint. REFERENCES,
* DEFAULT and nullability column options have no Index node; use getColumnOption() for them.
*/
public Index getIndex() {
return columnOption == null ? index : columnOption.getConstraint();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,49 @@ public List<Index> getIndexes() {
return indexes;
}

/**
* Returns column and table constraint declarations in source order, including MySQL UNIQUE
* KEY/INDEX declarations and explicit DEFAULT/NOT NULL options. Plain indexes, raw options, and
* constraints inherited from LIKE, a type or another table are not inferred.
*
* The list is an unmodifiable membership snapshot. Each view reads its original editable AST
* nodes; call this method again after inserting, removing or reclassifying declarations. For
* legacy construction without ordered table elements, columns precede table constraints.
*/
public List<ConstraintDeclaration> getConstraints() {
List<ConstraintDeclaration> declarations = new ArrayList<>();
if (tableElements != null) {
tableElements.forEach(element -> addConstraints(element, declarations));
} else {
if (columnDefinitions != null) {
columnDefinitions.forEach(column -> addConstraints(column, declarations));
}
if (indexes != null) {
indexes.forEach(index -> addConstraints(index, declarations));
}
}
return Collections.unmodifiableList(declarations);
}

private static void addConstraints(TableElement element,
List<ConstraintDeclaration> declarations) {
if (element instanceof ColumnDefinition) {
ColumnDefinition column = (ColumnDefinition) element;
if (column.getColumnOptions() != null) {
for (ColumnOption option : column.getColumnOptions()) {
if (option.getConstraintKind() != Index.Kind.OTHER) {
declarations.add(new ConstraintDeclaration(column, option));
}
}
}
} else if (element instanceof Index) {
Index index = (Index) element;
if (index.getKind() != null && index.getKind().canDescribeConstraint()) {
declarations.add(new ConstraintDeclaration(index));
}
}
}

public void setIndexes(List<Index> list) {
if (tableElements == null) {
indexes = list;
Expand Down
Loading