[#4254] Add support for default routine parameters in PostgreSQL
This commit is contained in:
parent
92cfc26f2c
commit
37612d24de
@ -110,7 +110,8 @@ public class PostgresRoutineDefinition extends AbstractRoutineDefinition {
|
||||
PARAMETERS.NUMERIC_SCALE,
|
||||
PARAMETERS.UDT_NAME,
|
||||
PARAMETERS.ORDINAL_POSITION,
|
||||
PARAMETERS.PARAMETER_MODE)
|
||||
PARAMETERS.PARAMETER_MODE,
|
||||
PARAMETERS.PARAMETER_DEFAULT)
|
||||
.from(PARAMETERS)
|
||||
.where(PARAMETERS.SPECIFIC_SCHEMA.equal(getSchema().getName()))
|
||||
.and(PARAMETERS.SPECIFIC_NAME.equal(specificName))
|
||||
@ -127,7 +128,7 @@ public class PostgresRoutineDefinition extends AbstractRoutineDefinition {
|
||||
record.getValue(PARAMETERS.NUMERIC_PRECISION),
|
||||
record.getValue(PARAMETERS.NUMERIC_SCALE),
|
||||
null,
|
||||
null,
|
||||
record.getValue(PARAMETERS.PARAMETER_DEFAULT) != null,
|
||||
record.getValue(PARAMETERS.UDT_NAME)
|
||||
);
|
||||
|
||||
@ -135,7 +136,8 @@ public class PostgresRoutineDefinition extends AbstractRoutineDefinition {
|
||||
this,
|
||||
record.getValue(PARAMETERS.PARAMETER_NAME),
|
||||
record.getValue(PARAMETERS.ORDINAL_POSITION),
|
||||
type
|
||||
type,
|
||||
record.getValue(PARAMETERS.PARAMETER_DEFAULT) != null
|
||||
);
|
||||
|
||||
addParameter(InOutDefinition.getFromString(inOut), parameter);
|
||||
|
||||
@ -47,7 +47,9 @@ import static org.jooq.SQLDialect.FIREBIRD;
|
||||
// ...
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
// ...
|
||||
import static org.jooq.impl.DSL.field;
|
||||
import static org.jooq.impl.DSL.function;
|
||||
import static org.jooq.impl.DSL.name;
|
||||
import static org.jooq.impl.DSL.table;
|
||||
import static org.jooq.impl.DSL.using;
|
||||
import static org.jooq.impl.DSL.val;
|
||||
@ -84,6 +86,7 @@ import org.jooq.Record;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.Result;
|
||||
import org.jooq.Routine;
|
||||
import org.jooq.SQLDialect;
|
||||
import org.jooq.Schema;
|
||||
import org.jooq.UDTField;
|
||||
import org.jooq.exception.ControlFlowSignal;
|
||||
@ -263,15 +266,24 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
|
||||
@Override
|
||||
public final int execute() {
|
||||
SQLDialect family = configuration.family();
|
||||
|
||||
results.clear();
|
||||
outValues.clear();
|
||||
|
||||
// [#4254] In PostgreSQL, there are only functions, no procedures. Some
|
||||
// functions cannot be called using a CallableStatement, e.g. those with
|
||||
// DEFAULT parameters
|
||||
if (family == POSTGRES) {
|
||||
return executeSelectFromPOSTGRES();
|
||||
}
|
||||
|
||||
// Procedures (no return value) are always executed as CallableStatement
|
||||
if (type == null) {
|
||||
else if (type == null) {
|
||||
return executeCallableStatement();
|
||||
}
|
||||
else {
|
||||
switch (configuration.dialect().family()) {
|
||||
switch (family) {
|
||||
|
||||
// [#852] Some RDBMS don't allow for using JDBC procedure escape
|
||||
// syntax for functions. Select functions from DUAL instead
|
||||
@ -280,7 +292,7 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
// [#692] HSQLDB cannot SELECT f() FROM [...] when f()
|
||||
// returns a cursor. Instead, SELECT * FROM table(f()) works
|
||||
if (SQLDataType.RESULT.equals(type.getSQLDataType())) {
|
||||
return executeSelectFrom();
|
||||
return executeSelectFromHSQLDB();
|
||||
}
|
||||
|
||||
// Fall through
|
||||
@ -306,13 +318,27 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
}
|
||||
}
|
||||
|
||||
private final int executeSelectFrom() {
|
||||
private final int executeSelectFromHSQLDB() {
|
||||
DSLContext create = create(configuration);
|
||||
Result<?> result = create.selectFrom(table(asField())).fetch();
|
||||
outValues.put(returnParameter, result);
|
||||
return 0;
|
||||
}
|
||||
|
||||
private final int executeSelectFromPOSTGRES() {
|
||||
DSLContext create = create(configuration);
|
||||
Result<?> result = create.select().from("{0}", asField()).fetch();
|
||||
|
||||
int i = 0;
|
||||
|
||||
if (returnParameter != null)
|
||||
outValues.put(returnParameter, returnParameter.getDataType().convert(result.getValue(0, i++)));
|
||||
for (Parameter<?> p : outParameters)
|
||||
outValues.put(p, p.getDataType().convert(result.getValue(0, i++)));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private final int executeSelect() {
|
||||
final Field<T> field = asField();
|
||||
outValues.put(returnParameter, create(configuration).select(field).fetchOne(field));
|
||||
@ -469,15 +495,8 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
|
||||
// IN parameters are rendered normally
|
||||
else {
|
||||
Field<?> value = getInValues().get(parameter);
|
||||
|
||||
// Disambiguate overloaded procedure signatures
|
||||
if (POSTGRES == context.family() && isOverloaded()) {
|
||||
value = value.cast(parameter.getType());
|
||||
}
|
||||
|
||||
context.sql(separator);
|
||||
toSQLInParam(context, parameter, value);
|
||||
toSQLInParam(context, parameter, getInValues().get(parameter));
|
||||
}
|
||||
|
||||
separator = ", ";
|
||||
@ -858,9 +877,16 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
*/
|
||||
private static final long serialVersionUID = -5730297947647252624L;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
RoutineField() {
|
||||
super(AbstractRoutine.this.getName(),
|
||||
AbstractRoutine.this.type);
|
||||
AbstractRoutine.this.type == null
|
||||
|
||||
// [#4254] PostgreSQL may have stored functions that don't
|
||||
// declare an explicit return type. Those function's return
|
||||
// type is in fact a RECORD type, consisting of OUT paramterers
|
||||
? (DataType<T>) SQLDataType.RESULT
|
||||
: AbstractRoutine.this.type);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -868,23 +894,25 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
RenderContext local = create(ctx).renderContext();
|
||||
toSQLQualifiedName(local);
|
||||
|
||||
Field<?>[] array = new Field<?>[getInParameters().size()];
|
||||
List<Field<?>> fields = new ArrayList<Field<?>>();
|
||||
for (Parameter<?> parameter : getInParameters()) {
|
||||
|
||||
int i = 0;
|
||||
for (Parameter<?> p : getInParameters()) {
|
||||
// [#1183] [#3533] Skip defaulted parameters
|
||||
if (inValuesDefaulted.contains(parameter))
|
||||
continue;
|
||||
|
||||
// Disambiguate overloaded function signatures
|
||||
if (POSTGRES == ctx.family() && isOverloaded()) {
|
||||
array[i] = getInValues().get(p).cast(p.getType());
|
||||
}
|
||||
else {
|
||||
array[i] = getInValues().get(p);
|
||||
}
|
||||
|
||||
i++;
|
||||
if (ctx.family() == POSTGRES)
|
||||
if (isOverloaded())
|
||||
fields.add(field("{0} := {1}", name(parameter.getName()), getInValues().get(parameter).cast(parameter.getType())));
|
||||
else
|
||||
fields.add(field("{0} := {1}", name(parameter.getName()), getInValues().get(parameter)));
|
||||
else
|
||||
fields.add(getInValues().get(parameter));
|
||||
}
|
||||
|
||||
Field<T> result = function(local.render(), getDataType(), array);
|
||||
Field<T> result = function(local.render(), getDataType(), fields.toArray(new Field[fields.size()]));
|
||||
|
||||
|
||||
// [#3592] Decrease SQL -> PL/SQL context switches with Oracle Scalar Subquery Caching
|
||||
if (TRUE.equals(settings(ctx.configuration()).isRenderScalarSubqueriesForStoredFunctions())) {
|
||||
|
||||
@ -88,6 +88,13 @@ class FunctionTable<R extends Record> extends AbstractTable<R> {
|
||||
break;
|
||||
}
|
||||
|
||||
// [#4254] This is required to enable using PostgreSQL functions
|
||||
// with defaulted parameters.
|
||||
case POSTGRES: {
|
||||
ctx.visit(function);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
throw new SQLDialectNotSupportedException("FUNCTION TABLE is not supported for " + ctx.configuration().dialect());
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user