From a161e1f850f89424e01a811ec27012fd5863b6b9 Mon Sep 17 00:00:00 2001 From: Minjae Lee Date: Sun, 6 Sep 2026 15:01:11 +0900 Subject: [PATCH 1/2] feat(parser): model PostgreSQL type domain and extension DDL --- .../sf/jsqlparser/parser/feature/Feature.java | 4 + .../statement/RoutineReference.java | 115 ++++++ .../statement/StatementFeatureVisitor.java | 49 +++ .../statement/StatementVisitor.java | 54 +++ .../statement/StatementVisitorAdapter.java | 60 +++ .../statement/alter/AlterDomain.java | 170 ++++++++ .../statement/alter/AlterExtension.java | 95 +++++ .../jsqlparser/statement/alter/AlterType.java | 247 ++++++++++++ .../statement/create/domain/CreateDomain.java | 102 +++++ .../create/domain/DomainConstraint.java | 68 ++++ .../create/extension/CreateExtension.java | 104 +++++ .../create/extension/ExtensionObject.java | 115 ++++++ .../create/type/CompositeTypeDefinition.java | 32 ++ .../statement/create/type/CreateType.java | 45 +++ .../create/type/EnumTypeDefinition.java | 33 ++ .../create/type/RangeTypeDefinition.java | 76 ++++ .../statement/create/type/TypeAttribute.java | 48 +++ .../statement/create/type/TypeDefinition.java | 16 + .../sf/jsqlparser/util/TablesNamesFinder.java | 58 +++ .../util/deparser/StatementDeParser.java | 43 +++ .../validation/feature/PostgresqlVersion.java | 5 +- .../validator/StatementValidator.java | 59 +++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 364 +++++++++++++++++- src/site/sphinx/usage.rst | 27 ++ .../statement/UnsupportedStatementTest.java | 4 +- .../create/PostgreSqlTypeDdlTest.java | 213 ++++++++++ src/test/resources/postgresql/type-ddl.sql | 75 ++++ 27 files changed, 2273 insertions(+), 8 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/RoutineReference.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/alter/AlterDomain.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/alter/AlterExtension.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/alter/AlterType.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/domain/CreateDomain.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/domain/DomainConstraint.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/extension/CreateExtension.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/extension/ExtensionObject.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/type/CompositeTypeDefinition.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/type/CreateType.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/type/EnumTypeDefinition.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/type/RangeTypeDefinition.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/type/TypeAttribute.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/type/TypeDefinition.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/create/PostgreSqlTypeDdlTest.java create mode 100644 src/test/resources/postgresql/type-ddl.sql diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java index bb68fa387..7cb2d65f8 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -559,6 +559,10 @@ public enum Feature { * @see CreateSequence */ createSequence, + /** + * Structured type, domain and extension statements. + */ + createType, alterType, createDomain, alterDomain, createExtension, alterExtension, /** * SQL "CREATE SYNONYM" statement is allowed * diff --git a/src/main/java/net/sf/jsqlparser/statement/RoutineReference.java b/src/main/java/net/sf/jsqlparser/statement/RoutineReference.java new file mode 100644 index 000000000..2237a1e62 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/RoutineReference.java @@ -0,0 +1,115 @@ +/*- + * #%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; + +import java.util.List; +import java.util.stream.Collectors; +import net.sf.jsqlparser.statement.create.table.ColDataType; +import java.io.Serializable; + +public class RoutineReference implements Serializable { + private String name; + private List arguments; + private boolean allArguments; + private List orderByArguments; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getArguments() { + return arguments; + } + + public void setArguments(List arguments) { + this.arguments = arguments; + } + + public boolean isAllArguments() { + return allArguments; + } + + public void setAllArguments(boolean allArguments) { + this.allArguments = allArguments; + } + + public List getOrderByArguments() { + return orderByArguments; + } + + public void setOrderByArguments(List orderByArguments) { + this.orderByArguments = orderByArguments; + } + + /** A signature argument is a data type, not an invocation expression. */ + public static class Argument implements java.io.Serializable { + public enum Mode { + IN, OUT, INOUT, VARIADIC + } + + private Mode mode; + private String name; + private ColDataType dataType; + + public Mode getMode() { + return mode; + } + + public void setMode(Mode mode) { + this.mode = mode; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ColDataType getDataType() { + return dataType; + } + + public void setDataType(ColDataType dataType) { + this.dataType = dataType; + } + + @Override + public String toString() { + return (mode == null ? "" : mode + " ") + (name == null ? "" : name + " ") + dataType; + } + } + + @Override + public String toString() { + if (arguments == null && !allArguments && orderByArguments == null) { + return name; + } + StringBuilder sql = new StringBuilder(name).append('('); + if (allArguments) { + sql.append('*'); + } else if (arguments != null) { + sql.append(arguments.stream().map(Object::toString).collect(Collectors.joining(", "))); + } + if (orderByArguments != null) { + if (arguments != null && !arguments.isEmpty()) { + sql.append(' '); + } + sql.append("ORDER BY ").append(orderByArguments.stream().map(Object::toString) + .collect(Collectors.joining(", "))); + } + return sql.append(')').toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementFeatureVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementFeatureVisitor.java index b083cca6b..024967047 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementFeatureVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementFeatureVisitor.java @@ -9,6 +9,13 @@ */ package net.sf.jsqlparser.statement; +import net.sf.jsqlparser.statement.create.type.CreateType; +import net.sf.jsqlparser.statement.alter.AlterType; +import net.sf.jsqlparser.statement.create.domain.CreateDomain; +import net.sf.jsqlparser.statement.alter.AlterDomain; +import net.sf.jsqlparser.statement.create.extension.CreateExtension; +import net.sf.jsqlparser.statement.alter.AlterExtension; + import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; @@ -846,4 +853,46 @@ public Void visit(TableFunction tableFunction, S context) { return super.visit(tableFunction, context); } } + + @Override + public Void visit(CreateType statement, S context) { + analysis.claimTopLevel(); + analysis.certain(StmtFeature.MODIFIES_SCHEMA); + return null; + } + + @Override + public Void visit(AlterType statement, S context) { + analysis.claimTopLevel(); + analysis.certain(StmtFeature.MODIFIES_SCHEMA); + return null; + } + + @Override + public Void visit(CreateDomain statement, S context) { + analysis.claimTopLevel(); + analysis.certain(StmtFeature.MODIFIES_SCHEMA); + return null; + } + + @Override + public Void visit(AlterDomain statement, S context) { + analysis.claimTopLevel(); + analysis.certain(StmtFeature.MODIFIES_SCHEMA); + return null; + } + + @Override + public Void visit(CreateExtension statement, S context) { + analysis.claimTopLevel(); + analysis.certain(StmtFeature.MODIFIES_SCHEMA); + return null; + } + + @Override + public Void visit(AlterExtension statement, S context) { + analysis.claimTopLevel(); + analysis.certain(StmtFeature.MODIFIES_SCHEMA); + return null; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java index fd787910d..49145d85f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java @@ -9,6 +9,13 @@ */ package net.sf.jsqlparser.statement; +import net.sf.jsqlparser.statement.create.type.CreateType; +import net.sf.jsqlparser.statement.alter.AlterType; +import net.sf.jsqlparser.statement.create.domain.CreateDomain; +import net.sf.jsqlparser.statement.alter.AlterDomain; +import net.sf.jsqlparser.statement.create.extension.CreateExtension; +import net.sf.jsqlparser.statement.alter.AlterExtension; + import net.sf.jsqlparser.statement.alter.Alter; import net.sf.jsqlparser.statement.alter.AlterSession; import net.sf.jsqlparser.statement.alter.AlterSystemStatement; @@ -393,4 +400,51 @@ default void visit(CreatePolicy createPolicy) { this.visit(createPolicy, null); } + default T visit(CreateType statement, S context) { + return null; + } + + default void visit(CreateType statement) { + visit(statement, null); + } + + default T visit(AlterType statement, S context) { + return null; + } + + default void visit(AlterType statement) { + visit(statement, null); + } + + default T visit(CreateDomain statement, S context) { + return null; + } + + default void visit(CreateDomain statement) { + visit(statement, null); + } + + default T visit(AlterDomain statement, S context) { + return null; + } + + default void visit(AlterDomain statement) { + visit(statement, null); + } + + default T visit(CreateExtension statement, S context) { + return null; + } + + default void visit(CreateExtension statement) { + visit(statement, null); + } + + default T visit(AlterExtension statement, S context) { + return null; + } + + default void visit(AlterExtension statement) { + visit(statement, null); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index 706fd9466..8effd4127 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -9,9 +9,17 @@ */ package net.sf.jsqlparser.statement; +import net.sf.jsqlparser.statement.create.type.CreateType; +import net.sf.jsqlparser.statement.alter.AlterType; +import net.sf.jsqlparser.statement.create.domain.CreateDomain; +import net.sf.jsqlparser.statement.alter.AlterDomain; +import net.sf.jsqlparser.statement.create.extension.CreateExtension; +import net.sf.jsqlparser.statement.alter.AlterExtension; + import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.schema.Partition; import net.sf.jsqlparser.statement.alter.Alter; import net.sf.jsqlparser.statement.alter.AlterExpression; @@ -596,4 +604,56 @@ public T visit(Import imprt, S context) { public T visit(Export export, S context) { return null; } + + @Override + public T visit(CreateType statement, S context) { + + return null; + } + + @Override + public T visit(AlterType statement, S context) { + + return null; + } + + @Override + public T visit(CreateDomain statement, S context) { + if (statement.getDefaultExpression() != null) { + statement.getDefaultExpression().accept(expressionVisitor, context); + } + statement.getConstraints().forEach(constraint -> { + if (constraint.getExpression() != null) { + constraint.getExpression().accept(expressionVisitor, context); + } + }); + return null; + } + + @Override + public T visit(AlterDomain statement, S context) { + if (statement.getDefaultExpression() != null) { + statement.getDefaultExpression().accept(expressionVisitor, context); + } + if (statement.getConstraint() != null + && statement.getConstraint().getExpression() != null) { + statement.getConstraint().getExpression().accept(expressionVisitor, context); + } + return null; + } + + @Override + public T visit(CreateExtension statement, S context) { + + return null; + } + + @Override + public T visit(AlterExtension statement, S context) { + if (statement.getMember() != null && statement.getMember().isTable()) { + new Table(statement.getMember().getName()) + .accept(fromItemVisitor, context); + } + return null; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterDomain.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterDomain.java new file mode 100644 index 000000000..3531ba814 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterDomain.java @@ -0,0 +1,170 @@ +/*- + * #%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.alter; + +import java.util.function.Consumer; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.statement.create.domain.DomainConstraint; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class AlterDomain implements Statement { + private String name; + private Action action; + private Expression defaultExpression; + private DomainConstraint constraint; + private String constraintName; + private String newName; + private boolean notValid; + private boolean ifExists; + private Behavior behavior; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Action getAction() { + return action; + } + + public void setAction(Action action) { + this.action = action; + } + + public Expression getDefaultExpression() { + return defaultExpression; + } + + public void setDefaultExpression(Expression defaultExpression) { + this.defaultExpression = defaultExpression; + } + + public DomainConstraint getConstraint() { + return constraint; + } + + public void setConstraint(DomainConstraint constraint) { + this.constraint = constraint; + } + + public String getConstraintName() { + return constraintName; + } + + public void setConstraintName(String constraintName) { + this.constraintName = constraintName; + } + + public String getNewName() { + return newName; + } + + public void setNewName(String newName) { + this.newName = newName; + } + + public boolean isNotValid() { + return notValid; + } + + public void setNotValid(boolean notValid) { + this.notValid = notValid; + } + + public boolean isIfExists() { + return ifExists; + } + + public void setIfExists(boolean ifExists) { + this.ifExists = ifExists; + } + + public Behavior getBehavior() { + return behavior; + } + + public void setBehavior(Behavior behavior) { + this.behavior = behavior; + } + + @Override + public T accept(StatementVisitor visitor, S context) { + return visitor.visit(this, context); + } + + public enum Action { + SET_DEFAULT, DROP_DEFAULT, SET_NOT_NULL, DROP_NOT_NULL, ADD_CONSTRAINT, DROP_CONSTRAINT, RENAME_CONSTRAINT, VALIDATE_CONSTRAINT, OWNER, RENAME, SET_SCHEMA + } + public enum Behavior { + CASCADE, RESTRICT + } + + public void appendTo(StringBuilder sql, Consumer expressions) { + sql.append("ALTER DOMAIN ").append(name).append(' '); + switch (action) { + case SET_DEFAULT: + sql.append("SET DEFAULT "); + expressions.accept(defaultExpression); + break; + case DROP_DEFAULT: + sql.append("DROP DEFAULT"); + break; + case SET_NOT_NULL: + sql.append("SET NOT NULL"); + break; + case DROP_NOT_NULL: + sql.append("DROP NOT NULL"); + break; + case ADD_CONSTRAINT: + sql.append("ADD "); + constraint.appendTo(sql, expressions); + if (notValid) { + sql.append(" NOT VALID"); + } + break; + case DROP_CONSTRAINT: + sql.append("DROP CONSTRAINT ").append(ifExists ? "IF EXISTS " : "") + .append(constraintName); + if (behavior != null) { + sql.append(' ').append(behavior); + } + break; + case RENAME_CONSTRAINT: + sql.append("RENAME CONSTRAINT ").append(constraintName).append(" TO ") + .append(newName); + break; + case VALIDATE_CONSTRAINT: + sql.append("VALIDATE CONSTRAINT ").append(constraintName); + break; + case OWNER: + sql.append("OWNER TO ").append(newName); + break; + case RENAME: + sql.append("RENAME TO ").append(newName); + break; + case SET_SCHEMA: + sql.append("SET SCHEMA ").append(newName); + break; + default: + throw new IllegalStateException("Unknown domain alteration: " + action); + } + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + appendTo(sql, sql::append); + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterExtension.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExtension.java new file mode 100644 index 000000000..0affa5f43 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterExtension.java @@ -0,0 +1,95 @@ +/*- + * #%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.alter; + +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.statement.create.extension.ExtensionObject; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class AlterExtension implements Statement { + private String name; + private Action action; + private Expression version; + private String schema; + private ExtensionObject member; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Action getAction() { + return action; + } + + public void setAction(Action action) { + this.action = action; + } + + public Expression getVersion() { + return version; + } + + public void setVersion(Expression version) { + this.version = version; + } + + public String getSchema() { + return schema; + } + + public void setSchema(String schema) { + this.schema = schema; + } + + public ExtensionObject getMember() { + return member; + } + + public void setMember(ExtensionObject member) { + this.member = member; + } + + @Override + public T accept(StatementVisitor visitor, S context) { + return visitor.visit(this, context); + } + + public enum Action { + UPDATE, SET_SCHEMA, ADD, DROP + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder("ALTER EXTENSION ").append(name).append(' '); + switch (action) { + case UPDATE: + sql.append("UPDATE"); + if (version != null) { + sql.append(" TO ").append(version); + } + break; + case SET_SCHEMA: + sql.append("SET SCHEMA ").append(schema); + break; + case ADD: + case DROP: + sql.append(action).append(' ').append(member); + break; + default: + throw new IllegalStateException("Unknown extension alteration: " + action); + } + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/alter/AlterType.java b/src/main/java/net/sf/jsqlparser/statement/alter/AlterType.java new file mode 100644 index 000000000..f49936d41 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/alter/AlterType.java @@ -0,0 +1,247 @@ +/*- + * #%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.alter; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; +import net.sf.jsqlparser.expression.StringValue; +import net.sf.jsqlparser.statement.create.type.TypeAttribute; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class AlterType implements Statement { + private String name; + private Action action; + private String newName; + private String attributeName; + private StringValue value; + private StringValue newValue; + private StringValue neighborValue; + private Position position; + private boolean ifNotExists; + private Behavior behavior; + private List attributeChanges = new ArrayList<>(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Action getAction() { + return action; + } + + public void setAction(Action action) { + this.action = action; + } + + public String getNewName() { + return newName; + } + + public void setNewName(String newName) { + this.newName = newName; + } + + public String getAttributeName() { + return attributeName; + } + + public void setAttributeName(String attributeName) { + this.attributeName = attributeName; + } + + public StringValue getValue() { + return value; + } + + public void setValue(StringValue value) { + this.value = value; + } + + public StringValue getNewValue() { + return newValue; + } + + public void setNewValue(StringValue newValue) { + this.newValue = newValue; + } + + public StringValue getNeighborValue() { + return neighborValue; + } + + public void setNeighborValue(StringValue neighborValue) { + this.neighborValue = neighborValue; + } + + public Position getPosition() { + return position; + } + + public void setPosition(Position position) { + this.position = position; + } + + public boolean isIfNotExists() { + return ifNotExists; + } + + public void setIfNotExists(boolean ifNotExists) { + this.ifNotExists = ifNotExists; + } + + public Behavior getBehavior() { + return behavior; + } + + public void setBehavior(Behavior behavior) { + this.behavior = behavior; + } + + public List getAttributeChanges() { + return attributeChanges; + } + + public void setAttributeChanges(List attributeChanges) { + this.attributeChanges = attributeChanges; + } + + @Override + public T accept(StatementVisitor visitor, S context) { + return visitor.visit(this, context); + } + + public enum Action { + OWNER, RENAME, SET_SCHEMA, RENAME_ATTRIBUTE, ADD_VALUE, RENAME_VALUE, ATTRIBUTES + } + public enum Position { + BEFORE, AFTER + } + public enum Behavior { + CASCADE, RESTRICT + } + public static class AttributeChange implements java.io.Serializable { + public enum Kind { + ADD, DROP, ALTER + } + + private Kind kind; + private TypeAttribute attribute; + private boolean ifExists; + private boolean useSetData; + private Behavior behavior; + + public Kind getKind() { + return kind; + } + + public void setKind(Kind kind) { + this.kind = kind; + } + + public TypeAttribute getAttribute() { + return attribute; + } + + public void setAttribute(TypeAttribute attribute) { + this.attribute = attribute; + } + + public boolean isIfExists() { + return ifExists; + } + + public void setIfExists(boolean ifExists) { + this.ifExists = ifExists; + } + + public boolean isUseSetData() { + return useSetData; + } + + public void setUseSetData(boolean useSetData) { + this.useSetData = useSetData; + } + + public Behavior getBehavior() { + return behavior; + } + + public void setBehavior(Behavior behavior) { + this.behavior = behavior; + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder().append(kind).append(" ATTRIBUTE "); + if (ifExists) { + sql.append("IF EXISTS "); + } + sql.append(attribute.getName()); + if (kind == Kind.ALTER) { + sql.append(useSetData ? " SET DATA TYPE" : " TYPE"); + } + if (kind != Kind.DROP) { + sql.append(' ').append(attribute.getDataType()); + if (attribute.getCollation() != null) { + sql.append(" COLLATE ").append(attribute.getCollation()); + } + } + if (behavior != null) { + sql.append(' ').append(behavior); + } + return sql.toString(); + } + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder("ALTER TYPE ").append(name).append(' '); + switch (action) { + case OWNER: + sql.append("OWNER TO ").append(newName); + break; + case RENAME: + sql.append("RENAME TO ").append(newName); + break; + case SET_SCHEMA: + sql.append("SET SCHEMA ").append(newName); + break; + case RENAME_ATTRIBUTE: + sql.append("RENAME ATTRIBUTE ").append(attributeName).append(" TO ") + .append(newName); + if (behavior != null) { + sql.append(' ').append(behavior); + } + break; + case ADD_VALUE: + sql.append("ADD VALUE ").append(ifNotExists ? "IF NOT EXISTS " : "").append(value); + if (position != null) { + sql.append(' ').append(position).append(' ').append(neighborValue); + } + break; + case RENAME_VALUE: + sql.append("RENAME VALUE ").append(value).append(" TO ").append(newValue); + break; + case ATTRIBUTES: + sql.append(attributeChanges.stream().map(Object::toString) + .collect(Collectors.joining(", "))); + break; + default: + throw new IllegalStateException("Unknown type alteration: " + action); + } + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/create/domain/CreateDomain.java b/src/main/java/net/sf/jsqlparser/statement/create/domain/CreateDomain.java new file mode 100644 index 000000000..61da30eb1 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/create/domain/CreateDomain.java @@ -0,0 +1,102 @@ +/*- + * #%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.domain; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.statement.create.table.ColDataType; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class CreateDomain implements Statement { + private String name; + private boolean useAs; + private ColDataType dataType; + private String collation; + private Expression defaultExpression; + private List constraints = new ArrayList<>(); + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public boolean isUseAs() { + return useAs; + } + + public void setUseAs(boolean useAs) { + this.useAs = useAs; + } + + public ColDataType getDataType() { + return dataType; + } + + public void setDataType(ColDataType dataType) { + this.dataType = dataType; + } + + public String getCollation() { + return collation; + } + + public void setCollation(String collation) { + this.collation = collation; + } + + public Expression getDefaultExpression() { + return defaultExpression; + } + + public void setDefaultExpression(Expression defaultExpression) { + this.defaultExpression = defaultExpression; + } + + public List getConstraints() { + return constraints; + } + + public void setConstraints(List constraints) { + this.constraints = constraints; + } + + @Override + public T accept(StatementVisitor visitor, S context) { + return visitor.visit(this, context); + } + + public void appendTo(StringBuilder sql, Consumer expressions) { + sql.append("CREATE DOMAIN ").append(name).append(useAs ? " AS " : " ").append(dataType); + if (collation != null) { + sql.append(" COLLATE ").append(collation); + } + if (defaultExpression != null) { + sql.append(" DEFAULT "); + expressions.accept(defaultExpression); + } + for (DomainConstraint constraint : constraints) { + sql.append(' '); + constraint.appendTo(sql, expressions); + } + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + appendTo(sql, sql::append); + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/create/domain/DomainConstraint.java b/src/main/java/net/sf/jsqlparser/statement/create/domain/DomainConstraint.java new file mode 100644 index 000000000..7b42733d7 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/create/domain/DomainConstraint.java @@ -0,0 +1,68 @@ +/*- + * #%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.domain; + +import java.util.function.Consumer; +import net.sf.jsqlparser.expression.Expression; +import java.io.Serializable; + +public class DomainConstraint implements Serializable { + private String name; + private Kind kind; + private Expression expression; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Kind getKind() { + return kind; + } + + public void setKind(Kind kind) { + this.kind = kind; + } + + public Expression getExpression() { + return expression; + } + + public void setExpression(Expression expression) { + this.expression = expression; + } + + public enum Kind { + NULL, NOT_NULL, CHECK + } + + public void appendTo(StringBuilder sql, Consumer expressions) { + if (name != null) { + sql.append("CONSTRAINT ").append(name).append(' '); + } + if (kind == Kind.CHECK) { + sql.append("CHECK ("); + expressions.accept(expression); + sql.append(')'); + } else { + sql.append(kind == Kind.NULL ? "NULL" : "NOT NULL"); + } + } + + @Override + public String toString() { + StringBuilder sql = new StringBuilder(); + appendTo(sql, sql::append); + return sql.toString(); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/create/extension/CreateExtension.java b/src/main/java/net/sf/jsqlparser/statement/create/extension/CreateExtension.java new file mode 100644 index 000000000..bbac3276e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/create/extension/CreateExtension.java @@ -0,0 +1,104 @@ +/*- + * #%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.extension; + +import java.util.ArrayList; +import java.util.List; +import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.statement.Statement; +import net.sf.jsqlparser.statement.StatementVisitor; + +public class CreateExtension implements Statement { + private String name; + private boolean ifNotExists; + private boolean useWith; + private List