[#4920] Generated functions without parameter names produce malformed SQL
This commit is contained in:
parent
65db390ee0
commit
153d161e70
@ -3886,6 +3886,7 @@ public class JavaGenerator extends AbstractGenerator {
|
||||
final String paramName = parameter.getName();
|
||||
final String paramComment = StringUtils.defaultString(parameter.getComment());
|
||||
final String isDefaulted = parameter.isDefaulted() ? "true" : "false";
|
||||
final String isUnnamed = parameter.isUnnamed() ? "true" : "false";
|
||||
final List<String> converters = out.ref(list(
|
||||
parameter.getType().getConverter(),
|
||||
parameter.getType().getBinding()
|
||||
@ -3893,8 +3894,8 @@ public class JavaGenerator extends AbstractGenerator {
|
||||
|
||||
out.tab(1).javadoc("The parameter <code>%s</code>.%s", parameter.getQualifiedOutputName(), defaultIfBlank(" " + paramComment, ""));
|
||||
|
||||
out.tab(1).println("val %s : %s[%s] = %s.createParameter(\"%s\", %s, %s[[before=, ][new %s]])",
|
||||
paramId, Parameter.class, paramType, AbstractRoutine.class, paramName, paramTypeRef, isDefaulted, converters);
|
||||
out.tab(1).println("val %s : %s[%s] = %s.createParameter(\"%s\", %s, %s, %s[[before=, ][new %s]])",
|
||||
paramId, Parameter.class, paramType, AbstractRoutine.class, paramName, paramTypeRef, isDefaulted, isUnnamed, converters);
|
||||
}
|
||||
|
||||
out.println("}");
|
||||
@ -3920,6 +3921,7 @@ public class JavaGenerator extends AbstractGenerator {
|
||||
final String paramName = parameter.getName();
|
||||
final String paramComment = StringUtils.defaultString(parameter.getComment());
|
||||
final String isDefaulted = parameter.isDefaulted() ? "true" : "false";
|
||||
final String isUnnamed = parameter.isUnnamed() ? "true" : "false";
|
||||
final List<String> converters = out.ref(list(
|
||||
parameter.getType().getConverter(),
|
||||
parameter.getType().getBinding()
|
||||
@ -3927,8 +3929,8 @@ public class JavaGenerator extends AbstractGenerator {
|
||||
|
||||
out.tab(1).javadoc("The parameter <code>%s</code>.%s", parameter.getQualifiedOutputName(), defaultIfBlank(" " + paramComment, ""));
|
||||
|
||||
out.tab(1).println("public static final %s<%s> %s = createParameter(\"%s\", %s, %s[[before=, ][new %s()]]);",
|
||||
Parameter.class, paramType, paramId, paramName, paramTypeRef, isDefaulted, converters);
|
||||
out.tab(1).println("public static final %s<%s> %s = createParameter(\"%s\", %s, %s, %s[[before=, ][new %s()]]);",
|
||||
Parameter.class, paramType, paramId, paramName, paramTypeRef, isDefaulted, isUnnamed, converters);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -52,19 +52,30 @@ public class DefaultParameterDefinition
|
||||
implements ParameterDefinition {
|
||||
|
||||
private final boolean isDefaulted;
|
||||
private final boolean isUnnamed;
|
||||
|
||||
public DefaultParameterDefinition(RoutineDefinition routine, String name, int position, DataTypeDefinition type) {
|
||||
this(routine, name, position, type, false);
|
||||
this(routine, name, position, type, false, false);
|
||||
}
|
||||
|
||||
public DefaultParameterDefinition(RoutineDefinition routine, String name, int position, DataTypeDefinition type, boolean isDefaulted) {
|
||||
this(routine, name, position, type, isDefaulted, false);
|
||||
}
|
||||
|
||||
public DefaultParameterDefinition(RoutineDefinition routine, String name, int position, DataTypeDefinition type, boolean isDefaulted, boolean isUnnamed) {
|
||||
super(routine, name, position, type, null);
|
||||
|
||||
this.isDefaulted = isDefaulted;
|
||||
this.isUnnamed = isUnnamed;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefaulted() {
|
||||
return isDefaulted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isUnnamed() {
|
||||
return isUnnamed;
|
||||
}
|
||||
}
|
||||
|
||||
@ -55,4 +55,11 @@ public interface ParameterDefinition extends TypedElementDefinition<RoutineDefin
|
||||
* @see Parameter#isDefaulted()
|
||||
*/
|
||||
boolean isDefaulted();
|
||||
|
||||
/**
|
||||
* Whether the parameter has a name.
|
||||
* <p>
|
||||
* @see Parameter#isUnnamed()
|
||||
*/
|
||||
boolean isUnnamed();
|
||||
}
|
||||
|
||||
@ -52,6 +52,7 @@ import java.util.Arrays;
|
||||
|
||||
import org.jooq.Record;
|
||||
import org.jooq.exception.DataAccessException;
|
||||
import org.jooq.tools.StringUtils;
|
||||
import org.jooq.util.AbstractRoutineDefinition;
|
||||
import org.jooq.util.DataTypeDefinition;
|
||||
import org.jooq.util.Database;
|
||||
@ -152,7 +153,8 @@ public class PostgresRoutineDefinition extends AbstractRoutineDefinition {
|
||||
record.getValue(PARAMETERS.PARAMETER_NAME),
|
||||
record.getValue(PARAMETERS.ORDINAL_POSITION),
|
||||
type,
|
||||
record.getValue(PARAMETERS.PARAMETER_DEFAULT) != null
|
||||
record.getValue(PARAMETERS.PARAMETER_DEFAULT) != null,
|
||||
StringUtils.isBlank(record.getValue(PARAMETERS.PARAMETER_NAME))
|
||||
);
|
||||
|
||||
addParameter(InOutDefinition.getFromString(inOut), parameter);
|
||||
|
||||
@ -114,4 +114,13 @@ public interface Parameter<T> extends QueryPart {
|
||||
* Currently, this is only supported for Oracle 11g
|
||||
*/
|
||||
boolean isDefaulted();
|
||||
|
||||
/**
|
||||
* Whether this parameter has a name or not.
|
||||
* <p>
|
||||
* Some databases (e.g. {@link SQLDialect#POSTGRES}) allow for using unnamed
|
||||
* parameters. In this case, {@link #getName()} will return a synthetic name
|
||||
* created from the parameter index.
|
||||
*/
|
||||
boolean isUnnamed();
|
||||
}
|
||||
|
||||
@ -122,6 +122,7 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
private ResultsImpl results;
|
||||
private boolean overloaded;
|
||||
private boolean hasDefaultedParameters;
|
||||
private boolean hasUnnamedParameters;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Call-data attributes (call-specific)
|
||||
@ -736,9 +737,14 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
return hasDefaultedParameters && !inValuesDefaulted.isEmpty();
|
||||
}
|
||||
|
||||
private final boolean hasUnnamedParameters() {
|
||||
return hasUnnamedParameters;
|
||||
}
|
||||
|
||||
private final void addParameter(Parameter<?> parameter) {
|
||||
allParameters.add(parameter);
|
||||
hasDefaultedParameters |= parameter.isDefaulted();
|
||||
hasUnnamedParameters |= parameter.isUnnamed();
|
||||
}
|
||||
|
||||
protected final void addInParameter(Parameter<?> parameter) {
|
||||
@ -811,7 +817,10 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
*
|
||||
* @param name The name of the field (case-sensitive!)
|
||||
* @param type The data type of the field
|
||||
*
|
||||
* @deprecated - Please, re-generate your routine code.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final <T> Parameter<T> createParameter(String name, DataType<T> type) {
|
||||
return createParameter(name, type, false, null, null);
|
||||
}
|
||||
@ -824,7 +833,10 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
* @param type The data type of the field
|
||||
* @param isDefaulted Whether the parameter is defaulted (see
|
||||
* {@link Parameter#isDefaulted()}
|
||||
*
|
||||
* @deprecated - Please, re-generate your routine code.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final <T> Parameter<T> createParameter(String name, DataType<T> type, boolean isDefaulted) {
|
||||
return createParameter(name, type, isDefaulted, null, null);
|
||||
}
|
||||
@ -837,7 +849,10 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
* @param type The data type of the field
|
||||
* @param isDefaulted Whether the parameter is defaulted (see
|
||||
* {@link Parameter#isDefaulted()}
|
||||
*
|
||||
* @deprecated - Please, re-generate your routine code.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final <T, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, Converter<T, U> converter) {
|
||||
return createParameter(name, type, isDefaulted, converter, null);
|
||||
}
|
||||
@ -850,7 +865,10 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
* @param type The data type of the field
|
||||
* @param isDefaulted Whether the parameter is defaulted (see
|
||||
* {@link Parameter#isDefaulted()}
|
||||
*
|
||||
* @deprecated - Please, re-generate your routine code.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final <T, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, Binding<T, U> binding) {
|
||||
return createParameter(name, type, isDefaulted, null, binding);
|
||||
}
|
||||
@ -863,15 +881,78 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
* @param type The data type of the field
|
||||
* @param isDefaulted Whether the parameter is defaulted (see
|
||||
* {@link Parameter#isDefaulted()}
|
||||
*
|
||||
* @deprecated - Please, re-generate your routine code.
|
||||
*/
|
||||
@Deprecated
|
||||
protected static final <T, X, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, Converter<X, U> converter, Binding<T, X> binding) {
|
||||
return createParameter(name, type, isDefaulted, false, converter, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may call this method to create {@link UDTField} objects that
|
||||
* are linked to this table.
|
||||
*
|
||||
* @param name The name of the field (case-sensitive!)
|
||||
* @param type The data type of the field
|
||||
* @param isDefaulted Whether the parameter is defaulted (see
|
||||
* {@link Parameter#isDefaulted()}
|
||||
* @param isUnnamed Whether the parameter is unnamed (see
|
||||
* {@link Parameter#isUnnamed()}.
|
||||
*/
|
||||
protected static final <T> Parameter<T> createParameter(String name, DataType<T> type, boolean isDefaulted, boolean isUnnamed) {
|
||||
return createParameter(name, type, isDefaulted, isUnnamed, null, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may call this method to create {@link UDTField} objects that
|
||||
* are linked to this table.
|
||||
*
|
||||
* @param name The name of the field (case-sensitive!)
|
||||
* @param type The data type of the field
|
||||
* @param isDefaulted Whether the parameter is defaulted (see
|
||||
* {@link Parameter#isDefaulted()}
|
||||
* @param isUnnamed Whether the parameter is unnamed (see
|
||||
* {@link Parameter#isUnnamed()}.
|
||||
*/
|
||||
protected static final <T, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, boolean isUnnamed, Converter<T, U> converter) {
|
||||
return createParameter(name, type, isDefaulted, isUnnamed, converter, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may call this method to create {@link UDTField} objects that
|
||||
* are linked to this table.
|
||||
*
|
||||
* @param name The name of the field (case-sensitive!)
|
||||
* @param type The data type of the field
|
||||
* @param isDefaulted Whether the parameter is defaulted (see
|
||||
* {@link Parameter#isDefaulted()}
|
||||
* @param isUnnamed Whether the parameter is unnamed (see
|
||||
* {@link Parameter#isUnnamed()}.
|
||||
*/
|
||||
protected static final <T, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, boolean isUnnamed, Binding<T, U> binding) {
|
||||
return createParameter(name, type, isDefaulted, isUnnamed, null, binding);
|
||||
}
|
||||
|
||||
/**
|
||||
* Subclasses may call this method to create {@link UDTField} objects that
|
||||
* are linked to this table.
|
||||
*
|
||||
* @param name The name of the field (case-sensitive!)
|
||||
* @param type The data type of the field
|
||||
* @param isDefaulted Whether the parameter is defaulted (see
|
||||
* {@link Parameter#isDefaulted()}
|
||||
* @param isUnnamed Whether the parameter is unnamed (see
|
||||
* {@link Parameter#isUnnamed()}.
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static final <T, X, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, Converter<X, U> converter, Binding<T, X> binding) {
|
||||
protected static final <T, X, U> Parameter<U> createParameter(String name, DataType<T> type, boolean isDefaulted, boolean isUnnamed, Converter<X, U> converter, Binding<T, X> binding) {
|
||||
final Binding<T, U> actualBinding = DefaultBinding.newBinding(converter, type, binding);
|
||||
final DataType<U> actualType = converter == null && binding == null
|
||||
? (DataType<U>) type
|
||||
: type.asConvertedDataType(actualBinding);
|
||||
|
||||
return new ParameterImpl<U>(name, actualType, isDefaulted, actualBinding);
|
||||
return new ParameterImpl<U>(name, actualType, actualBinding, isDefaulted, isUnnamed);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -909,11 +990,22 @@ public abstract class AbstractRoutine<T> extends AbstractQueryPart implements Ro
|
||||
continue;
|
||||
|
||||
// Disambiguate overloaded function signatures
|
||||
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)));
|
||||
if (ctx.family() == POSTGRES) {
|
||||
|
||||
// [#4920] In case there are any unnamed parameters, we mustn't
|
||||
if (hasUnnamedParameters()) {
|
||||
if (isOverloaded())
|
||||
fields.add(getInValues().get(parameter).cast(parameter.getType()));
|
||||
else
|
||||
fields.add(getInValues().get(parameter));
|
||||
}
|
||||
else {
|
||||
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));
|
||||
}
|
||||
|
||||
@ -57,17 +57,19 @@ import org.jooq.tools.StringUtils;
|
||||
*/
|
||||
class ParameterImpl<T> extends AbstractQueryPart implements Parameter<T> {
|
||||
|
||||
private static final long serialVersionUID = -5277225593751085577L;
|
||||
private static final long serialVersionUID = -5277225593751085577L;
|
||||
|
||||
private final String name;
|
||||
private final DataType<T> type;
|
||||
private final boolean isDefaulted;
|
||||
private final String name;
|
||||
private final DataType<T> type;
|
||||
private final boolean isDefaulted;
|
||||
private final boolean isUnnamed;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
ParameterImpl(String name, DataType<T> type, boolean isDefaulted, Binding<?, T> binding) {
|
||||
ParameterImpl(String name, DataType<T> type, Binding<?, T> binding, boolean isDefaulted, boolean isUnnamed) {
|
||||
this.name = name;
|
||||
this.isDefaulted = isDefaulted;
|
||||
this.type = type.asConvertedDataType((Binding<T, T>) binding);
|
||||
this.isDefaulted = isDefaulted;
|
||||
this.isUnnamed = isUnnamed;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -115,6 +117,11 @@ class ParameterImpl<T> extends AbstractQueryPart implements Parameter<T> {
|
||||
return isDefaulted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isUnnamed() {
|
||||
return isUnnamed;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// XXX: Object API
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user