From 630c7736ebaa5b5381e59f8f902182ceb7172dc3 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Mon, 24 Feb 2020 12:53:21 +0100 Subject: [PATCH] [jOOQ/jOOQ#8805] Support OVERLAY() function --- jOOQ/src/main/java/org/jooq/impl/DSL.java | 32 +++++ .../src/main/java/org/jooq/impl/Keywords.java | 2 + jOOQ/src/main/java/org/jooq/impl/Names.java | 1 + jOOQ/src/main/java/org/jooq/impl/Overlay.java | 131 ++++++++++++++++++ .../main/java/org/jooq/impl/ParserImpl.java | 23 +++ 5 files changed, 189 insertions(+) create mode 100644 jOOQ/src/main/java/org/jooq/impl/Overlay.java diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index aec2a298a8..3278a431fb 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -13954,6 +13954,38 @@ public class DSL { return new Position(nullSafe(search), nullSafe(in), nullSafe(startIndex)); } + /** + * Get the overlay(in, placing, startIndex) function. + */ + @Support + public static Field overlay(Field in, String placing, Number startIndex) { + return new Overlay(nullSafe(in), Tools.field(placing), Tools.field(startIndex)); + } + + /** + * Get the overlay(in, placing, startIndex) function. + */ + @Support + public static Field overlay(Field in, Field placing, Field startIndex) { + return new Overlay(nullSafe(in), nullSafe(placing), nullSafe(startIndex)); + } + + /** + * Get the overlay(in, placing, startIndex, length) function. + */ + @Support + public static Field overlay(Field in, String placing, Number startIndex, Number length) { + return new Overlay(nullSafe(in), Tools.field(placing), Tools.field(startIndex), Tools.field(length)); + } + + /** + * Get the overlay(in, placing, startIndex, length) function. + */ + @Support + public static Field overlay(Field in, Field placing, Field startIndex, Field length) { + return new Overlay(nullSafe(in), nullSafe(placing), nullSafe(startIndex), nullSafe(length)); + } + /** * Get the ascii(field) function. * diff --git a/jOOQ/src/main/java/org/jooq/impl/Keywords.java b/jOOQ/src/main/java/org/jooq/impl/Keywords.java index 7d549d5b3f..b7a517cad1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Keywords.java +++ b/jOOQ/src/main/java/org/jooq/impl/Keywords.java @@ -273,6 +273,7 @@ final class Keywords { static final Keyword K_PERCENT = keyword("percent"); static final Keyword K_PERIOD = keyword("period"); static final Keyword K_PIVOT = keyword("pivot"); + static final Keyword K_PLACING = keyword("placing"); static final Keyword K_POSITION = keyword("position"); static final Keyword K_PRECEDING = keyword("preceding"); static final Keyword K_PREVIOUS_VALUE_FOR = keyword("previous value for"); @@ -446,6 +447,7 @@ final class Keywords { static final Keyword F_NUMTODSINTERVAL = keyword("numtodsinterval"); static final Keyword F_NVL = keyword("nvl"); static final Keyword F_NVL2 = keyword("nvl2"); + static final Keyword F_OVERLAY = keyword("overlay"); static final Keyword F_POSITION = keyword("position"); static final Keyword F_POWER = keyword("power"); static final Keyword F_RAND = keyword("rand"); diff --git a/jOOQ/src/main/java/org/jooq/impl/Names.java b/jOOQ/src/main/java/org/jooq/impl/Names.java index d9a23e55c3..ce585405df 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Names.java +++ b/jOOQ/src/main/java/org/jooq/impl/Names.java @@ -93,6 +93,7 @@ final class Names { static final Name N_NULLIF = DSL.name("nullif"); static final Name N_NVL = DSL.name("nvl"); static final Name N_NVL2 = DSL.name("nvl2"); + static final Name N_OVERLAY = DSL.name("overlay"); static final Name N_PIVOT = DSL.name("pivot"); static final Name N_POSITION = DSL.name("position"); static final Name N_POWER = DSL.name("power"); diff --git a/jOOQ/src/main/java/org/jooq/impl/Overlay.java b/jOOQ/src/main/java/org/jooq/impl/Overlay.java new file mode 100644 index 0000000000..3b8fff82dd --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/Overlay.java @@ -0,0 +1,131 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Other licenses: + * ----------------------------------------------------------------------------- + * Commercial licenses for this work are available. These replace the above + * ASL 2.0 and offer limited warranties, support, maintenance, and commercial + * database integrations. + * + * For more information, please visit: http://www.jooq.org/licenses + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + * + */ + +package org.jooq.impl; + +// ... +// ... +// ... +import static org.jooq.SQLDialect.DERBY; +import static org.jooq.SQLDialect.H2; +// ... +import static org.jooq.SQLDialect.HSQLDB; +// ... +// ... +import static org.jooq.SQLDialect.MARIADB; +// ... +import static org.jooq.SQLDialect.MYSQL; +// ... +// ... +// ... +import static org.jooq.SQLDialect.SQLITE; +// ... +// ... +// ... +import static org.jooq.impl.DSL.inline; +import static org.jooq.impl.Keywords.F_OVERLAY; +import static org.jooq.impl.Keywords.K_FOR; +import static org.jooq.impl.Keywords.K_FROM; +import static org.jooq.impl.Keywords.K_PLACING; +import static org.jooq.impl.Names.N_OVERLAY; + +import java.util.Set; + +import org.jooq.Context; +import org.jooq.Field; +import org.jooq.SQLDialect; + +/** + * @author Lukas Eder + */ +final class Overlay extends AbstractField { + + private static final long serialVersionUID = 3544690069533526544L; + private static final Set NO_SUPPORT = SQLDialect.supportedBy(DERBY, H2, HSQLDB, MARIADB, MYSQL, SQLITE); + + private final Field in; + private final Field placing; + private final Field startIndex; + private final Field length; + + Overlay(Field in, Field placing, Field startIndex) { + this(in, placing, startIndex, null); + } + + Overlay(Field in, Field placing, Field startIndex, Field length) { + super(N_OVERLAY, in.getDataType()); + + this.in = in; + this.placing = placing; + this.startIndex = startIndex; + this.length = length; + } + + @Override + public final void accept(Context ctx) { + if (length != null) { + if (NO_SUPPORT.contains(ctx.family())) { + ctx.visit( + DSL.substring(in, inline(1), startIndex.minus(inline(1))) + .concat(placing) + .concat(DSL.substring(in, startIndex.plus(length))) + ); + } + else { + ctx.visit(F_OVERLAY).sql('(').visit(in).sql(' ') + .visit(K_PLACING).sql(' ').visit(placing).sql(' ') + .visit(K_FROM).sql(' ').visit(startIndex).sql(' ') + .visit(K_FOR).sql(' ').visit(length).sql(')'); + } + } + else { + if (NO_SUPPORT.contains(ctx.family())) { + ctx.visit( + DSL.substring(in, inline(1), startIndex.minus(inline(1))) + .concat(placing) + .concat(DSL.substring(in, startIndex.plus(DSL.length(placing)))) + ); + } + else { + ctx.visit(F_OVERLAY).sql('(').visit(in).sql(' ') + .visit(K_PLACING).sql(' ').visit(placing).sql(' ') + .visit(K_FROM).sql(' ').visit(startIndex).sql(')'); + } + } + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index df2ae5627d..a69c04ce95 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -194,6 +194,7 @@ import static org.jooq.impl.DSL.nvl2; import static org.jooq.impl.DSL.octetLength; import static org.jooq.impl.DSL.one; import static org.jooq.impl.DSL.orderBy; +import static org.jooq.impl.DSL.overlay; import static org.jooq.impl.DSL.partitionBy; import static org.jooq.impl.DSL.percentRank; import static org.jooq.impl.DSL.percentileCont; @@ -6116,6 +6117,8 @@ final class ParserImpl implements Parser { if (S.is(type)) if ((field = parseFieldReplaceIf(ctx)) != null) return field; + else if ((field = parseFieldOverlayIf(ctx)) != null) + return field; if (N.is(type)) if ((field = parseFieldOctetLengthIf(ctx)) != null) @@ -7547,6 +7550,26 @@ final class ParserImpl implements Parser { return null; } + private static final Field parseFieldOverlayIf(ParserContext ctx) { + if (parseFunctionNameIf(ctx, "OVERLAY")) { + parse(ctx, '('); + Field f1 = (Field) parseField(ctx, S); + parseKeyword(ctx, "PLACING"); + Field f2 = (Field) parseField(ctx, S); + parseKeyword(ctx, "FROM"); + Field f3 = (Field) parseField(ctx, N); + Field f4 = + parseKeywordIf(ctx, "FOR") + ? (Field) parseField(ctx, N) + : null; + parse(ctx, ')'); + + return f4 == null ? overlay(f1, f2, f3) : overlay(f1, f2, f3, f4); + } + + return null; + } + private static final Field parseFieldPositionIf(ParserContext ctx) { if (parseFunctionNameIf(ctx, "POSITION")) { parse(ctx, '(');