From af1e22b651cb0e2db7f8cf6af52ddfc4db9dc218 Mon Sep 17 00:00:00 2001 From: lukaseder Date: Wed, 16 May 2018 10:32:35 +0200 Subject: [PATCH] [#7171] Parse MySQL cast types { SIGNED | UNSIGNED } [ INTEGER ] --- .../resources/org/jooq/web/grammar-3.11.txt | 8 +- jOOQ/src/main/java/org/jooq/DatePart.java | 30 ++++ .../main/java/org/jooq/impl/ParserImpl.java | 141 +++++++++++++++++- 3 files changed, 177 insertions(+), 2 deletions(-) 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 dc171ed12b..f6e1906ac8 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 @@ -599,7 +599,7 @@ term = | 'BITXOR' '(' field ',' field ')' | 'BIT_XOR' '(' field ',' field ')' | case -| 'CAST' '(' field 'AS' dataType ')' +| 'CAST' '(' field 'AS' castDataType ')' | ( 'CEIL' | 'CEILING' ) '(' sum ')' | 'CHARINDEX' '(' field ',' field ')' | 'CHAR_LENGTH' '(' field ')' @@ -789,6 +789,12 @@ case = 'CASE' comparator = '=' | '!=' | '<>' | '>=' | '>' | '<=>' | '<=' | '<' ; +castDataType = + dataType +| 'SIGNED' [ 'INTEGER' ] +| 'UNSIGNED' [ 'INTEGER' ] +; + dataType = 'BIGINT' [ 'UNSIGNED' ] | 'BINARY' [ '(' unsignedInteger ')' ] diff --git a/jOOQ/src/main/java/org/jooq/DatePart.java b/jOOQ/src/main/java/org/jooq/DatePart.java index 4ad22af5df..36d9631309 100644 --- a/jOOQ/src/main/java/org/jooq/DatePart.java +++ b/jOOQ/src/main/java/org/jooq/DatePart.java @@ -39,6 +39,7 @@ package org.jooq; import static org.jooq.SQLDialect.POSTGRES; +// ... import java.time.temporal.ChronoField; @@ -96,6 +97,35 @@ public enum DatePart { // XXX: Vendor-specific date parts // ------------------------------------------------------------------------ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + /** * The millennium. The year 2000 is in the 2nd millennium, the year 2001 in * the 3rd. diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index d4fd864b20..a478784537 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -4312,6 +4312,8 @@ final class ParserImpl implements Parser { return field; else if ((field = parseFieldDateTruncIf(ctx)) != null) return field; + else if ((field = parseFieldDateAddIf(ctx)) != null) + return field; if (N.is(type)) if ((field = parseFieldDenseRankIf(ctx)) != null) @@ -5242,6 +5244,22 @@ final class ParserImpl implements Parser { return null; } + private static final Field parseFieldDateAddIf(ParserContext ctx) { + if (parseFunctionNameIf(ctx, "DATEADD")) { + parse(ctx, '('); + DatePart part = parseDatePart2(ctx); + parse(ctx, ','); + Field interval = (Field) parseField(ctx, Type.N); + parse(ctx, ','); + Field date = (Field) parseField(ctx, Type.D); + parse(ctx, ')'); + + return DSL.dateAdd(date, interval, part); + } + + return null; + } + private static final Date parseDateLiteral(ParserContext ctx) { try { return Date.valueOf(parseStringLiteral(ctx)); @@ -5273,6 +5291,105 @@ final class ParserImpl implements Parser { throw ctx.exception("Unsupported date part"); } + private static final DatePart parseDatePart2(ParserContext ctx) { + char character = ctx.character(); + + switch (character) { + case 'd': + case 'D': + if (parseKeywordIf(ctx, "DAYOFYEAR") || + parseKeywordIf(ctx, "DY")) + return DatePart.DAY_OF_YEAR; + else if (parseKeywordIf(ctx, "DAY") || + parseKeywordIf(ctx, "DD") || + parseKeywordIf(ctx, "D")) + return DatePart.DAY; + else if (parseKeywordIf(ctx, "DW")) + return DatePart.DAY_OF_WEEK; + + break; + + case 'h': + case 'H': + if (parseKeywordIf(ctx, "HOUR") || + parseKeywordIf(ctx, "HH")) + return DatePart.HOUR; + + break; + + case 'm': + case 'M': + if (parseKeywordIf(ctx, "MINUTE") || + parseKeywordIf(ctx, "MI")) + return DatePart.MINUTE; + else if (parseKeywordIf(ctx, "MICROSECOND") || + parseKeywordIf(ctx, "MCS")) + return DatePart.MICROSECOND; + else if (parseKeywordIf(ctx, "MILLISECOND") || + parseKeywordIf(ctx, "MS")) + return DatePart.MILLISECOND; + else if (parseKeywordIf(ctx, "MONTH") || + parseKeywordIf(ctx, "MM") || + parseKeywordIf(ctx, "M")) + return DatePart.MONTH; + + break; + + case 'n': + case 'N': + if (parseKeywordIf(ctx, "NANOSECOND") || + parseKeywordIf(ctx, "NS")) + return DatePart.NANOSECOND; + else if (parseKeywordIf(ctx, "N")) + return DatePart.MINUTE; + + break; + + case 'q': + case 'Q': + if (parseKeywordIf(ctx, "QUARTER") || + parseKeywordIf(ctx, "QQ") || + parseKeywordIf(ctx, "Q")) + return DatePart.QUARTER; + + break; + + case 's': + case 'S': + if (parseKeywordIf(ctx, "SECOND") || + parseKeywordIf(ctx, "SS") || + parseKeywordIf(ctx, "S")) + return DatePart.SECOND; + + break; + + case 'w': + case 'W': + if (parseKeywordIf(ctx, "WEEK") || + parseKeywordIf(ctx, "WK") || + parseKeywordIf(ctx, "WW")) + return DatePart.WEEK; + else if (parseKeywordIf(ctx, "WEEKDAY") || + parseKeywordIf(ctx, "W")) + return DatePart.DAY_OF_WEEK; + + break; + + case 'y': + case 'Y': + if (parseKeywordIf(ctx, "YEAR") || + parseKeywordIf(ctx, "YYYY") || + parseKeywordIf(ctx, "YY")) + return DatePart.YEAR; + else if (parseKeywordIf(ctx, "Y")) + return DatePart.DAY_OF_YEAR; + + break; + } + + throw ctx.expected("DatePart"); + } + private static final Field parseFieldAsciiIf(ParserContext ctx) { if (parseFunctionNameIf(ctx, "ASCII")) { parse(ctx, '('); @@ -5933,7 +6050,7 @@ final class ParserImpl implements Parser { parse(ctx, '('); Field field = parseField(ctx); parseKeyword(ctx, "AS"); - DataType type = parseDataType(ctx); + DataType type = parseCastDataType(ctx); parse(ctx, ')'); return cast(field, type); @@ -6788,6 +6905,28 @@ final class ParserImpl implements Parser { : 0; } + private static final DataType parseCastDataType(ParserContext ctx) { + char character = ctx.character(); + + switch (character) { + case 's': + case 'S': + if (parseKeywordIf(ctx, "SIGNED") && (parseKeywordIf(ctx, "INTEGER") || true)) + return SQLDataType.BIGINT; + + break; + + case 'u': + case 'U': + if (parseKeywordIf(ctx, "UNSIGNED") && (parseKeywordIf(ctx, "INTEGER") || true)) + return SQLDataType.BIGINTUNSIGNED; + + break; + } + + return parseDataType(ctx); + } + private static final DataType parseDataType(ParserContext ctx) { DataType result = parseDataTypePrefix(ctx);