From 5c974675802ad28e7d5fbf6d93e0cf2b854aa3c8 Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Tue, 25 Aug 2020 14:00:53 +0200 Subject: [PATCH] [jOOQ/jOOQ#8353] Fix known limitations of embeddable types - Embeddables in scalar subqueries - [jOOQ/jOOQ#10524] Better use of DataType::isEmbeddable --- .../main/java/org/jooq/impl/AbstractRecord.java | 3 +-- .../java/org/jooq/impl/BetweenCondition.java | 5 +++-- .../java/org/jooq/impl/CompareCondition.java | 5 ++--- jOOQ/src/main/java/org/jooq/impl/CursorImpl.java | 5 +++-- .../java/org/jooq/impl/EmbeddableTableField.java | 9 ++++++--- .../java/org/jooq/impl/FieldMapsForInsert.java | 1 - .../src/main/java/org/jooq/impl/InCondition.java | 3 +-- jOOQ/src/main/java/org/jooq/impl/Internal.java | 4 ++-- .../main/java/org/jooq/impl/IsDistinctFrom.java | 3 +-- jOOQ/src/main/java/org/jooq/impl/IsNull.java | 3 +-- .../jooq/impl/QuantifiedComparisonCondition.java | 3 +-- jOOQ/src/main/java/org/jooq/impl/Tools.java | 16 ++++++++++------ 12 files changed, 31 insertions(+), 29 deletions(-) diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java index 7f758d4660..f1245b0dbc 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractRecord.java @@ -44,7 +44,6 @@ import static org.jooq.impl.Tools.EMPTY_FIELD; import static org.jooq.impl.Tools.converterOrFail; import static org.jooq.impl.Tools.embeddedFields; import static org.jooq.impl.Tools.indexOrFail; -import static org.jooq.impl.Tools.isEmbeddable; import static org.jooq.impl.Tools.resetChangedOnNotNull; import static org.jooq.impl.Tools.settings; import static org.jooq.impl.Tools.ThreadGuard.Guard.RECORD_TOSTRING; @@ -330,7 +329,7 @@ abstract class AbstractRecord extends AbstractStore implements Record { @Override public final void set(Field field, T value) { - if (isEmbeddable(field)) { + if (field.getDataType().isEmbeddable()) { Field[] f = embeddedFields(field); Object[] v = value instanceof EmbeddableRecord ? ((EmbeddableRecord) value).intoArray() diff --git a/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java b/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java index bd0f870fac..a6923adb75 100644 --- a/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/BetweenCondition.java @@ -72,7 +72,6 @@ import static org.jooq.impl.Keywords.K_BETWEEN; import static org.jooq.impl.Keywords.K_NOT; import static org.jooq.impl.Keywords.K_SYMMETRIC; import static org.jooq.impl.Tools.embeddedFields; -import static org.jooq.impl.Tools.isEmbeddable; import java.util.Set; @@ -138,7 +137,9 @@ final class BetweenCondition extends AbstractCondition implements BetweenAndS } private final QueryPartInternal delegate(Configuration configuration) { - if (isEmbeddable(field) && isEmbeddable(minValue) && isEmbeddable(maxValue)) { + if (field.getDataType().isEmbeddable() + && minValue.getDataType().isEmbeddable() + && maxValue.getDataType().isEmbeddable()) { RowN f = row(embeddedFields(field)); RowN min = row(embeddedFields(minValue)); RowN max = row(embeddedFields(maxValue)); diff --git a/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java b/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java index 4171985745..1408c2a0d4 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/CompareCondition.java @@ -80,7 +80,6 @@ import static org.jooq.impl.Keywords.K_ESCAPE; import static org.jooq.impl.Keywords.K_VARCHAR; import static org.jooq.impl.Tools.castIfNeeded; import static org.jooq.impl.Tools.embeddedFields; -import static org.jooq.impl.Tools.isEmbeddable; import java.util.Set; @@ -122,9 +121,9 @@ final class CompareCondition extends AbstractCondition implements LikeEscapeStep @Override public final void accept(Context ctx) { - boolean field1Embeddable = isEmbeddable(field1); + boolean field1Embeddable = field1.getDataType().isEmbeddable(); - if (field1Embeddable && isEmbeddable(field2)) + if (field1Embeddable && field2.getDataType().isEmbeddable()) ctx.visit(row(embeddedFields(field1)).compare(comparator, embeddedFields(field2))); else if (field1Embeddable && field2 instanceof ScalarSubquery) ctx.visit(row(embeddedFields(field1)).compare(comparator, ((ScalarSubquery) field2).query)); diff --git a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java index dc0af246c5..5ca6c0631e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java +++ b/jOOQ/src/main/java/org/jooq/impl/CursorImpl.java @@ -39,6 +39,7 @@ package org.jooq.impl; // ... import static org.jooq.impl.Tools.embeddedFields; +import static org.jooq.impl.Tools.embeddedRecordType; import static org.jooq.impl.Tools.recordFactory; import java.io.InputStream; @@ -1698,9 +1699,9 @@ final class CursorImpl extends AbstractCursor implements Cu // TODO: [#4695] Calculate the correct Record[B] type recordType = RecordImplN.class; } - else if (field instanceof EmbeddableTableField) { + else if (field.getDataType().isEmbeddable()) { nested = embeddedFields(field); - recordType = (Class) ((EmbeddableTableField) field).recordType; + recordType = embeddedRecordType(field); } if (nested != null) { diff --git a/jOOQ/src/main/java/org/jooq/impl/EmbeddableTableField.java b/jOOQ/src/main/java/org/jooq/impl/EmbeddableTableField.java index 47727ec3fe..dba8fd9d1a 100644 --- a/jOOQ/src/main/java/org/jooq/impl/EmbeddableTableField.java +++ b/jOOQ/src/main/java/org/jooq/impl/EmbeddableTableField.java @@ -41,6 +41,7 @@ import static org.jooq.impl.QueryPartListView.wrap; import static org.jooq.impl.Tools.BooleanDataKey.DATA_LIST_ALREADY_INDENTED; import org.jooq.Context; +import org.jooq.EmbeddableRecord; import org.jooq.Name; import org.jooq.Record; import org.jooq.SQLDialect; @@ -50,18 +51,20 @@ import org.jooq.TableField; /** * @author Lukas Eder */ -final class EmbeddableTableField extends AbstractField implements TableField { +final class EmbeddableTableField> +extends AbstractField +implements TableField { /** * Generated UID */ private static final long serialVersionUID = -7105430856294526440L; - final Class recordType; + final Class recordType; final boolean replacesFields; final Table table; final TableField[] fields; - EmbeddableTableField(Name name, Class recordType, boolean replacesFields, Table table, TableField[] fields) { + EmbeddableTableField(Name name, Class recordType, boolean replacesFields, Table table, TableField[] fields) { super(name, new DefaultDataType<>(SQLDialect.DEFAULT, recordType, name.last())); this.recordType = recordType; diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java index beb750d8b4..292371f1e1 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java @@ -49,7 +49,6 @@ import static org.jooq.impl.Keywords.K_VALUES; import static org.jooq.impl.Tools.collect; import static org.jooq.impl.Tools.flatten; import static org.jooq.impl.Tools.flattenCollection; -import static org.jooq.impl.Tools.isEmbeddable; import static org.jooq.impl.Tools.lazy; import static org.jooq.impl.Tools.BooleanDataKey.DATA_EMULATE_BULK_INSERT_RETURNING; diff --git a/jOOQ/src/main/java/org/jooq/impl/InCondition.java b/jOOQ/src/main/java/org/jooq/impl/InCondition.java index 86ac7541d1..a6d15cc05e 100644 --- a/jOOQ/src/main/java/org/jooq/impl/InCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/InCondition.java @@ -79,7 +79,6 @@ import static org.jooq.impl.DSL.trueCondition; import static org.jooq.impl.Keywords.K_AND; import static org.jooq.impl.Keywords.K_OR; import static org.jooq.impl.Tools.embeddedFields; -import static org.jooq.impl.Tools.isEmbeddable; import static org.jooq.tools.StringUtils.defaultIfNull; import java.util.AbstractList; @@ -122,7 +121,7 @@ final class InCondition extends AbstractCondition { @Override public final void accept(Context ctx) { - if (isEmbeddable(field)) + if (field.getDataType().isEmbeddable()) if (comparator == IN) ctx.visit(row(embeddedFields(field)).in(rows())); else diff --git a/jOOQ/src/main/java/org/jooq/impl/Internal.java b/jOOQ/src/main/java/org/jooq/impl/Internal.java index e0c3db76e7..1b0f1f31ec 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Internal.java +++ b/jOOQ/src/main/java/org/jooq/impl/Internal.java @@ -79,7 +79,7 @@ public final class Internal { */ @SafeVarargs @NotNull - public static final TableField createEmbeddable(Name name, Class recordType, Table table, TableField... fields) { + public static final > TableField createEmbeddable(Name name, Class recordType, Table table, TableField... fields) { return createEmbeddable(name, recordType, false, table, fields); } @@ -88,7 +88,7 @@ public final class Internal { */ @SafeVarargs @NotNull - public static final TableField createEmbeddable(Name name, Class recordType, boolean replacesFields, Table table, TableField... fields) { + public static final > TableField createEmbeddable(Name name, Class recordType, boolean replacesFields, Table table, TableField... fields) { return new EmbeddableTableField<>(name, recordType, replacesFields, table, fields); } diff --git a/jOOQ/src/main/java/org/jooq/impl/IsDistinctFrom.java b/jOOQ/src/main/java/org/jooq/impl/IsDistinctFrom.java index a0d19d5686..2d4e6383c9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/IsDistinctFrom.java +++ b/jOOQ/src/main/java/org/jooq/impl/IsDistinctFrom.java @@ -67,7 +67,6 @@ import static org.jooq.impl.DSL.notExists; import static org.jooq.impl.DSL.row; import static org.jooq.impl.DSL.select; import static org.jooq.impl.Tools.embeddedFields; -import static org.jooq.impl.Tools.isEmbeddable; import java.util.Set; @@ -112,7 +111,7 @@ final class IsDistinctFrom extends AbstractCondition { @Override public final void accept(Context ctx) { - if (isEmbeddable(lhs) && isEmbeddable(rhs)) + if (lhs.getDataType().isEmbeddable() && rhs.getDataType().isEmbeddable()) ctx.visit(row(embeddedFields(lhs)).compare(comparator, row(embeddedFields(rhs)))); diff --git a/jOOQ/src/main/java/org/jooq/impl/IsNull.java b/jOOQ/src/main/java/org/jooq/impl/IsNull.java index 1f1ff3ea73..2dd6bfa8b0 100644 --- a/jOOQ/src/main/java/org/jooq/impl/IsNull.java +++ b/jOOQ/src/main/java/org/jooq/impl/IsNull.java @@ -45,7 +45,6 @@ import static org.jooq.impl.DSL.row; import static org.jooq.impl.Keywords.K_IS_NOT_NULL; import static org.jooq.impl.Keywords.K_IS_NULL; import static org.jooq.impl.Tools.embeddedFields; -import static org.jooq.impl.Tools.isEmbeddable; import org.jooq.Clause; import org.jooq.Context; @@ -75,7 +74,7 @@ final class IsNull extends AbstractCondition { @Override public final void accept(Context ctx) { - if (isEmbeddable(field)) + if (field.getDataType().isEmbeddable()) if (isNull) ctx.visit(row(embeddedFields(field)).isNull()); else diff --git a/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java b/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java index 5860efc2ed..943c2b80b9 100644 --- a/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java +++ b/jOOQ/src/main/java/org/jooq/impl/QuantifiedComparisonCondition.java @@ -72,7 +72,6 @@ import static org.jooq.impl.DSL.row; import static org.jooq.impl.DSL.select; import static org.jooq.impl.SQLDataType.VARCHAR; import static org.jooq.impl.Tools.embeddedFields; -import static org.jooq.impl.Tools.isEmbeddable; import static org.jooq.tools.Convert.convert; import java.util.ArrayList; @@ -123,7 +122,7 @@ final class QuantifiedComparisonCondition extends AbstractCondition implements L @Override public final void accept(Context ctx) { - if (isEmbeddable(field)) + if (field.getDataType().isEmbeddable()) ctx.visit(row(embeddedFields(field)).compare(comparator, query)); else accept0(ctx); diff --git a/jOOQ/src/main/java/org/jooq/impl/Tools.java b/jOOQ/src/main/java/org/jooq/impl/Tools.java index 9e94b9dc06..1571ed196f 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Tools.java +++ b/jOOQ/src/main/java/org/jooq/impl/Tools.java @@ -5335,9 +5335,15 @@ final class Tools { return array == null || array.length == 0; } - static final boolean isEmbeddable(Field field) { + @SuppressWarnings("unchecked") + static final Class embeddedRecordType(Field field) { return field instanceof EmbeddableTableField - || field instanceof Val && EmbeddableRecord.class.isAssignableFrom(field.getType()); + ? (Class) ((EmbeddableTableField) field).recordType + : field instanceof Val && ((Val) field).value instanceof EmbeddableRecord + ? ((AbstractRecord) ((Val) field).value).getClass() + : EmbeddableRecord.class.isAssignableFrom(field.getType()) + ? ((Field) field).getType() + : null; } @SuppressWarnings("unchecked") @@ -5346,12 +5352,10 @@ final class Tools { ? ((EmbeddableTableField) field).fields : field instanceof Val && ((Val) field).value instanceof EmbeddableRecord ? ((EmbeddableRecord) ((Val) field).value).valuesRow().fields() - - // It's an embeddable type, but it is null - : field instanceof Val && EmbeddableRecord.class.isAssignableFrom(field.getType()) - ? newInstance((Class>) field.getType()).valuesRow().fields() : field instanceof ScalarSubquery ? embeddedFields((ScalarSubquery) field) + : EmbeddableRecord.class.isAssignableFrom(field.getType()) + ? newInstance(((Field>) field).getType()).valuesRow().fields() : null; }