Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -186,15 +186,17 @@ public ResultObjectProvider executeQuery(StoreQuery q, Object[] params, Range ra
stmnt = conn.prepareCall(_proc.getCallSQL());

final StoredProcedureQuery spq = (StoredProcedureQuery) q;
// no parameter values at all: leave the (un)binding to the driver
final boolean bind = params != null && params.length > 0;
for (Column c : spq.getProcedure().getInColumns()) {
if (params != null && c.getIndex() < params.length) {
if (bind) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

c.getIndex() < params.length was dropped in 2 code blocks
Are you sure this check is not necessary anymore?

dict.setUnknown(stmnt, c.getIndex() + 1, params[c.getIndex()], c);
}
}
for (Column c : spq.getProcedure().getInOutColumns()) {
final int index = c.getIndex() + 1;
stmnt.registerOutParameter(index, c.getType());
if (params != null && index - 1 < params.length) {
if (bind) {
dict.setUnknown(stmnt, index, params[index - 1], c);
}
}
Expand Down Expand Up @@ -265,21 +267,29 @@ public Object[] toParameterArray(StoreQuery q, Map<?, ?> userParams) {
StoredProcedureQuery storedProcedureQuery = (StoredProcedureQuery) q;
Column[] inCols = storedProcedureQuery.getProcedure().getInColumns();
Column[] inOutCols = storedProcedureQuery.getProcedure().getInOutColumns();
int paramCount = inCols.length + inOutCols.length;
if (paramCount == 0) return NO_PARAM;
if (inCols.length + inOutCols.length == 0) return NO_PARAM;
// the values are indexed by the parameter position, OUT parameters leave a gap
int paramCount = 0;
for (final Column[] columns : asList(inCols, inOutCols)) {
for (Column c : columns) {
paramCount = Math.max(paramCount, c.getIndex() + 1);
}
}
Object[] array = new Object[paramCount];
int i = 0;
for (final Column[] columns : asList(inCols, inOutCols)) {
for (Column c : columns) {
// Try by name first, then by 1-based position (matching user's declaration)
Object val = userParams.get(c.getIdentifier().getName());
if (val == null) {
// Try by name first, then by 1-based position (matching user's declaration).
// An explicit null binding wins over a lookup by position.
String name = c.getIdentifier().getName();
Object val = null;
if (userParams.containsKey(name)) {
val = userParams.get(name);
} else if (userParams.containsKey(c.getIndex() + 1)) {
val = userParams.get(c.getIndex() + 1);
}
if (val == null) {
} else if (userParams.containsKey(c.getIndex())) {
val = userParams.get(c.getIndex());
}
array[i++] = val;
array[c.getIndex()] = val;
}
}
return array;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,67 @@ public void testGetSingleResultNonUniqueResultException() throws Exception {
}
}

/**
* Test that a named parameter explicitly bound to null is not replaced by
* the value registered under the position of that parameter.
*/
public void testExplicitNullNamedParameterWinsOverPosition() throws Exception {
Procedures.inParamsInteger = -1;
Procedures.inParamsString = null;

EntityManager em = emf.createEntityManager();
try {
exec(em, "DROP PROCEDURE TESTINS", true);
exec(em, "CREATE PROCEDURE TESTINS(SOME_NUMBER INTEGER,SOME_STRING VARCHAR(255)) " +
"PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
"'" + Procedures.class.getName() + ".inParams'", false);

StoredProcedureQuery spq = em.createStoredProcedureQuery("TESTINS");
spq.registerStoredProcedureParameter("SOME_NUMBER", Integer.class, ParameterMode.IN);
spq.registerStoredProcedureParameter("SOME_STRING", String.class, ParameterMode.IN);
spq.registerStoredProcedureParameter(2, String.class, ParameterMode.IN);
spq.setParameter("SOME_NUMBER", 42);
spq.setParameter(2, "positional");
spq.setParameter("SOME_STRING", null);
assertFalse(spq.execute());

assertEquals(42, Procedures.inParamsInteger);
assertNull(Procedures.inParamsString);
} finally {
em.close();
}
}

/**
* Test that IN parameters following an OUT parameter are bound at their position.
*/
public void testInParameterAfterOutParameter() throws Exception {
EntityManager em = emf.createEntityManager();
try {
exec(em, "DROP PROCEDURE XSUM", true);
exec(em, "CREATE PROCEDURE XSUM(IN A INTEGER,OUT S INTEGER,IN B INTEGER) " +
"PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
"'" + TestStoredProcedureQueryFixes.class.getName() + ".sum'", false);

StoredProcedureQuery spq = em.createStoredProcedureQuery("XSUM");
spq.registerStoredProcedureParameter(1, Integer.class, ParameterMode.IN);
spq.registerStoredProcedureParameter(2, Integer.class, ParameterMode.OUT);
spq.registerStoredProcedureParameter(3, Integer.class, ParameterMode.IN);
spq.setParameter(1, 3);
spq.setParameter(3, 4);
spq.execute();

assertEquals(7, spq.getOutputParameterValue(2));
} finally {
em.close();
}
}

// Derby stored procedure: s = a + b
public static void sum(int a, int[] s, int b) {
s[0] = a + b;
}

// Derby stored procedure: returns empty result set
public static void emptyResultSet(java.sql.ResultSet[] rs) throws Exception {
java.sql.Connection c = java.sql.DriverManager.getConnection("jdbc:default:connection");
Expand Down
Loading