[jOOQ/jOOQ#14166] Render correct SQL when CASE have empty contents
This commit is contained in:
parent
97c8e00d66
commit
607bde4fa3
@ -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 <code>CASE WHEN a IS NOT DISTINCT FROM b …</code> to an equivalent <code>DECODE</code> function.
|
||||
* <p>
|
||||
* When all <code>WHEN</code> clauses of a <code>CASE</code> expression use the <code>DISTINCT</code> predicate, then the
|
||||
* <code>CASE</code> expression can be transformed into a <code>DECODE</code> function call:
|
||||
* <ul>
|
||||
* <li><code>CASE WHEN a IS NOT DISTINCT FROM b THEN 1 END</code> is equivalent to <code>DECODE(a, b, 1)</code></li>
|
||||
* <li><code>CASE WHEN a IS NOT DISTINCT FROM b THEN 1 ELSE 2 END</code> is equivalent to <code>DECODE(a, b, 1, 2)</code></li>
|
||||
* <li><code>CASE WHEN a IS NOT DISTINCT FROM b THEN 1 WHEN a IS NOT DISTINCT FROM c THEN 2 END</code> is equivalent to <code>DECODE(a, b, 1, c, 2)</code></li>
|
||||
* <li><code>CASE WHEN a IS NOT DISTINCT FROM b THEN 1 WHEN a IS NOT DISTINCT FROM c THEN 2 ELSE 3 END</code> is equivalent to <code>DECODE(a, b, 1, c, 2, 3)</code></li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* 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 <code>CASE WHEN a THEN x WHEN b THEN x END</code> to <code>CASE WHEN a OR b THEN x END</code>.
|
||||
* <p>
|
||||
@ -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()));
|
||||
|
||||
@ -62,7 +62,7 @@ final class CaseImpl implements Case, UTransient {
|
||||
|
||||
@Override
|
||||
public final <V> CaseValueStep<V> value(Field<V> value) {
|
||||
return new CaseValueStepImpl<>(value);
|
||||
return new CaseSimpleValueStep<>(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -72,7 +72,7 @@ final class CaseImpl implements Case, UTransient {
|
||||
|
||||
@Override
|
||||
public final <T> CaseConditionStep<T> when(Condition condition, Field<T> result) {
|
||||
return new CaseConditionStepImpl<>(condition, result);
|
||||
return new CaseSearched<>(condition, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -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<T>
|
||||
final class CaseSearched<T>
|
||||
extends
|
||||
AbstractField<T>
|
||||
implements
|
||||
@ -80,15 +80,15 @@ implements
|
||||
{
|
||||
|
||||
private final List<Tuple2<Condition, Field<T>>> when;
|
||||
private Field<T> else_;
|
||||
private Field<T> else_;
|
||||
|
||||
CaseConditionStepImpl(DataType<T> type) {
|
||||
CaseSearched(DataType<T> type) {
|
||||
super(NQ_CASE, type);
|
||||
|
||||
this.when = new QueryPartList<>();
|
||||
}
|
||||
|
||||
CaseConditionStepImpl(Condition condition, Field<T> result) {
|
||||
CaseSearched(Condition condition, Field<T> 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 UnmodifiableList<? extends Tuple2<Condition, Field<T>>>, ? super Field<T>, ? extends CaseSearched<T>> $constructor() {
|
||||
return (w, e) -> {
|
||||
CaseConditionStepImpl<T> r = new CaseConditionStepImpl<>(getDataType());
|
||||
CaseSearched<T> r = new CaseSearched<>(getDataType());
|
||||
w.forEach(t -> r.when(t.$1(), t.$2()));
|
||||
r.else_(e);
|
||||
return r;
|
||||
@ -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<V, T>
|
||||
final class CaseSimple<V, T>
|
||||
extends
|
||||
AbstractField<T>
|
||||
implements
|
||||
@ -75,23 +75,23 @@ implements
|
||||
QOM.CaseSimple<V, T>
|
||||
{
|
||||
|
||||
private final Field<V> value;
|
||||
private final Field<V> value;
|
||||
private final List<Tuple2<Field<V>, Field<T>>> when;
|
||||
private Field<T> else_;
|
||||
private Field<T> else_;
|
||||
|
||||
CaseWhenStepImpl(Field<V> value, Field<V> compareValue, Field<T> result) {
|
||||
CaseSimple(Field<V> value, Field<V> compareValue, Field<T> result) {
|
||||
this(value, result.getDataType());
|
||||
|
||||
when(compareValue, result);
|
||||
}
|
||||
|
||||
CaseWhenStepImpl(Field<V> value, Map<? extends Field<V>, ? extends Field<T>> map) {
|
||||
CaseSimple(Field<V> value, Map<? extends Field<V>, ? extends Field<T>> map) {
|
||||
this(value, dataType(map));
|
||||
|
||||
mapFields(map);
|
||||
}
|
||||
|
||||
CaseWhenStepImpl(Field<V> value, DataType<T> type) {
|
||||
CaseSimple(Field<V> value, DataType<T> 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 Field<V>, ? super UnmodifiableList<? extends Tuple2<Field<V>, Field<T>>>, ? super Field<T>, ? extends CaseSimple<V, T>> $constructor() {
|
||||
return (v, w, e) -> {
|
||||
CaseWhenStepImpl<V, T> r = new CaseWhenStepImpl<>(v, getDataType());
|
||||
CaseSimple<V, T> r = new CaseSimple<>(v, getDataType());
|
||||
w.forEach(t -> r.when(t.$1(), t.$2()));
|
||||
r.else_(e);
|
||||
return r;
|
||||
@ -52,11 +52,11 @@ import org.jooq.impl.QOM.UTransient;
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class CaseValueStepImpl<V> implements CaseValueStep<V>, UTransient {
|
||||
final class CaseSimpleValueStep<V> implements CaseValueStep<V>, UTransient {
|
||||
|
||||
private final Field<V> value;
|
||||
|
||||
CaseValueStepImpl(Field<V> value) {
|
||||
CaseSimpleValueStep(Field<V> value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@ -82,7 +82,7 @@ final class CaseValueStepImpl<V> implements CaseValueStep<V>, UTransient {
|
||||
|
||||
@Override
|
||||
public final <T> CaseWhenStep<V, T> when(Field<V> compareValue, Field<T> result) {
|
||||
return new CaseWhenStepImpl<>(value, compareValue, result);
|
||||
return new CaseSimple<>(value, compareValue, result);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -99,6 +99,6 @@ final class CaseValueStepImpl<V> implements CaseValueStep<V>, UTransient {
|
||||
|
||||
@Override
|
||||
public final <T> CaseWhenStep<V, T> mapFields(Map<? extends Field<V>, ? extends Field<T>> fields) {
|
||||
return new CaseWhenStepImpl<>(value, fields);
|
||||
return new CaseSimple<>(value, fields);
|
||||
}
|
||||
}
|
||||
@ -1629,7 +1629,7 @@ implements
|
||||
for (Entry<FieldOrRow, FieldOrRowOrSelect> 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
|
||||
|
||||
@ -2117,6 +2117,64 @@ package org.jooq.impl;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@ -615,6 +615,21 @@ Case clauses can be proven to be unreachable, and thus removed:
|
||||
This feature is available in the commercial distribution only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="transformPatternsCaseDistinctToDecode" type="boolean" minOccurs="0" maxOccurs="1" default="true">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Transform <code>CASE WHEN a IS NOT DISTINCT FROM b ..</code> to an equivalent <code>DECODE</code> function.
|
||||
<p>
|
||||
When all <code>WHEN</code> clauses of a <code>CASE</code> expression use the <code>DISTINCT</code> predicate, then the
|
||||
<code>CASE</code> expression can be transformed into a <code>DECODE</code> function call:
|
||||
<ul>
|
||||
<li><code>CASE WHEN a IS NOT DISTINCT FROM b THEN 1 END</code> is equivalent to <code>DECODE(a, b, 1)</code></li>
|
||||
<li><code>CASE WHEN a IS NOT DISTINCT FROM b THEN 1 ELSE 2 END</code> is equivalent to <code>DECODE(a, b, 1, 2)</code></li>
|
||||
<li><code>CASE WHEN a IS NOT DISTINCT FROM b THEN 1 WHEN a IS NOT DISTINCT FROM c THEN 2 END</code> is equivalent to <code>DECODE(a, b, 1, c, 2)</code></li>
|
||||
<li><code>CASE WHEN a IS NOT DISTINCT FROM b THEN 1 WHEN a IS NOT DISTINCT FROM c THEN 2 ELSE 3 END</code> is equivalent to <code>DECODE(a, b, 1, c, 2, 3)</code></li>
|
||||
</ul>
|
||||
<p>
|
||||
This feature is available in the commercial distribution only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
|
||||
</element>
|
||||
|
||||
<element name="transformPatternsCaseMergeWhenWhen" type="boolean" minOccurs="0" maxOccurs="1" default="true">
|
||||
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Transform <code>CASE WHEN a THEN x WHEN b THEN x END</code> to <code>CASE WHEN a OR b THEN x END</code>.
|
||||
<p>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user