[#1183] Add support for DEFAULT values in Oracle stored procedure parameters
[#1252] Avoid JDBC escape syntax for stored procedure calls, where this is possible
This commit is contained in:
parent
e823bb6a7f
commit
5c6a588eec
@ -2507,6 +2507,10 @@ public class DefaultGenerator implements Generator {
|
||||
type instanceof TableDefinition ||
|
||||
type instanceof UDTDefinition;
|
||||
|
||||
boolean isDefaulted =
|
||||
column instanceof ParameterDefinition &&
|
||||
((ParameterDefinition) column).isDefaulted();
|
||||
|
||||
if (type instanceof TableDefinition) {
|
||||
if (generateInstanceFields()) {
|
||||
out.print("\tpublic final ");
|
||||
@ -2559,6 +2563,10 @@ public class DefaultGenerator implements Generator {
|
||||
}
|
||||
}
|
||||
|
||||
if (isDefaulted) {
|
||||
out.print(", true");
|
||||
}
|
||||
|
||||
out.println(");");
|
||||
}
|
||||
|
||||
|
||||
@ -46,7 +46,20 @@ public class DefaultParameterDefinition
|
||||
extends AbstractTypedElementDefinition<RoutineDefinition>
|
||||
implements ParameterDefinition {
|
||||
|
||||
private final boolean isDefaulted;
|
||||
|
||||
public DefaultParameterDefinition(RoutineDefinition routine, String name, int position, DataTypeDefinition type) {
|
||||
this(routine, name, position, type, false);
|
||||
}
|
||||
|
||||
public DefaultParameterDefinition(RoutineDefinition routine, String name, int position, DataTypeDefinition type, boolean isDefaulted) {
|
||||
super(routine, name, position, type, null);
|
||||
|
||||
this.isDefaulted = isDefaulted;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDefaulted() {
|
||||
return isDefaulted;
|
||||
}
|
||||
}
|
||||
|
||||
@ -35,6 +35,8 @@
|
||||
*/
|
||||
package org.jooq.util;
|
||||
|
||||
import org.jooq.Parameter;
|
||||
|
||||
/**
|
||||
* An interface defining a parameter of a stored procedure or stored function.
|
||||
*
|
||||
@ -42,4 +44,10 @@ package org.jooq.util;
|
||||
*/
|
||||
public interface ParameterDefinition extends TypedElementDefinition<RoutineDefinition> {
|
||||
|
||||
/**
|
||||
* Whether the parameter has a default value.
|
||||
* <p>
|
||||
* @see Parameter#isDefaulted()
|
||||
*/
|
||||
boolean isDefaulted();
|
||||
}
|
||||
|
||||
@ -76,7 +76,8 @@ public class OracleRoutineDefinition extends AbstractRoutineDefinition {
|
||||
ALL_ARGUMENTS.DATA_PRECISION,
|
||||
ALL_ARGUMENTS.DATA_SCALE,
|
||||
ALL_ARGUMENTS.TYPE_NAME,
|
||||
ALL_ARGUMENTS.POSITION)
|
||||
ALL_ARGUMENTS.POSITION,
|
||||
ALL_ARGUMENTS.DEFAULTED)
|
||||
.from(ALL_ARGUMENTS)
|
||||
.where(ALL_ARGUMENTS.OWNER.equal(getSchema().getName()))
|
||||
.and(ALL_ARGUMENTS.OBJECT_NAME.equal(getName()))
|
||||
@ -116,7 +117,8 @@ public class OracleRoutineDefinition extends AbstractRoutineDefinition {
|
||||
this,
|
||||
name,
|
||||
position,
|
||||
type);
|
||||
type,
|
||||
record.getValue(ALL_ARGUMENTS.DEFAULTED, boolean.class));
|
||||
|
||||
addParameter(inOut, parameter);
|
||||
}
|
||||
|
||||
@ -62,6 +62,8 @@ import org.jooq.UpdatableRecord;
|
||||
import org.jooq.UpdateQuery;
|
||||
import org.jooq.test.BaseTest;
|
||||
import org.jooq.test.jOOQAbstractTest;
|
||||
import org.jooq.tools.reflect.Reflect;
|
||||
import org.jooq.tools.reflect.ReflectException;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@ -220,6 +222,43 @@ extends BaseTest<A, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658, T725
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoredProcedureWithDefaultParameters() {
|
||||
if (cRoutines() == null) {
|
||||
log.info("SKIPPING", "procedure tests with default parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
Reflect pdefault;
|
||||
try {
|
||||
pdefault = Reflect.on(cRoutines().getPackage().getName() + ".routines.PDefault");
|
||||
|
||||
if (!pdefault.field("P_IN_NUMBER").call("isDefaulted").<Boolean>get()) {
|
||||
log.info("SKIPPING", "procedure tests with default parameters");
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (ReflectException e) {
|
||||
log.info("SKIPPING", "procedure tests with default parameters");
|
||||
return;
|
||||
}
|
||||
|
||||
Reflect executedWithDefaults = pdefault.create();
|
||||
executedWithDefaults.call("execute", create());
|
||||
assertEquals(0, executedWithDefaults.call("getPOutNumber").<Number>get().intValue());
|
||||
assertEquals("0", executedWithDefaults.call("getPOutVarchar").get());
|
||||
assertEquals(Date.valueOf("1981-07-10"), executedWithDefaults.call("getPOutDate").get());
|
||||
|
||||
Reflect executedWithoutDefault = pdefault.create();
|
||||
executedWithoutDefault.call("setPInNumber", 123);
|
||||
executedWithoutDefault.call("setPInVarchar", "abc");
|
||||
executedWithoutDefault.call("setPInDate", Date.valueOf("2012-01-01"));
|
||||
executedWithoutDefault.call("execute", create());
|
||||
assertEquals(123, executedWithoutDefault.call("getPOutNumber").<Number>get().intValue());
|
||||
assertEquals("abc", executedWithoutDefault.call("getPOutVarchar").get());
|
||||
assertEquals(Date.valueOf("2012-01-01"), executedWithoutDefault.call("getPOutDate").get());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoredFunctions() throws Exception {
|
||||
if (cRoutines() == null) {
|
||||
|
||||
@ -3,6 +3,7 @@ DROP PROCEDURE p_author_exists/
|
||||
DROP PROCEDURE p_create_author/
|
||||
DROP PROCEDURE p_create_author_by_name/
|
||||
DROP PROCEDURE p391/
|
||||
DROP PROCEDURE p_default/
|
||||
|
||||
DROP FUNCTION f_author_exists/
|
||||
DROP FUNCTION f_one/
|
||||
@ -402,6 +403,21 @@ BEGIN
|
||||
END
|
||||
/
|
||||
|
||||
CREATE PROCEDURE p_default (
|
||||
IN p_in_number INTEGER DEFAULT(0),
|
||||
OUT p_out_number INTEGER,
|
||||
IN p_in_varchar VARCHAR(10) DEFAULT('0'),
|
||||
OUT p_out_varchar VARCHAR(10),
|
||||
IN p_in_date DATE DEFAULT('1981-07-10'),
|
||||
OUT p_out_date DATE
|
||||
) LANGUAGE SQL
|
||||
BEGIN
|
||||
SET p_out_number = p_in_number;
|
||||
SET p_out_varchar = p_in_varchar;
|
||||
SET p_out_date = p_in_date;
|
||||
END
|
||||
/
|
||||
|
||||
CREATE FUNCTION f_author_exists (author_name varchar(50))
|
||||
RETURNS INTEGER
|
||||
LANGUAGE SQL
|
||||
|
||||
@ -227,6 +227,27 @@ public final class Routines {
|
||||
p.execute(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call LUKAS.P_DEFAULT
|
||||
*
|
||||
* @param pInNumber IN parameter
|
||||
* @param pOutNumber OUT parameter
|
||||
* @param pInVarchar IN parameter
|
||||
* @param pOutVarchar OUT parameter
|
||||
* @param pInDate IN parameter
|
||||
* @param pOutDate OUT parameter
|
||||
* @throws org.jooq.exception.DataAccessException if something went wrong executing the query
|
||||
*/
|
||||
public static org.jooq.test.db2.generatedclasses.routines.PDefault pDefault(org.jooq.Configuration configuration, java.lang.Integer pInNumber, java.lang.String pInVarchar, java.sql.Date pInDate) {
|
||||
org.jooq.test.db2.generatedclasses.routines.PDefault p = new org.jooq.test.db2.generatedclasses.routines.PDefault();
|
||||
p.setPInNumber(pInNumber);
|
||||
p.setPInVarchar(pInVarchar);
|
||||
p.setPInDate(pInDate);
|
||||
|
||||
p.execute(configuration);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call LUKAS.P_UNUSED
|
||||
*
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* This class is generated by jOOQ
|
||||
*/
|
||||
package org.jooq.test.db2.generatedclasses.routines;
|
||||
|
||||
/**
|
||||
* This class is generated by jOOQ.
|
||||
*/
|
||||
public class PDefault extends org.jooq.impl.AbstractRoutine<java.lang.Void> {
|
||||
|
||||
private static final long serialVersionUID = -140946464;
|
||||
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.Integer> P_IN_NUMBER = createParameter("P_IN_NUMBER", org.jooq.impl.SQLDataType.INTEGER);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.Integer> P_OUT_NUMBER = createParameter("P_OUT_NUMBER", org.jooq.impl.SQLDataType.INTEGER);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.String> P_IN_VARCHAR = createParameter("P_IN_VARCHAR", org.jooq.impl.SQLDataType.VARCHAR);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.String> P_OUT_VARCHAR = createParameter("P_OUT_VARCHAR", org.jooq.impl.SQLDataType.VARCHAR);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.sql.Date> P_IN_DATE = createParameter("P_IN_DATE", org.jooq.impl.SQLDataType.DATE);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.sql.Date> P_OUT_DATE = createParameter("P_OUT_DATE", org.jooq.impl.SQLDataType.DATE);
|
||||
|
||||
/**
|
||||
* Create a new routine call instance
|
||||
*/
|
||||
public PDefault() {
|
||||
super("P_DEFAULT", org.jooq.test.db2.generatedclasses.Lukas.LUKAS);
|
||||
|
||||
addInParameter(P_IN_NUMBER);
|
||||
addOutParameter(P_OUT_NUMBER);
|
||||
addInParameter(P_IN_VARCHAR);
|
||||
addOutParameter(P_OUT_VARCHAR);
|
||||
addInParameter(P_IN_DATE);
|
||||
addOutParameter(P_OUT_DATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>P_IN_NUMBER</code> parameter to the routine
|
||||
*/
|
||||
public void setPInNumber(java.lang.Integer value) {
|
||||
setValue(P_IN_NUMBER, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>P_IN_VARCHAR</code> parameter to the routine
|
||||
*/
|
||||
public void setPInVarchar(java.lang.String value) {
|
||||
setValue(P_IN_VARCHAR, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>P_IN_DATE</code> parameter to the routine
|
||||
*/
|
||||
public void setPInDate(java.sql.Date value) {
|
||||
setValue(P_IN_DATE, value);
|
||||
}
|
||||
|
||||
public java.lang.Integer getPOutNumber() {
|
||||
return getValue(P_OUT_NUMBER);
|
||||
}
|
||||
|
||||
public java.lang.String getPOutVarchar() {
|
||||
return getValue(P_OUT_VARCHAR);
|
||||
}
|
||||
|
||||
public java.sql.Date getPOutDate() {
|
||||
return getValue(P_OUT_DATE);
|
||||
}
|
||||
}
|
||||
@ -1346,6 +1346,11 @@ public abstract class jOOQAbstractTest<
|
||||
new RoutineAndUDTTests(this).testStoredProcedure();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStoredProcedureWithDefaultParameters() throws Exception {
|
||||
new RoutineAndUDTTests(this).testStoredProcedureWithDefaultParameters();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testArrayTables() throws Exception {
|
||||
new RoutineAndUDTTests(this).testArrayTables();
|
||||
|
||||
@ -53,6 +53,7 @@ DROP PROCEDURE p_tables2/
|
||||
DROP PROCEDURE p_tables3/
|
||||
DROP PROCEDURE p_tables4/
|
||||
DROP PROCEDURE p_many_parameters/
|
||||
DROP PROCEDURE p_default/
|
||||
DROP FUNCTION f_arrays1/
|
||||
DROP FUNCTION f_arrays2/
|
||||
DROP FUNCTION f_arrays3/
|
||||
@ -754,6 +755,22 @@ END p_tables4;
|
||||
/
|
||||
|
||||
|
||||
CREATE OR REPLACE PROCEDURE p_default (
|
||||
p_in_number IN number := 0,
|
||||
p_out_number OUT number,
|
||||
p_in_varchar IN varchar2 := '0',
|
||||
p_out_varchar OUT varchar2,
|
||||
p_in_date IN date := date '1981-07-10',
|
||||
p_out_date OUT date
|
||||
)
|
||||
IS
|
||||
BEGIN
|
||||
p_out_number := p_in_number;
|
||||
p_out_varchar := p_in_varchar;
|
||||
p_out_date := p_in_date;
|
||||
END p_default;
|
||||
/
|
||||
|
||||
CREATE OR REPLACE PROCEDURE p_many_parameters (
|
||||
f000 number, f001 number, f002 number, f003 number, f004 number,
|
||||
f005 number, f006 number, f007 number, f008 number, f009 number,
|
||||
|
||||
@ -784,6 +784,27 @@ public final class Routines {
|
||||
p.execute(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call TEST.P_DEFAULT
|
||||
*
|
||||
* @param pInNumber IN parameter
|
||||
* @param pOutNumber OUT parameter
|
||||
* @param pInVarchar IN parameter
|
||||
* @param pOutVarchar OUT parameter
|
||||
* @param pInDate IN parameter
|
||||
* @param pOutDate OUT parameter
|
||||
* @throws org.jooq.exception.DataAccessException if something went wrong executing the query
|
||||
*/
|
||||
public static org.jooq.test.oracle.generatedclasses.test.routines.PDefault pDefault(org.jooq.Configuration configuration, java.lang.Number pInNumber, java.lang.String pInVarchar, java.sql.Date pInDate) {
|
||||
org.jooq.test.oracle.generatedclasses.test.routines.PDefault p = new org.jooq.test.oracle.generatedclasses.test.routines.PDefault();
|
||||
p.setPInNumber(pInNumber);
|
||||
p.setPInVarchar(pInVarchar);
|
||||
p.setPInDate(pInDate);
|
||||
|
||||
p.execute(configuration);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call TEST.P_ENHANCE_ADDRESS1
|
||||
*
|
||||
|
||||
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* This class is generated by jOOQ
|
||||
*/
|
||||
package org.jooq.test.oracle.generatedclasses.test.routines;
|
||||
|
||||
/**
|
||||
* This class is generated by jOOQ.
|
||||
*/
|
||||
public class PDefault extends org.jooq.impl.AbstractRoutine<java.lang.Void> {
|
||||
|
||||
private static final long serialVersionUID = 1180154706;
|
||||
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.math.BigDecimal> P_IN_NUMBER = createParameter("P_IN_NUMBER", org.jooq.impl.SQLDataType.NUMERIC, true);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.math.BigDecimal> P_OUT_NUMBER = createParameter("P_OUT_NUMBER", org.jooq.impl.SQLDataType.NUMERIC);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.String> P_IN_VARCHAR = createParameter("P_IN_VARCHAR", org.jooq.impl.SQLDataType.VARCHAR, true);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.String> P_OUT_VARCHAR = createParameter("P_OUT_VARCHAR", org.jooq.impl.SQLDataType.VARCHAR);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.sql.Date> P_IN_DATE = createParameter("P_IN_DATE", org.jooq.impl.SQLDataType.DATE, true);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.sql.Date> P_OUT_DATE = createParameter("P_OUT_DATE", org.jooq.impl.SQLDataType.DATE);
|
||||
|
||||
/**
|
||||
* Create a new routine call instance
|
||||
*/
|
||||
public PDefault() {
|
||||
super("P_DEFAULT", org.jooq.test.oracle.generatedclasses.test.Test.TEST);
|
||||
|
||||
addInParameter(P_IN_NUMBER);
|
||||
addOutParameter(P_OUT_NUMBER);
|
||||
addInParameter(P_IN_VARCHAR);
|
||||
addOutParameter(P_OUT_VARCHAR);
|
||||
addInParameter(P_IN_DATE);
|
||||
addOutParameter(P_OUT_DATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>P_IN_NUMBER</code> parameter to the routine
|
||||
*/
|
||||
public void setPInNumber(java.lang.Number value) {
|
||||
setNumber(P_IN_NUMBER, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>P_IN_VARCHAR</code> parameter to the routine
|
||||
*/
|
||||
public void setPInVarchar(java.lang.String value) {
|
||||
setValue(P_IN_VARCHAR, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>P_IN_DATE</code> parameter to the routine
|
||||
*/
|
||||
public void setPInDate(java.sql.Date value) {
|
||||
setValue(P_IN_DATE, value);
|
||||
}
|
||||
|
||||
public java.math.BigDecimal getPOutNumber() {
|
||||
return getValue(P_OUT_NUMBER);
|
||||
}
|
||||
|
||||
public java.lang.String getPOutVarchar() {
|
||||
return getValue(P_OUT_VARCHAR);
|
||||
}
|
||||
|
||||
public java.sql.Date getPOutDate() {
|
||||
return getValue(P_OUT_DATE);
|
||||
}
|
||||
}
|
||||
@ -17,6 +17,7 @@ DROP PROCEDURE p_create_author/
|
||||
DROP PROCEDURE p_create_author_by_name/
|
||||
DROP PROCEDURE p_author_exists/
|
||||
DROP PROCEDURE p391/
|
||||
DROP PROCEDURE p_default/
|
||||
DROP FUNCTION f_many_parameters/
|
||||
DROP FUNCTION f_author_exists/
|
||||
DROP FUNCTION f_one/
|
||||
@ -573,6 +574,21 @@ BEGIN
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE PROCEDURE p_default (
|
||||
@p_in_number INTEGER = 0,
|
||||
@p_out_number INTEGER OUT,
|
||||
@p_in_varchar VARCHAR(10) = '0',
|
||||
@p_out_varchar VARCHAR(10) OUT,
|
||||
@p_in_date DATE = '1981-07-10',
|
||||
@p_out_date DATE OUT
|
||||
) AS
|
||||
BEGIN
|
||||
SET @p_out_number = @p_in_number;
|
||||
SET @p_out_varchar = @p_in_varchar;
|
||||
SET @p_out_date = @p_in_date;
|
||||
END;
|
||||
/
|
||||
|
||||
CREATE FUNCTION f_author_exists (@author_name VARCHAR(50))
|
||||
RETURNS int
|
||||
AS
|
||||
|
||||
@ -206,6 +206,30 @@ public final class Routines {
|
||||
p.execute(configuration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Call dbo.p_default
|
||||
*
|
||||
* @param pInNumber IN parameter
|
||||
* @param pOutNumber IN OUT parameter
|
||||
* @param pInVarchar IN parameter
|
||||
* @param pOutVarchar IN OUT parameter
|
||||
* @param pInDate IN parameter
|
||||
* @param pOutDate IN OUT parameter
|
||||
* @throws org.jooq.exception.DataAccessException if something went wrong executing the query
|
||||
*/
|
||||
public static org.jooq.test.sqlserver.generatedclasses.routines.PDefault pDefault(org.jooq.Configuration configuration, java.lang.Integer pInNumber, java.lang.Integer pOutNumber, java.lang.String pInVarchar, java.lang.String pOutVarchar, java.sql.Date pInDate, java.sql.Date pOutDate) {
|
||||
org.jooq.test.sqlserver.generatedclasses.routines.PDefault p = new org.jooq.test.sqlserver.generatedclasses.routines.PDefault();
|
||||
p.setPInNumber(pInNumber);
|
||||
p.setPOutNumber(pOutNumber);
|
||||
p.setPInVarchar(pInVarchar);
|
||||
p.setPOutVarchar(pOutVarchar);
|
||||
p.setPInDate(pInDate);
|
||||
p.setPOutDate(pOutDate);
|
||||
|
||||
p.execute(configuration);
|
||||
return p;
|
||||
}
|
||||
|
||||
/**
|
||||
* Call dbo.p_unused
|
||||
*
|
||||
|
||||
@ -0,0 +1,111 @@
|
||||
/**
|
||||
* This class is generated by jOOQ
|
||||
*/
|
||||
package org.jooq.test.sqlserver.generatedclasses.routines;
|
||||
|
||||
/**
|
||||
* This class is generated by jOOQ.
|
||||
*/
|
||||
public class PDefault extends org.jooq.impl.AbstractRoutine<java.lang.Void> {
|
||||
|
||||
private static final long serialVersionUID = -401798427;
|
||||
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.Integer> P_IN_NUMBER = createParameter("p_in_number", org.jooq.impl.SQLDataType.INTEGER);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.Integer> P_OUT_NUMBER = createParameter("p_out_number", org.jooq.impl.SQLDataType.INTEGER);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.String> P_IN_VARCHAR = createParameter("p_in_varchar", org.jooq.impl.SQLDataType.VARCHAR);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.lang.String> P_OUT_VARCHAR = createParameter("p_out_varchar", org.jooq.impl.SQLDataType.VARCHAR);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.sql.Date> P_IN_DATE = createParameter("p_in_date", org.jooq.impl.SQLDataType.DATE);
|
||||
|
||||
/**
|
||||
* An uncommented item
|
||||
*/
|
||||
public static final org.jooq.Parameter<java.sql.Date> P_OUT_DATE = createParameter("p_out_date", org.jooq.impl.SQLDataType.DATE);
|
||||
|
||||
/**
|
||||
* Create a new routine call instance
|
||||
*/
|
||||
public PDefault() {
|
||||
super("p_default", org.jooq.test.sqlserver.generatedclasses.Dbo.DBO);
|
||||
|
||||
addInParameter(P_IN_NUMBER);
|
||||
addInOutParameter(P_OUT_NUMBER);
|
||||
addInParameter(P_IN_VARCHAR);
|
||||
addInOutParameter(P_OUT_VARCHAR);
|
||||
addInParameter(P_IN_DATE);
|
||||
addInOutParameter(P_OUT_DATE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>p_in_number</code> parameter to the routine
|
||||
*/
|
||||
public void setPInNumber(java.lang.Integer value) {
|
||||
setValue(P_IN_NUMBER, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>p_out_number</code> parameter to the routine
|
||||
*/
|
||||
public void setPOutNumber(java.lang.Integer value) {
|
||||
setValue(P_OUT_NUMBER, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>p_in_varchar</code> parameter to the routine
|
||||
*/
|
||||
public void setPInVarchar(java.lang.String value) {
|
||||
setValue(P_IN_VARCHAR, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>p_out_varchar</code> parameter to the routine
|
||||
*/
|
||||
public void setPOutVarchar(java.lang.String value) {
|
||||
setValue(P_OUT_VARCHAR, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>p_in_date</code> parameter to the routine
|
||||
*/
|
||||
public void setPInDate(java.sql.Date value) {
|
||||
setValue(P_IN_DATE, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the <code>p_out_date</code> parameter to the routine
|
||||
*/
|
||||
public void setPOutDate(java.sql.Date value) {
|
||||
setValue(P_OUT_DATE, value);
|
||||
}
|
||||
|
||||
public java.lang.Integer getPOutNumber() {
|
||||
return getValue(P_OUT_NUMBER);
|
||||
}
|
||||
|
||||
public java.lang.String getPOutVarchar() {
|
||||
return getValue(P_OUT_VARCHAR);
|
||||
}
|
||||
|
||||
public java.sql.Date getPOutDate() {
|
||||
return getValue(P_OUT_DATE);
|
||||
}
|
||||
}
|
||||
@ -36,6 +36,8 @@
|
||||
|
||||
package org.jooq;
|
||||
|
||||
import static org.jooq.SQLDialect.ORACLE;
|
||||
|
||||
/**
|
||||
* A parameter to a stored procedure or function.
|
||||
*
|
||||
@ -44,4 +46,35 @@ package org.jooq;
|
||||
*/
|
||||
public interface Parameter<T> extends NamedTypeProviderQueryPart<T> {
|
||||
|
||||
/**
|
||||
* Whether this parameter has a default value
|
||||
* <p>
|
||||
* Procedures and functions with defaulted parameters behave slightly
|
||||
* different from ones without defaulted parameters. In PL/SQL and other
|
||||
* procedural languages, it is possible to pass parameters by name,
|
||||
* reordering names and omitting defaulted parameters: <code><pre>
|
||||
* CREATE PROCEDURE MY_PROCEDURE (P_DEFAULTED IN NUMBER := 0
|
||||
* P_MANDATORY IN NUMBER);
|
||||
*
|
||||
* -- The above procedure can be called as such:
|
||||
* BEGIN
|
||||
* -- Assign parameters by index
|
||||
* MY_PROCEDURE(1, 2);
|
||||
*
|
||||
* -- Assign parameters by name
|
||||
* MY_PROCEDURE(P_DEFAULTED => 1,
|
||||
* P_MANDATORY => 2);
|
||||
*
|
||||
* -- Omitting defaulted parameters
|
||||
* MY_PROCEDURE(P_MANDATORY => 2);
|
||||
* END;
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* If a procedure has defaulted parameters, jOOQ binds them by name, rather
|
||||
* than by index.
|
||||
* <p>
|
||||
* Currently, this is only supported for Oracle
|
||||
*/
|
||||
@Support({ ORACLE })
|
||||
boolean isDefaulted();
|
||||
}
|
||||
|
||||
@ -66,8 +66,10 @@ import org.jooq.exception.DataAccessException;
|
||||
* <li>DB2, H2, and HSQLDB don't allow for JDBC escape syntax when calling
|
||||
* functions. Functions must be used in a SELECT statement</li>
|
||||
* <li>H2 only knows functions (without OUT parameters)</li>
|
||||
* <li>Oracle functions may have OUT parameters/li>
|
||||
* <li>Oracle functions may have OUT parameters</li>
|
||||
* <li>Oracle knows functions that mustn't be used in SQL statements</li>
|
||||
* <li>Oracle parameters can have default values (to support this, jOOQ renders
|
||||
* PL/SQL instead of the JDBC escape syntax)</li>
|
||||
* <li>Postgres only knows functions (with all features combined)</li>
|
||||
* <li>The Sybase JDBC driver doesn't handle null values correctly when using
|
||||
* the JDBC escape syntax on functions</li>
|
||||
|
||||
@ -46,8 +46,10 @@ import java.sql.Types;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jooq.ArrayRecord;
|
||||
import org.jooq.Attachable;
|
||||
@ -82,21 +84,30 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
*/
|
||||
private static final long serialVersionUID = 6330037113167106443L;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Meta-data attributes (the same for every call)
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private final Package pkg;
|
||||
private final List<Parameter<?>> allParameters;
|
||||
private final List<Parameter<?>> inParameters;
|
||||
private final List<Parameter<?>> outParameters;
|
||||
private final Map<Parameter<?>, Field<?>> inValues;
|
||||
private final DataType<T> type;
|
||||
private Parameter<T> returnParameter;
|
||||
private boolean overloaded;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Call-data attributes (call-specific)
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
private final Map<Parameter<?>, Field<?>> inValues;
|
||||
private final Set<Parameter<?>> inValuesNonDefaulted;
|
||||
private transient Field<T> function;
|
||||
|
||||
private final AttachableImpl attachable;
|
||||
private final Map<Parameter<?>, Object> results;
|
||||
private final Map<Parameter<?>, Integer> parameterIndexes;
|
||||
|
||||
private Parameter<T> returnParameter;
|
||||
private boolean overloaded;
|
||||
private transient Field<T> function;
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Constructors
|
||||
// ------------------------------------------------------------------------
|
||||
@ -160,6 +171,7 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
this.inParameters = new ArrayList<Parameter<?>>();
|
||||
this.outParameters = new ArrayList<Parameter<?>>();
|
||||
this.inValues = new HashMap<Parameter<?>, Field<?>>();
|
||||
this.inValuesNonDefaulted = new HashSet<Parameter<?>>();
|
||||
this.results = new HashMap<Parameter<?>, Object>();
|
||||
this.type = type;
|
||||
}
|
||||
@ -189,9 +201,10 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
setField(parameter, val(null, parameter.getDataType()));
|
||||
}
|
||||
|
||||
// Add the field to the in-values
|
||||
// [#1183] Add the field to the in-values and mark them as non-defaulted
|
||||
else {
|
||||
inValues.put(parameter, value);
|
||||
inValuesNonDefaulted.add(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
@ -326,6 +339,12 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
@Override
|
||||
public final void bind(BindContext context) {
|
||||
for (Parameter<?> parameter : getParameters()) {
|
||||
|
||||
// [#1183] Skip defaulted parameters
|
||||
if (getInParameters().contains(parameter) && !inValuesNonDefaulted.contains(parameter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int index = context.peekIndex();
|
||||
parameterIndexes.put(parameter, index);
|
||||
|
||||
@ -349,19 +368,17 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
|
||||
@Override
|
||||
public final void toSQL(RenderContext context) {
|
||||
context.sql("{ ");
|
||||
toSQLBegin(context);
|
||||
|
||||
if (getReturnParameter() != null) {
|
||||
context.sql("? = ");
|
||||
toSQLAssign(context);
|
||||
}
|
||||
|
||||
context.sql("call ");
|
||||
toSQLQualifiedName(context);
|
||||
toSQLCall(context);
|
||||
context.sql("(");
|
||||
|
||||
String separator = "";
|
||||
for (Parameter<?> parameter : getParameters()) {
|
||||
context.sql(separator);
|
||||
|
||||
// The return value has already been written
|
||||
if (parameter.equals(getReturnParameter())) {
|
||||
@ -370,7 +387,13 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
|
||||
// OUT and IN OUT parameters are always written as a '?' bind variable
|
||||
else if (getOutParameters().contains(parameter)) {
|
||||
context.sql("?");
|
||||
context.sql(separator);
|
||||
toSQLOutParam(context, parameter);
|
||||
}
|
||||
|
||||
// [#1183] Omit defaulted parameters
|
||||
else if (!inValuesNonDefaulted.contains(parameter)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// IN parameters are rendered normally
|
||||
@ -382,13 +405,97 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
value = value.cast(parameter.getType());
|
||||
}
|
||||
|
||||
context.sql(value);
|
||||
context.sql(separator);
|
||||
toSQLInParam(context, parameter, value);
|
||||
}
|
||||
|
||||
separator = ", ";
|
||||
}
|
||||
|
||||
context.sql(") }");
|
||||
context.sql(")");
|
||||
toSQLEnd(context);
|
||||
}
|
||||
|
||||
private final void toSQLEnd(RenderContext context) {
|
||||
switch (context.getDialect()) {
|
||||
case ORACLE:
|
||||
context.sql(";")
|
||||
.formatIndentEnd()
|
||||
.formatSeparator()
|
||||
.keyword("end;");
|
||||
break;
|
||||
|
||||
default:
|
||||
context.sql(" }");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private final void toSQLBegin(RenderContext context) {
|
||||
switch (context.getDialect()) {
|
||||
case ORACLE:
|
||||
context.keyword("begin")
|
||||
.formatIndentStart()
|
||||
.formatSeparator();
|
||||
break;
|
||||
|
||||
default:
|
||||
context.sql("{ ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private final void toSQLAssign(RenderContext context) {
|
||||
switch (context.getDialect()) {
|
||||
case ORACLE:
|
||||
context.sql("? := ");
|
||||
break;
|
||||
|
||||
default:
|
||||
context.sql("? = ");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private final void toSQLCall(RenderContext context) {
|
||||
switch (context.getDialect()) {
|
||||
case ORACLE:
|
||||
break;
|
||||
|
||||
default:
|
||||
context.sql("call ");
|
||||
break;
|
||||
}
|
||||
|
||||
toSQLQualifiedName(context);
|
||||
}
|
||||
|
||||
private final void toSQLOutParam(RenderContext context, Parameter<?> parameter) {
|
||||
switch (context.getDialect()) {
|
||||
case ORACLE:
|
||||
context.sql(parameter);
|
||||
context.sql(" => ");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
context.sql("?");
|
||||
}
|
||||
|
||||
private final void toSQLInParam(RenderContext context, Parameter<?> parameter, Field<?> value) {
|
||||
switch (context.getDialect()) {
|
||||
case ORACLE:
|
||||
context.sql(parameter);
|
||||
context.sql(" => ");
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
context.sql(value);
|
||||
}
|
||||
|
||||
private final void toSQLQualifiedName(RenderContext context) {
|
||||
@ -407,11 +514,10 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
|
||||
private final void fetchOutParameters(ExecuteContext ctx) throws SQLException {
|
||||
for (Parameter<?> parameter : getParameters()) {
|
||||
int index = parameterIndexes.get(parameter);
|
||||
|
||||
if (parameter.equals(getReturnParameter()) ||
|
||||
getOutParameters().contains(parameter)) {
|
||||
|
||||
int index = parameterIndexes.get(parameter);
|
||||
results.put(parameter, FieldTypeHelper.getFromStatement(ctx, parameter.getType(), index));
|
||||
}
|
||||
}
|
||||
@ -527,6 +633,11 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
|
||||
// IN parameters are initialised with null by default
|
||||
inValues.put(parameter, val(null, parameter.getDataType()));
|
||||
|
||||
// [#1183] non-defaulted parameters are marked as such
|
||||
if (!parameter.isDefaulted()) {
|
||||
inValuesNonDefaulted.add(parameter);
|
||||
}
|
||||
}
|
||||
|
||||
protected final void addInOutParameter(Parameter<?> parameter) {
|
||||
@ -564,7 +675,20 @@ public abstract class AbstractRoutine<T> extends AbstractSchemaProviderQueryPart
|
||||
* @param type The data type of the field
|
||||
*/
|
||||
protected static final <T> Parameter<T> createParameter(String name, DataType<T> type) {
|
||||
return new ParameterImpl<T>(name, type);
|
||||
return createParameter(name, type, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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()}
|
||||
*/
|
||||
protected static final <T> Parameter<T> createParameter(String name, DataType<T> type, boolean isDefaulted) {
|
||||
return new ParameterImpl<T>(name, type, isDefaulted);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -54,8 +54,12 @@ class ParameterImpl<T> extends AbstractNamedTypeProviderQueryPart<T> implements
|
||||
|
||||
private static final long serialVersionUID = -5277225593751085577L;
|
||||
|
||||
ParameterImpl(String name, DataType<T> type) {
|
||||
private final boolean isDefaulted;
|
||||
|
||||
ParameterImpl(String name, DataType<T> type, boolean isDefaulted) {
|
||||
super(name, type);
|
||||
|
||||
this.isDefaulted = isDefaulted;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -70,4 +74,9 @@ class ParameterImpl<T> extends AbstractNamedTypeProviderQueryPart<T> implements
|
||||
public final void toSQL(RenderContext context) {
|
||||
context.literal(getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean isDefaulted() {
|
||||
return isDefaulted;
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user