From 91d933177857eed8a80e5fc82dae82ab03b6c267 Mon Sep 17 00:00:00 2001 From: lukaseder Date: Thu, 3 May 2018 14:02:53 +0200 Subject: [PATCH] [#7459] SEEK with UNION doesn't work correctly --- .../java/org/jooq/impl/SelectQueryImpl.java | 67 +++++++++++++------ 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index 46e1ee3c13..4bc4f1e1c2 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -1038,6 +1038,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp // synthetic parentheses boolean wrapQueryExpressionInDerivedTable; boolean wrapQueryExpressionBodyInDerivedTable = false; + boolean applySeekOnDerivedTable = applySeekOnDerivedTable(context); wrapQueryExpressionInDerivedTable = false @@ -1072,28 +1073,34 @@ final class SelectQueryImpl extends AbstractResultQuery imp + // [#7459] In the presence of UNIONs and other set operations, the SEEK + // predicate must be applied on a derived table, not on the individual subqueries + wrapQueryExpressionBodyInDerivedTable |= applySeekOnDerivedTable; + + if (wrapQueryExpressionBodyInDerivedTable) { + context.visit(K_SELECT).sql(' '); + context.formatIndentStart() + .formatNewLine() + .sql("t.*"); + if (alternativeFields != null && originalFields.length < alternativeFields.length) + context.sql(", ") + .formatSeparator() + .declareFields(true) + .visit(alternativeFields[alternativeFields.length - 1]) + .declareFields(false); - - - - - - - - - - - - - - - + context.formatIndentEnd() + .formatSeparator() + .visit(K_FROM).sql(" (") + .formatIndentStart() + .formatNewLine(); + } // [#1658] jOOQ applies left-associativity to set operators. In order to enforce that across // all databases, we need to wrap relevant subqueries in parentheses. @@ -1424,12 +1431,22 @@ final class SelectQueryImpl extends AbstractResultQuery imp context.data().remove(DATA_NESTED_SET_OPERATIONS); } + if (wrapQueryExpressionBodyInDerivedTable) { + context.formatIndentEnd() + .formatNewLine() + .sql(") t"); + if (applySeekOnDerivedTable) { + boolean qualify = context.qualify(); - - - - + context.formatSeparator() + .visit(K_WHERE) + .sql(' ') + .qualify(false) + .visit(getSeekCondition()) + .qualify(qualify); + } + } // ORDER BY clause for UNION // ------------------------- @@ -1527,6 +1544,10 @@ final class SelectQueryImpl extends AbstractResultQuery imp ctx.visit(actualLimit); } + private final boolean applySeekOnDerivedTable(Context ctx) { + return !getSeek().isEmpty() && !getOrderBy().isEmpty() && !unionOp.isEmpty(); + } + private final boolean wrapQueryExpressionBodyInDerivedTable(Context ctx) { return true @@ -1924,7 +1945,13 @@ final class SelectQueryImpl extends AbstractResultQuery imp } final ConditionProviderImpl getWhere() { - if (getOrderBy().isEmpty() || getSeek().isEmpty()) + + // Do not apply SEEK predicates in the WHERE clause, if: + // - There is no ORDER BY clause (SEEK is non-deterministic) + // - There is no SEEK clause (obvious case) + // - There are unions (union is nested in derived table + // and SEEK predicate is applied outside). See [#7459] + if (getOrderBy().isEmpty() || getSeek().isEmpty() || unionOp.size() > 0) return condition; ConditionProviderImpl result = new ConditionProviderImpl();