diff --git a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java index a476d7da66..6720811f69 100644 --- a/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java +++ b/jOOQ/src/main/java/org/jooq/impl/FieldMapsForInsert.java @@ -99,12 +99,15 @@ import org.jooq.exception.DataTypeException; import org.jooq.impl.AbstractStoreQuery.UnknownField; import org.jooq.impl.QOM.UNotYetImplemented; import org.jooq.impl.Tools.BooleanDataKey; +import org.jooq.impl.Tools.ExtendedDataKey; + /** * @author Lukas Eder */ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImplemented { - static final Set CASTS_NEEDED = SQLDialect.supportedBy(POSTGRES, TRINO, YUGABYTEDB); + static final Set CASTS_NEEDED = SQLDialect.supportedBy(POSTGRES, TRINO, YUGABYTEDB); + static final Set CASTS_NEEDED_FOR_MERGE = SQLDialect.supportedBy(POSTGRES, YUGABYTEDB); final Table table; final Map, Field> empty; @@ -387,9 +390,12 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple Select select = null; Map, List>> v = valuesFlattened(ctx, statementType); + boolean needsCast = CASTS_NEEDED_FOR_MERGE.contains(ctx.dialect()) + && ctx.data(ExtendedDataKey.DATA_INSERT_ON_DUPLICATE_KEY_UPDATE) != null; + for (int i = 0; i < rows; i++) { int row = i; - Select iteration = DSL.select(Tools.map(v.values(), l -> l.get(row))); + Select iteration = DSL.select(Tools.map(v.values(), l -> castNullsIfNeeded(ctx, needsCast, l.get(row)))); if (select == null) select = iteration; @@ -400,6 +406,21 @@ final class FieldMapsForInsert extends AbstractQueryPart implements UNotYetImple return select; } + /** + * [#15412] The SELECT representation of the + * VALUES clause may need some extra casts in some RDBMS, when + * INSERT … ON DUPLICATE KEY UPDATE is emulated using + * MERGE. + */ + final Field castNullsIfNeeded(Context ctx, boolean needsCast, Field f) { + if (needsCast && f instanceof Val val) { + if (val.isInline(ctx) && val.getValue() == null) + return f.cast(f.getDataType()); + } + + return f; + } + final void toSQL92Values(Context ctx) { boolean indent = (values.size() > 1);