diff --git a/jOOQ-manual/src/main/resources/org/jooq/web/grammar-3.11.txt b/jOOQ-manual/src/main/resources/org/jooq/web/grammar-3.11.txt index 54e2b4230d..4e6cd39601 100644 --- a/jOOQ-manual/src/main/resources/org/jooq/web/grammar-3.11.txt +++ b/jOOQ-manual/src/main/resources/org/jooq/web/grammar-3.11.txt @@ -132,7 +132,7 @@ createSchemaStatement = 'CREATE SCHEMA' [ 'IF NOT EXISTS' ] schemaName createSequenceStatement = 'CREATE' ( 'SEQUENCE' | 'GENERATOR' ) [ 'IF NOT EXISTS' ] sequenceName ; -createViewStatement = 'CREATE VIEW' [ 'IF NOT EXISTS' ] tableName +createViewStatement = 'CREATE' [ 'OR' ( 'ALTER' | 'REPLACE') ] 'VIEW' [ 'IF NOT EXISTS' ] tableName [ '(' fieldNames ')' ] 'AS' select ; diff --git a/jOOQ/src/main/java/org/jooq/DSLContext.java b/jOOQ/src/main/java/org/jooq/DSLContext.java index 8608f5caac..6da6a1e73d 100644 --- a/jOOQ/src/main/java/org/jooq/DSLContext.java +++ b/jOOQ/src/main/java/org/jooq/DSLContext.java @@ -8775,6 +8775,104 @@ public interface DSLContext extends Scope , AutoCloseable { CreateViewAsStep createView(Table view, BiFunction, ? super Integer, ? extends Field> fieldNameFunction); + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + * + * @see DSL#createOrReplaceView(String, String...) + */ + @Support({ H2, POSTGRES }) + CreateViewAsStep createOrReplaceView(String view, String... fields); + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + * + * @see DSL#createOrReplaceView(Name, Name...) + */ + @Support({ H2, POSTGRES }) + CreateViewAsStep createOrReplaceView(Name view, Name... fields); + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + * + * @see DSL#createOrReplaceView(Table, Field...) + */ + @Support({ H2, POSTGRES }) + CreateViewAsStep createOrReplaceView(Table view, Field... fields); + + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + *

+ * This works like {@link #createOrReplaceView(String, String...)} except that the + * view's field names are derived from the view's {@link Select} statement + * using a function. + * + * @see DSL#createOrReplaceView(String, String...) + */ + @Support({ H2, POSTGRES }) + CreateViewAsStep createOrReplaceView(String view, Function, ? extends String> fieldNameFunction); + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + *

+ * This works like {@link #createOrReplaceView(String, String...)} except that the + * view's field names are derived from the view's {@link Select} statement + * using a function. + * + * @see DSL#createOrReplaceView(String, String...) + */ + @Support({ H2, POSTGRES }) + CreateViewAsStep createOrReplaceView(String view, BiFunction, ? super Integer, ? extends String> fieldNameFunction); + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + *

+ * This works like {@link #createOrReplaceView(Name, Name...)} except that the + * view's field names are derived from the view's {@link Select} statement + * using a function. + * + * @see DSL#createOrReplaceView(String, String...) + */ + @Support({ H2, POSTGRES }) + CreateViewAsStep createOrReplaceView(Name view, Function, ? extends Name> fieldNameFunction); + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + *

+ * This works like {@link #createOrReplaceView(Name, Name...)} except that the + * view's field names are derived from the view's {@link Select} statement + * using a function. + * + * @see DSL#createOrReplaceView(String, String...) + */ + @Support({ H2, POSTGRES }) + CreateViewAsStep createOrReplaceView(Name view, BiFunction, ? super Integer, ? extends Name> fieldNameFunction); + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + *

+ * This works like {@link #createOrReplaceView(Table, Field...)} except that the + * view's field names are derived from the view's {@link Select} statement + * using a function. + * + * @see DSL#createOrReplaceView(String, String...) + */ + @Support({ H2, POSTGRES }) + CreateViewAsStep createOrReplaceView(Table view, Function, ? extends Field> fieldNameFunction); + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + *

+ * This works like {@link #createOrReplaceView(Table, Field...)} except that the + * view's field names are derived from the view's {@link Select} statement + * using a function. + * + * @see DSL#createOrReplaceView(String, String...) + */ + @Support({ H2, POSTGRES }) + CreateViewAsStep createOrReplaceView(Table view, BiFunction, ? super Integer, ? extends Field> fieldNameFunction); + + /** * Create a new DSL CREATE VIEW statement. * diff --git a/jOOQ/src/main/java/org/jooq/impl/CreateViewImpl.java b/jOOQ/src/main/java/org/jooq/impl/CreateViewImpl.java index 7d8c568c65..14b8338da4 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CreateViewImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CreateViewImpl.java @@ -45,6 +45,7 @@ import static org.jooq.Clause.CREATE_VIEW_NAME; // ... import static org.jooq.SQLDialect.DERBY; import static org.jooq.SQLDialect.FIREBIRD; +import static org.jooq.SQLDialect.H2; // ... // ... import static org.jooq.SQLDialect.POSTGRES; @@ -54,9 +55,13 @@ import static org.jooq.conf.ParamType.INLINED; import static org.jooq.impl.DSL.name; import static org.jooq.impl.DSL.selectFrom; import static org.jooq.impl.DSL.table; +import static org.jooq.impl.Keywords.K_ALTER; import static org.jooq.impl.Keywords.K_AS; -import static org.jooq.impl.Keywords.K_CREATE_VIEW; +import static org.jooq.impl.Keywords.K_CREATE; import static org.jooq.impl.Keywords.K_IF_NOT_EXISTS; +import static org.jooq.impl.Keywords.K_OR; +import static org.jooq.impl.Keywords.K_REPLACE; +import static org.jooq.impl.Keywords.K_VIEW; import java.util.EnumSet; import java.util.List; @@ -87,11 +92,13 @@ final class CreateViewImpl extends AbstractQuery implements /** * Generated UID */ - private static final long serialVersionUID = 8904572826501186329L; - private static final Clause[] CLAUSES = { CREATE_VIEW }; + private static final long serialVersionUID = 8904572826501186329L; + private static final Clause[] CLAUSES = { CREATE_VIEW }; private static final EnumSet NO_SUPPORT_IF_NOT_EXISTS = EnumSet.of(DERBY, FIREBIRD, POSTGRES); + private static final EnumSet NO_SUPPORT_OR_REPLACE = EnumSet.of(H2); private final boolean ifNotExists; + private final boolean orReplace; private final Table view; private final BiFunction, ? super Integer, ? extends Field> fieldNameFunction; @@ -99,7 +106,7 @@ final class CreateViewImpl extends AbstractQuery implements private Field[] fields; private Select select; - CreateViewImpl(Configuration configuration, Table view, Field[] fields, boolean ifNotExists) { + CreateViewImpl(Configuration configuration, Table view, Field[] fields, boolean ifNotExists, boolean orReplace) { super(configuration); this.view = view; @@ -108,16 +115,18 @@ final class CreateViewImpl extends AbstractQuery implements this.fieldNameFunction = null; this.ifNotExists = ifNotExists; + this.orReplace = orReplace; } - CreateViewImpl(Configuration configuration, Table view, BiFunction, ? super Integer, ? extends Field> fieldNameFunction, boolean ifNotExists) { + CreateViewImpl(Configuration configuration, Table view, BiFunction, ? super Integer, ? extends Field> fieldNameFunction, boolean ifNotExists, boolean orReplace) { super(configuration); this.view = view; this.fields = null; this.fieldNameFunction = fieldNameFunction; this.ifNotExists = ifNotExists; + this.orReplace = orReplace; } @@ -171,7 +180,25 @@ final class CreateViewImpl extends AbstractQuery implements ParamType paramType = ctx.paramType(); ctx.start(CREATE_VIEW_NAME) - .visit(K_CREATE_VIEW) + .visit(K_CREATE); + + if (orReplace && !NO_SUPPORT_OR_REPLACE.contains(ctx.family())) { + ctx.sql(' ').visit(K_OR); + + switch (ctx.family()) { + + + + + + + default: + ctx.sql(' ').visit(K_REPLACE); + break; + } + } + + ctx.sql(' ').visit(K_VIEW) .sql(' '); if (ifNotExists && supportsIfNotExists(ctx)) diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 24b1a1a879..844ca36029 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -7009,6 +7009,80 @@ public class DSL { } + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + * + * @see DSLContext#createOrReplaceView(String, String...) + */ + @Support({ H2, POSTGRES }) + public static CreateViewAsStep createOrReplaceView(String view, String... fields) { + return dsl().createOrReplaceView(view, fields); + } + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + * + * @see DSLContext#createOrReplaceView(Name, Name...) + */ + @Support({ H2, POSTGRES }) + public static CreateViewAsStep createOrReplaceView(Name view, Name... fields) { + return dsl().createOrReplaceView(view, fields); + } + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + * + * @see DSLContext#createOrReplaceView(Table, Field...) + */ + @Support({ H2, POSTGRES }) + public static CreateViewAsStep createOrReplaceView(Table view, Field... fields) { + return dsl().createOrReplaceView(view, fields); + } + + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + *

+ * This works like {@link #createOrReplaceView(Table, Field...)} except that the + * view's field names are derived from the view's {@link Select} statement + * using a function. + * + * @see DSLContext#createOrReplaceView(String, String...) + */ + @Support({ H2, POSTGRES }) + public static CreateViewAsStep createOrReplaceView(String view, Function, ? extends String> fieldNameFunction) { + return dsl().createOrReplaceView(view, fieldNameFunction); + } + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + *

+ * This works like {@link #createOrReplaceView(Table, Field...)} except that the + * view's field names are derived from the view's {@link Select} statement + * using a function. + * + * @see DSLContext#createOrReplaceView(Name, Name...) + */ + @Support({ H2, POSTGRES }) + public static CreateViewAsStep createOrReplaceView(Name view, Function, ? extends Name> fieldNameFunction) { + return dsl().createOrReplaceView(view, fieldNameFunction); + } + + /** + * Create a new DSL CREATE OR REPLACE VIEW statement. + *

+ * This works like {@link #createOrReplaceView(Table, Field...)} except that the + * view's field names are derived from the view's {@link Select} statement + * using a function. + * + * @see DSLContext#createOrReplaceView(Table, Field...) + */ + @Support({ H2, POSTGRES }) + public static CreateViewAsStep createOrReplaceView(Table view, Function, ? extends Field> fieldNameFunction) { + return dsl().createOrReplaceView(view, fieldNameFunction); + } + + /** * Create a new DSL CREATE VIEW IF NOT EXISTS statement. * diff --git a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java index aaeae9c4f6..c70d0442db 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java +++ b/jOOQ/src/main/java/org/jooq/impl/DefaultDSLContext.java @@ -2995,7 +2995,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri @Override public CreateViewAsStep createView(Table view, Field... fields) { - return new CreateViewImpl(configuration(), view, fields, false); + return new CreateViewImpl(configuration(), view, fields, false, false); } @@ -3026,7 +3026,54 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri @Override public CreateViewAsStep createView(Table view, BiFunction, ? super Integer, ? extends Field> fieldNameFunction) { - return new CreateViewImpl(configuration(), view, fieldNameFunction, false); + return new CreateViewImpl(configuration(), view, fieldNameFunction, false, false); + } + + + @Override + public CreateViewAsStep createOrReplaceView(String view, String... fields) { + return createOrReplaceView(table(name(view)), Tools.fieldsByName(view, fields)); + } + + @Override + public CreateViewAsStep createOrReplaceView(Name view, Name... fields) { + return createOrReplaceView(table(view), Tools.fieldsByName(fields)); + } + + @Override + public CreateViewAsStep createOrReplaceView(Table view, Field... fields) { + return new CreateViewImpl(configuration(), view, fields, false, true); + } + + + @Override + public CreateViewAsStep createOrReplaceView(String view, Function, ? extends String> fieldNameFunction) { + return createOrReplaceView(table(name(view)), (f, i) -> field(name(fieldNameFunction.apply(f)))); + } + + @Override + public CreateViewAsStep createOrReplaceView(String view, BiFunction, ? super Integer, ? extends String> fieldNameFunction) { + return createOrReplaceView(table(name(view)), (f, i) -> field(name(fieldNameFunction.apply(f, i)))); + } + + @Override + public CreateViewAsStep createOrReplaceView(Name view, Function, ? extends Name> fieldNameFunction) { + return createOrReplaceView(table(view), (f, i) -> field(fieldNameFunction.apply(f))); + } + + @Override + public CreateViewAsStep createOrReplaceView(Name view, BiFunction, ? super Integer, ? extends Name> fieldNameFunction) { + return createOrReplaceView(table(view), (f, i) -> field(fieldNameFunction.apply(f, i))); + } + + @Override + public CreateViewAsStep createOrReplaceView(Table view, Function, ? extends Field> fieldNameFunction) { + return createOrReplaceView(view, (f, i) -> fieldNameFunction.apply(f)); + } + + @Override + public CreateViewAsStep createOrReplaceView(Table view, BiFunction, ? super Integer, ? extends Field> fieldNameFunction) { + return new CreateViewImpl(configuration(), view, fieldNameFunction, false, true); } @@ -3042,7 +3089,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri @Override public CreateViewAsStep createViewIfNotExists(Table view, Field... fields) { - return new CreateViewImpl(configuration(), view, fields, true); + return new CreateViewImpl(configuration(), view, fields, true, false); } @@ -3073,7 +3120,7 @@ public class DefaultDSLContext extends AbstractScope implements DSLContext, Seri @Override public CreateViewAsStep createViewIfNotExists(Table view, BiFunction, ? super Integer, ? extends Field> fieldNameFunction) { - return new CreateViewImpl(configuration(), view, fieldNameFunction, true); + return new CreateViewImpl(configuration(), view, fieldNameFunction, true, false); } diff --git a/jOOQ/src/main/java/org/jooq/impl/Keywords.java b/jOOQ/src/main/java/org/jooq/impl/Keywords.java index 7c070ffaf3..229b2d3208 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Keywords.java +++ b/jOOQ/src/main/java/org/jooq/impl/Keywords.java @@ -87,7 +87,6 @@ final class Keywords { static final Keyword K_CONTINUE_IDENTITY = keyword("continue identity"); static final Keyword K_CREATE = keyword("create"); static final Keyword K_CREATE_SCHEMA = keyword("create schema"); - static final Keyword K_CREATE_VIEW = keyword("create view"); static final Keyword K_CROSS_JOIN_LATERAL = keyword("cross join lateral"); static final Keyword K_CURRENT_SCHEMA = keyword("current_schema"); static final Keyword K_CURRENT_ROW = keyword("current row"); @@ -225,6 +224,7 @@ final class Keywords { static final Keyword K_RENAME_INDEX = keyword("rename index"); static final Keyword K_RENAME_TABLE = keyword("rename table"); static final Keyword K_RENAME_TO = keyword("rename to"); + static final Keyword K_REPLACE = keyword("replace"); static final Keyword K_RESPECT_NULLS = keyword("respect nulls"); static final Keyword K_RESTART = keyword("restart"); static final Keyword K_RESTART_IDENTITY = keyword("restart identity"); diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index bb2ac22fe9..fe6f796800 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -739,6 +739,8 @@ final class ParserImpl implements Parser { result = parseSelect(ctx, null, with); else if (!parseSelect && peekKeyword(ctx, "UPDATE")) result = parseUpdate(ctx, with); + else if ((parseWhitespaceIf(ctx) || true) && ctx.done()) + throw ctx.exception("Missing statement after WITH"); else throw ctx.exception("Unsupported statement after WITH"); @@ -1532,10 +1534,14 @@ final class ParserImpl implements Parser { return parseCreateSchema(ctx); else if (parseKeywordIf(ctx, "SEQUENCE")) return parseCreateSequence(ctx); + else if (parseKeywordIf(ctx, "OR REPLACE VIEW")) + return parseCreateView(ctx, true); + else if (parseKeywordIf(ctx, "OR ALTER VIEW")) + return parseCreateView(ctx, true); else if (parseKeywordIf(ctx, "VIEW")) - return parseCreateView(ctx); + return parseCreateView(ctx, false); else - throw ctx.expected("GENERATOR", "GLOBAL TEMPORARY TABLE", "INDEX", "SCHEMA", "SEQUENCE", "TABLE", "TEMPORARY TABLE", "UNIQUE INDEX", "VIEW"); + throw ctx.expected("GENERATOR", "GLOBAL TEMPORARY TABLE", "INDEX", "OR ALTER VIEW", "OR REPLACE VIEW", "SCHEMA", "SEQUENCE", "TABLE", "TEMPORARY TABLE", "UNIQUE INDEX", "VIEW"); } private static final Query parseAlter(ParserContext ctx) { @@ -1778,8 +1784,8 @@ final class ParserImpl implements Parser { return user(parseName(ctx)); } - private static final DDLQuery parseCreateView(ParserContext ctx) { - boolean ifNotExists = parseKeywordIf(ctx, "IF NOT EXISTS"); + private static final DDLQuery parseCreateView(ParserContext ctx, boolean orReplace) { + boolean ifNotExists = !orReplace && parseKeywordIf(ctx, "IF NOT EXISTS"); Table view = parseTableName(ctx); Field[] fields = EMPTY_FIELD; @@ -1797,6 +1803,8 @@ final class ParserImpl implements Parser { return ifNotExists ? ctx.dsl.createViewIfNotExists(view, fields).as(select) + : orReplace + ? ctx.dsl.createOrReplaceView(view, fields).as(select) : ctx.dsl.createView(view, fields).as(select); }