diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index c47f6ec0e8..119f5b5fbe 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -183,7 +183,9 @@ public class Settings @XmlElement(defaultValue = "true") protected Boolean transformPatternsCaseElseNull = true; @XmlElement(defaultValue = "true") - protected Boolean transformPatternsCaseUnreachableClauses = true; + protected Boolean transformPatternsUnreachableCaseClauses = true; + @XmlElement(defaultValue = "true") + protected Boolean transformPatternsUnreachableDecodeClauses = true; @XmlElement(defaultValue = "true") protected Boolean transformPatternsCaseDistinctToDecode = true; @XmlElement(defaultValue = "true") @@ -2274,20 +2276,52 @@ public class Settings * {@link Boolean } * */ - public Boolean isTransformPatternsCaseUnreachableClauses() { - return transformPatternsCaseUnreachableClauses; + public Boolean isTransformPatternsUnreachableCaseClauses() { + return transformPatternsUnreachableCaseClauses; } /** - * Sets the value of the transformPatternsCaseUnreachableClauses property. + * Sets the value of the transformPatternsUnreachableCaseClauses property. * * @param value * allowed object is * {@link Boolean } * */ - public void setTransformPatternsCaseUnreachableClauses(Boolean value) { - this.transformPatternsCaseUnreachableClauses = value; + public void setTransformPatternsUnreachableCaseClauses(Boolean value) { + this.transformPatternsUnreachableCaseClauses = value; + } + + /** + * Transform DECODE by removing unreachable clauses. + *

+ * DECODE clauses can be proven to be unreachable, and thus removed: + *

+ *

+ * This feature is available in the commercial distribution only. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isTransformPatternsUnreachableDecodeClauses() { + return transformPatternsUnreachableDecodeClauses; + } + + /** + * Sets the value of the transformPatternsUnreachableDecodeClauses property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setTransformPatternsUnreachableDecodeClauses(Boolean value) { + this.transformPatternsUnreachableDecodeClauses = value; } /** @@ -5568,8 +5602,13 @@ public class Settings return this; } - public Settings withTransformPatternsCaseUnreachableClauses(Boolean value) { - setTransformPatternsCaseUnreachableClauses(value); + public Settings withTransformPatternsUnreachableCaseClauses(Boolean value) { + setTransformPatternsUnreachableCaseClauses(value); + return this; + } + + public Settings withTransformPatternsUnreachableDecodeClauses(Boolean value) { + setTransformPatternsUnreachableDecodeClauses(value); return this; } @@ -6595,7 +6634,8 @@ public class Settings builder.append("transformPatternsMergeRangePredicates", transformPatternsMergeRangePredicates); builder.append("transformPatternsMergeBetweenSymmetricPredicates", transformPatternsMergeBetweenSymmetricPredicates); builder.append("transformPatternsCaseElseNull", transformPatternsCaseElseNull); - builder.append("transformPatternsCaseUnreachableClauses", transformPatternsCaseUnreachableClauses); + builder.append("transformPatternsUnreachableCaseClauses", transformPatternsUnreachableCaseClauses); + builder.append("transformPatternsUnreachableDecodeClauses", transformPatternsUnreachableDecodeClauses); builder.append("transformPatternsCaseDistinctToDecode", transformPatternsCaseDistinctToDecode); builder.append("transformPatternsCaseMergeWhenWhen", transformPatternsCaseMergeWhenWhen); builder.append("transformPatternsCaseMergeWhenElse", transformPatternsCaseMergeWhenElse); @@ -7335,12 +7375,21 @@ public class Settings return false; } } - if (transformPatternsCaseUnreachableClauses == null) { - if (other.transformPatternsCaseUnreachableClauses!= null) { + if (transformPatternsUnreachableCaseClauses == null) { + if (other.transformPatternsUnreachableCaseClauses!= null) { return false; } } else { - if (!transformPatternsCaseUnreachableClauses.equals(other.transformPatternsCaseUnreachableClauses)) { + if (!transformPatternsUnreachableCaseClauses.equals(other.transformPatternsUnreachableCaseClauses)) { + return false; + } + } + if (transformPatternsUnreachableDecodeClauses == null) { + if (other.transformPatternsUnreachableDecodeClauses!= null) { + return false; + } + } else { + if (!transformPatternsUnreachableDecodeClauses.equals(other.transformPatternsUnreachableDecodeClauses)) { return false; } } @@ -8533,7 +8582,8 @@ public class Settings result = ((prime*result)+((transformPatternsMergeRangePredicates == null)? 0 :transformPatternsMergeRangePredicates.hashCode())); result = ((prime*result)+((transformPatternsMergeBetweenSymmetricPredicates == null)? 0 :transformPatternsMergeBetweenSymmetricPredicates.hashCode())); result = ((prime*result)+((transformPatternsCaseElseNull == null)? 0 :transformPatternsCaseElseNull.hashCode())); - result = ((prime*result)+((transformPatternsCaseUnreachableClauses == null)? 0 :transformPatternsCaseUnreachableClauses.hashCode())); + result = ((prime*result)+((transformPatternsUnreachableCaseClauses == null)? 0 :transformPatternsUnreachableCaseClauses.hashCode())); + result = ((prime*result)+((transformPatternsUnreachableDecodeClauses == null)? 0 :transformPatternsUnreachableDecodeClauses.hashCode())); result = ((prime*result)+((transformPatternsCaseDistinctToDecode == null)? 0 :transformPatternsCaseDistinctToDecode.hashCode())); result = ((prime*result)+((transformPatternsCaseMergeWhenWhen == null)? 0 :transformPatternsCaseMergeWhenWhen.hashCode())); result = ((prime*result)+((transformPatternsCaseMergeWhenElse == null)? 0 :transformPatternsCaseMergeWhenElse.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/impl/Choose.java b/jOOQ/src/main/java/org/jooq/impl/Choose.java index 77a7379757..419a5ae6f4 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Choose.java +++ b/jOOQ/src/main/java/org/jooq/impl/Choose.java @@ -37,16 +37,17 @@ */ package org.jooq.impl; +import static org.jooq.impl.DSL.NULL; import static org.jooq.impl.DSL.choose; import static org.jooq.impl.DSL.function; import static org.jooq.impl.DSL.inline; import static org.jooq.impl.Names.N_CHOOSE; import static org.jooq.impl.Tools.EMPTY_FIELD; +import static org.jooq.impl.Tools.nullSafeDataType; import org.jooq.CaseValueStep; import org.jooq.CaseWhenStep; import org.jooq.Context; -import org.jooq.DataType; import org.jooq.Field; import org.jooq.Function2; import org.jooq.impl.QOM.UnmodifiableList; @@ -60,19 +61,19 @@ final class Choose extends AbstractField implements QOM.Choose { private Field[] values; Choose(Field index, Field[] values) { - super(N_CHOOSE, dataType(values)); + super(N_CHOOSE, nullSafeDataType(values)); this.index = index; this.values = values; } - @SuppressWarnings("unchecked") - private static final DataType dataType(Field[] values) { - return values == null || values.length == 0 ? (DataType) SQLDataType.OTHER : values[0].getDataType(); - } - @Override public final void accept(Context ctx) { + if (values.length == 0) { + ctx.visit(NULL(getDataType())); + return; + } + switch (ctx.family()) { @@ -80,19 +81,46 @@ final class Choose extends AbstractField implements QOM.Choose { - default: { + + + + + + + + + + + + + + case CUBRID: + case DERBY: + case FIREBIRD: + case H2: + case HSQLDB: + case IGNITE: + case MARIADB: + case MYSQL: + case POSTGRES: + case SQLITE: + case YUGABYTEDB: { CaseValueStep s = choose(index); CaseWhenStep when = null; - for (int i = 0; i < values.length; i++) { + for (int i = 0; i < values.length; i++) when = when == null ? s.when(inline(i + 1), values[i]) : when.when(inline(i + 1), values[i]); - } ctx.visit(when); break; } + + default: { + ctx.visit(function(N_CHOOSE, getDataType(), Tools.combine(index, values))); + break; + } } } diff --git a/jOOQ/src/main/java/org/jooq/impl/Concat.java b/jOOQ/src/main/java/org/jooq/impl/Concat.java index e6608ba43c..8a4df0eecc 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Concat.java +++ b/jOOQ/src/main/java/org/jooq/impl/Concat.java @@ -37,6 +37,7 @@ */ package org.jooq.impl; +import static org.jooq.impl.DSL.NULL; import static org.jooq.impl.DSL.function; import static org.jooq.impl.DSL.inline; import static org.jooq.impl.DSL.systemName; @@ -66,6 +67,14 @@ final class Concat extends AbstractField implements QOM.Concat { @Override public final void accept(Context ctx) { + if (arguments.length == 0) { + ctx.visit(NULL(getDataType())); + return; + } + else if (arguments.length == 1) { + ctx.visit(arguments[0]); + return; + } // [#461] Type cast the concat expression, if this isn't a VARCHAR field Field[] cast = castAllIfNeeded(arguments, String.class); @@ -76,12 +85,6 @@ final class Concat extends AbstractField implements QOM.Concat { - } - - // If there is only one argument, return it immediately - if (cast.length == 1) { - ctx.visit(cast[0]); - return; } ExpressionOperator op = CONCAT; diff --git a/jOOQ/src/main/java/org/jooq/impl/Greatest.java b/jOOQ/src/main/java/org/jooq/impl/Greatest.java index 7a6ea1f64a..af3433c13a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Greatest.java +++ b/jOOQ/src/main/java/org/jooq/impl/Greatest.java @@ -37,11 +37,13 @@ */ package org.jooq.impl; +import static org.jooq.impl.DSL.NULL; import static org.jooq.impl.DSL.function; import static org.jooq.impl.Names.N_GREATEST; import static org.jooq.impl.Names.N_MAX; import static org.jooq.impl.Names.N_MAXVALUE; import static org.jooq.impl.Tools.EMPTY_FIELD; +import static org.jooq.impl.Tools.nullSafeDataType; import org.jooq.Context; import org.jooq.DataType; @@ -58,16 +60,18 @@ final class Greatest extends AbstractField implements QOM.Greatest { @SuppressWarnings({ "unchecked", "rawtypes" }) Greatest(Field... args) { - super(N_GREATEST, (DataType) Tools.nullSafeDataType(args[0])); + super(N_GREATEST, (DataType) nullSafeDataType(args)); this.args = (QueryPartListView) QueryPartListView.wrap(args); } @Override public final void accept(Context ctx) { - - // In any dialect, a single argument is always the greatest - if (args.size() == 1) { + if (args.isEmpty()) { + ctx.visit(NULL(getDataType())); + return; + } + else if (args.size() == 1) { ctx.visit(args.get(0)); return; } diff --git a/jOOQ/src/main/java/org/jooq/impl/Least.java b/jOOQ/src/main/java/org/jooq/impl/Least.java index 024280ea15..f7befe44d1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Least.java +++ b/jOOQ/src/main/java/org/jooq/impl/Least.java @@ -37,11 +37,13 @@ */ package org.jooq.impl; +import static org.jooq.impl.DSL.NULL; import static org.jooq.impl.DSL.function; import static org.jooq.impl.Names.N_LEAST; import static org.jooq.impl.Names.N_MIN; import static org.jooq.impl.Names.N_MINVALUE; import static org.jooq.impl.Tools.EMPTY_FIELD; +import static org.jooq.impl.Tools.nullSafeDataType; import org.jooq.Context; import org.jooq.DataType; @@ -58,16 +60,18 @@ final class Least extends AbstractField implements QOM.Least { @SuppressWarnings({ "unchecked", "rawtypes" }) Least(Field... args) { - super(N_LEAST, (DataType) Tools.nullSafeDataType(args[0])); + super(N_LEAST, (DataType) nullSafeDataType(args)); this.args = (QueryPartListView) QueryPartListView.wrap(args); } @Override public final void accept(Context ctx) { - - // In any dialect, a single argument is always the least - if (args.size() == 1) { + if (args.isEmpty()) { + ctx.visit(NULL(getDataType())); + return; + } + else if (args.size() == 1) { ctx.visit(args.get(0)); return; } diff --git a/jOOQ/src/main/java/org/jooq/impl/Patterns.java b/jOOQ/src/main/java/org/jooq/impl/Patterns.java index 2f4b897d6f..9991b53ac9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Patterns.java +++ b/jOOQ/src/main/java/org/jooq/impl/Patterns.java @@ -2204,6 +2204,22 @@ package org.jooq.impl; + + + + + + + + + + + + + + + + diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index c5088dd130..f6cb490354 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -6965,6 +6965,11 @@ final class Tools { return (DataType) (field == null ? SQLDataType.OTHER : field.getDataType()); } + @SuppressWarnings("unchecked") + static final DataType nullSafeDataType(Field[] values) { + return isEmpty(values) ? (DataType) SQLDataType.OTHER : values[0].getDataType(); + } + static final Field nullSafeNotNull(Field field, DataType type) { return nullableIf(false, nullSafe(field, type)); } 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 1ac7293f81..65143d89a7 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 @@ -595,7 +595,7 @@ This feature is available in the commercial distribution only.]]>< This feature is available in the commercial distribution only.]]> - + CASE by removing unreachable clauses.

Case clauses can be proven to be unreachable, and thus removed: @@ -607,6 +607,18 @@ Case clauses can be proven to be unreachable, and thus removed: This feature is available in the commercial distribution only.]]> + + DECODE by removing unreachable clauses. +

+DECODE clauses can be proven to be unreachable, and thus removed: +

+

+This feature is available in the commercial distribution only.]]> + + CASE WHEN a IS NOT DISTINCT FROM b .. to an equivalent DECODE function.