Skip to content

Commit 83b4fbf

Browse files
committed
Support dialect-specific CREATE INDEX definitions
1 parent eddb1fb commit 83b4fbf

14 files changed

Lines changed: 512 additions & 50 deletions

File tree

‎src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public enum Dialect {
4646
AdjacentStringLiterals.WHITESPACE,
4747
Feature.allowDoubleQuotedStrings,
4848
Feature.allowBackslashEscapeCharacter), SNOWFLAKE(
49-
Feature.allowBackslashEscapeCharacter), INFORMIX;
49+
Feature.allowBackslashEscapeCharacter), INFORMIX, SPANNER;
5050

5151
private final Set<Feature> lexerFeatures;
5252
private final AdjacentStringLiterals adjacentStringLiterals;

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,9 @@ public <S> T visit(Truncate truncate, S context) {
334334

335335
@Override
336336
public <S> T visit(CreateIndex createIndex, S context) {
337-
337+
TableDefinitionTraversal.visit(createIndex,
338+
expression -> expression.accept(expressionVisitor, context),
339+
table -> table.accept(fromItemVisitor, context));
338340
return null;
339341
}
340342

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

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -9,14 +9,12 @@
99
*/
1010
package net.sf.jsqlparser.statement.create.index;
1111

12-
import static java.util.stream.Collectors.joining;
13-
1412
import java.util.*;
13+
import java.util.function.Consumer;
1514
import net.sf.jsqlparser.expression.Expression;
1615
import net.sf.jsqlparser.schema.*;
1716
import net.sf.jsqlparser.statement.*;
1817
import net.sf.jsqlparser.statement.create.table.*;
19-
import net.sf.jsqlparser.statement.select.PlainSelect;
2018

2119
public class CreateIndex implements Statement {
2220

@@ -27,6 +25,7 @@ public class CreateIndex implements Statement {
2725
private boolean usingIfNotExists = false;
2826
private boolean concurrently;
2927
private boolean only;
28+
private boolean nullFiltered;
3029
private List<String> includeColumns;
3130
private Boolean nullsDistinct;
3231
private List<Index.Option> storageParameters;
@@ -66,6 +65,20 @@ public void setOnly(boolean only) {
6665
this.only = only;
6766
}
6867

68+
/** Whether this Spanner index omits rows with null key values. */
69+
public boolean isNullFiltered() {
70+
return nullFiltered;
71+
}
72+
73+
public void setNullFiltered(boolean nullFiltered) {
74+
this.nullFiltered = nullFiltered;
75+
}
76+
77+
public CreateIndex withNullFiltered(boolean nullFiltered) {
78+
setNullFiltered(nullFiltered);
79+
return this;
80+
}
81+
6982
public List<String> getIncludeColumns() {
7083
return includeColumns;
7184
}
@@ -142,10 +155,15 @@ public String toString() {
142155

143156
/** Shared rendering for the statement model and CreateIndexDeParser. */
144157
public StringBuilder appendTo(StringBuilder buffer) {
158+
return appendTo(buffer, expression -> buffer.append(expression));
159+
}
160+
161+
/** Shares rendering while allowing visitors to transform key and option expressions. */
162+
public StringBuilder appendTo(StringBuilder buffer, Consumer<Expression> expressionPrinter) {
145163
appendIndexHeader(buffer);
146164
appendIndexTarget(buffer);
147-
appendIndexColumns(buffer);
148-
appendPostgreSqlTail(buffer);
165+
appendIndexColumns(buffer, expressionPrinter);
166+
appendPostgreSqlTail(buffer, expressionPrinter);
149167
if (tailParameters != null) {
150168
for (String param : tailParameters) {
151169
buffer.append(" ").append(param);
@@ -159,6 +177,12 @@ private void appendIndexHeader(StringBuilder buffer) {
159177
if (index.getType() != null) {
160178
buffer.append(index.getType()).append(" ");
161179
}
180+
if (index.getClustering() != null) {
181+
buffer.append(index.getClustering()).append(" ");
182+
}
183+
if (nullFiltered) {
184+
buffer.append("NULL_FILTERED ");
185+
}
162186
buffer.append("INDEX ");
163187
if (concurrently) {
164188
buffer.append("CONCURRENTLY ");
@@ -185,32 +209,38 @@ private void appendIndexTarget(StringBuilder buffer) {
185209
}
186210
}
187211

188-
private void appendIndexColumns(StringBuilder buffer) {
189-
if (index.getColumnsNames() != null) {
212+
private void appendIndexColumns(StringBuilder buffer, Consumer<Expression> expressionPrinter) {
213+
if (index.getColumns() != null) {
190214
buffer.append(" (");
191-
buffer.append(index.getColumns().stream()
192-
.map(Index.ColumnParams::toString)
193-
.collect(joining(", ")));
215+
for (Iterator<Index.ColumnParams> columns = index.getColumns().iterator(); columns
216+
.hasNext();) {
217+
columns.next().appendTo(buffer, expressionPrinter);
218+
if (columns.hasNext()) {
219+
buffer.append(", ");
220+
}
221+
}
194222
buffer.append(")");
195223
}
196224
}
197225

198-
private void appendPostgreSqlTail(StringBuilder buffer) {
226+
private void appendPostgreSqlTail(StringBuilder buffer,
227+
Consumer<Expression> expressionPrinter) {
199228
if (includeColumns != null) {
200229
buffer.append(" INCLUDE (").append(String.join(", ", includeColumns)).append(")");
201230
}
202231
if (nullsDistinct != null) {
203232
buffer.append(" NULLS ").append(nullsDistinct ? "DISTINCT" : "NOT DISTINCT");
204233
}
205234
if (storageParameters != null) {
206-
buffer.append(" WITH ")
207-
.append(PlainSelect.getStringList(storageParameters, true, true));
235+
buffer.append(" WITH ");
236+
Index.Option.appendListTo(buffer, storageParameters, expressionPrinter);
208237
}
209238
if (tableSpace != null) {
210239
buffer.append(" TABLESPACE ").append(tableSpace);
211240
}
212241
if (where != null) {
213-
buffer.append(" WHERE ").append(where);
242+
buffer.append(" WHERE ");
243+
expressionPrinter.accept(where);
214244
}
215245
}
216246

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

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -511,7 +511,7 @@ public void appendTo(StringBuilder builder, Consumer<Expression> expressionPrint
511511
}
512512
appendParams(builder);
513513
appendCollation(builder);
514-
appendOperatorClass(builder);
514+
appendOperatorClass(builder, expressionPrinter);
515515
appendSortOrder(builder);
516516
appendNullOrdering(builder);
517517
if (exclusionOperator != null) {
@@ -531,13 +531,13 @@ private void appendCollation(StringBuilder builder) {
531531
}
532532
}
533533

534-
private void appendOperatorClass(StringBuilder builder) {
534+
private void appendOperatorClass(StringBuilder builder,
535+
Consumer<Expression> expressionPrinter) {
535536
if (operatorClass != null && !hasParam(operatorClass)) {
536537
builder.append(" ").append(operatorClass);
537538
if (operatorClassParameters != null && !operatorClassParameters.isEmpty()) {
538-
builder.append(" ")
539-
.append(PlainSelect.getStringList(
540-
operatorClassParameters, true, true));
539+
builder.append(" ");
540+
Option.appendListTo(builder, operatorClassParameters, expressionPrinter);
541541
}
542542
}
543543
}
@@ -559,7 +559,7 @@ private boolean hasParam(String expected) {
559559
}
560560
}
561561

562-
/** A named PostgreSQL index option with an optional value. */
562+
/** A named index option with an optional value. */
563563
public static class Option implements Serializable {
564564
private String name;
565565
private Expression value;
@@ -614,7 +614,33 @@ public Option withUseEquals(boolean useEquals) {
614614

615615
@Override
616616
public String toString() {
617-
return value == null ? name : name + (useEquals ? " = " : " ") + value;
617+
if (value == null) {
618+
return name;
619+
}
620+
StringBuilder builder = new StringBuilder();
621+
return appendTo(builder, expression -> builder.append(expression)).toString();
622+
}
623+
624+
public StringBuilder appendTo(StringBuilder builder,
625+
Consumer<Expression> expressionPrinter) {
626+
builder.append(name);
627+
if (value != null) {
628+
builder.append(useEquals ? " = " : " ");
629+
expressionPrinter.accept(value);
630+
}
631+
return builder;
632+
}
633+
634+
public static StringBuilder appendListTo(StringBuilder builder, List<Option> options,
635+
Consumer<Expression> expressionPrinter) {
636+
builder.append('(');
637+
for (int i = 0; i < options.size(); i++) {
638+
if (i > 0) {
639+
builder.append(", ");
640+
}
641+
options.get(i).appendTo(builder, expressionPrinter);
642+
}
643+
return builder.append(')');
618644
}
619645
}
620646
}

‎src/main/java/net/sf/jsqlparser/util/TableDefinitionTraversal.java‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import net.sf.jsqlparser.schema.Table;
1616
import net.sf.jsqlparser.statement.LikeClause;
1717
import net.sf.jsqlparser.statement.alter.AlterExpression;
18+
import net.sf.jsqlparser.statement.create.index.CreateIndex;
1819
import net.sf.jsqlparser.statement.create.table.CheckConstraint;
1920
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
2021
import net.sf.jsqlparser.statement.create.table.ColumnOption;
@@ -29,6 +30,16 @@
2930
public final class TableDefinitionTraversal {
3031
private TableDefinitionTraversal() {}
3132

33+
public static void visit(CreateIndex createIndex, Consumer<Expression> expressions,
34+
Consumer<Table> tables) {
35+
accept(createIndex.getTable(), tables);
36+
if (createIndex.getIndex() != null) {
37+
visit(createIndex.getIndex(), expressions, tables);
38+
}
39+
visitOptions(createIndex.getStorageParameters(), expressions);
40+
accept(createIndex.getWhere(), expressions);
41+
}
42+
3243
public static void visit(CreateTable table, Consumer<Expression> expressions,
3344
Consumer<Table> tables) {
3445
if (table.getTableElements() != null) {

‎src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java‎

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1552,7 +1552,9 @@ public void visit(Truncate truncate) {
15521552

15531553
@Override
15541554
public <S> Void visit(CreateIndex createIndex, S context) {
1555-
throwUnsupported(createIndex);
1555+
TableDefinitionTraversal.visit(createIndex,
1556+
expression -> expression.accept(this, context),
1557+
table -> visit(table, context));
15561558
return null;
15571559
}
15581560

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

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,28 @@
99
*/
1010
package net.sf.jsqlparser.util.deparser;
1111

12+
import net.sf.jsqlparser.expression.ExpressionVisitor;
1213
import net.sf.jsqlparser.statement.create.index.CreateIndex;
1314

1415
public class CreateIndexDeParser extends AbstractDeParser<CreateIndex> {
16+
private final ExpressionVisitor<StringBuilder> expressionVisitor;
1517

1618
public CreateIndexDeParser(StringBuilder buffer) {
19+
this(buffer, null);
20+
}
21+
22+
public CreateIndexDeParser(StringBuilder buffer,
23+
ExpressionVisitor<StringBuilder> expressionVisitor) {
1724
super(buffer);
25+
this.expressionVisitor = expressionVisitor;
1826
}
1927

2028
@Override
2129
public void deParse(CreateIndex createIndex) {
22-
createIndex.appendTo(builder);
30+
if (expressionVisitor == null) {
31+
createIndex.appendTo(builder);
32+
} else {
33+
createIndex.appendTo(builder, expression -> expression.accept(expressionVisitor, null));
34+
}
2335
}
2436
}

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,8 @@ public StatementDeParser(ExpressionDeParser expressionDeParser, SelectDeParser s
141141

142142
@Override
143143
public <S> StringBuilder visit(CreateIndex createIndex, S context) {
144-
CreateIndexDeParser createIndexDeParser = new CreateIndexDeParser(builder);
144+
CreateIndexDeParser createIndexDeParser =
145+
new CreateIndexDeParser(builder, expressionDeParser);
145146
createIndexDeParser.deParse(createIndex);
146147
return builder;
147148
}

‎src/main/java/net/sf/jsqlparser/util/validation/validator/CreateIndexValidator.java‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
import net.sf.jsqlparser.parser.feature.Feature;
1515
import net.sf.jsqlparser.statement.create.index.CreateIndex;
1616
import net.sf.jsqlparser.statement.create.table.Index;
17+
import net.sf.jsqlparser.util.TableDefinitionTraversal;
1718
import net.sf.jsqlparser.util.validation.ValidationCapability;
1819
import net.sf.jsqlparser.util.validation.metadata.NamedObject;
1920

@@ -38,6 +39,9 @@ public void validate(CreateIndex createIndex) {
3839
NamedObject.table);
3940
}
4041
}
42+
TableDefinitionTraversal.visit(createIndex, this::validateOptionalExpression, table -> {
43+
// Table and index names are validated above for each capability.
44+
});
4145
}
4246

4347
}

0 commit comments

Comments
 (0)