diff --git a/jOOQ/src/main/java/org/jooq/conf/Settings.java b/jOOQ/src/main/java/org/jooq/conf/Settings.java index 978d818a2a..a779e64530 100644 --- a/jOOQ/src/main/java/org/jooq/conf/Settings.java +++ b/jOOQ/src/main/java/org/jooq/conf/Settings.java @@ -187,6 +187,8 @@ public class Settings @XmlElement(defaultValue = "true") protected Boolean transformPatternsCaseUnreachableClauses = true; @XmlElement(defaultValue = "true") + protected Boolean transformPatternsCaseDistinctToDecode = true; + @XmlElement(defaultValue = "true") protected Boolean transformPatternsCaseMergeWhenWhen = true; @XmlElement(defaultValue = "true") protected Boolean transformPatternsCaseMergeWhenElse = true; @@ -2316,6 +2318,41 @@ public class Settings this.transformPatternsCaseUnreachableClauses = value; } + /** + * Transform CASE WHEN a IS NOT DISTINCT FROM b … to an equivalent DECODE function. + *

+ * When all WHEN clauses of a CASE expression use the DISTINCT predicate, then the + * CASE expression can be transformed into a DECODE function call: + *

+ *

+ * This feature is available in the commercial distribution only. + * + * @return + * possible object is + * {@link Boolean } + * + */ + public Boolean isTransformPatternsCaseDistinctToDecode() { + return transformPatternsCaseDistinctToDecode; + } + + /** + * Sets the value of the transformPatternsCaseDistinctToDecode property. + * + * @param value + * allowed object is + * {@link Boolean } + * + */ + public void setTransformPatternsCaseDistinctToDecode(Boolean value) { + this.transformPatternsCaseDistinctToDecode = value; + } + /** * Transform CASE WHEN a THEN x WHEN b THEN x END to CASE WHEN a OR b THEN x END. *

@@ -5541,6 +5578,11 @@ public class Settings return this; } + public Settings withTransformPatternsCaseDistinctToDecode(Boolean value) { + setTransformPatternsCaseDistinctToDecode(value); + return this; + } + public Settings withTransformPatternsCaseMergeWhenWhen(Boolean value) { setTransformPatternsCaseMergeWhenWhen(value); return this; @@ -6555,6 +6597,7 @@ public class Settings builder.append("transformPatternsCaseElseNull", transformPatternsCaseElseNull); builder.append("transformPatternsCaseElseCase", transformPatternsCaseElseCase); builder.append("transformPatternsCaseUnreachableClauses", transformPatternsCaseUnreachableClauses); + builder.append("transformPatternsCaseDistinctToDecode", transformPatternsCaseDistinctToDecode); builder.append("transformPatternsCaseMergeWhenWhen", transformPatternsCaseMergeWhenWhen); builder.append("transformPatternsCaseMergeWhenElse", transformPatternsCaseMergeWhenElse); builder.append("transformPatternsCaseToCaseAbbreviation", transformPatternsCaseToCaseAbbreviation); @@ -7310,6 +7353,15 @@ public class Settings return false; } } + if (transformPatternsCaseDistinctToDecode == null) { + if (other.transformPatternsCaseDistinctToDecode!= null) { + return false; + } + } else { + if (!transformPatternsCaseDistinctToDecode.equals(other.transformPatternsCaseDistinctToDecode)) { + return false; + } + } if (transformPatternsCaseMergeWhenWhen == null) { if (other.transformPatternsCaseMergeWhenWhen!= null) { return false; @@ -8483,6 +8535,7 @@ public class Settings result = ((prime*result)+((transformPatternsCaseElseNull == null)? 0 :transformPatternsCaseElseNull.hashCode())); result = ((prime*result)+((transformPatternsCaseElseCase == null)? 0 :transformPatternsCaseElseCase.hashCode())); result = ((prime*result)+((transformPatternsCaseUnreachableClauses == null)? 0 :transformPatternsCaseUnreachableClauses.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())); result = ((prime*result)+((transformPatternsCaseToCaseAbbreviation == null)? 0 :transformPatternsCaseToCaseAbbreviation.hashCode())); diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseImpl.java index 186aedc7c1..a9168439e5 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CaseImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CaseImpl.java @@ -62,7 +62,7 @@ final class CaseImpl implements Case, UTransient { @Override public final CaseValueStep value(Field value) { - return new CaseValueStepImpl<>(value); + return new CaseSimpleValueStep<>(value); } @Override @@ -72,7 +72,7 @@ final class CaseImpl implements Case, UTransient { @Override public final CaseConditionStep when(Condition condition, Field result) { - return new CaseConditionStepImpl<>(condition, result); + return new CaseSearched<>(condition, result); } @Override diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseSearched.java similarity index 90% rename from jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java rename to jOOQ/src/main/java/org/jooq/impl/CaseSearched.java index 2fcfdae0d0..da10ef549d 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CaseConditionStepImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CaseSearched.java @@ -39,6 +39,7 @@ package org.jooq.impl; import static java.lang.Boolean.TRUE; // ... +import static org.jooq.impl.DSL.NULL; import static org.jooq.impl.DSL.one; import static org.jooq.impl.DSL.select; import static org.jooq.impl.Keywords.K_CASE; @@ -64,14 +65,13 @@ import org.jooq.Function2; import org.jooq.Record1; // ... import org.jooq.Select; -import org.jooq.impl.QOM.CaseSearched; import org.jooq.impl.QOM.Tuple2; import org.jooq.impl.QOM.UnmodifiableList; /** * @author Lukas Eder */ -final class CaseConditionStepImpl +final class CaseSearched extends AbstractField implements @@ -80,15 +80,15 @@ implements { private final List>> when; - private Field else_; + private Field else_; - CaseConditionStepImpl(DataType type) { + CaseSearched(DataType type) { super(NQ_CASE, type); this.when = new QueryPartList<>(); } - CaseConditionStepImpl(Condition condition, Field result) { + CaseSearched(Condition condition, Field result) { this(result.getDataType()); when(condition, result); @@ -163,7 +163,14 @@ implements @Override public final void accept(Context ctx) { - switch (ctx.family()) { + if (when.isEmpty()) { + if (else_ != null) + ctx.visit(else_); + else + ctx.visit(NULL(getDataType())); + } + else { + switch (ctx.family()) { @@ -174,9 +181,10 @@ implements - default: - acceptNative(ctx); - break; + default: + acceptNative(ctx); + break; + } } } @@ -265,7 +273,7 @@ implements @Override public final Function2>>, ? super Field, ? extends CaseSearched> $constructor() { return (w, e) -> { - CaseConditionStepImpl r = new CaseConditionStepImpl<>(getDataType()); + CaseSearched r = new CaseSearched<>(getDataType()); w.forEach(t -> r.when(t.$1(), t.$2())); r.else_(e); return r; diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseSimple.java similarity index 87% rename from jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java rename to jOOQ/src/main/java/org/jooq/impl/CaseSimple.java index f792548cf0..edd995f384 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CaseWhenStepImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CaseSimple.java @@ -38,6 +38,7 @@ package org.jooq.impl; import static java.lang.Boolean.TRUE; +import static org.jooq.impl.DSL.NULL; import static org.jooq.impl.Keywords.K_CASE; import static org.jooq.impl.Keywords.K_ELSE; import static org.jooq.impl.Keywords.K_END; @@ -60,14 +61,13 @@ import org.jooq.DataType; import org.jooq.Field; import org.jooq.Function3; // ... -import org.jooq.impl.QOM.CaseSimple; import org.jooq.impl.QOM.Tuple2; import org.jooq.impl.QOM.UnmodifiableList; /** * @author Lukas Eder */ -final class CaseWhenStepImpl +final class CaseSimple extends AbstractField implements @@ -75,23 +75,23 @@ implements QOM.CaseSimple { - private final Field value; + private final Field value; private final List, Field>> when; - private Field else_; + private Field else_; - CaseWhenStepImpl(Field value, Field compareValue, Field result) { + CaseSimple(Field value, Field compareValue, Field result) { this(value, result.getDataType()); when(compareValue, result); } - CaseWhenStepImpl(Field value, Map, ? extends Field> map) { + CaseSimple(Field value, Map, ? extends Field> map) { this(value, dataType(map)); mapFields(map); } - CaseWhenStepImpl(Field value, DataType type) { + CaseSimple(Field value, DataType type) { super(NQ_CASE, type); this.value = value; @@ -168,7 +168,14 @@ implements @Override public final void accept(Context ctx) { - switch (ctx.family()) { + if (when.isEmpty()) { + if (else_ != null) + ctx.visit(else_); + else + ctx.visit(NULL(getDataType())); + } + else { + switch (ctx.family()) { @@ -179,14 +186,15 @@ implements - // The DERBY dialect doesn't support the simple CASE clause - case DERBY: - acceptSearched(ctx); - break; + // The DERBY dialect doesn't support the simple CASE clause + case DERBY: + acceptSearched(ctx); + break; - default: - acceptNative(ctx); - break; + default: + acceptNative(ctx); + break; + } } } @@ -284,7 +292,7 @@ implements @Override public final Function3, ? super UnmodifiableList, Field>>, ? super Field, ? extends CaseSimple> $constructor() { return (v, w, e) -> { - CaseWhenStepImpl r = new CaseWhenStepImpl<>(v, getDataType()); + CaseSimple r = new CaseSimple<>(v, getDataType()); w.forEach(t -> r.when(t.$1(), t.$2())); r.else_(e); return r; diff --git a/jOOQ/src/main/java/org/jooq/impl/CaseValueStepImpl.java b/jOOQ/src/main/java/org/jooq/impl/CaseSimpleValueStep.java similarity index 92% rename from jOOQ/src/main/java/org/jooq/impl/CaseValueStepImpl.java rename to jOOQ/src/main/java/org/jooq/impl/CaseSimpleValueStep.java index d2715b5cf1..c763222ce3 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CaseValueStepImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CaseSimpleValueStep.java @@ -52,11 +52,11 @@ import org.jooq.impl.QOM.UTransient; * * @author Lukas Eder */ -final class CaseValueStepImpl implements CaseValueStep, UTransient { +final class CaseSimpleValueStep implements CaseValueStep, UTransient { private final Field value; - CaseValueStepImpl(Field value) { + CaseSimpleValueStep(Field value) { this.value = value; } @@ -82,7 +82,7 @@ final class CaseValueStepImpl implements CaseValueStep, UTransient { @Override public final CaseWhenStep when(Field compareValue, Field result) { - return new CaseWhenStepImpl<>(value, compareValue, result); + return new CaseSimple<>(value, compareValue, result); } @Override @@ -99,6 +99,6 @@ final class CaseValueStepImpl implements CaseValueStep, UTransient { @Override public final CaseWhenStep mapFields(Map, ? extends Field> fields) { - return new CaseWhenStepImpl<>(value, fields); + return new CaseSimple<>(value, fields); } } diff --git a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java index 02390a1e57..8d11622525 100644 --- a/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/MergeImpl.java @@ -1629,7 +1629,7 @@ implements for (Entry e : m.updateMap.entrySet()) { FieldOrRowOrSelect exp = update.updateMap.get(e.getKey()); - if (exp instanceof CaseConditionStepImpl c) + if (exp instanceof CaseSearched c) c.when(negate.and(condition), e.getValue()); // [#10523] [#13325] TODO: ClassCastException when we're using Row here, once supported diff --git a/jOOQ/src/main/java/org/jooq/impl/Patterns.java b/jOOQ/src/main/java/org/jooq/impl/Patterns.java index d7954a63aa..4867970dac 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Patterns.java +++ b/jOOQ/src/main/java/org/jooq/impl/Patterns.java @@ -2117,6 +2117,64 @@ package org.jooq.impl; + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 7816d34185..db5204be9d 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 @@ -615,6 +615,21 @@ Case 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. +

+When all WHEN clauses of a CASE expression use the DISTINCT predicate, then the +CASE expression can be transformed into a DECODE function call: +

+

+This feature is available in the commercial distribution only.]]> + + CASE WHEN a THEN x WHEN b THEN x END to CASE WHEN a OR b THEN x END.