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 8756b74d2e..7c1a1f7fe8 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 @@ -440,12 +440,12 @@ sortField = field [ 'ASC' | 'DESC' ] [ 'NULLS FIRST' | 'NULLS LAST' ] tables = table { ',' table } ; -table = tableFactor { unqualifiedJoin | innerJoin | outerJoin | semiAntiJoin } +table = lateral { unqualifiedJoin | innerJoin | outerJoin | semiAntiJoin } ; unqualifiedJoin = ( 'CROSS JOIN' | 'CROSS APPLY' | 'OUTER APPLY' | 'NATURAL' [ ( 'LEFT' | 'RIGHT' ) [ 'OUTER' ] ] 'JOIN' ) -tableFactor +lateral ; innerJoin = @@ -463,13 +463,18 @@ outerJoin = semiAntiJoin = 'LEFT' ( 'SEMI' | 'ANTI' ) 'JOIN' table joinQualification ; +lateral = + 'LATERAL' tableFactor +| tableFactor +; + tableFactor = - 'LATERAL' '(' select ')' [ correlationName ] -| tableFunction [ correlationName ] -| '(' select ')' [ correlationName ] -| values [ correlationName ] -| tableName [ versions ] [ correlationName ] [ tableHints ] + tableName [ versions ] [ correlationName ] [ tableHints ] | '(' table ')' [ correlationName ] +| '(' select ')' [ correlationName ] +| tableFunction [ correlationName ] +| 'UNNEST' '(' field ')' +| values [ correlationName ] ; tableFunction = diff --git a/jOOQ/src/main/java/org/jooq/impl/DSL.java b/jOOQ/src/main/java/org/jooq/impl/DSL.java index 135d6c68f8..359f1003eb 100644 --- a/jOOQ/src/main/java/org/jooq/impl/DSL.java +++ b/jOOQ/src/main/java/org/jooq/impl/DSL.java @@ -8531,17 +8531,13 @@ public class DSL { */ @Support({ H2, HSQLDB, POSTGRES }) public static Table unnest(Field cursor) { - if (cursor == null) { + if (cursor == null) throw new IllegalArgumentException(); - } // The field is an actual CURSOR or REF CURSOR returned from a stored // procedure or from a NESTED TABLE - else if (cursor.getType() == Result.class) { + else if (cursor.getType() == Result.class) return new org.jooq.impl.FunctionTable(cursor); - } - - @@ -8554,9 +8550,8 @@ public class DSL { // The field is a regular array - else if (cursor.getType().isArray() && cursor.getType() != byte[].class) { + else if (cursor.getType().isArray() && cursor.getType() != byte[].class) return new ArrayTable(cursor); - } // The field has any other type. Try to make it an array throw new SQLDialectNotSupportedException("Converting arbitrary types into array tables is currently not supported"); diff --git a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java index 11ec79ffcf..9a89ab47de 100644 --- a/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/ParserImpl.java @@ -221,6 +221,7 @@ import static org.jooq.impl.DSL.translate; import static org.jooq.impl.DSL.trim; import static org.jooq.impl.DSL.trunc; import static org.jooq.impl.DSL.unique; +import static org.jooq.impl.DSL.unnest; import static org.jooq.impl.DSL.user; import static org.jooq.impl.DSL.values; import static org.jooq.impl.DSL.varPop; @@ -3385,7 +3386,7 @@ final class ParserImpl implements Parser { } private static final Table parseTable(ParserContext ctx) { - Table result = parseTableFactor(ctx); + Table result = parseLateral(ctx); for (;;) { Table joined = parseJoinedTableIf(ctx, result); @@ -3396,20 +3397,29 @@ final class ParserImpl implements Parser { } } + private static final Table parseLateral(ParserContext ctx) { + if (parseKeywordIf(ctx, "LATERAL")) + return lateral(parseTableFactor(ctx)); + else + return parseTableFactor(ctx); + } + private static final Table parseTableFactor(ParserContext ctx) { Table result = null; // TODO [#5306] Support FINAL TABLE () // TOOD ONLY ( table primary ) - if (parseKeywordIf(ctx, "LATERAL")) { + if (parseFunctionNameIf(ctx, "UNNEST")) { parse(ctx, '('); - result = lateral(parseSelect(ctx)); + Field f = parseField(ctx, Type.A); + + // Work around a missing feature in unnest() + if (!f.getType().isArray()) + f = f.coerce(f.getDataType().getArrayDataType()); + + result = unnest(f); parse(ctx, ')'); } - else if (parseFunctionNameIf(ctx, "UNNEST")) { - // TODO - throw ctx.notImplemented("UNNEST"); - } else if (parseFunctionNameIf(ctx, "GENERATE_SERIES")) { parse(ctx, '('); Field from = toField(ctx, parseConcat(ctx, Type.N)); @@ -3693,7 +3703,7 @@ final class ParserImpl implements Parser { } private static final Table parseJoinedTable(ParserContext ctx) { - Table result = parseTableFactor(ctx); + Table result = parseLateral(ctx); for (;;) { Table joined = parseJoinedTableIf(ctx, result); @@ -3711,7 +3721,7 @@ final class ParserImpl implements Parser { if (joinType == null) return null; - Table right = joinType.qualified() ? parseTable(ctx) : parseTableFactor(ctx); + Table right = joinType.qualified() ? parseTable(ctx) : parseLateral(ctx); TableOptionalOnStep s0; TablePartitionByStep s1;