Skip to content

Commit 7b9d420

Browse files
authored
feat(parser): model PostgreSQL schema DDL clauses (#2552)
* feat(parser): model PostgreSQL schema DDL clauses * style: simplify schema visitor type reference
1 parent ae37fd2 commit 7b9d420

38 files changed

Lines changed: 2208 additions & 292 deletions

‎src/main/java/net/sf/jsqlparser/schema/Sequence.java‎

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,15 @@ public class Sequence extends ASTNodeAccessImpl implements MultiPartName {
3030

3131
private List<Parameter> parameters;
3232
private String dataType;
33+
private SequenceOwnership ownership;
34+
35+
public SequenceOwnership getOwnership() {
36+
return ownership;
37+
}
38+
39+
public void setOwnership(SequenceOwnership ownership) {
40+
this.ownership = ownership;
41+
}
3342

3443
public Sequence() {}
3544

@@ -151,6 +160,9 @@ public String toString() {
151160
sql.append(" ").append(parameter.formatParameter());
152161
}
153162
}
163+
if (ownership != null) {
164+
sql.append(' ').append(ownership);
165+
}
154166
return sql.toString();
155167
}
156168

@@ -175,7 +187,7 @@ public Sequence addParameters(Collection<? extends Parameter> parameters) {
175187
* The available parameters to a sequence
176188
*/
177189
public enum ParameterType {
178-
INCREMENT_BY, INCREMENT, START_WITH, START, RESTART_WITH, MAXVALUE, NOMAXVALUE, MINVALUE, NOMINVALUE, CYCLE, NOCYCLE, CACHE, NOCACHE, ORDER, NOORDER, KEEP, NOKEEP, SESSION, GLOBAL;
190+
INCREMENT_BY, INCREMENT, START_WITH, START, RESTART_WITH, MAXVALUE, NOMAXVALUE, MINVALUE, NOMINVALUE, CYCLE, NOCYCLE, CACHE, NOCACHE, ORDER, NOORDER, KEEP, NOKEEP, SESSION, GLOBAL, NO_MINVALUE, NO_MAXVALUE, NO_CYCLE;
179191

180192
public static ParameterType from(String type) {
181193
return Enum.valueOf(ParameterType.class, type.toUpperCase(Locale.ROOT));
@@ -185,7 +197,7 @@ public static ParameterType from(String type) {
185197
/**
186198
* Represents a parameter when declaring a sequence
187199
*/
188-
public static class Parameter {
200+
public static class Parameter implements java.io.Serializable {
189201

190202
private final ParameterType option;
191203
private Long value;
@@ -198,6 +210,15 @@ public Long getValue() {
198210
return value;
199211
}
200212

213+
public ParameterType getOption() {
214+
return option;
215+
}
216+
217+
@Override
218+
public String toString() {
219+
return formatParameter();
220+
}
221+
201222
public void setValue(Long value) {
202223
this.value = value;
203224
}
@@ -222,6 +243,10 @@ public String formatParameter() {
222243
case MINVALUE:
223244
case CACHE:
224245
return prefix(option.name());
246+
case NO_MINVALUE:
247+
case NO_MAXVALUE:
248+
case NO_CYCLE:
249+
return option.name().replace('_', ' ');
225250
default:
226251
// fallthrough just return option name
227252
return option.name();
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.schema;
11+
12+
import java.io.Serializable;
13+
import java.util.Objects;
14+
15+
/** Distinguishes explicit OWNED BY NONE from an owning column and from an omitted clause. */
16+
public class SequenceOwnership implements Serializable {
17+
private final Column column;
18+
19+
private SequenceOwnership(Column column) {
20+
this.column = column;
21+
}
22+
23+
public static SequenceOwnership none() {
24+
return new SequenceOwnership(null);
25+
}
26+
27+
public static SequenceOwnership ownedBy(Column column) {
28+
return new SequenceOwnership(Objects.requireNonNull(column, "column"));
29+
}
30+
31+
public Column getColumn() {
32+
return column;
33+
}
34+
35+
public boolean isNone() {
36+
return column == null;
37+
}
38+
39+
@Override
40+
public String toString() {
41+
return "OWNED BY " + (column == null ? "NONE" : column);
42+
}
43+
}

‎src/main/java/net/sf/jsqlparser/statement/LikeClause.java‎

Lines changed: 88 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -12,26 +12,94 @@
1212
import net.sf.jsqlparser.schema.Column;
1313
import net.sf.jsqlparser.schema.Table;
1414
import net.sf.jsqlparser.statement.imprt.ImportColumn;
15+
import net.sf.jsqlparser.statement.create.table.TableElement;
1516
import net.sf.jsqlparser.statement.select.PlainSelect;
1617
import net.sf.jsqlparser.statement.select.SelectItem;
1718

1819
import java.io.Serializable;
20+
import java.util.ArrayList;
1921
import java.util.List;
2022

2123
/**
22-
* Exasol Like Clause
24+
* A LIKE clause used in table definitions and Exasol imports.
2325
*
2426
* @see <a href="https://docs.exasol.com/db/latest/sql/create_table.htm">Like Clause in CREATE
2527
* TABLE</a>
2628
* @see <a href="https://docs.exasol.com/db/latest/sql/import.htm">Like Clause in IMPORT</a>
2729
*/
28-
public class LikeClause implements ImportColumn, Serializable {
30+
public class LikeClause implements ImportColumn, TableElement, Serializable {
2931
private Table table;
3032
private List<SelectItem<Column>> columnsList;
3133

32-
private Boolean includingDefaults;
33-
private Boolean includingIdentity;
34-
private Boolean includingComments;
34+
private List<Option> options = new ArrayList<>();
35+
36+
public enum OptionKind {
37+
ALL, COMMENTS, COMPRESSION, CONSTRAINTS, DEFAULTS, GENERATED, IDENTITY, INDEXES, STATISTICS, STORAGE
38+
}
39+
40+
public static class Option implements Serializable {
41+
private final OptionKind kind;
42+
private final boolean including;
43+
44+
public Option(OptionKind kind, boolean including) {
45+
this.kind = kind;
46+
this.including = including;
47+
}
48+
49+
public OptionKind getKind() {
50+
return kind;
51+
}
52+
53+
public boolean isIncluding() {
54+
return including;
55+
}
56+
57+
@Override
58+
public String toString() {
59+
return (including ? "INCLUDING " : "EXCLUDING ") + kind;
60+
}
61+
}
62+
63+
/** Options in source order, including repeated options and ALL. */
64+
public List<Option> getOptions() {
65+
return options;
66+
}
67+
68+
public void setOptions(List<Option> options) {
69+
this.options = options == null ? new ArrayList<>() : new ArrayList<>(options);
70+
}
71+
72+
public void addOption(OptionKind kind, boolean including) {
73+
options.add(new Option(kind, including));
74+
}
75+
76+
/** Resolves ALL and explicit options in declaration order; omission defaults to exclusion. */
77+
public boolean isIncluding(OptionKind kind) {
78+
boolean including = false;
79+
for (Option option : options) {
80+
if (option.getKind() == kind || option.getKind() == OptionKind.ALL) {
81+
including = option.isIncluding();
82+
}
83+
}
84+
return including;
85+
}
86+
87+
private Boolean explicitIncluding(OptionKind kind) {
88+
Boolean including = null;
89+
for (Option option : options) {
90+
if (option.getKind() == kind) {
91+
including = option.isIncluding();
92+
}
93+
}
94+
return including;
95+
}
96+
97+
private void setIncluding(OptionKind kind, Boolean including) {
98+
options.removeIf(option -> option.getKind() == kind);
99+
if (including != null) {
100+
addOption(kind, including);
101+
}
102+
}
35103

36104
public Table getTable() {
37105
return table;
@@ -50,51 +118,51 @@ public void setColumnsList(List<SelectItem<Column>> columnsList) {
50118
}
51119

52120
public Boolean isIncludingDefaults() {
53-
return includingDefaults;
121+
return explicitIncluding(OptionKind.DEFAULTS);
54122
}
55123

56124
public void setIncludingDefaults(Boolean includingDefaults) {
57-
this.includingDefaults = includingDefaults;
125+
setIncluding(OptionKind.DEFAULTS, includingDefaults);
58126
}
59127

60128
public Boolean isExcludingDefaults() {
61-
return includingDefaults == null ? null : !includingDefaults;
129+
return isIncludingDefaults() == null ? null : !isIncludingDefaults();
62130
}
63131

64132
public void setExcludingDefaults(Boolean excludingDefaults) {
65-
this.includingDefaults = !excludingDefaults;
133+
setIncludingDefaults(excludingDefaults == null ? null : !excludingDefaults);
66134
}
67135

68136
public Boolean isIncludingIdentity() {
69-
return includingIdentity;
137+
return explicitIncluding(OptionKind.IDENTITY);
70138
}
71139

72140
public void setIncludingIdentity(Boolean includingIdentity) {
73-
this.includingIdentity = includingIdentity;
141+
setIncluding(OptionKind.IDENTITY, includingIdentity);
74142
}
75143

76144
public Boolean isExcludingIdentity() {
77-
return includingIdentity == null ? null : !includingIdentity;
145+
return isIncludingIdentity() == null ? null : !isIncludingIdentity();
78146
}
79147

80148
public void setExcludingIdentity(Boolean excludingIdentity) {
81-
this.includingIdentity = !excludingIdentity;
149+
setIncludingIdentity(excludingIdentity == null ? null : !excludingIdentity);
82150
}
83151

84152
public Boolean isIncludingComments() {
85-
return includingComments;
153+
return explicitIncluding(OptionKind.COMMENTS);
86154
}
87155

88156
public void setIncludingComments(Boolean includingComments) {
89-
this.includingComments = includingComments;
157+
setIncluding(OptionKind.COMMENTS, includingComments);
90158
}
91159

92160
public Boolean isExcludingComments() {
93-
return includingComments == null ? null : !includingComments;
161+
return isIncludingComments() == null ? null : !isIncludingComments();
94162
}
95163

96164
public void setExcludingComments(Boolean excludingComments) {
97-
this.includingComments = !excludingComments;
165+
setIncludingComments(excludingComments == null ? null : !excludingComments);
98166
}
99167

100168
public StringBuilder appendTo(StringBuilder builder) {
@@ -105,38 +173,15 @@ public StringBuilder appendTo(StringBuilder builder) {
105173
PlainSelect.appendStringListTo(builder, columnsList, true, true);
106174
}
107175

108-
if (includingDefaults != null) {
109-
if (includingDefaults) {
110-
builder.append(" INCLUDING ");
111-
} else {
112-
builder.append(" EXCLUDING ");
113-
}
114-
builder.append(" DEFAULTS ");
115-
}
116-
117-
if (includingIdentity != null) {
118-
if (includingIdentity) {
119-
builder.append(" INCLUDING ");
120-
} else {
121-
builder.append(" EXCLUDING ");
122-
}
123-
builder.append(" IDENTITY ");
124-
}
125-
126-
if (includingComments != null) {
127-
if (includingComments) {
128-
builder.append(" INCLUDING ");
129-
} else {
130-
builder.append(" EXCLUDING ");
131-
}
132-
builder.append(" COMMENTS ");
176+
for (Option option : options) {
177+
builder.append(' ').append(option);
133178
}
134179

135180
return builder;
136181
}
137182

138183
@Override
139184
public String toString() {
140-
return appendTo(new StringBuilder()).toString();
185+
return appendTo(new StringBuilder()).toString().trim();
141186
}
142187
}

‎src/main/java/net/sf/jsqlparser/statement/StatementFeatureVisitor.java‎

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,6 @@ public <S> Void visit(CreateTable createTable, S context) {
431431
if (createTable.getSelect() != null) {
432432
// CTAS reads; it does not return a result set - the top level is already claimed
433433
analysis.certain(StmtFeature.READS_DATA);
434-
createTable.getSelect().accept(analysis.selects, context);
435434
}
436435
return super.visit(createTable, context);
437436
}
@@ -440,11 +439,17 @@ public <S> Void visit(CreateTable createTable, S context) {
440439
public <S> Void visit(CreateView createView, S context) {
441440
analysis.claimTopLevel();
442441
analysis.certain(StmtFeature.MODIFIES_SCHEMA);
443-
analysis.suppressReads(() -> {
442+
if (createView.isMaterialized() && !Boolean.FALSE.equals(createView.getWithData())) {
444443
if (createView.getSelect() != null) {
445-
createView.getSelect().accept(analysis.selects, null);
444+
createView.getSelect().accept(analysis.selects, context);
446445
}
447-
});
446+
} else {
447+
analysis.suppressReads(() -> {
448+
if (createView.getSelect() != null) {
449+
createView.getSelect().accept(analysis.selects, null);
450+
}
451+
});
452+
}
448453
return null;
449454
}
450455

0 commit comments

Comments
 (0)