[jOOQ/jOOQ#14065] More expression repetition avoidance
This includes: - Additional tests to detect repetition - [jOOQ/jOOQ#14066] Split SimpleQueryPart into two, allowing for marking types that are always simple - Turn more QueryPart types into SimpleQueryPart
This commit is contained in:
parent
2449f09b9d
commit
c48dd42de3
@ -112,7 +112,7 @@ import org.jooq.impl.QOM.UEmpty;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class Alias<Q extends QueryPart> extends AbstractQueryPart implements UEmpty {
|
||||
final class Alias<Q extends QueryPart> extends AbstractQueryPart implements UEmpty, SimpleCheckQueryPart {
|
||||
|
||||
private static final Clause[] CLAUSES_TABLE_REFERENCE = { TABLE, TABLE_REFERENCE };
|
||||
private static final Clause[] CLAUSES_TABLE_ALIAS = { TABLE, TABLE_ALIAS };
|
||||
@ -148,6 +148,12 @@ final class Alias<Q extends QueryPart> extends AbstractQueryPart implements UEmp
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isSimple(Context<?> ctx) {
|
||||
return wrapped instanceof Table && !ctx.declareTables()
|
||||
|| wrapped instanceof Field && !ctx.declareFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
|
||||
|
||||
@ -43,20 +43,17 @@ import static org.jooq.impl.Tools.getMappedCatalog;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.jooq.Catalog;
|
||||
import org.jooq.Clause;
|
||||
import org.jooq.Comment;
|
||||
import org.jooq.Context;
|
||||
import org.jooq.Function1;
|
||||
import org.jooq.Name;
|
||||
import org.jooq.Schema;
|
||||
// ...
|
||||
import org.jooq.QueryPart;
|
||||
// ...
|
||||
import org.jooq.Schema;
|
||||
// ...
|
||||
import org.jooq.tools.StringUtils;
|
||||
|
||||
/**
|
||||
@ -67,7 +64,7 @@ import org.jooq.tools.StringUtils;
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@org.jooq.Internal
|
||||
public class CatalogImpl extends AbstractNamed implements Catalog {
|
||||
public class CatalogImpl extends AbstractNamed implements Catalog, SimpleQueryPart {
|
||||
private static final Clause[] CLAUSES = { CATALOG, CATALOG_REFERENCE };
|
||||
static final Catalog DEFAULT_CATALOG = new CatalogImpl("");
|
||||
|
||||
|
||||
@ -79,15 +79,17 @@ final class Decode<T, Z> extends AbstractField<Z> implements UNotYetImplemented
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
if (EMULATE_DISTINCT.contains(ctx.dialect())) {
|
||||
CaseConditionStep<Z> when = DSL.choose().when(field.isNotDistinctFrom(search), result);
|
||||
ctx.visit(Tools.derivedTableIf(ctx, more.length > 1, field, f -> {
|
||||
CaseConditionStep<Z> when = DSL.choose().when(f.isNotDistinctFrom(search), result);
|
||||
|
||||
for (int i = 0; i + 1 < more.length; i += 2)
|
||||
when = when.when(field.isNotDistinctFrom((Field<T>) more[i]), (Field<Z>) more[i + 1]);
|
||||
for (int i = 0; i + 1 < more.length; i += 2)
|
||||
when = when.when(f.isNotDistinctFrom((Field<T>) more[i]), (Field<Z>) more[i + 1]);
|
||||
|
||||
if (more.length % 2 == 0)
|
||||
ctx.visit(when);
|
||||
else
|
||||
ctx.visit(when.otherwise((Field<Z>) more[more.length - 1]));
|
||||
if (more.length % 2 == 0)
|
||||
return when;
|
||||
else
|
||||
return when.otherwise((Field<Z>) more[more.length - 1]);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -51,7 +51,7 @@ import org.jooq.impl.QOM.UEmpty;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class FalseCondition extends AbstractCondition implements False, UEmpty {
|
||||
final class FalseCondition extends AbstractCondition implements False, UEmpty, SimpleQueryPart {
|
||||
|
||||
private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON };
|
||||
static final FalseCondition INSTANCE = new FalseCondition();
|
||||
|
||||
@ -52,7 +52,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class FieldAlias<T> extends AbstractField<T> implements QOM.FieldAlias<T> {
|
||||
final class FieldAlias<T> extends AbstractField<T> implements QOM.FieldAlias<T>, SimpleCheckQueryPart {
|
||||
|
||||
private final Alias<Field<T>> alias;
|
||||
|
||||
@ -62,6 +62,11 @@ final class FieldAlias<T> extends AbstractField<T> implements QOM.FieldAlias<T>
|
||||
this.alias = new Alias<>(field, this, alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isSimple(Context<?> ctx) {
|
||||
return !ctx.declareFields();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void accept(Context<?> ctx) {
|
||||
ctx.visit(alias);
|
||||
|
||||
@ -57,7 +57,7 @@ import org.jooq.impl.QOM.UEmpty;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class NullCondition extends AbstractCondition implements Null, UEmpty {
|
||||
final class NullCondition extends AbstractCondition implements Null, UEmpty, SimpleQueryPart {
|
||||
|
||||
private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON };
|
||||
static final NullCondition INSTANCE = new NullCondition();
|
||||
|
||||
@ -76,7 +76,7 @@ extends
|
||||
AbstractQueryPart
|
||||
implements
|
||||
UnmodifiableCollection<T>,
|
||||
SimpleQueryPart,
|
||||
SimpleCheckQueryPart,
|
||||
SeparatedQueryPart
|
||||
permits
|
||||
|
||||
|
||||
@ -80,7 +80,7 @@ import org.jooq.tools.StringUtils;
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@org.jooq.Internal
|
||||
public class SchemaImpl extends AbstractNamed implements Schema {
|
||||
public class SchemaImpl extends AbstractNamed implements Schema, SimpleQueryPart {
|
||||
|
||||
private static final Clause[] CLAUSES = { SCHEMA, SCHEMA_REFERENCE };
|
||||
static final Schema DEFAULT_SCHEMA = new SchemaImpl("");
|
||||
|
||||
65
jOOQ/src/main/java/org/jooq/impl/SimpleCheckQueryPart.java
Normal file
65
jOOQ/src/main/java/org/jooq/impl/SimpleCheckQueryPart.java
Normal file
@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Other licenses:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Commercial licenses for this work are available. These replace the above
|
||||
* ASL 2.0 and offer limited warranties, support, maintenance, and commercial
|
||||
* database integrations.
|
||||
*
|
||||
* For more information, please visit: http://www.jooq.org/licenses
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.OrderField;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.QueryPartInternal;
|
||||
|
||||
/**
|
||||
* A marker interface for all query parts that are capable of generating
|
||||
* "simple" SQL. This information is used mainly for formatting decisions.
|
||||
* <p>
|
||||
* Unlike {@link SimpleQueryPart}, which marks a {@link QueryPart} that is
|
||||
* unconditionally simple, this allows for checking whether a {@link QueryPart}
|
||||
* is {@link #isSimple(Context)}
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
interface SimpleCheckQueryPart extends QueryPartInternal {
|
||||
|
||||
/**
|
||||
* Whether the {@link QueryPart} really is simple.
|
||||
* <p>
|
||||
* e.g. an {@link OrderField} can be simple if its contents are also simple.
|
||||
*/
|
||||
default boolean isSimple(Context<?> ctx) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -37,25 +37,16 @@
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import org.jooq.Context;
|
||||
import org.jooq.OrderField;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.QueryPartInternal;
|
||||
|
||||
/**
|
||||
* A marker interface for all query parts that are capable of generating
|
||||
* "simple" SQL. This information is used mainly for formatting decisions.
|
||||
* <p>
|
||||
* Unlike {@link SimpleCheckQueryPart}, this is always simple.
|
||||
*
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
interface SimpleQueryPart extends QueryPartInternal {
|
||||
|
||||
/**
|
||||
* Whether the {@link QueryPart} really is simple.
|
||||
* <p>
|
||||
* e.g. an {@link OrderField} can be simple if its contents are also simple.
|
||||
*/
|
||||
default boolean isSimple(Context<?> ctx) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,7 +77,7 @@ import org.jooq.QueryPart;
|
||||
import org.jooq.impl.QOM.NullOrdering;
|
||||
|
||||
|
||||
final class SortFieldImpl<T> extends AbstractQueryPart implements SortField<T>, SimpleQueryPart {
|
||||
final class SortFieldImpl<T> extends AbstractQueryPart implements SortField<T>, SimpleCheckQueryPart {
|
||||
|
||||
// DB2 supports NULLS FIRST/LAST only in OLAP (window) functions
|
||||
private static final Set<SQLDialect> NO_SUPPORT_NULLS = SQLDialect.supportedUntil(CUBRID, MARIADB, MYSQL);
|
||||
|
||||
@ -62,7 +62,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class TableAlias<R extends Record> extends AbstractTable<R> implements QOM.TableAlias<R> {
|
||||
final class TableAlias<R extends Record> extends AbstractTable<R> implements QOM.TableAlias<R>, SimpleCheckQueryPart {
|
||||
|
||||
final Alias<Table<R>> alias;
|
||||
transient FieldsImpl<R> aliasedFields;
|
||||
@ -85,6 +85,11 @@ final class TableAlias<R extends Record> extends AbstractTable<R> implements QOM
|
||||
this.alias = new Alias<>(table, this, alias, fieldAliases, wrapInParentheses);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isSimple(Context<?> ctx) {
|
||||
return !ctx.declareTables();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register fields for this table alias
|
||||
*/
|
||||
|
||||
@ -133,7 +133,7 @@ extends
|
||||
implements
|
||||
ScopeMappable,
|
||||
ScopeNestable,
|
||||
SimpleQueryPart,
|
||||
SimpleCheckQueryPart,
|
||||
UNotYetImplemented
|
||||
{
|
||||
|
||||
|
||||
@ -3721,7 +3721,8 @@ final class Tools {
|
||||
}
|
||||
|
||||
static final boolean isSimple(Context<?> ctx, QueryPart part) {
|
||||
return part instanceof SimpleQueryPart && ((SimpleQueryPart) part).isSimple(ctx);
|
||||
return part instanceof SimpleQueryPart
|
||||
|| part instanceof SimpleCheckQueryPart && ((SimpleCheckQueryPart) part).isSimple(ctx);
|
||||
}
|
||||
|
||||
static final boolean isSimple(Context<?> ctx, QueryPart... parts) {
|
||||
@ -7176,10 +7177,7 @@ final class Tools {
|
||||
Field<T1> f1,
|
||||
Function1<? super Field<T1>, ? extends Field<R>> f
|
||||
) {
|
||||
if (derivedTableEnabled(ctx) && !isSimple(ctx, f1))
|
||||
return DSL.field(select(f.apply(f1.as("f1"))).from(select(f1.as("f1")).asTable("t")));
|
||||
else
|
||||
return f.apply(f1);
|
||||
return derivedTableIf(ctx, true, f1, f);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7192,10 +7190,7 @@ final class Tools {
|
||||
Field<T2> f2,
|
||||
Function2<? super Field<T1>, ? super Field<T2>, ? extends Field<R>> f
|
||||
) {
|
||||
if (derivedTableEnabled(ctx) && !isSimple(ctx, f1) && !isSimple(ctx, f2))
|
||||
return DSL.field(select(f.apply(f1.as("f1"), f2.as("f2"))).from(select(f1.as("f1"), f2.as("f2")).asTable("t")));
|
||||
else
|
||||
return f.apply(f1, f2);
|
||||
return derivedTableIf(ctx, true, f1, f2, f);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -7209,8 +7204,56 @@ final class Tools {
|
||||
Field<T3> f3,
|
||||
Function3<? super Field<T1>, ? super Field<T2>, ? super Field<T3>, ? extends Field<R>> f
|
||||
) {
|
||||
if (derivedTableEnabled(ctx) && !isSimple(ctx, f1) && !isSimple(ctx, f2) && !isSimple(ctx, f3))
|
||||
return DSL.field(select(f.apply(f1.as("f1"), f2.as("f2"), f3.as("f3"))).from(select(f1.as("f1"), f2.as("f2"), f3.as("f3")).asTable("t")));
|
||||
return derivedTableIf(ctx, true, f1, f2, f3, f);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an expression in a derived table to allow for simplifying
|
||||
* referencing it.
|
||||
*/
|
||||
static final <T1, R> Field<R> derivedTableIf(
|
||||
Context<?> ctx,
|
||||
boolean condition,
|
||||
Field<T1> f1,
|
||||
Function1<? super Field<T1>, ? extends Field<R>> f
|
||||
) {
|
||||
if (condition && derivedTableEnabled(ctx) && !isSimple(ctx, f1))
|
||||
return DSL.field(select(f.apply(DSL.field(name("f1"), f1.getDataType()))).from(select(f1.as("f1")).asTable("t")));
|
||||
else
|
||||
return f.apply(f1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap expressions in a derived table to allow for simplifying referencing
|
||||
* them.
|
||||
*/
|
||||
static final <T1, T2, R> Field<R> derivedTableIf(
|
||||
Context<?> ctx,
|
||||
boolean condition,
|
||||
Field<T1> f1,
|
||||
Field<T2> f2,
|
||||
Function2<? super Field<T1>, ? super Field<T2>, ? extends Field<R>> f
|
||||
) {
|
||||
if (condition && derivedTableEnabled(ctx) && !isSimple(ctx, f1) && !isSimple(ctx, f2))
|
||||
return DSL.field(select(f.apply(DSL.field(name("f1"), f1.getDataType()), DSL.field(name("f2"), f2.getDataType()))).from(select(f1.as("f1"), f2.as("f2")).asTable("t")));
|
||||
else
|
||||
return f.apply(f1, f2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap expressions in a derived table to allow for simplifying referencing
|
||||
* them.
|
||||
*/
|
||||
static final <T1, T2, T3, R> Field<R> derivedTableIf(
|
||||
Context<?> ctx,
|
||||
boolean condition,
|
||||
Field<T1> f1,
|
||||
Field<T2> f2,
|
||||
Field<T3> f3,
|
||||
Function3<? super Field<T1>, ? super Field<T2>, ? super Field<T3>, ? extends Field<R>> f
|
||||
) {
|
||||
if (condition && derivedTableEnabled(ctx) && !isSimple(ctx, f1) && !isSimple(ctx, f2) && !isSimple(ctx, f3))
|
||||
return DSL.field(select(f.apply(DSL.field(name("f1"), f1.getDataType()), DSL.field(name("f2"), f2.getDataType()), DSL.field(name("f3"), f3.getDataType()))).from(select(f1.as("f1"), f2.as("f2"), f3.as("f3")).asTable("t")));
|
||||
else
|
||||
return f.apply(f1, f2, f3);
|
||||
}
|
||||
|
||||
@ -71,7 +71,7 @@ import org.jooq.impl.QOM.UEmpty;
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
final class TrueCondition extends AbstractCondition implements True, UEmpty {
|
||||
final class TrueCondition extends AbstractCondition implements True, UEmpty, SimpleQueryPart {
|
||||
|
||||
private static final Clause[] CLAUSES = { CONDITION, CONDITION_COMPARISON };
|
||||
static final TrueCondition INSTANCE = new TrueCondition();
|
||||
|
||||
Loading…
Reference in New Issue
Block a user