[jOOQ/jOOQ#7863] Fixed binding of %ROWTYPE IN and OUT parameters

Previous commits fixed TABLE OF X%ROWTYPE bindings, but the X%ROWTYPE emulation was not implemented yet. Those can't be bound using ordinary SQLData API, it seems.
This commit is contained in:
Lukas Eder 2021-04-21 15:44:14 +02:00
parent 32c08aafe1
commit d210d5f35d
12 changed files with 45 additions and 39 deletions

View File

@ -84,9 +84,9 @@ import org.jooq.JSONB;
import org.jooq.Name;
import org.jooq.Nullability;
// ...
import org.jooq.QualifiedRecord;
import org.jooq.Result;
import org.jooq.SQLDialect;
import org.jooq.UDTRecord;
import org.jooq.XML;
import org.jooq.tools.Convert;
import org.jooq.types.Interval;
@ -374,7 +374,7 @@ abstract class AbstractDataType<T> extends AbstractNamed implements DataType<T>
else if (EnumType.class.isAssignableFrom(tType))
return Types.VARCHAR;
else if (UDTRecord.class.isAssignableFrom(tType))
else if (QualifiedRecord.class.isAssignableFrom(tType))
return Types.STRUCT;
else if (Result.class.isAssignableFrom(tType)) {
switch (configuration.family()) {
@ -648,7 +648,7 @@ abstract class AbstractDataType<T> extends AbstractNamed implements DataType<T>
@Override
public final boolean isUDT() {
return UDTRecord.class.isAssignableFrom(tType0());
return QualifiedRecord.class.isAssignableFrom(tType0());
}
@Override

View File

@ -54,9 +54,8 @@ import org.jooq.DataType;
import org.jooq.Name;
import org.jooq.Param;
import org.jooq.ParamMode;
import org.jooq.UDTRecord;
import org.jooq.QualifiedRecord;
import org.jooq.conf.ParamType;
import org.jooq.tools.JooqLogger;
import org.jooq.tools.StringUtils;
/**
@ -106,8 +105,8 @@ abstract class AbstractParam<T> extends AbstractParamX<T> implements SimpleQuery
? paramName
// [#3707] Protect value.toString call for certain jOOQ types.
: value instanceof UDTRecord
? ((UDTRecord<?>) value).getUDT().getName()
: value instanceof QualifiedRecord
? ((QualifiedRecord<?>) value).getQualifier().getName()

View File

@ -121,8 +121,10 @@ import org.jooq.Package;
import org.jooq.Param;
import org.jooq.Parameter;
// ...
import org.jooq.QualifiedRecord;
import org.jooq.QueryPart;
import org.jooq.Record;
import org.jooq.RecordQualifier;
import org.jooq.RenderContext;
import org.jooq.Result;
import org.jooq.Results;
@ -132,7 +134,6 @@ import org.jooq.Schema;
import org.jooq.Statement;
import org.jooq.UDT;
import org.jooq.UDTField;
import org.jooq.UDTRecord;
import org.jooq.XMLFormat;
import org.jooq.conf.SettingsTools;
import org.jooq.exception.ControlFlowSignal;
@ -1094,7 +1095,6 @@ public abstract class AbstractRoutine<T> extends AbstractNamed implements Routin
private final void toSQLAssign(RenderContext context) {
@ -1470,6 +1470,16 @@ public abstract class AbstractRoutine<T> extends AbstractNamed implements Routin

View File

@ -129,7 +129,7 @@ final class ArrayTable extends AbstractTable<Record> {
// [#1114] [#7863] VARRAY/TABLE of OBJECT have more than one field
if (Record.class.isAssignableFrom(arrayType)) {
try {
Record record = (Record) arrayType.getConstructor().newInstance();
Record record = (Record) arrayType.getDeclaredConstructor().newInstance();
for (Field<?> f : record.fields())
result.add(DSL.field(name(alias.last(), f.getName()), f.getDataType()));

View File

@ -292,6 +292,7 @@ import org.jooq.Parameter;
import org.jooq.PlainSQL;
import org.jooq.Privilege;
// ...
import org.jooq.QualifiedRecord;
import org.jooq.QuantifiedSelect;
import org.jooq.Queries;
import org.jooq.Query;
@ -26608,15 +26609,14 @@ public class DSL {
public static <T> Param<T> val(Object value, DataType<T> type) {
// Advanced data types have dedicated constant types
if (value instanceof UDTRecord) {
return new UDTConstant((UDTRecord) value);
if (value instanceof QualifiedRecord) {
return new QualifiedRecordConstant((QualifiedRecord<?>) value);
}
// The default behaviour
else {
T converted = type.convert(value);

View File

@ -509,7 +509,7 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
if (QualifiedRecord.class.isAssignableFrom(type)) {
Class<QualifiedRecord<?>> t = (Class<QualifiedRecord<?>>) type;
result.put(getMappedUDTName(configuration, t), t);
QualifiedRecord<?> r = t.getConstructor().newInstance();
QualifiedRecord<?> r = t.getDeclaredConstructor().newInstance();
for (Field<?> field : r.getQualifier().fields())
typeMap(field.getType(), configuration, result);
}
@ -3531,8 +3531,8 @@ public class DefaultBinding<T, U> implements Binding<T, U> {
@Override
final void set0(BindingSetSQLOutputContext<U> ctx, Record value) throws SQLException {
if (value instanceof UDTRecord)
ctx.output().writeObject((UDTRecord<?>) value);
if (value instanceof QualifiedRecord)
ctx.output().writeObject((QualifiedRecord<?>) value);
else
throw new UnsupportedOperationException("Type " + dataType + " is not supported");
}

View File

@ -56,8 +56,8 @@ import org.jooq.ConverterProvider;
import org.jooq.EnumType;
import org.jooq.JSON;
import org.jooq.JSONB;
import org.jooq.QualifiedRecord;
import org.jooq.Record;
import org.jooq.UDTRecord;
import org.jooq.XML;
import org.jooq.exception.DataTypeException;
import org.jooq.tools.Convert;
@ -112,7 +112,7 @@ public final class DefaultConverterProvider implements ConverterProvider, Serial
|| isXML(tWrapper)
|| Record.class.isAssignableFrom(tWrapper)
|| Struct.class.isAssignableFrom(tWrapper) && UDTRecord.class.isAssignableFrom(uWrapper)
|| Struct.class.isAssignableFrom(tWrapper) && QualifiedRecord.class.isAssignableFrom(uWrapper)
) {
return new AbstractConverter<T, U>(tType, uType) {

View File

@ -76,9 +76,8 @@ import org.jooq.EnumType;
import org.jooq.Field;
import org.jooq.Name;
import org.jooq.Nullability;
import org.jooq.QualifiedRecord;
import org.jooq.SQLDialect;
import org.jooq.TableRecord;
import org.jooq.UDTRecord;
import org.jooq.exception.MappingException;
import org.jooq.exception.SQLDialectNotSupportedException;
import org.jooq.types.UByte;
@ -691,12 +690,10 @@ public class DefaultDataType<T> extends AbstractDataTypeX<T> {
// jOOQ data types are handled here
try {
if (UDTRecord.class.isAssignableFrom(type))
return (DataType<T>) ((UDTRecord<?>) type.newInstance()).getUDT().getDataType();
// [#7174] PostgreSQL table records can be function argument types
else if (TableRecord.class.isAssignableFrom(type))
return (DataType<T>) ((TableRecord<?>) type.newInstance()).getTable().getDataType();
if (QualifiedRecord.class.isAssignableFrom(type))
return (DataType<T>) ((QualifiedRecord<?>) type.getDeclaredConstructor().newInstance()).getQualifier().getDataType();

View File

@ -45,20 +45,20 @@ import static org.jooq.impl.Keywords.K_ROW;
import org.jooq.BindContext;
import org.jooq.Context;
import org.jooq.Field;
import org.jooq.QualifiedRecord;
import org.jooq.RenderContext;
import org.jooq.UDTRecord;
import org.jooq.conf.ParamType;
import org.jooq.exception.SQLDialectNotSupportedException;
/**
* @author Lukas Eder
*/
final class UDTConstant<R extends UDTRecord<R>> extends AbstractParam<R> {
final class QualifiedRecordConstant<R extends QualifiedRecord<R>> extends AbstractParam<R> {
private static final long serialVersionUID = 6807729087019209084L;
UDTConstant(R value) {
super(value, value.getUDT().getDataType());
QualifiedRecordConstant(R value) {
super(value, value.getQualifier().getDataType());
}
@Override
@ -136,7 +136,7 @@ final class UDTConstant<R extends UDTRecord<R>> extends AbstractParam<R> {
break;
default: {
ctx.visit(value.getUDT());
ctx.visit(value.getQualifier());
break;
}
}

View File

@ -2981,7 +2981,7 @@ final class Tools {
}
/**
* Map an {@link UDTRecord} according to the configured
* Map an {@link QualifiedRecord} according to the configured
* {@link org.jooq.SchemaMapping}
*/
@SuppressWarnings("unchecked")
@ -2990,7 +2990,7 @@ final class Tools {
}
/**
* Map an {@link UDTRecord} according to the configured
* Map an {@link QualifiedRecord} according to the configured
* {@link org.jooq.SchemaMapping}
*/
static final String getMappedUDTName(Configuration configuration, QualifiedRecord<?> record) {
@ -5615,7 +5615,7 @@ final class Tools {
private static final EmbeddableRecord<?> newInstance(Class<? extends EmbeddableRecord<?>> type) {
try {
return type.getConstructor().newInstance();
return type.getDeclaredConstructor().newInstance();
}
catch (Exception e) {
throw new MappingException("Cannot create EmbeddableRecord type", e);

View File

@ -92,10 +92,10 @@ import org.jooq.EnumType;
import org.jooq.Field;
import org.jooq.JSON;
import org.jooq.JSONB;
import org.jooq.QualifiedRecord;
import org.jooq.Record;
import org.jooq.Result;
import org.jooq.SQLDialect;
import org.jooq.UDTRecord;
import org.jooq.XML;
import org.jooq.exception.DataTypeException;
import org.jooq.impl.IdentityConverter;
@ -197,7 +197,7 @@ public final class Convert {
try {
Class<?> klass = Class.forName("com.fasterxml.jackson.databind.ObjectMapper");
jsonMapper = klass.getConstructor().newInstance();
jsonMapper = klass.getDeclaredConstructor().newInstance();
jsonReadMethod = klass.getMethod("readValue", String.class, Class.class);
log.debug("Jackson is available");
}
@ -207,7 +207,7 @@ public final class Convert {
try {
Class<?> klass = Class.forName("com.google.gson.Gson");
jsonMapper = klass.getConstructor().newInstance();
jsonMapper = klass.getDeclaredConstructor().newInstance();
jsonReadMethod = klass.getMethod("fromJson", String.class, Class.class);
log.debug("Gson is available");
}
@ -1092,9 +1092,9 @@ public final class Convert {
else if (Struct.class.isAssignableFrom(fromClass)) {
Struct struct = (Struct) from;
if (UDTRecord.class.isAssignableFrom(toClass)) {
if (QualifiedRecord.class.isAssignableFrom(toClass)) {
try {
UDTRecord<?> record = ((UDTRecord<?>) toClass.newInstance());
QualifiedRecord<?> record = ((QualifiedRecord<?>) toClass.getDeclaredConstructor().newInstance());
record.from(struct.getAttributes());
return (U) record;
}

View File

@ -263,7 +263,7 @@ public final class MiniJAXB {
}
else if (a != null) {
@SuppressWarnings("unchecked")
XmlAdapter<Object, Object> adapter = a.value().getConstructor().newInstance();
XmlAdapter<Object, Object> adapter = a.value().getDeclaredConstructor().newInstance();
Reflect.on(result).set(childName, adapter.unmarshal(childElement.getTextContent().trim()));
}
else {
@ -438,7 +438,7 @@ public final class MiniJAXB {
// We're assuming that XJC generated objects are all in the same package
Package pkg = klass.getPackage();
try {
T defaults = klass.getConstructor().newInstance();
T defaults = klass.getDeclaredConstructor().newInstance();
for (Method setter : klass.getMethods()) {
if (setter.getName().startsWith("set")) {