Skip to content

Commit 3ba2546

Browse files
authored
fix(parser): model PostgreSQL CREATE INDEX clauses (#2536)
* fix(parser): model PostgreSQL CREATE INDEX clauses * fix(ci): reduce index column rendering complexity
1 parent c77bb0f commit 3ba2546

5 files changed

Lines changed: 434 additions & 18 deletions

File tree

‎src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java‎

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,11 @@
1212
import static java.util.stream.Collectors.joining;
1313

1414
import java.util.*;
15+
import net.sf.jsqlparser.expression.Expression;
1516
import net.sf.jsqlparser.schema.*;
1617
import net.sf.jsqlparser.statement.*;
1718
import net.sf.jsqlparser.statement.create.table.*;
19+
import net.sf.jsqlparser.statement.select.PlainSelect;
1820

1921
public class CreateIndex implements Statement {
2022

@@ -25,6 +27,11 @@ public class CreateIndex implements Statement {
2527
private boolean usingIfNotExists = false;
2628
private boolean concurrently;
2729
private boolean only;
30+
private List<String> includeColumns;
31+
private Boolean nullsDistinct;
32+
private List<Index.Option> storageParameters;
33+
private String tableSpace;
34+
private Expression where;
2835

2936
public boolean isIndexTypeBeforeOn() {
3037
return indexTypeBeforeOn;
@@ -59,6 +66,46 @@ public void setOnly(boolean only) {
5966
this.only = only;
6067
}
6168

69+
public List<String> getIncludeColumns() {
70+
return includeColumns;
71+
}
72+
73+
public void setIncludeColumns(List<String> includeColumns) {
74+
this.includeColumns = includeColumns;
75+
}
76+
77+
public Boolean getNullsDistinct() {
78+
return nullsDistinct;
79+
}
80+
81+
public void setNullsDistinct(Boolean nullsDistinct) {
82+
this.nullsDistinct = nullsDistinct;
83+
}
84+
85+
public List<Index.Option> getStorageParameters() {
86+
return storageParameters;
87+
}
88+
89+
public void setStorageParameters(List<Index.Option> storageParameters) {
90+
this.storageParameters = storageParameters;
91+
}
92+
93+
public String getTableSpace() {
94+
return tableSpace;
95+
}
96+
97+
public void setTableSpace(String tableSpace) {
98+
this.tableSpace = tableSpace;
99+
}
100+
101+
public Expression getWhere() {
102+
return where;
103+
}
104+
105+
public void setWhere(Expression where) {
106+
this.where = where;
107+
}
108+
62109
@Override
63110
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
64111
return statementVisitor.visit(this, context);
@@ -135,6 +182,8 @@ public String toString() {
135182

136183
buffer.append(")");
137184

185+
appendPostgreSqlTail(buffer);
186+
138187
if (tailParameters != null) {
139188
for (String param : tailParameters) {
140189
buffer.append(" ").append(param);
@@ -145,6 +194,25 @@ public String toString() {
145194
return buffer.toString();
146195
}
147196

197+
private void appendPostgreSqlTail(StringBuilder buffer) {
198+
if (includeColumns != null) {
199+
buffer.append(" INCLUDE (").append(String.join(", ", includeColumns)).append(")");
200+
}
201+
if (nullsDistinct != null) {
202+
buffer.append(" NULLS ").append(nullsDistinct ? "DISTINCT" : "NOT DISTINCT");
203+
}
204+
if (storageParameters != null) {
205+
buffer.append(" WITH ")
206+
.append(PlainSelect.getStringList(storageParameters, true, true));
207+
}
208+
if (tableSpace != null) {
209+
buffer.append(" TABLESPACE ").append(tableSpace);
210+
}
211+
if (where != null) {
212+
buffer.append(" WHERE ").append(where);
213+
}
214+
}
215+
148216
public CreateIndex withTable(Table table) {
149217
this.setTable(table);
150218
return this;
@@ -169,4 +237,29 @@ public CreateIndex withOnly(boolean only) {
169237
setOnly(only);
170238
return this;
171239
}
240+
241+
public CreateIndex withIncludeColumns(List<String> includeColumns) {
242+
setIncludeColumns(includeColumns);
243+
return this;
244+
}
245+
246+
public CreateIndex withNullsDistinct(Boolean nullsDistinct) {
247+
setNullsDistinct(nullsDistinct);
248+
return this;
249+
}
250+
251+
public CreateIndex withStorageParameters(List<Index.Option> storageParameters) {
252+
setStorageParameters(storageParameters);
253+
return this;
254+
}
255+
256+
public CreateIndex withTableSpace(String tableSpace) {
257+
setTableSpace(tableSpace);
258+
return this;
259+
}
260+
261+
public CreateIndex withWhere(Expression where) {
262+
setWhere(where);
263+
return this;
264+
}
172265
}

‎src/main/java/net/sf/jsqlparser/statement/create/table/Index.java‎

Lines changed: 184 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -200,9 +200,22 @@ public void setCommentText(String commentText) {
200200
}
201201

202202
public static class ColumnParams implements Serializable {
203+
public enum SortOrder {
204+
ASC, DESC
205+
}
206+
207+
public enum NullOrdering {
208+
FIRST, LAST
209+
}
210+
203211
public final String columnName;
204212
public final List<String> params;
205213
private final Expression expression;
214+
private String collation;
215+
private String operatorClass;
216+
private List<Option> operatorClassParameters;
217+
private SortOrder sortOrder;
218+
private NullOrdering nullOrdering;
206219

207220
public ColumnParams(String columnName) {
208221
this.columnName = columnName;
@@ -244,10 +257,179 @@ public boolean isExpression() {
244257
return expression != null;
245258
}
246259

260+
public String getCollation() {
261+
return collation;
262+
}
263+
264+
public void setCollation(String collation) {
265+
this.collation = collation;
266+
}
267+
268+
public String getOperatorClass() {
269+
return operatorClass;
270+
}
271+
272+
public void setOperatorClass(String operatorClass) {
273+
this.operatorClass = operatorClass;
274+
}
275+
276+
public List<Option> getOperatorClassParameters() {
277+
return operatorClassParameters;
278+
}
279+
280+
public void setOperatorClassParameters(List<Option> operatorClassParameters) {
281+
this.operatorClassParameters = operatorClassParameters;
282+
}
283+
284+
public SortOrder getSortOrder() {
285+
return sortOrder;
286+
}
287+
288+
public void setSortOrder(SortOrder sortOrder) {
289+
this.sortOrder = sortOrder;
290+
}
291+
292+
public NullOrdering getNullOrdering() {
293+
return nullOrdering;
294+
}
295+
296+
public void setNullOrdering(NullOrdering nullOrdering) {
297+
this.nullOrdering = nullOrdering;
298+
}
299+
300+
public ColumnParams withCollation(String collation) {
301+
setCollation(collation);
302+
return this;
303+
}
304+
305+
public ColumnParams withOperatorClass(String operatorClass) {
306+
setOperatorClass(operatorClass);
307+
return this;
308+
}
309+
310+
public ColumnParams withOperatorClassParameters(List<Option> operatorClassParameters) {
311+
setOperatorClassParameters(operatorClassParameters);
312+
return this;
313+
}
314+
315+
public ColumnParams withSortOrder(SortOrder sortOrder) {
316+
setSortOrder(sortOrder);
317+
return this;
318+
}
319+
320+
public ColumnParams withNullOrdering(NullOrdering nullOrdering) {
321+
setNullOrdering(nullOrdering);
322+
return this;
323+
}
324+
325+
@Override
326+
public String toString() {
327+
StringBuilder builder = new StringBuilder(
328+
expression != null ? "(" + expression + ")" : columnName);
329+
appendParams(builder);
330+
appendCollation(builder);
331+
appendOperatorClass(builder);
332+
appendSortOrder(builder);
333+
appendNullOrdering(builder);
334+
return builder.toString();
335+
}
336+
337+
private void appendParams(StringBuilder builder) {
338+
if (params != null) {
339+
builder.append(" ").append(String.join(" ", params));
340+
}
341+
}
342+
343+
private void appendCollation(StringBuilder builder) {
344+
if (collation != null && !hasParam("COLLATE")) {
345+
builder.append(" COLLATE ").append(collation);
346+
}
347+
}
348+
349+
private void appendOperatorClass(StringBuilder builder) {
350+
if (operatorClass != null && !hasParam(operatorClass)) {
351+
builder.append(" ").append(operatorClass);
352+
if (operatorClassParameters != null && !operatorClassParameters.isEmpty()) {
353+
builder.append(" ")
354+
.append(PlainSelect.getStringList(
355+
operatorClassParameters, true, true));
356+
}
357+
}
358+
}
359+
360+
private void appendSortOrder(StringBuilder builder) {
361+
if (sortOrder != null && !hasParam(sortOrder.name())) {
362+
builder.append(" ").append(sortOrder);
363+
}
364+
}
365+
366+
private void appendNullOrdering(StringBuilder builder) {
367+
if (nullOrdering != null && !hasParam("NULLS")) {
368+
builder.append(" NULLS ").append(nullOrdering);
369+
}
370+
}
371+
372+
private boolean hasParam(String expected) {
373+
return params != null && params.stream().anyMatch(expected::equalsIgnoreCase);
374+
}
375+
}
376+
377+
/** A named PostgreSQL index option with an optional value. */
378+
public static class Option implements Serializable {
379+
private String name;
380+
private Expression value;
381+
private boolean useEquals;
382+
383+
public Option() {}
384+
385+
public Option(String name, Expression value, boolean useEquals) {
386+
this.name = name;
387+
this.value = value;
388+
this.useEquals = useEquals;
389+
}
390+
391+
public String getName() {
392+
return name;
393+
}
394+
395+
public void setName(String name) {
396+
this.name = name;
397+
}
398+
399+
public Expression getValue() {
400+
return value;
401+
}
402+
403+
public void setValue(Expression value) {
404+
this.value = value;
405+
}
406+
407+
public boolean isUseEquals() {
408+
return useEquals;
409+
}
410+
411+
public void setUseEquals(boolean useEquals) {
412+
this.useEquals = useEquals;
413+
}
414+
415+
public Option withName(String name) {
416+
setName(name);
417+
return this;
418+
}
419+
420+
public Option withValue(Expression value) {
421+
setValue(value);
422+
return this;
423+
}
424+
425+
public Option withUseEquals(boolean useEquals) {
426+
setUseEquals(useEquals);
427+
return this;
428+
}
429+
247430
@Override
248431
public String toString() {
249-
String head = expression != null ? "(" + expression + ")" : columnName;
250-
return head + (params != null ? " " + String.join(" ", params) : "");
432+
return value == null ? name : name + (useEquals ? " = " : " ") + value;
251433
}
252434
}
253435
}

‎src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import net.sf.jsqlparser.statement.create.index.CreateIndex;
1515
import net.sf.jsqlparser.statement.create.table.Index;
16+
import net.sf.jsqlparser.statement.select.PlainSelect;
1617

1718
public class CreateIndexDeParser extends AbstractDeParser<CreateIndex> {
1819

@@ -66,6 +67,25 @@ public void deParse(CreateIndex createIndex) {
6667
builder.append(")");
6768
}
6869

70+
if (createIndex.getIncludeColumns() != null) {
71+
builder.append(" INCLUDE (")
72+
.append(String.join(", ", createIndex.getIncludeColumns())).append(")");
73+
}
74+
if (createIndex.getNullsDistinct() != null) {
75+
builder.append(" NULLS ")
76+
.append(createIndex.getNullsDistinct() ? "DISTINCT" : "NOT DISTINCT");
77+
}
78+
if (createIndex.getStorageParameters() != null) {
79+
builder.append(" WITH ").append(PlainSelect.getStringList(
80+
createIndex.getStorageParameters(), true, true));
81+
}
82+
if (createIndex.getTableSpace() != null) {
83+
builder.append(" TABLESPACE ").append(createIndex.getTableSpace());
84+
}
85+
if (createIndex.getWhere() != null) {
86+
builder.append(" WHERE ").append(createIndex.getWhere());
87+
}
88+
6989
if (createIndex.getTailParameters() != null) {
7090
for (String param : createIndex.getTailParameters()) {
7191
builder.append(" ").append(param);

0 commit comments

Comments
 (0)