diff --git a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java index 8ce5c93e8..050401b59 100644 --- a/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java +++ b/src/main/java/net/sf/jsqlparser/parser/AbstractJSqlParser.java @@ -46,7 +46,7 @@ public enum Dialect { AdjacentStringLiterals.WHITESPACE, Feature.allowDoubleQuotedStrings, Feature.allowBackslashEscapeCharacter), SNOWFLAKE( - Feature.allowBackslashEscapeCharacter), INFORMIX; + Feature.allowBackslashEscapeCharacter), INFORMIX, SPANNER; private final Set lexerFeatures; private final AdjacentStringLiterals adjacentStringLiterals; diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index ef5ed487f..268afe2dc 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -334,7 +334,9 @@ public T visit(Truncate truncate, S context) { @Override public T visit(CreateIndex createIndex, S context) { - + TableDefinitionTraversal.visit(createIndex, + expression -> expression.accept(expressionVisitor, context), + table -> table.accept(fromItemVisitor, context)); return null; } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java b/src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java index 194e78fc5..415e4800d 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/index/CreateIndex.java @@ -9,14 +9,12 @@ */ package net.sf.jsqlparser.statement.create.index; -import static java.util.stream.Collectors.joining; - import java.util.*; +import java.util.function.Consumer; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.schema.*; import net.sf.jsqlparser.statement.*; import net.sf.jsqlparser.statement.create.table.*; -import net.sf.jsqlparser.statement.select.PlainSelect; public class CreateIndex implements Statement { @@ -27,6 +25,7 @@ public class CreateIndex implements Statement { private boolean usingIfNotExists = false; private boolean concurrently; private boolean only; + private boolean nullFiltered; private List includeColumns; private Boolean nullsDistinct; private List storageParameters; @@ -66,6 +65,20 @@ public void setOnly(boolean only) { this.only = only; } + /** Whether this Spanner index omits rows with null key values. */ + public boolean isNullFiltered() { + return nullFiltered; + } + + public void setNullFiltered(boolean nullFiltered) { + this.nullFiltered = nullFiltered; + } + + public CreateIndex withNullFiltered(boolean nullFiltered) { + setNullFiltered(nullFiltered); + return this; + } + public List getIncludeColumns() { return includeColumns; } @@ -142,10 +155,15 @@ public String toString() { /** Shared rendering for the statement model and CreateIndexDeParser. */ public StringBuilder appendTo(StringBuilder buffer) { + return appendTo(buffer, expression -> buffer.append(expression)); + } + + /** Shares rendering while allowing visitors to transform key and option expressions. */ + public StringBuilder appendTo(StringBuilder buffer, Consumer expressionPrinter) { appendIndexHeader(buffer); appendIndexTarget(buffer); - appendIndexColumns(buffer); - appendPostgreSqlTail(buffer); + appendIndexColumns(buffer, expressionPrinter); + appendPostgreSqlTail(buffer, expressionPrinter); if (tailParameters != null) { for (String param : tailParameters) { buffer.append(" ").append(param); @@ -159,6 +177,12 @@ private void appendIndexHeader(StringBuilder buffer) { if (index.getType() != null) { buffer.append(index.getType()).append(" "); } + if (index.getClustering() != null) { + buffer.append(index.getClustering()).append(" "); + } + if (nullFiltered) { + buffer.append("NULL_FILTERED "); + } buffer.append("INDEX "); if (concurrently) { buffer.append("CONCURRENTLY "); @@ -185,17 +209,22 @@ private void appendIndexTarget(StringBuilder buffer) { } } - private void appendIndexColumns(StringBuilder buffer) { - if (index.getColumnsNames() != null) { + private void appendIndexColumns(StringBuilder buffer, Consumer expressionPrinter) { + if (index.getColumns() != null) { buffer.append(" ("); - buffer.append(index.getColumns().stream() - .map(Index.ColumnParams::toString) - .collect(joining(", "))); + for (Iterator columns = index.getColumns().iterator(); columns + .hasNext();) { + columns.next().appendTo(buffer, expressionPrinter); + if (columns.hasNext()) { + buffer.append(", "); + } + } buffer.append(")"); } } - private void appendPostgreSqlTail(StringBuilder buffer) { + private void appendPostgreSqlTail(StringBuilder buffer, + Consumer expressionPrinter) { if (includeColumns != null) { buffer.append(" INCLUDE (").append(String.join(", ", includeColumns)).append(")"); } @@ -203,14 +232,15 @@ private void appendPostgreSqlTail(StringBuilder buffer) { buffer.append(" NULLS ").append(nullsDistinct ? "DISTINCT" : "NOT DISTINCT"); } if (storageParameters != null) { - buffer.append(" WITH ") - .append(PlainSelect.getStringList(storageParameters, true, true)); + buffer.append(" WITH "); + Index.Option.appendListTo(buffer, storageParameters, expressionPrinter); } if (tableSpace != null) { buffer.append(" TABLESPACE ").append(tableSpace); } if (where != null) { - buffer.append(" WHERE ").append(where); + buffer.append(" WHERE "); + expressionPrinter.accept(where); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java b/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java index d5a4f4b05..cab867601 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java @@ -511,7 +511,7 @@ public void appendTo(StringBuilder builder, Consumer expressionPrint } appendParams(builder); appendCollation(builder); - appendOperatorClass(builder); + appendOperatorClass(builder, expressionPrinter); appendSortOrder(builder); appendNullOrdering(builder); if (exclusionOperator != null) { @@ -531,13 +531,13 @@ private void appendCollation(StringBuilder builder) { } } - private void appendOperatorClass(StringBuilder builder) { + private void appendOperatorClass(StringBuilder builder, + Consumer expressionPrinter) { if (operatorClass != null && !hasParam(operatorClass)) { builder.append(" ").append(operatorClass); if (operatorClassParameters != null && !operatorClassParameters.isEmpty()) { - builder.append(" ") - .append(PlainSelect.getStringList( - operatorClassParameters, true, true)); + builder.append(" "); + Option.appendListTo(builder, operatorClassParameters, expressionPrinter); } } } @@ -559,7 +559,7 @@ private boolean hasParam(String expected) { } } - /** A named PostgreSQL index option with an optional value. */ + /** A named index option with an optional value. */ public static class Option implements Serializable { private String name; private Expression value; @@ -614,7 +614,33 @@ public Option withUseEquals(boolean useEquals) { @Override public String toString() { - return value == null ? name : name + (useEquals ? " = " : " ") + value; + if (value == null) { + return name; + } + StringBuilder builder = new StringBuilder(); + return appendTo(builder, expression -> builder.append(expression)).toString(); + } + + public StringBuilder appendTo(StringBuilder builder, + Consumer expressionPrinter) { + builder.append(name); + if (value != null) { + builder.append(useEquals ? " = " : " "); + expressionPrinter.accept(value); + } + return builder; + } + + public static StringBuilder appendListTo(StringBuilder builder, List