From d445b361eb264105d2011401ec966d3abb282199 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Wed, 30 Nov 2022 17:11:29 +0100 Subject: [PATCH] [jOOQ/jOOQ#11830] Add Settings.renderRowConditionForSeekClause to allow for avoiding row predicate usage --- .../src/main/java/org/jooq/conf/Settings.java | 46 +++++++++++++++++++ .../java/org/jooq/impl/SelectQueryImpl.java | 9 ++-- .../org/jooq/xsd/jooq-runtime-3.18.0.xsd | 8 ++++ 3 files changed, 59 insertions(+), 4 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 2fe6e36ba7..9e43ae8d67 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -105,6 +105,8 @@ public class Settings protected Boolean renderParenthesisAroundSetOperationQueries = false; @XmlElement(defaultValue = "true") protected Boolean renderVariablesInDerivedTablesForEmulations = true; + @XmlElement(defaultValue = "true") + protected Boolean renderRowConditionForSeekClause = true; @XmlElement(defaultValue = ".") protected String namePathSeparator = "."; @XmlElement(defaultValue = "false") @@ -1150,6 +1152,34 @@ public class Settings this.renderVariablesInDerivedTablesForEmulations = value; } + /** + * Whether a (a, b) < (:a, :b) row predicate should be rendered for the SEEK clause. + *

+ * Some RDBMS may support (a, b) < (:a, :b) row predicate syntax, which is very convenient for SEEK clause implementations, but fail to optimise this predicate as could be expected. + * This flag allows for expanding the predicate to the much more verbose, but equivalent (a < :a) OR (a = :a AND b < :b). Dialects without native support for row predicates aren't affected + * by this flag. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isRenderRowConditionForSeekClause() { + return renderRowConditionForSeekClause; + } + + /** + * Sets the value of the renderRowConditionForSeekClause property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setRenderRowConditionForSeekClause(Boolean value) { + this.renderRowConditionForSeekClause = value; + } + /** * The character(s) to be used as a separator in paths encoded in a {@link Name} *

@@ -5819,6 +5849,11 @@ public class Settings return this; } + public Settings withRenderRowConditionForSeekClause(Boolean value) { + setRenderRowConditionForSeekClause(value); + return this; + } + /** * The character(s) to be used as a separator in paths encoded in a {@link Name} *

@@ -7105,6 +7140,7 @@ public class Settings builder.append("renderGroupConcatMaxLenSessionVariable", renderGroupConcatMaxLenSessionVariable); builder.append("renderParenthesisAroundSetOperationQueries", renderParenthesisAroundSetOperationQueries); builder.append("renderVariablesInDerivedTablesForEmulations", renderVariablesInDerivedTablesForEmulations); + builder.append("renderRowConditionForSeekClause", renderRowConditionForSeekClause); builder.append("namePathSeparator", namePathSeparator); builder.append("bindOffsetDateTimeType", bindOffsetDateTimeType); builder.append("bindOffsetTimeType", bindOffsetTimeType); @@ -7556,6 +7592,15 @@ public class Settings return false; } } + if (renderRowConditionForSeekClause == null) { + if (other.renderRowConditionForSeekClause!= null) { + return false; + } + } else { + if (!renderRowConditionForSeekClause.equals(other.renderRowConditionForSeekClause)) { + return false; + } + } if (namePathSeparator == null) { if (other.namePathSeparator!= null) { return false; @@ -9193,6 +9238,7 @@ public class Settings result = ((prime*result)+((renderGroupConcatMaxLenSessionVariable == null)? 0 :renderGroupConcatMaxLenSessionVariable.hashCode())); result = ((prime*result)+((renderParenthesisAroundSetOperationQueries == null)? 0 :renderParenthesisAroundSetOperationQueries.hashCode())); result = ((prime*result)+((renderVariablesInDerivedTablesForEmulations == null)? 0 :renderVariablesInDerivedTablesForEmulations.hashCode())); + result = ((prime*result)+((renderRowConditionForSeekClause == null)? 0 :renderRowConditionForSeekClause.hashCode())); result = ((prime*result)+((namePathSeparator == null)? 0 :namePathSeparator.hashCode())); result = ((prime*result)+((bindOffsetDateTimeType == null)? 0 :bindOffsetDateTimeType.hashCode())); result = ((prime*result)+((bindOffsetTimeType == null)? 0 :bindOffsetTimeType.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java index 3d75aef08a..860cdacde7 100644 --- a/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/SelectQueryImpl.java @@ -37,6 +37,7 @@ */ package org.jooq.impl; +import static java.lang.Boolean.FALSE; import static java.lang.Boolean.TRUE; import static java.util.Arrays.asList; import static java.util.Collections.emptyList; @@ -2558,7 +2559,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp context.formatSeparator() .visit(K_WHERE) .sql(' ') - .qualify(false, c -> c.visit(getSeekCondition())); + .qualify(false, c -> c.visit(getSeekCondition(context))); } } @@ -3955,7 +3956,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp // - There are no unions (union is nested in derived table // and SEEK predicate is applied outside). See [#7459] if (!getOrderBy().isEmpty() && !getSeek().isEmpty() && unionOp.isEmpty()) - result.addConditions(getSeekCondition()); + result.addConditions(getSeekCondition(ctx)); @@ -3967,7 +3968,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp } @SuppressWarnings({ "rawtypes", "unchecked" }) - final Condition getSeekCondition() { + final Condition getSeekCondition(Context ctx) { SortFieldList o = getOrderBy(); Condition c = null; @@ -3979,7 +3980,7 @@ final class SelectQueryImpl extends AbstractResultQuery imp // If we have uniform sorting, more efficient row value expression // predicates can be applied, which can be heavily optimised on some // databases. - if (o.size() > 1 && o.uniform()) { + if (o.size() > 1 && o.uniform() && !FALSE.equals(ctx.settings().isRenderRowConditionForSeekClause())) { if (o.get(0).getOrder() != DESC ^ seekBefore) c = row(o.fields()).gt(row(getSeek())); else diff --git a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd index 48d3ff39d5..45d9929d97 100644 --- a/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd +++ b/jOOQ/src/main/resources/org/jooq/xsd/jooq-runtime-3.18.0.xsd @@ -220,6 +220,14 @@ For details, see https://gith For details, see https://github.com/jOOQ/jOOQ/issues/14065.]]> + + (a, b) < (:a, :b) row predicate should be rendered for the SEEK clause. +

+Some RDBMS may support (a, b) < (:a, :b) row predicate syntax, which is very convenient for SEEK clause implementations, but fail to optimise this predicate as could be expected. +This flag allows for expanding the predicate to the much more verbose, but equivalent (a < :a) OR (a = :a AND b < :b). Dialects without native support for row predicates aren't affected +by this flag.]]> + +