mapping db param to jpa param for stored procedure parameter names + starting to impl cursor support (need testing)

git-svn-id: https://svn.apache.org/repos/asf/openjpa/branches/openjpa_jpa-2.1@1684055 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Romain Manni-Bucau 2015-06-07 18:12:39 +00:00
parent 00c2dd313d
commit 8ebeebda85
8 changed files with 86 additions and 44 deletions

View File

@ -37,7 +37,7 @@ import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -105,7 +105,7 @@ public class StoredProcedureQuery extends AbstractStoreQuery {
}
}
}
return new StoredProcedureQueryExecutor(this, mappings, classes);
return new StoredProcedureQueryExecutor(this, mappings, classes, _meta);
}
public boolean supportsParameterDeclarations() {
@ -128,9 +128,11 @@ public class StoredProcedureQuery extends AbstractStoreQuery {
public class StoredProcedureQueryExecutor extends AbstractExecutor {
private final List<Class<?>> _resultClasses;
private final List<QueryResultMapping> _resultMappings;
private final Map<String, String> _parametersNameMapping = new HashMap<String, String>();
private final Map<String, String> _parametersNameMappingReverse = new HashMap<String, String>();
public StoredProcedureQueryExecutor(StoredProcedureQuery q, List<QueryResultMapping> resultMapping,
List<Class<?>> classes) {
List<Class<?>> classes, MultiQueryMetaData _meta) {
QueryContext ctx = q.getContext();
_resultMappings = resultMapping;
_resultClasses = classes;
@ -140,6 +142,14 @@ public class StoredProcedureQuery extends AbstractStoreQuery {
if (_proc == null) {
throw new RuntimeException("Can not find stored procedure " + procName);
}
for (final Column c : _proc.getColumns()) {
final String name = _meta.getParameters().get(c.getIndex()).getName();
if (name != null) {
final String dbName = c.getIdentifier().getName();
_parametersNameMapping.put(name, dbName);
_parametersNameMappingReverse.put(dbName, name);
}
}
}
StoredProcedure getStoredProcedure(Connection conn, DBDictionary dict, String procedureName) {
@ -167,21 +177,26 @@ public class StoredProcedureQuery extends AbstractStoreQuery {
Connection conn = _store.getConnection();
CallableStatement stmnt = conn.prepareCall(_proc.getCallSQL());
final StoredProcedureQuery spq = StoredProcedureQuery.class.cast(q);
for (Column c : spq.getProcedure().getInColumns()) {
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());
dict.setUnknown(stmnt, index, params[index - 1], c);
}
for (Column c : spq.getProcedure().getOutColumns()) {
stmnt.registerOutParameter(c.getIndex() + 1, c.getType());
Column[] columns = StoredProcedureQuery.class.cast(q).getProcedure().getColumns();
for (final MultiQueryMetaData.Parameter p : _meta.getParameters()) {
final Column column = columns[p.getPosition()];
switch (p.getMode()) {
case IN:
dict.setUnknown(stmnt, p.getPosition() + 1, params[p.getPosition()], column);
break;
case INOUT: // dont break to get the out part as well
dict.setUnknown(stmnt, p.getPosition() + 1, params[p.getPosition()], column);
case OUT:
case CURSOR:
final int index = p.getPosition() + 1;
stmnt.registerOutParameter(index, column.getType());
}
}
JDBCFetchConfiguration fetch = (JDBCFetchConfiguration)q.getContext().getFetchConfiguration();
ResultObjectProvider rop = new XROP(_resultMappings, _resultClasses, _store, fetch, stmnt);
ResultObjectProvider rop = new XROP(
_resultMappings, _resultClasses, _parametersNameMapping,
_store, fetch, stmnt);
rop.open();
return rop;
} catch (Exception e) {
@ -199,7 +214,7 @@ public class StoredProcedureQuery extends AbstractStoreQuery {
storedProcedureQuery.getProcedure().getInColumns(),
storedProcedureQuery.getProcedure().getInOutColumns())) {
for (Column c : columns) {
array[i] = userParams.get(c.getIdentifier().getName());
array[i] = userParams.get(_parametersNameMappingReverse.get(c.getIdentifier().getName()));
if (array[i++] == null) {
userParams.get(c.getIndex());
}

View File

@ -29,6 +29,7 @@ import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
/**
* Gets multiple Result Object Providers each with different mapping.
@ -41,16 +42,18 @@ public class XROP implements BatchedResultObjectProvider {
private final JDBCFetchConfiguration fetch;
private final List<QueryResultMapping> _multi;
private final List<Class<?>> _resultClasses;
private final Map<String, String> _nameMapping;
private int index;
private final JDBCStore store;
// Result of first execution
private boolean executionResult;
public XROP(List<QueryResultMapping> mappings, List<Class<?>> classes,
JDBCStore store, JDBCFetchConfiguration fetch,
Map<String, String> _parametersNameMapping, JDBCStore store, JDBCFetchConfiguration fetch,
CallableStatement stmt) {
_multi = mappings;
_resultClasses = classes;
_nameMapping = _parametersNameMapping;
this.stmt = stmt;
this.fetch = fetch;
this.store = store;
@ -87,6 +90,10 @@ public class XROP implements BatchedResultObjectProvider {
if (rs == null)
return null;
return mapResultSet(rs);
}
private ResultObjectProvider mapResultSet(final ResultSet rs) throws SQLException {
ResultSetResult res = new ResultSetResult(rs, store.getDBDictionary());
res.setCloseConnection(false);
res.setCloseStatement(false);
@ -150,7 +157,7 @@ public class XROP implements BatchedResultObjectProvider {
@Override
public Object getOut(String name) {
try {
return stmt.getObject(name);
return mapIfNeeded(stmt.getObject(_nameMapping.get(name)));
} catch (SQLException e) {
return null;
}
@ -159,12 +166,19 @@ public class XROP implements BatchedResultObjectProvider {
@Override
public Object getOut(int position) {
try {
return stmt.getObject(position);
return mapIfNeeded(stmt.getObject(position));
} catch (SQLException e) {
return null;
}
}
private Object mapIfNeeded(final Object object) throws SQLException {
if (ResultSet.class.isInstance(object)) {
return mapResultSet(ResultSet.class.cast(object));
}
return object;
}
/**
* Throws exception.
*/

View File

@ -18,11 +18,11 @@
*/
package org.apache.openjpa.meta;
import org.apache.openjpa.kernel.QueryLanguages;
import java.util.ArrayList;
import java.util.List;
import org.apache.openjpa.kernel.QueryLanguages;
/**
@ -153,17 +153,10 @@ public class MultiQueryMetaData extends QueryMetaData {
private final Mode mode;
private final int position;
public Parameter(String name, Class<?> type, Mode mode) {
public Parameter(int position, String name, Class<?> type, Mode mode) {
this.name = name;
this.type = type;
this.mode = mode;
this.position = -1;
}
public Parameter(int position, Class<?> type, Mode mode) {
this.name = null;
this.type = type;
this.mode = mode;
this.position = position;
}

View File

@ -58,12 +58,12 @@ public class TestStoredProcedure extends SingleEMFTestCase {
Procedures.inParamsString = null;
EntityManager em = emf.createEntityManager();
exec(em, "CREATE PROCEDURE TESTINS(some_number INTEGER,some_string VARCHAR(255)) " +
exec(em, "CREATE PROCEDURE TESTINS(SOME_NUMBER INTEGER,SOME_STRING VARCHAR(255)) " +
"PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
"'" + Procedures.class.getName() + ".inParams'");
StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.inParams");
procedure.setParameter("SOME_NUMBER", 2015);
procedure.setParameter("SOME_STRING", "openjpa");
procedure.setParameter("some_number", 2015);
procedure.setParameter("some_string", "openjpa");
assertFalse(procedure.execute());
assertEquals(2015, Procedures.inParamsInteger);
assertEquals("openjpa", Procedures.inParamsString);
@ -72,7 +72,7 @@ public class TestStoredProcedure extends SingleEMFTestCase {
Procedures.inParamsInteger = -1;
Procedures.inParamsString = null;
StoredProcedureQuery procedure2 = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.inParams");
procedure2.setParameter("SOME_NUMBER", 20152);
procedure2.setParameter("some_number", 20152);
assertFalse(procedure2.execute());
em.close();
assertEquals(20152, Procedures.inParamsInteger);
@ -81,11 +81,11 @@ public class TestStoredProcedure extends SingleEMFTestCase {
public void testOut() {
EntityManager em = emf.createEntityManager();
exec(em, "CREATE PROCEDURE XTWO(IN some_number INTEGER,OUT x2 INTEGER) " +
exec(em, "CREATE PROCEDURE XTWO(IN SOME_NUMBER INTEGER,OUT x2 INTEGER) " +
"PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
"'" + Procedures.class.getName() + ".x2'");
StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.x2");
procedure.setParameter("SOME_NUMBER", 5);
procedure.setParameter("some_number", 5);
assertFalse(procedure.execute());
// assertEquals(10, procedure.getOutputParameterValue("result")); // not impl by derby
assertEquals(10, procedure.getOutputParameterValue(2));
@ -98,7 +98,7 @@ public class TestStoredProcedure extends SingleEMFTestCase {
"PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
"'" + Procedures.class.getName() + ".inout'");
StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.inout");
procedure.setParameter("P", 5);
procedure.setParameter("p", 5);
assertFalse(procedure.execute());
// assertEquals(10, procedure.getOutputParameterValue("p")); // not impl by derby
assertEquals(10, procedure.getOutputParameterValue(1));

View File

@ -40,24 +40,22 @@ import static javax.persistence.ParameterMode.OUT;
name = "EntityWithStoredProcedure.inParams",
procedureName = "TESTINS",
parameters = {
@StoredProcedureParameter(name = "SOME_NUMBER", type = Integer.class),
@StoredProcedureParameter(name = "SOME_STRING", type = String.class)
@StoredProcedureParameter(name = "some_number", type = Integer.class),
@StoredProcedureParameter(name = "some_string", type = String.class)
}
),
@NamedStoredProcedureQuery(
name = "EntityWithStoredProcedure.x2",
procedureName = "XTWO",
parameters = {
@StoredProcedureParameter(name = "SOME_NUMBER", type = Integer.class),
@StoredProcedureParameter(name = "RESULT", type = Integer.class, mode = OUT)
@StoredProcedureParameter(name = "some_number", type = Integer.class),
@StoredProcedureParameter(name = "result", type = Integer.class, mode = OUT)
}
),
@NamedStoredProcedureQuery(
name = "EntityWithStoredProcedure.inout",
procedureName = "XINOUT",
parameters = {
@StoredProcedureParameter(name = "P ", type = Integer.class, mode = INOUT)
}
parameters = @StoredProcedureParameter(name = "p", type = Integer.class, mode = INOUT)
),
@NamedStoredProcedureQuery(
name = "EntityWithStoredProcedure.mapping",

View File

@ -2216,6 +2216,7 @@ public class AnnotationPersistenceMetaDataParser
StoredProcedureParameter[] params = proc.parameters();
for (StoredProcedureParameter param : params) {
MultiQueryMetaData.Parameter p = new MultiQueryMetaData.Parameter(
meta.getParameterCount(),
param.name(), param.type(), toKernelParameterMode(param.mode()));
meta.registerParameter(p);
}

View File

@ -29,12 +29,18 @@ import org.apache.openjpa.util.UserException;
import java.util.Calendar;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.persistence.*;
import javax.persistence.FlushModeType;
import javax.persistence.LockModeType;
import javax.persistence.NoResultException;
import javax.persistence.NonUniqueResultException;
import javax.persistence.Parameter;
import javax.persistence.ParameterMode;
import javax.persistence.StoredProcedureQuery;
import javax.persistence.TemporalType;
/**
* Implements Store Procedure based query for JPA facade.
@ -61,6 +67,7 @@ public class StoredProcedureQueryImpl implements StoredProcedureQuery {
private final MultiQueryMetaData _meta;
private QueryResultCallback _callback;
private boolean _declaredParams; // mainly a flag for now (null or not)
private Iterator<MultiQueryMetaData.Parameter> cursorIterator;
/**
* Construct a query for executing a Stored Procedure.
@ -133,6 +140,19 @@ public class StoredProcedureQueryImpl implements StoredProcedureQuery {
execute();
try {
Object list = _callback.callback();
if (list == null) { // check if there is a cursor
if (cursorIterator == null) {
cursorIterator = _meta.getParameters().iterator();
}
while (cursorIterator.hasNext()) {
final MultiQueryMetaData.Parameter p = cursorIterator.next();
if (p.getMode() == MultiQueryMetaData.Parameter.Mode.CURSOR) {
list = p.getName() == null ?
getOutputParameterValue(p.getPosition()) : getOutputParameterValue(p.getName());
break;
}
}
}
RuntimeExceptionTranslator trans = PersistenceExceptions
.getRollbackTranslator(_delegate.getEntityManager());
return new DelegatingResultList((ResultList) list, trans);

View File

@ -758,6 +758,7 @@ public class XMLPersistenceMetaDataParser
return false;
}
meta.registerParameter(new MultiQueryMetaData.Parameter(
meta.getParameterCount(),
attrs.getValue("name"), type,
MultiQueryMetaData.Parameter.Mode.valueOf(attrs.getValue("mode"))));
return true;