[jOOQ/jOOQ#14166] More empty argument lists handling:

- Choose
- Concat
- FieldFunction
- Greatest
- Least

This includes:

- [jOOQ/jOOQ#9085] Change the DEFAULT behaviour of CHOOSE
This commit is contained in:
Lukas Eder 2022-11-07 09:21:27 +01:00
parent 1f8df77c13
commit 0daacb3b89
8 changed files with 160 additions and 38 deletions

View File

@ -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 <code>DECODE</code> by removing unreachable clauses.
* <p>
* DECODE clauses can be proven to be unreachable, and thus removed:
* <ul>
* <li><code>DECODE(a, b, 1, c, 2, b, 3)</code> is equivalent to <code>DECODE(a, b, 1, c, 2)</code></li>
* <li><code>DECODE(a, b, 1, c, 2, b, 3, 4)</code> is equivalent to <code>DECODE(a, b, 1, c, 2, 4)</code></li>
* </ul>
* <p>
* 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()));

View File

@ -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<T> extends AbstractField<T> implements QOM.Choose<T> {
private Field<T>[] values;
Choose(Field<Integer> index, Field<T>[] values) {
super(N_CHOOSE, dataType(values));
super(N_CHOOSE, nullSafeDataType(values));
this.index = index;
this.values = values;
}
@SuppressWarnings("unchecked")
private static final <T> DataType<T> dataType(Field<T>[] values) {
return values == null || values.length == 0 ? (DataType<T>) 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<T> extends AbstractField<T> implements QOM.Choose<T> {
default: {
case CUBRID:
case DERBY:
case FIREBIRD:
case H2:
case HSQLDB:
case IGNITE:
case MARIADB:
case MYSQL:
case POSTGRES:
case SQLITE:
case YUGABYTEDB: {
CaseValueStep<Integer> s = choose(index);
CaseWhenStep<Integer, T> 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;
}
}
}

View File

@ -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<String> 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<String>[] cast = castAllIfNeeded(arguments, String.class);
@ -76,12 +85,6 @@ final class Concat extends AbstractField<String> implements QOM.Concat {
}
// If there is only one argument, return it immediately
if (cast.length == 1) {
ctx.visit(cast[0]);
return;
}
ExpressionOperator op = CONCAT;

View File

@ -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<T> extends AbstractField<T> implements QOM.Greatest<T> {
@SuppressWarnings({ "unchecked", "rawtypes" })
Greatest(Field<?>... args) {
super(N_GREATEST, (DataType<T>) Tools.nullSafeDataType(args[0]));
super(N_GREATEST, (DataType<T>) 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;
}

View File

@ -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<T> extends AbstractField<T> implements QOM.Least<T> {
@SuppressWarnings({ "unchecked", "rawtypes" })
Least(Field<?>... args) {
super(N_LEAST, (DataType<T>) Tools.nullSafeDataType(args[0]));
super(N_LEAST, (DataType<T>) 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;
}

View File

@ -2204,6 +2204,22 @@ package org.jooq.impl;

View File

@ -6965,6 +6965,11 @@ final class Tools {
return (DataType<T>) (field == null ? SQLDataType.OTHER : field.getDataType());
}
@SuppressWarnings("unchecked")
static final <T> DataType<T> nullSafeDataType(Field<T>[] values) {
return isEmpty(values) ? (DataType<T>) SQLDataType.OTHER : values[0].getDataType();
}
static final <T> Field<T> nullSafeNotNull(Field<T> field, DataType<?> type) {
return nullableIf(false, nullSafe(field, type));
}

View File

@ -595,7 +595,7 @@ This feature is available in the commercial distribution only.]]></jxb:javadoc><
This feature is available in the commercial distribution only.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="transformPatternsCaseUnreachableClauses" type="boolean" minOccurs="0" maxOccurs="1" default="true">
<element name="transformPatternsUnreachableCaseClauses" type="boolean" minOccurs="0" maxOccurs="1" default="true">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Transform <code>CASE</code> by removing unreachable clauses.
<p>
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.]]></jxb:javadoc></jxb:property></appinfo></annotation>
</element>
<element name="transformPatternsUnreachableDecodeClauses" type="boolean" minOccurs="0" maxOccurs="1" default="true">
<annotation><appinfo><jxb:property><jxb:javadoc><![CDATA[Transform <code>DECODE</code> by removing unreachable clauses.
<p>
DECODE clauses can be proven to be unreachable, and thus removed:
<ul>
<li><code>DECODE(a, b, 1, c, 2, b, 3)</code> is equivalent to <code>DECODE(a, b, 1, c, 2)</code></li>
<li><code>DECODE(a, b, 1, c, 2, b, 3, 4)</code> is equivalent to <code>DECODE(a, b, 1, c, 2, 4)</code></li>
</ul>
<p>
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>