[jOOQ/jOOQ#14112] Cannot pass null values as arguments for PL/SQL RECORD types

This commit is contained in:
Lukas Eder 2022-10-19 16:40:44 +02:00
parent 35fb3973e6
commit 30568537fd
3 changed files with 46 additions and 26 deletions

View File

@ -1484,6 +1484,11 @@ implements

View File

@ -123,6 +123,7 @@ import static org.jooq.impl.SQLDataType.VARCHAR;
import static org.jooq.impl.Tools.EMPTY_FIELD;
import static org.jooq.impl.Tools.combine;
import static org.jooq.impl.Tools.configuration;
import static org.jooq.impl.Tools.getRecordQualifier;
import static org.jooq.impl.Tools.isEmpty;
import static org.jooq.impl.Tools.map;
import static org.jooq.impl.Tools.mostSpecificArray;
@ -31610,8 +31611,10 @@ public class DSL {
public static <T> Param<T> val(Object value, DataType<T> type) {
// Advanced data types have dedicated constant types
if (value instanceof QualifiedRecord)
return new QualifiedRecordConstant((QualifiedRecord<?>) value);
if (value instanceof QualifiedRecord<?> r)
return new QualifiedRecordConstant(r, r.getQualifier());
else if (value == null && QualifiedRecord.class.isAssignableFrom(type.getType()))
return new QualifiedRecordConstant(null, getRecordQualifier(type));

View File

@ -41,6 +41,7 @@ package org.jooq.impl;
import static org.jooq.conf.ParamType.INLINED;
import static org.jooq.impl.DSL.val;
import static org.jooq.impl.DefaultBinding.DefaultRecordBinding.REQUIRE_RECORD_CAST;
import static org.jooq.impl.Keywords.K_NULL;
import static org.jooq.impl.Keywords.K_ROW;
import static org.jooq.impl.Tools.getMappedUDTName;
@ -48,6 +49,7 @@ import org.jooq.BindContext;
import org.jooq.Context;
import org.jooq.Field;
import org.jooq.QualifiedRecord;
import org.jooq.RecordQualifier;
import org.jooq.RenderContext;
import org.jooq.conf.ParamType;
import org.jooq.exception.SQLDialectNotSupportedException;
@ -58,8 +60,12 @@ import org.jooq.impl.QOM.UNotYetImplemented;
*/
final class QualifiedRecordConstant<R extends QualifiedRecord<R>> extends AbstractParam<R> implements UNotYetImplemented {
QualifiedRecordConstant(R value) {
super(value, value.getQualifier().getDataType());
final RecordQualifier<R> qualifier;
QualifiedRecordConstant(R value, RecordQualifier<R> qualifier) {
super(value, qualifier.getDataType());
this.qualifier = qualifier;
}
@Override
@ -132,34 +138,39 @@ final class QualifiedRecordConstant<R extends QualifiedRecord<R>> extends Abstra
private final void toSQLInline(RenderContext ctx) {
Cast.renderCastIf(ctx,
c -> {
switch (c.family()) {
if (value == null) {
c.visit(K_NULL);
}
else {
switch (c.family()) {
case POSTGRES:
case YUGABYTEDB:
c.visit(K_ROW);
break;
case POSTGRES:
case YUGABYTEDB:
c.visit(K_ROW);
break;
default: {
c.visit(value.getQualifier());
break;
default: {
c.visit(qualifier);
break;
}
}
c.sql('(');
String separator = "";
for (Field<?> field : value.fields()) {
c.sql(separator);
c.visit(val(value.get(field), field));
separator = ", ";
}
c.sql(')');
}
c.sql('(');
String separator = "";
for (Field<?> field : value.fields()) {
c.sql(separator);
c.visit(val(value.get(field), field));
separator = ", ";
}
c.sql(')');
},
// [#13174] Need to cast inline UDT ROW expressions to the UDT type
c -> c.visit(value.getQualifier()),
c -> c.visit(qualifier),
() -> REQUIRE_RECORD_CAST.contains(ctx.dialect())
);
}
@ -198,8 +209,9 @@ final class QualifiedRecordConstant<R extends QualifiedRecord<R>> extends Abstra
// inlined instead: ROW(.., .., ..)
case POSTGRES:
case YUGABYTEDB: {
for (Field<?> field : value.fields())
ctx.visit(val(value.get(field)));
if (value != null)
for (Field<?> field : value.fields())
ctx.visit(val(value.get(field), field.getDataType()));
break;
}