diff --git a/jOOQ/src/main/java/org/jooq/impl/CreateTableImpl.java b/jOOQ/src/main/java/org/jooq/impl/CreateTableImpl.java index 822edeade2..9c7ffef4b9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CreateTableImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CreateTableImpl.java @@ -417,16 +417,24 @@ final class CreateTableImpl extends AbstractQuery implements ctx.end(CREATE_TABLE_CONSTRAINTS); - if (!indexes.isEmpty() && !NO_SUPPORT_INDEXES.contains(ctx.family())) - for (Index index : indexes) + if (!indexes.isEmpty() && !NO_SUPPORT_INDEXES.contains(ctx.family())) { + ctx.qualify(false); + + for (Index index : indexes) { ctx.sql(',') .formatSeparator() - .visit(K_INDEX).sql(' ').visit(index.getUnqualifiedName()) - .sql(" (") - .qualify(false) + .visit(K_INDEX); + + if (!"".equals(index.getName())) + ctx.sql(' ').visit(index.getUnqualifiedName()); + + ctx.sql(" (") .visit(new SortFieldList(index.getFields())) - .qualify(qualify) .sql(')'); + } + + ctx.qualify(qualify); + } ctx.formatIndentEnd() .formatNewLine() diff --git a/jOOQ/src/main/java/org/jooq/impl/Internal.java b/jOOQ/src/main/java/org/jooq/impl/Internal.java index 28cab6d8b3..fa2b0f1d18 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Internal.java +++ b/jOOQ/src/main/java/org/jooq/impl/Internal.java @@ -60,14 +60,21 @@ public final class Internal { /** * Factory method for indexes. */ - public static Index createIndex(String name, Table table, OrderField[] sortFields, boolean unique) { - return new IndexImpl(DSL.name(name), table, sortFields, null, unique); + public static final Index createIndex(String name, Table table, OrderField[] sortFields, boolean unique) { + return createIndex(DSL.name(name), table, sortFields, unique); + } + + /** + * Factory method for indexes. + */ + public static final Index createIndex(Name name, Table table, OrderField[] sortFields, boolean unique) { + return new IndexImpl(name, table, sortFields, null, unique); } /** * Factory method for identities. */ - public static Identity createIdentity(Table table, TableField field) { + public static final Identity createIdentity(Table table, TableField field) { return new IdentityImpl(table, field); } @@ -77,7 +84,7 @@ public final class Internal { @SafeVarargs - public static UniqueKey createUniqueKey(Table table, TableField... fields) { + public static final UniqueKey createUniqueKey(Table table, TableField... fields) { return new UniqueKeyImpl(table, fields); } @@ -87,7 +94,7 @@ public final class Internal { @SafeVarargs - public static UniqueKey createUniqueKey(Table table, String name, TableField... fields) { + public static final UniqueKey createUniqueKey(Table table, String name, TableField... fields) { return new UniqueKeyImpl(table, name, fields); } @@ -97,7 +104,7 @@ public final class Internal { @SafeVarargs - public static ForeignKey createForeignKey(UniqueKey key, Table table, TableField... fields) { + public static final ForeignKey createForeignKey(UniqueKey key, Table table, TableField... fields) { return createForeignKey(key, table, null, fields); } @@ -107,7 +114,7 @@ public final class Internal { @SafeVarargs - public static ForeignKey createForeignKey(UniqueKey key, Table table, String name, TableField... fields) { + public static final ForeignKey createForeignKey(UniqueKey key, Table table, String name, TableField... fields) { ForeignKey result = new ReferenceImpl(key, table, name, fields); if (key instanceof UniqueKeyImpl) diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index d7fd5c55ee..41ed69890e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -285,6 +285,7 @@ import org.jooq.CreateTableAsStep; import org.jooq.CreateTableColumnStep; import org.jooq.CreateTableCommentStep; import org.jooq.CreateTableConstraintStep; +import org.jooq.CreateTableIndexStep; import org.jooq.CreateTableStorageStep; import org.jooq.CreateTableWithDataStep; import org.jooq.DDLQuery; @@ -311,6 +312,7 @@ import org.jooq.GrantWithGrantOptionStep; import org.jooq.GroupConcatOrderByStep; import org.jooq.GroupConcatSeparatorStep; import org.jooq.GroupField; +import org.jooq.Index; import org.jooq.Insert; import org.jooq.InsertOnConflictDoUpdateStep; import org.jooq.InsertOnConflictWhereStep; @@ -825,7 +827,7 @@ final class ParserImpl implements Parser { return result; } - private static void parseLimit(ParserContext ctx, SelectQueryImpl result, boolean offset) { + private static final void parseLimit(ParserContext ctx, SelectQueryImpl result, boolean offset) { boolean offsetStandard = false; boolean offsetPostgres = false; @@ -2106,11 +2108,27 @@ final class ParserImpl implements Parser { else { List> fields = new ArrayList>(); List constraints = new ArrayList(); + List indexes = new ArrayList(); boolean primary = false; boolean noConstraint = true; parse(ctx, '('); + + columnLoop: do { + int position = ctx.position(); + + // [#7348] Look ahead if the next tokens indicate a MySQL index definition + if (parseKeywordIf(ctx, "KEY") || parseKeywordIf(ctx, "INDEX")) { + if (parseIf(ctx, '(') || parseIdentifierIf(ctx) != null) { + ctx.position(position); + noConstraint = false; + break columnLoop; + } + + ctx.position(position); + } + Name fieldName = parseIdentifier(ctx); DataType type = parseDataType(ctx); Comment fieldComment = null; @@ -2308,8 +2326,10 @@ final class ParserImpl implements Parser { constraints.add(parseForeignKeySpecification(ctx, constraint)); else if (parseKeywordIf(ctx, "CHECK")) constraints.add(parseCheckSpecification(ctx, constraint)); + else if (constraint == null && (parseKeywordIf(ctx, "KEY") || parseKeywordIf(ctx, "INDEX"))) + indexes.add(parseIndexSpecification(ctx, tableName)); else - throw ctx.expected("CHECK", "FOREIGN KEY", "PRIMARY KEY", "UNIQUE"); + throw ctx.expected("CHECK", "CONSTRAINT", "FOREIGN KEY", "INDEX", "KEY", "PRIMARY KEY", "UNIQUE"); } while (parseIf(ctx, ',')); } @@ -2325,20 +2345,23 @@ final class ParserImpl implements Parser { CreateTableConstraintStep s3 = constraints.isEmpty() ? s2 : s2.constraints(constraints); - CreateTableCommentStep s4 = s3; + CreateTableIndexStep s4 = indexes.isEmpty() + ? s3 + : s3.indexes(indexes); + CreateTableCommentStep s5 = s4; if (temporary && parseKeywordIf(ctx, "ON COMMIT")) { if (parseKeywordIf(ctx, "DELETE ROWS")) - s4 = s3.onCommitDeleteRows(); + s5 = s4.onCommitDeleteRows(); else if (parseKeywordIf(ctx, "DROP")) - s4 = s3.onCommitDrop(); + s5 = s4.onCommitDrop(); else if (parseKeywordIf(ctx, "PRESERVE ROWS")) - s4 = s3.onCommitPreserveRows(); + s5 = s4.onCommitPreserveRows(); else throw ctx.unsupportedClause(); } - storageStep = commentStep = s4; + storageStep = commentStep = s5; } List storage = new ArrayList(); @@ -2477,6 +2500,14 @@ final class ParserImpl implements Parser { return storageStep; } + private static final Index parseIndexSpecification(ParserContext ctx, Table table) { + Name name = parseIdentifierIf(ctx); + parse(ctx, '('); + SortField[] fields = parseSortSpecification(ctx).toArray(EMPTY_SORTFIELD); + parse(ctx, ')'); + return Internal.createIndex(name == null ? DSL.name("") : name, table, fields, false); + } + private static final Constraint parsePrimaryKeySpecification(ParserContext ctx, ConstraintTypeStep constraint) { parse(ctx, '('); Field[] fieldNames = parseFieldNames(ctx).toArray(EMPTY_FIELD);