mirror of https://github.com/apache/openjpa.git
OPENJPA-2592 OPENJPA-2654 merge JPA-2.1 work originally done by rmannibucau in the openjpa-jpa-2.1 branch
Thanks to Romain for all the hard work! git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@1756850 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
commit
64e9f3868f
|
@ -459,7 +459,7 @@ databaseName=${db.name}
|
|||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -95,7 +95,7 @@
|
|||
<version>4.0.2.GA</version>
|
||||
<scope>test</scope>
|
||||
<exclusions>
|
||||
<!-- force usage of the geronimo-jpa_2.0_spec -->
|
||||
<!-- force usage of the geronimo-jpa_2.1_spec -->
|
||||
<exclusion>
|
||||
<groupId>org.hibernate.java-persistence</groupId>
|
||||
<artifactId>jpa-api</artifactId>
|
||||
|
|
|
@ -32,6 +32,16 @@ public class DummyProvider1 implements PersistenceProvider {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateSchema(PersistenceUnitInfo info, Map map) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateSchema(String persistenceUnitName, Map map) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public EntityManagerFactory createEntityManagerFactory(String s, Map map) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -32,6 +32,16 @@ public class DummyProvider2 implements PersistenceProvider {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateSchema(PersistenceUnitInfo info, Map map) {
|
||||
// no-op
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateSchema(String persistenceUnitName, Map map) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public EntityManagerFactory createEntityManagerFactory(String s, Map map) {
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -46,6 +46,7 @@ public class DBIdentifier extends IdentifierImpl implements Cloneable, Identifie
|
|||
INDEX,
|
||||
FOREIGN_KEY,
|
||||
CONSTANT,
|
||||
PROCEDURE,
|
||||
NULL
|
||||
}
|
||||
|
||||
|
@ -603,6 +604,10 @@ public class DBIdentifier extends IdentifierImpl implements Cloneable, Identifie
|
|||
return newIdentifier(name,id, toUpper, delimit, false);
|
||||
}
|
||||
|
||||
public static DBIdentifier newProcedure(String name) {
|
||||
return newIdentifier(name, DBIdentifierType.PROCEDURE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new identifier (potentially a compound QualifiedDBIdentifier) with the provided
|
||||
* name an type. Optionally, converting the name to upper case and delimiting it.
|
||||
|
|
|
@ -910,6 +910,9 @@ public class JDBCStoreManager implements StoreManager, JDBCStore {
|
|||
if (QueryLanguages.LANG_PREPARED_SQL.equals(language)) {
|
||||
return new PreparedSQLStoreQuery(this);
|
||||
}
|
||||
if (QueryLanguages.LANG_STORED_PROC.equals(language)) {
|
||||
return new StoredProcedureQuery(this);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,212 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.jdbc.kernel;
|
||||
|
||||
import org.apache.openjpa.jdbc.meta.MappingRepository;
|
||||
import org.apache.openjpa.jdbc.meta.QueryResultMapping;
|
||||
import org.apache.openjpa.jdbc.schema.Column;
|
||||
import org.apache.openjpa.jdbc.sql.DBDictionary;
|
||||
import org.apache.openjpa.jdbc.sql.StoredProcedure;
|
||||
import org.apache.openjpa.kernel.AbstractStoreQuery;
|
||||
import org.apache.openjpa.kernel.QueryContext;
|
||||
import org.apache.openjpa.kernel.QueryOperations;
|
||||
import org.apache.openjpa.kernel.StoreQuery;
|
||||
import org.apache.openjpa.lib.rop.ResultObjectProvider;
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.MultiQueryMetaData;
|
||||
import org.apache.openjpa.meta.QueryMetaData;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.Connection;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
/**
|
||||
* Executes a stored procedure.
|
||||
*
|
||||
* @author ppoddar
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class StoredProcedureQuery extends AbstractStoreQuery {
|
||||
private static final Object[] NO_PARAM = new Object[0];
|
||||
|
||||
JDBCStore _store;
|
||||
StoredProcedure _proc;
|
||||
private MultiQueryMetaData _meta;
|
||||
|
||||
public StoredProcedureQuery(JDBCStore store) {
|
||||
_store = store;
|
||||
}
|
||||
|
||||
public int getOperation() {
|
||||
return QueryOperations.OP_SELECT;
|
||||
}
|
||||
|
||||
public StoredProcedure getProcedure() {
|
||||
return _proc;
|
||||
}
|
||||
|
||||
public DBDictionary getDictionary() {
|
||||
return _store.getDBDictionary();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setQuery(Object meta) {
|
||||
if (meta == null || meta instanceof MultiQueryMetaData) {
|
||||
_meta = (MultiQueryMetaData)meta;
|
||||
return true;
|
||||
} else {
|
||||
throw new InternalException("Unknown " + meta);
|
||||
}
|
||||
}
|
||||
|
||||
public Executor newDataStoreExecutor(ClassMetaData meta, boolean subclasses) {
|
||||
List<QueryResultMapping> mappings = null;
|
||||
List<Class<?>> classes = null;
|
||||
if (_meta != null) {
|
||||
List<QueryMetaData> parts = _meta.getComponents();
|
||||
if (parts != null && !parts.isEmpty()) {
|
||||
mappings = new ArrayList<QueryResultMapping>();
|
||||
classes = new ArrayList<Class<?>>();
|
||||
MappingRepository repos = _store.getConfiguration().getMappingRepositoryInstance();
|
||||
for (QueryMetaData part : parts) {
|
||||
QueryResultMapping mapping = repos.getQueryResultMapping(ctx.getResultMappingScope(),
|
||||
part.getResultSetMappingName(),
|
||||
null, true);
|
||||
if (mapping != null) {
|
||||
mappings.add(mapping);
|
||||
}
|
||||
if (part.getResultType() != null) {
|
||||
classes.add(part.getResultType());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return new StoredProcedureQueryExecutor(this, mappings, classes);
|
||||
}
|
||||
|
||||
public boolean supportsParameterDeclarations() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean supportsDataStoreExecution() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean requiresCandidateType() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean requiresParameterDeclarations() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public class StoredProcedureQueryExecutor extends AbstractExecutor {
|
||||
private final List<Class<?>> _resultClasses;
|
||||
private final List<QueryResultMapping> _resultMappings;
|
||||
|
||||
public StoredProcedureQueryExecutor(StoredProcedureQuery q, List<QueryResultMapping> resultMapping,
|
||||
List<Class<?>> classes) {
|
||||
QueryContext ctx = q.getContext();
|
||||
_resultMappings = resultMapping;
|
||||
_resultClasses = classes;
|
||||
// Look for the named Stored Procedure in the database
|
||||
String procName = ctx.getQueryString();
|
||||
_proc = getStoredProcedure(_store.getConnection(), _store.getDBDictionary(), procName);
|
||||
if (_proc == null) {
|
||||
throw new RuntimeException("Can not find stored procedure " + procName);
|
||||
}
|
||||
}
|
||||
|
||||
StoredProcedure getStoredProcedure(Connection conn, DBDictionary dict, String procedureName) {
|
||||
try {
|
||||
StoredProcedure sp = dict.getStoredProcedure(conn.getMetaData(), null, null, procedureName);
|
||||
if (sp != null) {
|
||||
return sp;
|
||||
}
|
||||
} catch (SQLException ex) {
|
||||
throw new RuntimeException(ex);
|
||||
} finally {
|
||||
try {
|
||||
conn.close();
|
||||
} catch (SQLException ex) {
|
||||
|
||||
}
|
||||
}
|
||||
throw new RuntimeException("Procedure [" + procedureName + "] not found");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResultObjectProvider executeQuery(StoreQuery q, Object[] params, Range range) {
|
||||
try {
|
||||
DBDictionary dict = _store.getDBDictionary();
|
||||
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());
|
||||
}
|
||||
|
||||
JDBCFetchConfiguration fetch = (JDBCFetchConfiguration)q.getContext().getFetchConfiguration();
|
||||
ResultObjectProvider rop = new XROP(_resultMappings, _resultClasses, _store, fetch, stmnt);
|
||||
rop.open();
|
||||
return rop;
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object[] toParameterArray(StoreQuery q, Map<?, ?> userParams) {
|
||||
if (userParams == null) return NO_PARAM;
|
||||
Object[] array = new Object[userParams.size()];
|
||||
int i = 0;
|
||||
StoredProcedureQuery storedProcedureQuery = StoredProcedureQuery.class.cast(q);
|
||||
for (final Column[] columns : asList(
|
||||
storedProcedureQuery.getProcedure().getInColumns(),
|
||||
storedProcedureQuery.getProcedure().getInOutColumns())) {
|
||||
for (Column c : columns) {
|
||||
array[i] = userParams.get(c.getIdentifier().getName());
|
||||
if (array[i++] == null) {
|
||||
userParams.get(c.getIndex());
|
||||
}
|
||||
}
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,205 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.jdbc.kernel;
|
||||
|
||||
|
||||
import org.apache.openjpa.jdbc.meta.QueryResultMapping;
|
||||
import org.apache.openjpa.jdbc.sql.ResultSetResult;
|
||||
import org.apache.openjpa.lib.rop.BatchedResultObjectProvider;
|
||||
import org.apache.openjpa.lib.rop.ResultObjectProvider;
|
||||
import org.apache.openjpa.util.InternalException;
|
||||
|
||||
import java.sql.CallableStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Gets multiple Result Object Providers each with different mapping.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class XROP implements BatchedResultObjectProvider {
|
||||
private final CallableStatement stmt;
|
||||
private final JDBCFetchConfiguration fetch;
|
||||
private final List<QueryResultMapping> _multi;
|
||||
private final List<Class<?>> _resultClasses;
|
||||
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,
|
||||
CallableStatement stmt) {
|
||||
_multi = mappings;
|
||||
_resultClasses = classes;
|
||||
this.stmt = stmt;
|
||||
this.fetch = fetch;
|
||||
this.store = store;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does not support random access.
|
||||
*/
|
||||
@Override
|
||||
public boolean supportsRandomAccess() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Opens this provider by executing the underlying Statment.
|
||||
* The result of execution is memorized.
|
||||
*/
|
||||
@Override
|
||||
public void open() throws Exception {
|
||||
executionResult = stmt.execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current result set, wraps it with a {@link ResultSetResult}, then wraps
|
||||
* again with appropriate ROP based on the result set mapping.
|
||||
* <br>
|
||||
* The ResultSet and the associated connection must not be closed.
|
||||
*
|
||||
* @return a provider or null if the underlying statement has no more results.
|
||||
*/
|
||||
@Override
|
||||
public ResultObjectProvider getResultObject() throws Exception {
|
||||
ResultSet rs = stmt.getResultSet();
|
||||
if (rs == null)
|
||||
return null;
|
||||
|
||||
ResultSetResult res = new ResultSetResult(rs, store.getDBDictionary());
|
||||
res.setCloseConnection(false);
|
||||
res.setCloseStatement(false);
|
||||
try {
|
||||
if (_resultClasses != null && _resultClasses.size() > index) {
|
||||
Class<?> mapping = _resultClasses.get(index);
|
||||
if (mapping != null) {
|
||||
return new GenericResultObjectProvider(mapping, store, fetch, res);
|
||||
}
|
||||
}
|
||||
if (_multi != null && _multi.size() > index) {
|
||||
QueryResultMapping mapping = _multi.get(index);
|
||||
if (mapping != null) {
|
||||
return new MappedQueryResultObjectProvider(mapping, store, fetch, res);
|
||||
}
|
||||
}
|
||||
return new SQLProjectionResultObjectProvider(store, fetch, res, null);
|
||||
} finally {
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Closes the underlying statement.
|
||||
*/
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
stmt.close();
|
||||
}
|
||||
|
||||
/**
|
||||
* Affirms if more result sets are available.
|
||||
* <br>
|
||||
* <b.NOTE</b>: The side effect is to advance to the statement's next result.
|
||||
*/
|
||||
public boolean hasMoreResults() {
|
||||
try {
|
||||
return stmt.getMoreResults();
|
||||
} catch (SQLException e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean getExecutionResult() {
|
||||
return executionResult;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the update count, provided the current result of the statement is not a result set.
|
||||
*/
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
try {
|
||||
return stmt.getUpdateCount();
|
||||
} catch (SQLException e) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOut(String name) {
|
||||
try {
|
||||
return stmt.getObject(name);
|
||||
} catch (SQLException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOut(int position) {
|
||||
try {
|
||||
return stmt.getObject(position);
|
||||
} catch (SQLException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws exception.
|
||||
*/
|
||||
@Override
|
||||
public boolean next() throws Exception {
|
||||
throw new InternalException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns false.
|
||||
*/
|
||||
@Override
|
||||
public boolean absolute(int pos) throws Exception {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@code -1}.
|
||||
*/
|
||||
@Override
|
||||
public int size() throws Exception {
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws exception.
|
||||
*/
|
||||
@Override
|
||||
public void reset() throws Exception {
|
||||
throw new InternalException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleCheckedException(Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
|
||||
}
|
|
@ -210,7 +210,7 @@ public class MappingRepository extends MetaDataRepository {
|
|||
* Return the query result mapping for the given name.
|
||||
*/
|
||||
public QueryResultMapping getQueryResultMapping(Class<?> cls, String name, ClassLoader loader, boolean mustExist) {
|
||||
QueryResultMapping res = null;
|
||||
QueryResultMapping res;
|
||||
if (_locking) {
|
||||
synchronized (this) {
|
||||
res = getQueryResultMappingInternal(cls, name, loader);
|
||||
|
@ -232,13 +232,13 @@ public class MappingRepository extends MetaDataRepository {
|
|||
|
||||
// check cache
|
||||
Object key = getQueryResultKey(cls, name);
|
||||
QueryResultMapping res = (QueryResultMapping) _results.get(key);
|
||||
QueryResultMapping res = _results.get(key);
|
||||
if (res != null)
|
||||
return res;
|
||||
|
||||
// get metadata for class, which will find results in metadata file
|
||||
if (cls != null && getMetaData(cls, envLoader, false) != null) {
|
||||
res = (QueryResultMapping) _results.get(key);
|
||||
res = _results.get(key);
|
||||
if (res != null)
|
||||
return res;
|
||||
}
|
||||
|
@ -250,7 +250,7 @@ public class MappingRepository extends MetaDataRepository {
|
|||
.getResultSetMappingScope(name, envLoader);
|
||||
// not in cache; load
|
||||
getMetaDataFactory().load(cls, MODE_META | MODE_MAPPING, envLoader);
|
||||
return (QueryResultMapping) _results.get(key);
|
||||
return _results.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -262,6 +262,7 @@ public class QueryResultMapping
|
|||
private Map<List<MetaDataContext>, ColumnMap> _mappings = null;
|
||||
private Map<List<MetaDataContext>, FetchInfo> _eager = null;
|
||||
private FetchInfo _fetchInfo = null; // for top-level
|
||||
private Collection<String> _constructorParams = null;
|
||||
|
||||
/**
|
||||
* Supply candidate type on construction.
|
||||
|
@ -546,6 +547,13 @@ public class QueryResultMapping
|
|||
info.excludes.clear(fm.getIndex());
|
||||
}
|
||||
}
|
||||
|
||||
public void addConstructorParam(final String name) {
|
||||
if (_constructorParams == null) {
|
||||
_constructorParams = new ArrayList<String>();
|
||||
}
|
||||
_constructorParams.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -63,6 +63,9 @@ public class Column
|
|||
private DBIdentifier _typeName = DBIdentifier.NULL;
|
||||
private int _javaType = JavaTypes.OBJECT;
|
||||
private int _size = 0;
|
||||
private int _precision = -1;
|
||||
private int _scale = -1;
|
||||
private int _radix = 10;
|
||||
private int _decimals = 0;
|
||||
private String _defaultStr = null;
|
||||
private Object _default = null;
|
||||
|
@ -378,6 +381,29 @@ public class Column
|
|||
_decimals = digits;
|
||||
}
|
||||
|
||||
public int getPrecision() {
|
||||
return _precision;
|
||||
}
|
||||
|
||||
public void setPrecision(int p) {
|
||||
_precision = p;
|
||||
}
|
||||
|
||||
public int getScale() {
|
||||
return _scale;
|
||||
}
|
||||
|
||||
public void setScale(int s) {
|
||||
_scale = s;
|
||||
}
|
||||
public int getRadix() {
|
||||
return _radix;
|
||||
}
|
||||
|
||||
public void setRadix(int r) {
|
||||
_radix = r;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the default value set for the column, if any.
|
||||
*/
|
||||
|
@ -492,6 +518,22 @@ public class Column
|
|||
return _notNull != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets nullability of this receiver by the given flag.
|
||||
* @param flag one of the JDBC nullability flag namely
|
||||
* <LI> {@link DatabaseMetaData#columnNullableUnknown} : not known if the column can be set to null value
|
||||
* <LI> {@link DatabaseMetaData#columnNullable} : the column can be set to null value
|
||||
* <LI> {@link DatabaseMetaData#columnNoNulls} : the column can not be set to null value
|
||||
*/
|
||||
public void setNullability(short flag) {
|
||||
switch (flag) {
|
||||
case DatabaseMetaData.columnNullableUnknown : _notNull = null; break;
|
||||
case DatabaseMetaData.columnNullable : _notNull = false; break;
|
||||
case DatabaseMetaData.columnNoNulls : _notNull = true; break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether this column is auto-assigned a value on insert.
|
||||
*/
|
||||
|
@ -611,7 +653,7 @@ public class Column
|
|||
/**
|
||||
* Set the column's 0-based index in the owning table.
|
||||
*/
|
||||
void setIndex(int index) {
|
||||
public void setIndex(int index) {
|
||||
_index = index;
|
||||
}
|
||||
|
||||
|
|
|
@ -60,6 +60,7 @@ import java.util.List;
|
|||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
|
||||
import javax.sql.DataSource;
|
||||
|
||||
|
@ -4704,6 +4705,47 @@ public class DBDictionary
|
|||
return toDBName(namingUtil.getGeneratedKeySequenceName(col, maxAutoAssignNameLength));
|
||||
}
|
||||
|
||||
protected Map<String, StoredProcedure> _procs = new TreeMap<String, StoredProcedure>();
|
||||
|
||||
/**
|
||||
* Gets the metadata of the stored procedure by the given name either from the cached version or
|
||||
* by enquiring the database.
|
||||
* @param meta the database meta data
|
||||
* @param catalog the catalog name or null
|
||||
* @param schema the schema name or null
|
||||
* @param procedure the procedure name
|
||||
* @return metadata about the named procedure or null
|
||||
* @throws SQLException when metadata query goes wrong
|
||||
*/
|
||||
public StoredProcedure getStoredProcedure(DatabaseMetaData meta, DBIdentifier catalog, DBIdentifier schema,
|
||||
String procedure) throws SQLException {
|
||||
if (_procs.containsKey(procedure)) {
|
||||
return _procs.get(procedure);
|
||||
}
|
||||
ResultSet rs = meta.getProcedureColumns(
|
||||
getCatalogNameForMetadata(catalog),
|
||||
getSchemaNameForMetadata(schema),
|
||||
procedure,
|
||||
null);
|
||||
StoredProcedure sp = null;
|
||||
if (rs.next()) {
|
||||
sp = new StoredProcedure(rs);
|
||||
} else {
|
||||
ResultSet rsExist = meta.getProcedures(
|
||||
getCatalogNameForMetadata(catalog),
|
||||
getSchemaNameForMetadata(schema),
|
||||
procedure);
|
||||
if (rsExist.next()) {
|
||||
sp = new StoredProcedure((String) null);
|
||||
sp.setCatalog(catalog);
|
||||
sp.setSchema(schema);
|
||||
sp.setName(procedure);
|
||||
}
|
||||
}
|
||||
_procs.put(procedure, sp);
|
||||
return sp;
|
||||
}
|
||||
|
||||
///////////////////////////////
|
||||
// Configurable implementation
|
||||
///////////////////////////////
|
||||
|
|
|
@ -59,6 +59,7 @@ public class ResultSetResult
|
|||
private final Statement _stmnt;
|
||||
private final ResultSet _rs;
|
||||
private final DBDictionary _dict;
|
||||
private boolean _closeStatement = true;
|
||||
private boolean _closeConn = true;
|
||||
private int _row = -1;
|
||||
private int _size = -1;
|
||||
|
@ -178,13 +179,17 @@ public class ResultSetResult
|
|||
_closeConn = closeConn;
|
||||
}
|
||||
|
||||
public void setCloseStatement(boolean closeStatement) {
|
||||
_closeStatement = closeStatement;
|
||||
}
|
||||
|
||||
public void close() {
|
||||
super.close();
|
||||
try {
|
||||
_rs.close();
|
||||
} catch (SQLException se) {
|
||||
}
|
||||
if (_stmnt != null)
|
||||
if (_stmnt != null && _closeStatement)
|
||||
try {
|
||||
_stmnt.close();
|
||||
} catch (SQLException se) {
|
||||
|
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.jdbc.sql;
|
||||
|
||||
import org.apache.openjpa.jdbc.identifier.DBIdentifier;
|
||||
import org.apache.openjpa.jdbc.schema.Column;
|
||||
import org.apache.openjpa.jdbc.schema.Schemas;
|
||||
import org.apache.openjpa.meta.MultiQueryMetaData;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.sql.DatabaseMetaData;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Holds metadata about a Database Stored Procedure.
|
||||
* This is different than {@link MultiQueryMetaData} which holds the metadata
|
||||
* about what the user has specified.
|
||||
* <br>
|
||||
* An instance of this class can be constructed either by reading from database meta data
|
||||
* or by programatic assignment. If an instance if created programmatically, then
|
||||
* its SQL body or parameters can be added.
|
||||
* <br>
|
||||
* This class can generate the SQL statement to create, drop or delete this procedure.
|
||||
*
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public class StoredProcedure {
|
||||
private DBIdentifier _catalog;
|
||||
private DBIdentifier _schema;
|
||||
private DBIdentifier _name;
|
||||
private List<Column> _cols = new ArrayList<Column>();
|
||||
private List<String> _params = new ArrayList<String>();
|
||||
|
||||
|
||||
private List<String> _sql = new ArrayList<String>();
|
||||
private final boolean _fromDatabase;
|
||||
|
||||
/**
|
||||
* An enumeration on type of parameter for a Stored Procedure.
|
||||
* The enumerted values has the same ordinal numbers as found
|
||||
* in corresponding integer values in {@link DatabaseMetaData}.
|
||||
*/
|
||||
public enum PARAM {UNKNOW, IN, INOUT, RESULT, OUT, RETURN}
|
||||
|
||||
public enum SQL {NONE,MODIFY,READ, CONTAINS};
|
||||
|
||||
/**
|
||||
* Create a procedure of the given name.
|
||||
*/
|
||||
public StoredProcedure(String name) {
|
||||
_name = DBIdentifier.newProcedure(name);
|
||||
_fromDatabase = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
*
|
||||
* 1. PROCEDURE_CAT - String - the procedure catalog name
|
||||
* 2. PROCEDURE_SCHEM - String - the procedure schema name (possibly null)
|
||||
* 3. PROCEDURE_NAME - String - the procedure name
|
||||
* 4. COLUMN_NAME - String - the name of the column
|
||||
* 5. COLUMN_TYPE - short - the kind of column or parameter, as follows:
|
||||
* DatabaseMetaData.procedureColumnUnknown - type unknown
|
||||
* DatabaseMetaData.procedureColumnIn - an IN parameter
|
||||
* DatabaseMetaData.procedureColumnInOut - an INOUT parameter
|
||||
* DatabaseMetaData.procedureColumnOut - an OUT parameter
|
||||
* DatabaseMetaData.procedureColumnReturn - a return value
|
||||
* DatabaseMetaData.procedureReturnsResult - a result column in a result set
|
||||
* 6. DATA_TYPE - int - the SQL type of the data, as in java.sql.Types
|
||||
* 7. TYPE_NAME - String - the SQL type name, for a UDT it is fully qualified
|
||||
* 8. PRECISION - int - the precision
|
||||
* 9. LENGTH - int - the length of the data in bytes
|
||||
* 10.SCALE - short - the scale for numeric types
|
||||
* 11.RADIX - short - the Radix for numeric data (typically 2 or 10)
|
||||
* 12.NULLABLE - short - can the data contain null:
|
||||
* DatabaseMetaData.procedureNoNulls - NULLs not permitted
|
||||
* DatabaseMetaData.procedureNullable - NULLs are permitted
|
||||
* DatabaseMetaData.procedureNullableUnknown - NULL status unknown
|
||||
* 13.REMARKS - String - an explanatory comment about the data item
|
||||
* </pre>
|
||||
**/
|
||||
|
||||
public StoredProcedure(ResultSet rs) throws SQLException {
|
||||
_fromDatabase = true;
|
||||
int i = 0;
|
||||
do {
|
||||
if (i == 0) {
|
||||
// get stored procedure metadata
|
||||
_catalog = DBIdentifier.newCatalog(rs.getString(1));
|
||||
_schema = DBIdentifier.newSchema(rs.getString(2));
|
||||
_name = DBIdentifier.newIdentifier(rs.getString(3), DBIdentifier.DBIdentifierType.PROCEDURE, false);
|
||||
}
|
||||
Column col = new Column();
|
||||
_cols.add(col);
|
||||
col.setIdentifier(DBIdentifier.newColumn(rs.getString(4)));
|
||||
col.setFlag(rs.getShort(5), true);
|
||||
col.setType(rs.getInt(6));
|
||||
col.setTypeIdentifier(DBIdentifier.newConstant(rs.getString(7)));
|
||||
col.setPrecision(rs.getInt(8));
|
||||
col.setSize(rs.getInt(9));
|
||||
col.setScale(rs.getInt(10));
|
||||
col.setRadix(rs.getShort(11));
|
||||
col.setNullability(rs.getShort(12));
|
||||
col.setComment(rs.getString(13));
|
||||
col.setIndex(i);
|
||||
_params.add(col.getIdentifier().getName() + " " + col.getTypeIdentifier().getName());
|
||||
i++;
|
||||
} while (rs.next());
|
||||
}
|
||||
|
||||
public void setCatalog(DBIdentifier catalog) {
|
||||
this._catalog = catalog;
|
||||
}
|
||||
|
||||
public void setSchema(DBIdentifier schema) {
|
||||
this._schema = schema;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this._name = DBIdentifier.newIdentifier(name, DBIdentifier.DBIdentifierType.PROCEDURE, false);
|
||||
}
|
||||
|
||||
public Column[] getInColumns() {
|
||||
return getColumns((short)DatabaseMetaData.procedureColumnIn);
|
||||
}
|
||||
|
||||
public Column[] getInOutColumns() {
|
||||
return getColumns((short)DatabaseMetaData.procedureColumnInOut);
|
||||
}
|
||||
|
||||
public Column[] getOutColumns() {
|
||||
return getColumns((short)DatabaseMetaData.procedureColumnOut);
|
||||
}
|
||||
|
||||
public Column[] getReturnColumns() {
|
||||
return getColumns((short)DatabaseMetaData.procedureColumnReturn);
|
||||
}
|
||||
|
||||
public Column[] getResultColumns() {
|
||||
return getColumns((short)DatabaseMetaData.procedureColumnResult);
|
||||
}
|
||||
|
||||
public Column[] getColumns() {
|
||||
return _cols.toArray(new Column[_cols.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of columns with the given flag.
|
||||
* @param flag
|
||||
* @return
|
||||
*/
|
||||
int countColumn(short flag) {
|
||||
int count = 0;
|
||||
for (Column col : _cols) {
|
||||
if (col.getFlag(flag)) count++;
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
Column[] getColumns(short flag) { // TODO: cache?
|
||||
List<Column> cols = null;
|
||||
for (Column col : _cols) {
|
||||
if (col.getFlag(flag)) {
|
||||
if (cols == null) cols = new ArrayList<Column>();
|
||||
cols.add(col);
|
||||
}
|
||||
}
|
||||
return cols == null ? Schemas.EMPTY_COLUMNS : cols.toArray(new Column[cols.size()]);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the name of this procedure.
|
||||
*/
|
||||
public String getName() {
|
||||
return _name.getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an {@code IN} parameter of the given name and type.
|
||||
* @param var name of the variable
|
||||
* @param typeName name of the SQL type e.g. {@code VARCAR(32)}
|
||||
* @return this procedure instance
|
||||
*/
|
||||
public StoredProcedure addParameter(String var, String typeName) {
|
||||
return addParameter(PARAM.IN, var, typeName);
|
||||
}
|
||||
/**
|
||||
* Adds the given parameter declaration.
|
||||
*
|
||||
* @param param type of parameter.
|
||||
* @param var name of the variable
|
||||
* @param typeName name of the SQL type e.g. {@code VARCAR(32)}
|
||||
* @return this procedure instance
|
||||
*/
|
||||
public StoredProcedure addParameter(PARAM param, String var, String typeName) {
|
||||
assertMutable();
|
||||
|
||||
_params.add(param + " " + var + " " + typeName);
|
||||
return this;
|
||||
}
|
||||
|
||||
public StoredProcedure setLanguage(String language) {
|
||||
_sql.add("LANGUAGE " + language);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL for creating this procedure.
|
||||
*/
|
||||
public String getCreateSQL() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("CREATE PROCEDURE ");
|
||||
buf.append(_name);
|
||||
buf.append(" (");
|
||||
for (Iterator<String> p = _params.iterator(); p.hasNext();) {
|
||||
buf.append(p.next());
|
||||
buf.append(p.hasNext() ? "," : "");
|
||||
}
|
||||
buf.append(") ");
|
||||
//buf.append("(");
|
||||
for (String s : _sql) buf.append(s).append(" ");
|
||||
//buf.append(")");
|
||||
|
||||
return buf.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL for dropping this procedure.
|
||||
*/
|
||||
public String getDropSQL() {
|
||||
return "DROP PROCEDURE " + _name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the SQL for calling this procedure.
|
||||
*/
|
||||
public String getCallSQL() {
|
||||
StringBuilder buf = new StringBuilder();
|
||||
buf.append("CALL ");
|
||||
buf.append(_name); buf.append(" (");
|
||||
for (Iterator<String> p = _params.iterator(); p.hasNext();) {
|
||||
p.next();
|
||||
buf.append("?");
|
||||
if (p.hasNext()) buf.append(",");
|
||||
}
|
||||
buf.append(")");
|
||||
return buf.toString().trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a read SQL statement via an external method.
|
||||
*/
|
||||
public StoredProcedure setSQL(SQL sql) {
|
||||
switch (sql) {
|
||||
case CONTAINS : _sql.add("CONTAINS SQL"); break;
|
||||
case NONE : _sql.add("NO SQL"); break;
|
||||
case MODIFY : _sql.add("MODIFIES SQL DATA"); break;
|
||||
case READ : _sql.add("READS SQL DATA"); break;
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the language whose parameter passing convention will be used to pass paramater values.
|
||||
* @param lang
|
||||
* @return
|
||||
*/
|
||||
public StoredProcedure setParameterStyle(String lang) {
|
||||
_sql.add("PARAMETER STYLE " + lang);
|
||||
return this;
|
||||
}
|
||||
|
||||
public StoredProcedure setExternalName(Class<?> cls, String method, Class<?>... paramTypes) {
|
||||
assertStaticMethod(cls, method, paramTypes);
|
||||
_sql.add("EXTERNAL NAME '" + cls.getName() + '.' + method + "'");
|
||||
return this;
|
||||
}
|
||||
|
||||
public StoredProcedure setResult(int i) {
|
||||
return setResult(i, false);
|
||||
}
|
||||
|
||||
public StoredProcedure setResult(int i, boolean dynamic) {
|
||||
assertMutable();
|
||||
_sql.add((dynamic ? "DYNAMIC " : "") + "RESULT SETS " + i);
|
||||
return this;
|
||||
}
|
||||
|
||||
private void assertStaticMethod(Class<?> cls, String method, Class<?>...paramTypes) {
|
||||
try {
|
||||
Method m = cls.getMethod(method, paramTypes);
|
||||
if (m == null || !Modifier.isStatic(m.getModifiers())) {
|
||||
throw new RuntimeException("No static method " + method + " with arguments "
|
||||
+ Arrays.toString(paramTypes) + " in " + cls);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
throw new RuntimeException("No static method " + method + " with arguments "
|
||||
+ Arrays.toString(paramTypes) + " in " + cls, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void assertMutable() {
|
||||
if (_fromDatabase) {
|
||||
throw new IllegalStateException(this + " is not mutable");
|
||||
}
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return getName();
|
||||
}
|
||||
}
|
|
@ -44,7 +44,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.openjpa</groupId>
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.apache.openjpa.kernel.exps.Path;
|
|||
import org.apache.openjpa.kernel.exps.QueryExpressions;
|
||||
import org.apache.openjpa.kernel.exps.Val;
|
||||
import org.apache.openjpa.lib.log.Log;
|
||||
import org.apache.openjpa.lib.rop.BatchedResultObjectProvider;
|
||||
import org.apache.openjpa.lib.rop.EagerResultList;
|
||||
import org.apache.openjpa.lib.rop.ListResultList;
|
||||
import org.apache.openjpa.lib.rop.MergedResultObjectProvider;
|
||||
|
@ -1233,6 +1234,9 @@ public class QueryImpl
|
|||
protected Object toResult(StoreQuery q, StoreQuery.Executor ex,
|
||||
ResultObjectProvider rop, StoreQuery.Range range)
|
||||
throws Exception {
|
||||
if (rop instanceof BatchedResultObjectProvider) {
|
||||
return new QueryResultCallback(this, q, ex, (BatchedResultObjectProvider) rop, range);
|
||||
}
|
||||
// pack projections if necessary
|
||||
String[] aliases = ex.getProjectionAliases(q);
|
||||
if (!ex.isPacking(q)) {
|
||||
|
|
|
@ -34,6 +34,7 @@ import org.apache.openjpa.util.InternalException;
|
|||
public class QueryLanguages {
|
||||
|
||||
public static final String LANG_SQL = "openjpa.SQL";
|
||||
public static final String LANG_STORED_PROC = "openjpa.StoredProcedure.SQL";
|
||||
public static final String LANG_PREPARED_SQL = "openjpa.prepared.SQL";
|
||||
public static final String LANG_METHODQL = "openjpa.MethodQL";
|
||||
|
||||
|
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.kernel;
|
||||
|
||||
import org.apache.openjpa.kernel.StoreQuery.Executor;
|
||||
import org.apache.openjpa.kernel.StoreQuery.Range;
|
||||
import org.apache.openjpa.lib.rop.BatchedResultObjectProvider;
|
||||
|
||||
/**
|
||||
* A callabck is used when a query results in multiple non-identical result sets.
|
||||
* Designed to use with Stored Procedure Query.
|
||||
*
|
||||
* @author ppoddar
|
||||
*/
|
||||
public class QueryResultCallback {
|
||||
private final StoreQuery storeQuery;
|
||||
private final StoreQuery.Executor executor;
|
||||
private final BatchedResultObjectProvider parent;
|
||||
private final StoreQuery.Range range;
|
||||
private final QueryImpl kernel;
|
||||
|
||||
public QueryResultCallback(QueryImpl kernel, StoreQuery storeQuery, Executor executor,
|
||||
BatchedResultObjectProvider parent, Range range) {
|
||||
super();
|
||||
this.kernel = kernel;
|
||||
this.storeQuery = storeQuery;
|
||||
this.executor = executor;
|
||||
this.parent = parent;
|
||||
this.range = range;
|
||||
}
|
||||
|
||||
public Object callback() throws Exception {
|
||||
return kernel.toResult(storeQuery, executor, parent.getResultObject(), range);
|
||||
}
|
||||
|
||||
public boolean hasMoreResults() {
|
||||
return parent.hasMoreResults();
|
||||
}
|
||||
|
||||
public boolean getExecutionResult() {
|
||||
return parent.getExecutionResult();
|
||||
}
|
||||
|
||||
public int getUpdateCount() {
|
||||
return parent.getUpdateCount();
|
||||
}
|
||||
|
||||
public Object getOut(int position) {
|
||||
return parent.getOut(position);
|
||||
}
|
||||
|
||||
public Object getOut(String name) {
|
||||
return parent.getOut(name);
|
||||
}
|
||||
}
|
|
@ -2002,7 +2002,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
return null;
|
||||
|
||||
// check cache
|
||||
QueryMetaData qm = (QueryMetaData) _queries.get(name);
|
||||
QueryMetaData qm = _queries.get(name);
|
||||
if (qm != null)
|
||||
return qm;
|
||||
|
||||
|
@ -2030,10 +2030,10 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
public QueryMetaData[] getQueryMetaDatas() {
|
||||
if (_locking) {
|
||||
synchronized (this) {
|
||||
return (QueryMetaData[]) _queries.values().toArray(new QueryMetaData[_queries.size()]);
|
||||
return _queries.values().toArray(new QueryMetaData[_queries.size()]);
|
||||
}
|
||||
} else {
|
||||
return (QueryMetaData[]) _queries.values().toArray(new QueryMetaData[_queries.size()]);
|
||||
return _queries.values().toArray(new QueryMetaData[_queries.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2072,10 +2072,22 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
}
|
||||
}
|
||||
|
||||
public QueryMetaData addQueryMetaData(QueryMetaData meta) {
|
||||
if (_locking) {
|
||||
synchronized (this) {
|
||||
final QueryMetaData queryMetaData = _queries.get(meta.getName());
|
||||
return queryMetaData != null ? queryMetaData : _queries.put(meta.getName(), meta);
|
||||
}
|
||||
} else {
|
||||
final QueryMetaData queryMetaData = _queries.get(meta.getName());
|
||||
return queryMetaData != null ? queryMetaData : _queries.put(meta.getName(), meta);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new query metadata instance.
|
||||
*/
|
||||
protected QueryMetaData newQueryMetaData(Class<?> cls, String name) {
|
||||
public QueryMetaData newQueryMetaData(Class<?> cls, String name) {
|
||||
QueryMetaData meta =
|
||||
new QueryMetaData(name, _conf.getCompatibilityInstance().getConvertPositionalParametersToNamed());
|
||||
meta.setDefiningType(cls);
|
||||
|
@ -2118,7 +2130,7 @@ public class MetaDataRepository implements PCRegistry.RegisterClassListener, Con
|
|||
* Searches all cached query metadata by name.
|
||||
*/
|
||||
public QueryMetaData searchQueryMetaDataByName(String name) {
|
||||
return (QueryMetaData) _queries.get(name);
|
||||
return _queries.get(name);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.meta;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.openjpa.kernel.QueryLanguages;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Extends {@link QueryMetaData} to allow multiple {@link QueryMetaData#getResultType() result class} or
|
||||
* {@link QueryMetaData#getResultSetMappingName() mapping names}.
|
||||
* <br>
|
||||
* Designed for mapping the results from a Stored Procudure that can produce more than one {@link java.sql.ResultSet},
|
||||
* each being mapped with a different mapping specification.
|
||||
*
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MultiQueryMetaData extends QueryMetaData {
|
||||
private final String _procedureName;
|
||||
private final boolean _isTemporary;
|
||||
private final List<QueryMetaData> _parts = new ArrayList<QueryMetaData>();
|
||||
private final List<Parameter> _params = new ArrayList<MultiQueryMetaData.Parameter>();
|
||||
|
||||
/**
|
||||
* Create this meta data given a scope of definition, a logical identifier, a procedure name
|
||||
* and whether its usage is temporary.
|
||||
* @param scope defining scope
|
||||
* @param logicalName name as an identifier
|
||||
* @param procedureName name of the database procedure
|
||||
*/
|
||||
public MultiQueryMetaData(Class<?> scope, String logicalName, String procedureName, boolean isTemporary) {
|
||||
super(logicalName, false);
|
||||
setLanguage(QueryLanguages.LANG_STORED_PROC);
|
||||
setSource(null, scope, -1, null);
|
||||
_procedureName = procedureName;
|
||||
_isTemporary = isTemporary;
|
||||
}
|
||||
|
||||
public String getProcedureName() {
|
||||
return _procedureName;
|
||||
}
|
||||
|
||||
public List<QueryMetaData> getComponents() {
|
||||
return _parts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Affirms if this metadata is ephimeral.
|
||||
* Ephimenral metadata is removed from the repository after usage.
|
||||
* @return
|
||||
*/
|
||||
public boolean isEphimeral() {
|
||||
return _isTemporary;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResultSetMappingName(String name) {
|
||||
throw new UnsupportedOperationException("Not allowed to set mapping name. It is automatically set");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setResultType(Class cls) {
|
||||
throw new UnsupportedOperationException("Not allowed to set result type. It is automatically set");
|
||||
}
|
||||
|
||||
public void addComponent(Class<?> resultClass) {
|
||||
QueryMetaData part = newQueryMetaData();
|
||||
part.setResultType(resultClass);
|
||||
_parts.add(part);
|
||||
}
|
||||
|
||||
public void addComponent(String mappingName) {
|
||||
QueryMetaData part = newQueryMetaData();
|
||||
part.setResultSetMappingName(mappingName);
|
||||
_parts.add(part);
|
||||
}
|
||||
|
||||
private QueryMetaData newQueryMetaData() {
|
||||
QueryMetaData part = new QueryMetaData(getName() + "#" + _parts.size(), false);
|
||||
part.setLanguage(getLanguage());
|
||||
part.setSource(null, getDefiningType(), -1, null);
|
||||
return part;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Gets the component metadata at the given part index.
|
||||
* @param i a valid integer index
|
||||
* @return
|
||||
*/
|
||||
public QueryMetaData getComponent(int i) {
|
||||
if (i < 0 || i >= _parts.size()) {
|
||||
throw new ArrayIndexOutOfBoundsException("Invalid index " + i
|
||||
+ ". Available " + _parts.size() + " parts");
|
||||
}
|
||||
return _parts.get(i);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number of component metadata contained in this metada.
|
||||
*/
|
||||
public int getComponentCount() {
|
||||
return _parts.size();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given parameter.
|
||||
* @param p
|
||||
*/
|
||||
public void registerParameter(Parameter p) {
|
||||
_params.add(p);
|
||||
}
|
||||
|
||||
public List<Parameter> getParameters() {
|
||||
return _params;
|
||||
}
|
||||
|
||||
public int getParameterCount() {
|
||||
return _params.size();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A parameter
|
||||
*
|
||||
*/
|
||||
public static class Parameter {
|
||||
public enum Mode {IN,OUT,INOUT,CURSOR};
|
||||
private final String name;
|
||||
private final Class<?> type;
|
||||
private final Mode mode;
|
||||
private final int position;
|
||||
|
||||
public Parameter(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;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return position;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public Mode getMode() {
|
||||
return mode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.lib.rop;
|
||||
|
||||
|
||||
/**
|
||||
* A provider for multiple result sets.
|
||||
* This provider acts as a container of other result providers. The underlying providers
|
||||
* contain the actual data and are {@link ResultObjectProvider#getResultObject() iterated}
|
||||
* for the results, while this provider iterates over its underlying providers.
|
||||
* <br>
|
||||
* Designed for the specific purpose of getting results from the execution of Stored Procedures
|
||||
* that can produce more than one result set and an optional update count. Few methods related
|
||||
* to iterating multiple results and update count mirror the methods in JDBC {@link java.sql.Statement}.
|
||||
* <br>
|
||||
*
|
||||
* @see org.apache.openjpa.kernel.QueryResultCallback
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
*
|
||||
*/
|
||||
public interface BatchedResultObjectProvider extends ResultObjectProvider {
|
||||
/**
|
||||
* Gets the next result object provider from its batch.
|
||||
*/
|
||||
ResultObjectProvider getResultObject() throws Exception;
|
||||
|
||||
/**
|
||||
* Affirms if this batch contains more results.
|
||||
*/
|
||||
boolean hasMoreResults();
|
||||
|
||||
/**
|
||||
* Gets the result of executing the underlying JDBC statement.
|
||||
* @return a boolean value whose semantics is same as {@link java.sql.PreparedStatement#execute()}.
|
||||
*/
|
||||
boolean getExecutionResult();
|
||||
|
||||
|
||||
/**
|
||||
* Gets the count of records updated by the underlying JDBC statement.
|
||||
* @return an integer value whose semantics is same as {@link java.sql.CallableStatement#getUpdateCount()}.
|
||||
*/
|
||||
int getUpdateCount();
|
||||
|
||||
Object getOut(String name);
|
||||
Object getOut(int position);
|
||||
}
|
|
@ -34,6 +34,7 @@ import javax.persistence.AttributeOverride;
|
|||
import javax.persistence.AttributeOverrides;
|
||||
import javax.persistence.CollectionTable;
|
||||
import javax.persistence.ColumnResult;
|
||||
import javax.persistence.ConstructorResult;
|
||||
import javax.persistence.DiscriminatorColumn;
|
||||
import javax.persistence.DiscriminatorValue;
|
||||
import javax.persistence.EntityResult;
|
||||
|
@ -620,6 +621,9 @@ public class AnnotationPersistenceMappingParser
|
|||
entityResult.addMapping(field.name(), sColName.getName());
|
||||
}
|
||||
}
|
||||
for (ConstructorResult constructorResult : anno.classes()) {
|
||||
throw new UnsupportedOperationException("JPA 2.1, not yet impl");
|
||||
}
|
||||
for (ColumnResult column : anno.columns()) {
|
||||
DBIdentifier sName = DBIdentifier.newColumn(column.name(), delimit());
|
||||
result.addColumnResult(sName.getName());
|
||||
|
|
|
@ -114,5 +114,5 @@ enum MappingTag {
|
|||
X_MAPPING_OVERRIDES,
|
||||
X_SECONDARY_TABLE,
|
||||
X_SECONDARY_TABLES,
|
||||
X_TABLE,
|
||||
X_TABLE
|
||||
}
|
||||
|
|
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.jdbc.procedure;
|
||||
|
||||
import org.apache.openjpa.jdbc.procedure.derby.Procedures;
|
||||
import org.apache.openjpa.jdbc.procedure.entity.EntityWithStoredProcedure;
|
||||
import org.apache.openjpa.jdbc.sql.DerbyDictionary;
|
||||
import org.apache.openjpa.persistence.test.DatabasePlatform;
|
||||
import org.apache.openjpa.persistence.test.SingleEMFTestCase;
|
||||
|
||||
import java.util.Iterator;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
|
||||
@DatabasePlatform("org.apache.derby.jdbc.EmbeddedDriver")
|
||||
public class TestStoredProcedure extends SingleEMFTestCase {
|
||||
@Override
|
||||
public void setUp() {
|
||||
setUp(
|
||||
"openjpa.RuntimeUnenhancedClasses", "unsupported",
|
||||
"openjpa.DynamicEnhancementAgent", "false",
|
||||
EntityWithStoredProcedure.class, EntityWithStoredProcedure.Mapping2.class);
|
||||
setSupportedDatabases(DerbyDictionary.class);
|
||||
}
|
||||
|
||||
public void testSimple() {
|
||||
Procedures.simpleCalled = false;
|
||||
|
||||
EntityManager em = emf.createEntityManager();
|
||||
exec(em, "CREATE PROCEDURE TESTSIMPLE() " +
|
||||
"PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
|
||||
"'" + Procedures.class.getName() + ".simple'");
|
||||
StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.simple");
|
||||
assertFalse(procedure.execute());
|
||||
em.close();
|
||||
assertTrue(Procedures.simpleCalled);
|
||||
}
|
||||
|
||||
public void testInParams() {
|
||||
Procedures.inParamsInteger = -1;
|
||||
Procedures.inParamsString = null;
|
||||
|
||||
EntityManager em = emf.createEntityManager();
|
||||
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");
|
||||
assertFalse(procedure.execute());
|
||||
assertEquals(2015, Procedures.inParamsInteger);
|
||||
assertEquals("openjpa", Procedures.inParamsString);
|
||||
|
||||
// null case
|
||||
Procedures.inParamsInteger = -1;
|
||||
Procedures.inParamsString = null;
|
||||
StoredProcedureQuery procedure2 = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.inParams");
|
||||
procedure2.setParameter("SOME_NUMBER", 20152);
|
||||
assertFalse(procedure2.execute());
|
||||
em.close();
|
||||
assertEquals(20152, Procedures.inParamsInteger);
|
||||
assertNull(Procedures.inParamsString);
|
||||
}
|
||||
|
||||
public void testOut() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
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);
|
||||
assertFalse(procedure.execute());
|
||||
// assertEquals(10, procedure.getOutputParameterValue("result")); // not impl by derby
|
||||
assertEquals(10, procedure.getOutputParameterValue(2));
|
||||
em.close();
|
||||
}
|
||||
|
||||
public void testInOut() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
exec(em, "CREATE PROCEDURE XINOUT(INOUT P INTEGER) " +
|
||||
"PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME " +
|
||||
"'" + Procedures.class.getName() + ".inout'");
|
||||
StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.inout");
|
||||
procedure.setParameter("P", 5);
|
||||
assertFalse(procedure.execute());
|
||||
// assertEquals(10, procedure.getOutputParameterValue("p")); // not impl by derby
|
||||
assertEquals(10, procedure.getOutputParameterValue(1));
|
||||
em.close();
|
||||
}
|
||||
|
||||
public void testMapping() {
|
||||
EntityManager em = emf.createEntityManager();
|
||||
{
|
||||
em.getTransaction().begin();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
final EntityWithStoredProcedure entity = new EntityWithStoredProcedure();
|
||||
entity.setId(1 + i);
|
||||
entity.setName("#" + entity.getId());
|
||||
em.persist(entity);
|
||||
}
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
}
|
||||
|
||||
exec(em, "CREATE PROCEDURE MAPPING() " +
|
||||
"PARAMETER STYLE JAVA LANGUAGE JAVA DYNAMIC RESULT SETS 2 EXTERNAL NAME " +
|
||||
"'" + Procedures.class.getName() + ".mapping'");
|
||||
StoredProcedureQuery procedure = em.createNamedStoredProcedureQuery("EntityWithStoredProcedure.mapping");
|
||||
assertTrue(procedure.execute());
|
||||
final Iterator r1 = procedure.getResultList().iterator();
|
||||
final EntityWithStoredProcedure next1 = EntityWithStoredProcedure.class.cast(r1.next());
|
||||
assertEquals(1, next1.getId());
|
||||
assertEquals("#1", next1.getName());
|
||||
assertNotNull(next1);
|
||||
final EntityWithStoredProcedure next2 = EntityWithStoredProcedure.class.cast(r1.next());
|
||||
assertNotNull(next2);
|
||||
assertEquals(2, next2.getId());
|
||||
assertEquals("#2", next2.getName());
|
||||
assertFalse(r1.hasNext());
|
||||
assertTrue(procedure.hasMoreResults());
|
||||
final Iterator r2 = procedure.getResultList().iterator();
|
||||
final EntityWithStoredProcedure.Mapping2 next3 = EntityWithStoredProcedure.Mapping2.class.cast(r2.next());
|
||||
assertNotNull(next3);
|
||||
assertFalse(r2.hasNext());
|
||||
assertEquals(next2.getId(), next3.getId());
|
||||
assertEquals(next2.getName(), next3.getName());
|
||||
|
||||
{
|
||||
em.getTransaction().begin();
|
||||
for (int i = 0; i < 2; i++) {
|
||||
em.remove(em.find(EntityWithStoredProcedure.class, i + 1L));
|
||||
}
|
||||
em.getTransaction().commit();
|
||||
em.clear();
|
||||
}
|
||||
em.close();
|
||||
}
|
||||
|
||||
private void exec(final EntityManager em, final String proc) {
|
||||
final EntityTransaction tx = em.getTransaction();
|
||||
tx.begin();
|
||||
try {
|
||||
em.createNativeQuery(proc).executeUpdate();
|
||||
tx.commit();
|
||||
} catch (final Exception e) { // already exists or another error
|
||||
e.printStackTrace();
|
||||
try {
|
||||
tx.rollback();
|
||||
} catch (final Exception ignored) {
|
||||
// no-op
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.jdbc.procedure.derby;
|
||||
|
||||
import java.sql.Connection;
|
||||
import java.sql.DriverManager;
|
||||
import java.sql.ResultSet;
|
||||
|
||||
import static junit.framework.Assert.fail;
|
||||
|
||||
public final class Procedures {
|
||||
public static boolean simpleCalled;
|
||||
|
||||
public static void simple() {
|
||||
simpleCalled = true;
|
||||
}
|
||||
|
||||
public static int inParamsInteger;
|
||||
public static String inParamsString;
|
||||
|
||||
public static void inParams(int integer, String string) {
|
||||
inParamsInteger = integer;
|
||||
inParamsString = string;
|
||||
}
|
||||
|
||||
public static void x2(int integer, int[] out) {
|
||||
out[0] = integer * 2;
|
||||
}
|
||||
|
||||
public static void inout(int[] p) {
|
||||
p[0] = p[0] * 2;
|
||||
}
|
||||
|
||||
public static void mapping(ResultSet[] r0, ResultSet[] r1) {
|
||||
try {
|
||||
Connection c = DriverManager.getConnection("jdbc:default:connection");
|
||||
r0[0] = c.createStatement().executeQuery("SELECT * FROM EntityWithStoredProcedure order by id");
|
||||
r1[0] = c.createStatement().executeQuery("SELECT * FROM EntityWithStoredProcedure where id = 2");
|
||||
} catch (final Exception ex) {
|
||||
fail(ex.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,145 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.jdbc.procedure.entity;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityResult;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.NamedStoredProcedureQueries;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.persistence.SqlResultSetMapping;
|
||||
import javax.persistence.SqlResultSetMappings;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
|
||||
import static javax.persistence.ParameterMode.INOUT;
|
||||
import static javax.persistence.ParameterMode.OUT;
|
||||
|
||||
@Entity
|
||||
@NamedStoredProcedureQueries({
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "EntityWithStoredProcedure.simple",
|
||||
procedureName = "TESTSIMPLE"
|
||||
),
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "EntityWithStoredProcedure.inParams",
|
||||
procedureName = "TESTINS",
|
||||
parameters = {
|
||||
@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)
|
||||
}
|
||||
),
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "EntityWithStoredProcedure.inout",
|
||||
procedureName = "XINOUT",
|
||||
parameters = {
|
||||
@StoredProcedureParameter(name = "P ", type = Integer.class, mode = INOUT)
|
||||
}
|
||||
),
|
||||
@NamedStoredProcedureQuery(
|
||||
name = "EntityWithStoredProcedure.mapping",
|
||||
procedureName = "MAPPING",
|
||||
resultSetMappings = {"mapping1", "mapping2"}
|
||||
)
|
||||
})
|
||||
@SqlResultSetMappings({
|
||||
@SqlResultSetMapping(
|
||||
name = "mapping1",
|
||||
entities = @EntityResult(entityClass = EntityWithStoredProcedure.class)
|
||||
),
|
||||
@SqlResultSetMapping(
|
||||
name = "mapping2",
|
||||
entities = @EntityResult(entityClass = EntityWithStoredProcedure.Mapping2.class)
|
||||
)
|
||||
})
|
||||
public class EntityWithStoredProcedure {
|
||||
@Id
|
||||
private long id;
|
||||
private String name;
|
||||
|
||||
public EntityWithStoredProcedure() {
|
||||
// no-op
|
||||
}
|
||||
|
||||
public EntityWithStoredProcedure(final long id, final String name) {
|
||||
this.id = id;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (this == o) return true;
|
||||
if (o == null || getClass() != o.getClass()) return false;
|
||||
EntityWithStoredProcedure that = (EntityWithStoredProcedure) o;
|
||||
return id == that.id && name.equals(that.name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = (int) (id ^ (id >>> 32));
|
||||
result = 31 * result + name.hashCode();
|
||||
return result;
|
||||
}
|
||||
|
||||
@Entity
|
||||
public static class Mapping2 {
|
||||
@Id
|
||||
private long id;
|
||||
private String name;
|
||||
|
||||
public long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -28,6 +28,8 @@ import javax.persistence.*;
|
|||
import org.apache.openjpa.jdbc.meta.strats.*;
|
||||
import org.apache.openjpa.persistence.*;
|
||||
import org.apache.openjpa.persistence.jdbc.*;
|
||||
import org.apache.openjpa.persistence.jdbc.ForeignKey;
|
||||
import org.apache.openjpa.persistence.jdbc.Index;
|
||||
import org.apache.openjpa.persistence.jdbc.OrderColumn;
|
||||
|
||||
|
||||
|
|
|
@ -223,9 +223,9 @@ public abstract class AbstractPersistenceTestCase extends TestCase {
|
|||
* Safely close the given factory.
|
||||
*/
|
||||
protected boolean closeEMF(EntityManagerFactory emf) {
|
||||
boolean brc = false;
|
||||
boolean brc;
|
||||
if (emf == null || !emf.isOpen()) {
|
||||
return brc;
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
closeAllOpenEMs(emf);
|
||||
|
|
|
@ -44,7 +44,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
|
@ -83,6 +83,10 @@ public abstract class AbstractQuery<X> implements OpenJPAQuerySPI<X> {
|
|||
return result;
|
||||
}
|
||||
|
||||
public boolean isProcedure() {
|
||||
return QueryLanguages.LANG_STORED_PROC.equals(getLanguage());
|
||||
}
|
||||
|
||||
public boolean isNative() {
|
||||
return QueryLanguages.LANG_SQL.equals(getLanguage());
|
||||
}
|
||||
|
@ -131,8 +135,8 @@ public abstract class AbstractQuery<X> implements OpenJPAQuerySPI<X> {
|
|||
if (pos < 1) {
|
||||
throw new IllegalArgumentException(_loc.get("illegal-index", pos).getMessage());
|
||||
}
|
||||
Parameter<?> param = null;
|
||||
if (isNative()) {
|
||||
Parameter<?> param;
|
||||
if (isNative() || isProcedure()) {
|
||||
param = new ParameterImpl<Object>(pos, Object.class);
|
||||
declareParameter(pos, param);
|
||||
} else {
|
||||
|
|
|
@ -63,6 +63,8 @@ import static org.apache.openjpa.persistence.MetaDataTag.QUERIES;
|
|||
import static org.apache.openjpa.persistence.MetaDataTag.QUERY;
|
||||
import static org.apache.openjpa.persistence.MetaDataTag.READ_ONLY;
|
||||
import static org.apache.openjpa.persistence.MetaDataTag.SEQ_GENERATOR;
|
||||
import static org.apache.openjpa.persistence.MetaDataTag.STOREDPROCEDURE_QUERIES;
|
||||
import static org.apache.openjpa.persistence.MetaDataTag.STOREDPROCEDURE_QUERY;
|
||||
import static org.apache.openjpa.persistence.MetaDataTag.TYPE;
|
||||
import static org.apache.openjpa.persistence.MetaDataTag.VERSION;
|
||||
|
||||
|
@ -120,9 +122,12 @@ import javax.persistence.NamedNativeQueries;
|
|||
import javax.persistence.NamedNativeQuery;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.NamedStoredProcedureQueries;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.persistence.OneToMany;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.OrderBy;
|
||||
import javax.persistence.ParameterMode;
|
||||
import javax.persistence.PostLoad;
|
||||
import javax.persistence.PostPersist;
|
||||
import javax.persistence.PostRemove;
|
||||
|
@ -132,6 +137,7 @@ import javax.persistence.PreRemove;
|
|||
import javax.persistence.PreUpdate;
|
||||
import javax.persistence.QueryHint;
|
||||
import javax.persistence.SequenceGenerator;
|
||||
import javax.persistence.StoredProcedureParameter;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
@ -156,6 +162,7 @@ import org.apache.openjpa.meta.LifecycleMetaData;
|
|||
import org.apache.openjpa.meta.MetaDataFactory;
|
||||
import org.apache.openjpa.meta.MetaDataModes;
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
import org.apache.openjpa.meta.MultiQueryMetaData;
|
||||
import org.apache.openjpa.meta.Order;
|
||||
import org.apache.openjpa.meta.QueryMetaData;
|
||||
import org.apache.openjpa.meta.SequenceMetaData;
|
||||
|
@ -203,6 +210,8 @@ public class AnnotationPersistenceMetaDataParser
|
|||
_tags.put(MapsId.class, MAPPED_BY_ID);
|
||||
_tags.put(NamedNativeQueries.class, NATIVE_QUERIES);
|
||||
_tags.put(NamedNativeQuery.class, NATIVE_QUERY);
|
||||
_tags.put(NamedStoredProcedureQueries.class, STOREDPROCEDURE_QUERIES);
|
||||
_tags.put(NamedStoredProcedureQuery.class, STOREDPROCEDURE_QUERY);
|
||||
_tags.put(NamedQueries.class, QUERIES);
|
||||
_tags.put(NamedQuery.class, QUERY);
|
||||
_tags.put(OrderBy.class, ORDER_BY);
|
||||
|
@ -471,6 +480,14 @@ public class AnnotationPersistenceMetaDataParser
|
|||
if (isQueryMode() && (pkgMode & MODE_QUERY) == 0)
|
||||
parseNamedQueries(pkg, (NamedQuery) anno);
|
||||
break;
|
||||
case STOREDPROCEDURE_QUERIES:
|
||||
if (isQueryMode())
|
||||
parseNamedStoredProcedureQueries(pkg, ((NamedStoredProcedureQueries) anno).value());
|
||||
break;
|
||||
case STOREDPROCEDURE_QUERY:
|
||||
if (isQueryMode())
|
||||
parseNamedStoredProcedureQueries(pkg, ((NamedStoredProcedureQuery) anno));
|
||||
break;
|
||||
case SEQ_GENERATOR:
|
||||
if (isMappingOverrideMode() &&
|
||||
(pkgMode & MODE_MAPPING) == 0)
|
||||
|
@ -623,6 +640,14 @@ public class AnnotationPersistenceMetaDataParser
|
|||
if (isQueryMode() && (meta.getSourceMode() & MODE_QUERY)==0)
|
||||
parseNamedQueries(_cls, (NamedQuery) anno);
|
||||
break;
|
||||
case STOREDPROCEDURE_QUERIES:
|
||||
if (isQueryMode())
|
||||
parseNamedStoredProcedureQueries(_cls, ((NamedStoredProcedureQueries) anno).value());
|
||||
break;
|
||||
case STOREDPROCEDURE_QUERY:
|
||||
if (isQueryMode())
|
||||
parseNamedStoredProcedureQueries(_cls, ((NamedStoredProcedureQuery) anno));
|
||||
break;
|
||||
case SEQ_GENERATOR:
|
||||
if (isMappingOverrideMode())
|
||||
parseSequenceGenerator(_cls, (SequenceGenerator) anno);
|
||||
|
@ -1043,8 +1068,8 @@ public class AnnotationPersistenceMetaDataParser
|
|||
* If FetchGroup A includes FetchGroup B, then a bi-link is set between
|
||||
* A and B. Both A and B must be declared in the same Class.
|
||||
* <br>
|
||||
* Call {@link #parseFetchAttribute(ClassMetaData,
|
||||
* org.apache.openjpa.meta.FetchGroup, FetchAttribute)} only after the
|
||||
* Call {@link #parseFetchAttribute(ClassMetaData, org.apache.openjpa.meta.FetchGroup, FetchAttributeImpl)}
|
||||
* only after the
|
||||
* bi-links have been established, because a field f will not only add the
|
||||
* fetch group A which explicitly includes f to its custom fetch groups but
|
||||
* also will also add any fetch group B that includes A.
|
||||
|
@ -2128,5 +2153,75 @@ public class AnnotationPersistenceMetaDataParser
|
|||
protected String normalizeCatalogName(String catName) {
|
||||
return catName;
|
||||
}
|
||||
|
||||
|
||||
protected MultiQueryMetaData.Parameter.Mode toKernelParameterMode(ParameterMode mode) {
|
||||
switch (mode) {
|
||||
case IN : return MultiQueryMetaData.Parameter.Mode.IN;
|
||||
case OUT: return MultiQueryMetaData.Parameter.Mode.OUT;
|
||||
case INOUT: return MultiQueryMetaData.Parameter.Mode.INOUT;
|
||||
case REF_CURSOR: return MultiQueryMetaData.Parameter.Mode.CURSOR;
|
||||
default : return MultiQueryMetaData.Parameter.Mode.IN;
|
||||
}
|
||||
}
|
||||
|
||||
protected void addSourceInfo(AnnotatedElement el, QueryMetaData meta) {
|
||||
meta.setSource(getSourceFile(), (el instanceof Class) ? el : null,
|
||||
SourceTracker.SRC_ANNOTATIONS, getSourceFile() == null ? "" : getSourceFile().getPath());
|
||||
if (isMetaDataMode())
|
||||
meta.setSourceMode(MODE_META);
|
||||
else if (isMappingMode())
|
||||
meta.setSourceMode(MODE_MAPPING);
|
||||
else
|
||||
meta.setSourceMode(MODE_QUERY);
|
||||
}
|
||||
|
||||
protected void addHints(QueryMetaData meta, QueryHint...hints) {
|
||||
for (QueryHint hint : hints)
|
||||
meta.addHint(hint.name(), hint.value());
|
||||
|
||||
}
|
||||
|
||||
private void parseNamedStoredProcedureQueries(AnnotatedElement el, NamedStoredProcedureQuery... procs) {
|
||||
for (NamedStoredProcedureQuery proc : procs) {
|
||||
if (StringUtils.isEmpty(proc.name()))
|
||||
throw new MetaDataException(_loc.get("stored-proc-no-name", el));
|
||||
if (StringUtils.isEmpty(proc.procedureName()))
|
||||
throw new MetaDataException(_loc.get("stored-proc-no-dbname", el));
|
||||
|
||||
// Query metadata name
|
||||
MultiQueryMetaData meta = new MultiQueryMetaData(_cls, proc.name(), proc.procedureName(), false);
|
||||
QueryMetaData existing = getRepository().addQueryMetaData(meta);
|
||||
if (existing != null && existing.getDefiningType() != meta.getDefiningType()) {
|
||||
getLog().warn(_loc.get("dup-query", meta.getName(), el, existing.getDefiningType()));
|
||||
}
|
||||
|
||||
// Important: The query string is the name of the database stored procedure
|
||||
meta.setQueryString(proc.procedureName());
|
||||
|
||||
// For each mapping name/result class, add a component metadata
|
||||
// The spec restricts that either ResultMappingName or ResultClasses be specified, but not both.
|
||||
// This is relevant because the order of mapping must match the order in which the
|
||||
// components are returned
|
||||
Class<?>[] resultClasses = proc.resultClasses();
|
||||
String[] resultSetMappings = proc.resultSetMappings();
|
||||
if (resultClasses.length > 0 && resultSetMappings.length > 0)
|
||||
throw new MetaDataException(_loc.get("stored-proc-both-mapping", el));
|
||||
for (Class<?> res : resultClasses) {
|
||||
meta.addComponent(res);
|
||||
}
|
||||
for (String mapping : resultSetMappings) {
|
||||
meta.addComponent(mapping);
|
||||
}
|
||||
StoredProcedureParameter[] params = proc.parameters();
|
||||
for (StoredProcedureParameter param : params) {
|
||||
MultiQueryMetaData.Parameter p = new MultiQueryMetaData.Parameter(
|
||||
param.name(), param.type(), toKernelParameterMode(param.mode()));
|
||||
meta.registerParameter(p);
|
||||
}
|
||||
addHints(meta, proc.hints());
|
||||
addSourceInfo(el, meta);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,7 @@ import java.util.HashMap;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Cache;
|
||||
import javax.persistence.EntityManagerFactory;
|
||||
import javax.persistence.PersistenceUnitUtil;
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.spi.LoadState;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
|
@ -44,6 +42,7 @@ import org.apache.openjpa.lib.log.Log;
|
|||
import org.apache.openjpa.lib.util.Closeable;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
import org.apache.openjpa.meta.QueryMetaData;
|
||||
import org.apache.openjpa.persistence.criteria.CriteriaBuilderImpl;
|
||||
import org.apache.openjpa.persistence.criteria.OpenJPACriteriaBuilder;
|
||||
import org.apache.openjpa.persistence.meta.MetamodelImpl;
|
||||
|
@ -150,7 +149,7 @@ public class EntityManagerFactoryImpl
|
|||
}
|
||||
|
||||
public OpenJPAEntityManagerSPI createEntityManager() {
|
||||
return createEntityManager(null);
|
||||
return createEntityManager((Map) null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -242,7 +241,17 @@ public class EntityManagerFactoryImpl
|
|||
}
|
||||
return em;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public EntityManager createEntityManager(SynchronizationType synchronizationType) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityManager createEntityManager(SynchronizationType synchronizationType, Map map) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new entity manager around the given broker.
|
||||
*/
|
||||
|
@ -354,6 +363,28 @@ public class EntityManagerFactoryImpl
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNamedQuery(String name, Query query) {
|
||||
org.apache.openjpa.kernel.Query kernelQuery = ((QueryImpl<?>)query).getDelegate();
|
||||
MetaDataRepository metaDataRepositoryInstance = _factory.getConfiguration().getMetaDataRepositoryInstance();
|
||||
QueryMetaData metaData = metaDataRepositoryInstance.newQueryMetaData(null, null);
|
||||
metaData.setFrom(kernelQuery);
|
||||
metaDataRepositoryInstance.addQueryMetaData(metaData);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> cls) {
|
||||
if (cls.isInstance(this)) {
|
||||
return cls.cast(this);
|
||||
}
|
||||
throw new javax.persistence.PersistenceException(this + " is not a " + cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> void addNamedEntityGraph(String graphName, EntityGraph<T> entityGraph) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the identifier for the specified entity. If not managed by any
|
||||
* of the em's in this PU or not persistence capable, return null.
|
||||
|
|
|
@ -36,19 +36,24 @@ import java.util.Collection;
|
|||
import java.util.EnumSet;
|
||||
import java.util.HashMap;
|
||||
import java.util.IdentityHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import javax.persistence.CacheRetrieveMode;
|
||||
import javax.persistence.CacheStoreMode;
|
||||
import javax.persistence.EntityGraph;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.FlushModeType;
|
||||
import javax.persistence.LockModeType;
|
||||
import javax.persistence.PessimisticLockScope;
|
||||
import javax.persistence.Query;
|
||||
import javax.persistence.StoredProcedureQuery;
|
||||
import javax.persistence.Tuple;
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.CriteriaDelete;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.CriteriaUpdate;
|
||||
import javax.persistence.criteria.ParameterExpression;
|
||||
import javax.persistence.metamodel.Metamodel;
|
||||
|
||||
|
@ -79,6 +84,8 @@ import org.apache.openjpa.lib.util.Closeable;
|
|||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.meta.ClassMetaData;
|
||||
import org.apache.openjpa.meta.FieldMetaData;
|
||||
import org.apache.openjpa.meta.MetaDataRepository;
|
||||
import org.apache.openjpa.meta.MultiQueryMetaData;
|
||||
import org.apache.openjpa.meta.QueryMetaData;
|
||||
import org.apache.openjpa.meta.SequenceMetaData;
|
||||
import org.apache.openjpa.persistence.criteria.CriteriaBuilderImpl;
|
||||
|
@ -116,7 +123,8 @@ public class EntityManagerImpl
|
|||
private Map<FetchConfiguration,FetchPlan> _plans = new IdentityHashMap<FetchConfiguration,FetchPlan>(1);
|
||||
protected RuntimeExceptionTranslator _ret = PersistenceExceptions.getRollbackTranslator(this);
|
||||
private boolean _convertPositionalParams = false;
|
||||
|
||||
private boolean _isJoinedToTransaction;
|
||||
|
||||
public EntityManagerImpl() {
|
||||
// for Externalizable
|
||||
}
|
||||
|
@ -556,12 +564,24 @@ public class EntityManagerImpl
|
|||
}
|
||||
|
||||
public void joinTransaction() {
|
||||
if (!_broker.syncWithManagedTransaction()) {
|
||||
throw new TransactionRequiredException(_loc.get
|
||||
("no-managed-trans"), null, null, false);
|
||||
} else {
|
||||
_isJoinedToTransaction = true;
|
||||
}
|
||||
|
||||
assertNotCloseInvoked();
|
||||
if (!_broker.syncWithManagedTransaction())
|
||||
throw new TransactionRequiredException(_loc.get
|
||||
("no-managed-trans"), null, null, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJoinedToTransaction() {
|
||||
return isActive() && _isJoinedToTransaction;
|
||||
}
|
||||
|
||||
public void begin() {
|
||||
_broker.begin();
|
||||
}
|
||||
|
@ -1077,6 +1097,64 @@ public class EntityManagerImpl
|
|||
return newQueryImpl(kernelQuery, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createNamedStoredProcedureQuery(String name) {
|
||||
QueryMetaData meta = getQueryMetadata(name);
|
||||
if (!MultiQueryMetaData.class.isInstance(meta)) {
|
||||
throw new RuntimeException(name + " is not an identifier for a Stored Procedure Query");
|
||||
}
|
||||
return newProcedure(((MultiQueryMetaData)meta).getProcedureName(), (MultiQueryMetaData)meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName) {
|
||||
return newProcedure(procedureName, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, Class... resultClasses) {
|
||||
String tempName = "StoredProcedure-"+System.nanoTime();
|
||||
MultiQueryMetaData meta = new MultiQueryMetaData(null, tempName, procedureName, true);
|
||||
for (Class<?> res : resultClasses) {
|
||||
meta.addComponent(res);
|
||||
}
|
||||
return newProcedure(procedureName, meta);
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery createStoredProcedureQuery(String procedureName, String... resultSetMappings) {
|
||||
String tempName = "StoredProcedure-"+System.nanoTime();
|
||||
MultiQueryMetaData meta = new MultiQueryMetaData(null, tempName, procedureName, true);
|
||||
for (String mapping : resultSetMappings) {
|
||||
meta.addComponent(mapping);
|
||||
}
|
||||
return newProcedure(procedureName, meta);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a query to execute a Stored Procedure.
|
||||
* <br>
|
||||
* Construction of a {@link StoredProcedureQuery} object is a three step process
|
||||
* <LI>
|
||||
* <LI>a {@link org.apache.openjpa.kernel.Query kernel query} {@code kQ} is created for
|
||||
* {@link QueryLanguages#LANG_SQL SQL} language with the string {@code S}
|
||||
* <LI>a {@link QueryImpl facade query} {@code fQ} is created that delegates to the kernel query {@code kQ}
|
||||
* <LI>a {@link StoredProcedureQueryImpl stored procedure query} is created that delegates to the facade query
|
||||
* {@code fQ}.
|
||||
* <br>
|
||||
*
|
||||
*/
|
||||
private StoredProcedureQuery newProcedure(String procedureName, MultiQueryMetaData meta) {
|
||||
org.apache.openjpa.kernel.QueryImpl kernelQuery = (org.apache.openjpa.kernel.QueryImpl)
|
||||
_broker.newQuery(QueryLanguages.LANG_STORED_PROC, procedureName);
|
||||
kernelQuery.getStoreQuery().setQuery(meta);
|
||||
if (meta != null) {
|
||||
getConfiguration().getMetaDataRepositoryInstance().addQueryMetaData(meta);
|
||||
kernelQuery.setResultMapping(null, meta.getResultSetMappingName());
|
||||
}
|
||||
return new StoredProcedureQueryImpl(procedureName, meta, new QueryImpl(this, _ret, kernelQuery, meta));
|
||||
}
|
||||
|
||||
protected <T> QueryImpl<T> newQueryImpl(org.apache.openjpa.kernel.Query kernelQuery, QueryMetaData qmd) {
|
||||
return new QueryImpl<T>(this, _ret, kernelQuery, qmd);
|
||||
}
|
||||
|
@ -1633,7 +1711,17 @@ public class EntityManagerImpl
|
|||
}
|
||||
return facadeQuery;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Query createQuery(CriteriaUpdate updateQuery) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query createQuery(CriteriaDelete deleteQuery) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
public OpenJPAQuery createDynamicQuery(
|
||||
org.apache.openjpa.persistence.query.QueryDefinition qdef) {
|
||||
String jpql = _emf.getDynamicQueryBuilder().toJPQL(qdef);
|
||||
|
@ -1790,6 +1878,26 @@ public class EntityManagerImpl
|
|||
return _emf.getMetamodel();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> EntityGraph<T> createEntityGraph(Class<T> rootType) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGraph<?> createEntityGraph(String graphName) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public EntityGraph<?> getEntityGraph(String graphName) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> List<EntityGraph<? super T>> getEntityGraphs(Class<T> entityClass) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given property to the given value, reflectively.
|
||||
*
|
||||
|
@ -1892,4 +2000,13 @@ public class EntityManagerImpl
|
|||
}
|
||||
return properties;
|
||||
}
|
||||
|
||||
private QueryMetaData getQueryMetadata(String name) {
|
||||
MetaDataRepository repos = _broker.getConfiguration().getMetaDataRepositoryInstance();
|
||||
QueryMetaData meta = repos.getQueryMetaData(null, name, _broker.getClassLoader(), true);
|
||||
if (meta == null) {
|
||||
throw new RuntimeException("No query named [" + name + "]");
|
||||
}
|
||||
return meta;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,5 +88,8 @@ public enum MetaDataTag {
|
|||
READ_ONLY,
|
||||
TYPE,
|
||||
REPLICATED,
|
||||
OPENJPA_VERSION
|
||||
OPENJPA_VERSION,
|
||||
// JPA 2.1
|
||||
STOREDPROCEDURE_QUERIES,
|
||||
STOREDPROCEDURE_QUERY
|
||||
}
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.apache.openjpa.persistence;
|
|||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.net.URL;
|
||||
import java.security.AccessController;
|
||||
import java.util.ArrayList;
|
||||
|
@ -39,6 +40,8 @@ import javax.persistence.NamedNativeQueries;
|
|||
import javax.persistence.NamedNativeQuery;
|
||||
import javax.persistence.NamedQueries;
|
||||
import javax.persistence.NamedQuery;
|
||||
import javax.persistence.NamedStoredProcedureQueries;
|
||||
import javax.persistence.NamedStoredProcedureQuery;
|
||||
import javax.persistence.SqlResultSetMapping;
|
||||
import javax.persistence.SqlResultSetMappings;
|
||||
import javax.persistence.metamodel.StaticMetamodel;
|
||||
|
@ -371,10 +374,20 @@ public class PersistenceMetaDataFactory
|
|||
hasNamedNativeQuery(queryName, ((NamedNativeQueries) cls.
|
||||
getAnnotation(NamedNativeQueries.class)).value()))
|
||||
return cls;
|
||||
if (isAnnotated(cls, NamedStoredProcedureQuery.class)
|
||||
&& hasNamedStoredProcedure(queryName, cls.getAnnotation(NamedStoredProcedureQuery.class)))
|
||||
return cls;
|
||||
if (isAnnotated(cls, NamedStoredProcedureQueries.class)
|
||||
&& hasNamedStoredProcedure(queryName, cls.getAnnotation(NamedStoredProcedureQueries.class).value()))
|
||||
return cls;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private boolean isAnnotated(Class<?> cls, Class<? extends Annotation> annotationClazz) {
|
||||
return AccessController.doPrivileged(J2DoPrivHelper.isAnnotationPresentAction(cls, annotationClazz));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getResultSetMappingScope(String rsMappingName,
|
||||
ClassLoader loader) {
|
||||
|
@ -418,6 +431,14 @@ public class PersistenceMetaDataFactory
|
|||
return false;
|
||||
}
|
||||
|
||||
private boolean hasNamedStoredProcedure(String query, NamedStoredProcedureQuery... queries) {
|
||||
for (NamedStoredProcedureQuery q : queries) {
|
||||
if (query.equals(q.name()))
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasNamedNativeQuery(String query,
|
||||
NamedNativeQuery... queries) {
|
||||
for (NamedNativeQuery q : queries) {
|
||||
|
|
|
@ -220,6 +220,16 @@ public class PersistenceProviderImpl
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateSchema(PersistenceUnitInfo info, Map map) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean generateSchema(String persistenceUnitName, Map map) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
public void setPersistenceEnvironmentInfo(OpenJPAConfiguration conf, PersistenceUnitInfo pui) {
|
||||
// OPENJPA-1460 Fix scope visibility of orm.xml when it is packaged in both ear file and war file
|
||||
if (conf instanceof OpenJPAConfigurationImpl) {
|
||||
|
|
|
@ -129,7 +129,15 @@ public class StoreCacheImpl
|
|||
public void evictAll() {
|
||||
_cache.clear();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> cls) {
|
||||
if (cls.isInstance(this)) {
|
||||
return cls.cast(this);
|
||||
}
|
||||
throw new javax.persistence.PersistenceException(cls.getName() + " not supported");
|
||||
}
|
||||
|
||||
public CacheStatistics getStatistics() {
|
||||
return (_cache == null) ? null : _cache.getStatistics();
|
||||
}
|
||||
|
|
|
@ -0,0 +1,415 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*/
|
||||
package org.apache.openjpa.persistence;
|
||||
|
||||
import org.apache.openjpa.kernel.DelegatingResultList;
|
||||
import org.apache.openjpa.kernel.QueryResultCallback;
|
||||
import org.apache.openjpa.lib.rop.ResultList;
|
||||
import org.apache.openjpa.lib.rop.ResultObjectProvider;
|
||||
import org.apache.openjpa.lib.util.Localizer;
|
||||
import org.apache.openjpa.meta.MultiQueryMetaData;
|
||||
import org.apache.openjpa.util.RuntimeExceptionTranslator;
|
||||
import org.apache.openjpa.util.UserException;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.NoResultException;
|
||||
import javax.persistence.NonUniqueResultException;
|
||||
|
||||
/**
|
||||
* Implements Store Procedure based query for JPA facade.
|
||||
* <br>
|
||||
* A {@link StoredProcedureQuery stored procedure query} differs from other query types because it may return
|
||||
* more than one result set, apart from an optional update count, whereas the traditional query processing in OpenJPA
|
||||
* via the abstractions of {@link ResultObjectProvider} and {@link org.apache.openjpa.jdbc.sql.Result}
|
||||
* assumed that a query will return its
|
||||
* result in a single list.
|
||||
* <br>
|
||||
* This query resorts to a callback mechanism, where the execution of the query returns not a result, but a
|
||||
* {@link QueryResultCallback callback object} that can be used to callback to OpenJPA kernel to get a series of
|
||||
* results via the traditional result processing pathway.
|
||||
*
|
||||
* @author Pinaki Poddar
|
||||
* @author Romain Manni-Bucau
|
||||
*/
|
||||
// TODO: add lock
|
||||
public class StoredProcedureQueryImpl implements StoredProcedureQuery {
|
||||
private static final Localizer _loc = Localizer.forPackage(QueryImpl.class);
|
||||
|
||||
private final String _name;
|
||||
private final QueryImpl<?> _delegate;
|
||||
private final MultiQueryMetaData _meta;
|
||||
private QueryResultCallback _callback;
|
||||
private boolean _declaredParams; // mainly a flag for now (null or not)
|
||||
|
||||
/**
|
||||
* Construct a query for executing a Stored Procedure.
|
||||
* @param procedureName name of the database stored procedure.
|
||||
* @param meta
|
||||
* @param delegate the delegate which manages bind parameters on behalf of this
|
||||
*/
|
||||
public StoredProcedureQueryImpl(String procedureName, MultiQueryMetaData meta, QueryImpl<?> delegate) {
|
||||
_name = procedureName;
|
||||
if (!isValidProcedureName(procedureName)) {
|
||||
throw new RuntimeException(procedureName + " is not a valid procedure name");
|
||||
}
|
||||
_meta = meta;
|
||||
_delegate = delegate;
|
||||
_delegate.compile();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the facade delegate that manages bind parameters on behalf of this receiver.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public OpenJPAQuery<?> getDelegate() {
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the kernel delegate that is handles actual execution on behalf of this receiver.
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public org.apache.openjpa.kernel.Query getExecutableQuery() {
|
||||
return _delegate.getDelegate();
|
||||
}
|
||||
|
||||
private void buildParametersIfNeeded() {
|
||||
if (!_declaredParams) {
|
||||
for (MultiQueryMetaData.Parameter entry : _meta.getParameters()) {
|
||||
final Object key;
|
||||
final Parameter<?> param;
|
||||
if (entry.getName() == null) {
|
||||
key = entry.getPosition();
|
||||
param = new ParameterImpl(entry.getPosition(), entry.getType());
|
||||
} else {
|
||||
key = entry.getName();
|
||||
param = new ParameterImpl(entry.getName(), entry.getType());
|
||||
}
|
||||
_delegate.declareParameter(key, param);
|
||||
}
|
||||
_declaredParams = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes this receiver by delegation to the underlying executable query.
|
||||
* <br>
|
||||
* This method is multi-call safe. The underlying executable query is executed
|
||||
* <em>only</em> for the first invocation. Subsequent
|
||||
*/
|
||||
@Override
|
||||
public boolean execute() {
|
||||
if (_callback == null) {
|
||||
_callback = (QueryResultCallback) getExecutableQuery().execute(_delegate.getParameterValues());
|
||||
}
|
||||
return _callback.getExecutionResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List getResultList() {
|
||||
execute();
|
||||
try {
|
||||
Object list = _callback.callback();
|
||||
RuntimeExceptionTranslator trans = PersistenceExceptions
|
||||
.getRollbackTranslator(_delegate.getEntityManager());
|
||||
return new DelegatingResultList((ResultList) list, trans);
|
||||
} catch (Exception ex) {
|
||||
throw new javax.persistence.PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getSingleResult() {
|
||||
execute();
|
||||
try {
|
||||
ResultList result = (ResultList) _callback.callback();
|
||||
if (result == null || result.isEmpty())
|
||||
throw new NoResultException(_loc.get("no-result", _name)
|
||||
.getMessage());
|
||||
if (result.size() > 1)
|
||||
throw new NonUniqueResultException(_loc.get("non-unique-result",
|
||||
_name, result.size()).getMessage());
|
||||
RuntimeExceptionTranslator trans = PersistenceExceptions
|
||||
.getRollbackTranslator(_delegate.getEntityManager());
|
||||
return new DelegatingResultList(result, trans).iterator().next();
|
||||
} catch (Exception ex) {
|
||||
throw new javax.persistence.PersistenceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasMoreResults() {
|
||||
return _callback != null && _callback.hasMoreResults();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getUpdateCount() {
|
||||
assertExecuted();
|
||||
return _callback.getUpdateCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int executeUpdate() {
|
||||
execute();
|
||||
return _callback.getUpdateCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Parameter<T> getParameter(String name, Class<T> type) {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.getParameter(name, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> Parameter<T> getParameter(int position, Class<T> type) {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.getParameter(position, type);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isBound(Parameter<?> param) {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.isBound(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T getParameterValue(Parameter<T> param) {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.getParameterValue(param);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T unwrap(Class<T> cls) {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.unwrap(cls);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> StoredProcedureQuery setParameter(Parameter<T> param, T value) {
|
||||
buildParametersIfNeeded();
|
||||
_delegate.setParameter(param, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setParameter(Parameter<Calendar> param, Calendar cal, TemporalType temporalType) {
|
||||
buildParametersIfNeeded();
|
||||
_delegate.setParameter(param, cal, temporalType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setParameter(Parameter<Date> param, Date value, TemporalType temporalType) {
|
||||
buildParametersIfNeeded();
|
||||
_delegate.setParameter(param, value, temporalType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery registerStoredProcedureParameter(int position, Class type, ParameterMode mode) {
|
||||
buildParametersIfNeeded();
|
||||
ParameterImpl param = new ParameterImpl(position, type);
|
||||
_delegate.declareParameter(position, param);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery registerStoredProcedureParameter(String name, Class type, ParameterMode mode) {
|
||||
buildParametersIfNeeded();
|
||||
ParameterImpl param = new ParameterImpl(name, type);
|
||||
_delegate.declareParameter(name, param);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOutputParameterValue(int position) {
|
||||
return _callback == null ? null : _callback.getOut(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getOutputParameterValue(String parameterName) {
|
||||
return _callback == null ? null : _callback.getOut(parameterName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public javax.persistence.Query setMaxResults(int maxResult) {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.setMaxResults(maxResult);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxResults() {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.getMaxResults();
|
||||
}
|
||||
|
||||
@Override
|
||||
public javax.persistence.Query setFirstResult(int startPosition) {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.setFirstResult(startPosition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getFirstResult() {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.getFirstResult();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, Object> getHints() {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.getHints();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<Parameter<?>> getParameters() {
|
||||
buildParametersIfNeeded();
|
||||
return _delegate.getParameters();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter<?> getParameter(String name) {
|
||||
buildParametersIfNeeded();
|
||||
return _delegate.getParameter(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parameter<?> getParameter(int position) {
|
||||
buildParametersIfNeeded();
|
||||
return _delegate.getParameter(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParameterValue(String name) {
|
||||
buildParametersIfNeeded();
|
||||
return _delegate.getParameterValue(name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getParameterValue(int position) {
|
||||
buildParametersIfNeeded();
|
||||
return _delegate.getParameter(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlushModeType getFlushMode() {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.getFlushMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public javax.persistence.Query setLockMode(LockModeType lockMode) {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.setLockMode(lockMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LockModeType getLockMode() {
|
||||
// TODO JPA 2.1 Method
|
||||
return _delegate.getLockMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setHint(String hintName, Object value) {
|
||||
_delegate.setHint(hintName, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setParameter(String name, Object value) {
|
||||
buildParametersIfNeeded();
|
||||
_delegate.setParameter(name, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setParameter(String name, Calendar cal, TemporalType temporalType) {
|
||||
buildParametersIfNeeded();
|
||||
_delegate.setParameter(name, cal, temporalType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setParameter(String name, Date date, TemporalType temporalType) {
|
||||
buildParametersIfNeeded();
|
||||
_delegate.setParameter(name, date, temporalType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setParameter(int position, Object value) {
|
||||
buildParametersIfNeeded();
|
||||
_delegate.setParameter(position, value);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setParameter(int position, Calendar value, TemporalType temporalType) {
|
||||
buildParametersIfNeeded();
|
||||
_delegate.setParameter(position, value, temporalType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setParameter(int position, Date value, TemporalType temporalType) {
|
||||
buildParametersIfNeeded();
|
||||
_delegate.setParameter(position, value, temporalType);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public StoredProcedureQuery setFlushMode(FlushModeType flushMode) {
|
||||
// TODO JPA 2.1 Method
|
||||
_delegate.setFlushMode(flushMode);
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that user has executed this query.
|
||||
*/
|
||||
void assertExecuted() {
|
||||
if (_callback == null) {
|
||||
throw new UserException(this + " has not been executed");
|
||||
}
|
||||
}
|
||||
|
||||
boolean isValidProcedureName(String s) {
|
||||
if (s == null || s.trim().length() == 0) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < s.length(); i++) {
|
||||
char ch = s.charAt(i);
|
||||
if (ch == '#' || ch == '$' || Character.isJavaIdentifierPart(ch))
|
||||
continue;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return _name;
|
||||
}
|
||||
}
|
|
@ -601,7 +601,7 @@ public class XMLPersistenceMetaDataParser
|
|||
@Override
|
||||
protected boolean startSystemElement(String name, Attributes attrs)
|
||||
throws SAXException {
|
||||
Object tag = (Object) _elems.get(name);
|
||||
Object tag = _elems.get(name);
|
||||
boolean ret = false;
|
||||
if (tag == null) {
|
||||
if (isMappingOverrideMode())
|
||||
|
|
|
@ -29,13 +29,22 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
|
||||
import javax.persistence.Tuple;
|
||||
import javax.persistence.criteria.CollectionJoin;
|
||||
import javax.persistence.criteria.CompoundSelection;
|
||||
import javax.persistence.criteria.CriteriaDelete;
|
||||
import javax.persistence.criteria.CriteriaUpdate;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.From;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
import javax.persistence.criteria.MapJoin;
|
||||
import javax.persistence.criteria.Order;
|
||||
import javax.persistence.criteria.ParameterExpression;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.Root;
|
||||
import javax.persistence.criteria.Selection;
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
import javax.persistence.criteria.Subquery;
|
||||
import javax.persistence.criteria.Predicate.BooleanOperator;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
|
@ -108,6 +117,16 @@ public class CriteriaBuilderImpl implements OpenJPACriteriaBuilder, ExpressionPa
|
|||
return new CriteriaQueryImpl<Tuple>(_model, Tuple.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> CriteriaUpdate<T> createCriteriaUpdate(Class<T> targetEntity) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> CriteriaDelete<T> createCriteriaDelete(Class<T> targetEntity) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
public Object parse(String ql, ExpressionStoreQuery query) {
|
||||
throw new AbstractMethodError();
|
||||
}
|
||||
|
@ -252,6 +271,41 @@ public class CriteriaBuilderImpl implements OpenJPACriteriaBuilder, ExpressionPa
|
|||
return new Expressions.DatabaseFunction(name, type, args);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X, T, V extends T> Join<X, V> treat(Join<X, T> join, Class<V> type) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X, T, E extends T> CollectionJoin<X, E> treat(CollectionJoin<X, T> join, Class<E> type) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X, T, E extends T> SetJoin<X, E> treat(SetJoin<X, T> join, Class<E> type) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X, T, E extends T> ListJoin<X, E> treat(ListJoin<X, T> join, Class<E> type) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X, K, T, V extends T> MapJoin<X, K, V> treat(MapJoin<X, K, T> join, Class<V> type) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X, T extends X> Path<T> treat(Path<X> path, Class<T> type) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X, T extends X> Root<T> treat(Root<X> root, Class<T> type) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
public Predicate ge(Expression<? extends Number> x,
|
||||
Expression<? extends Number> y) {
|
||||
return new Expressions.GreaterThanEqual(x,y);
|
||||
|
|
|
@ -29,6 +29,7 @@ import javax.persistence.criteria.ListJoin;
|
|||
import javax.persistence.criteria.MapJoin;
|
||||
import javax.persistence.criteria.Path;
|
||||
import javax.persistence.criteria.PluralJoin;
|
||||
import javax.persistence.criteria.Predicate;
|
||||
import javax.persistence.criteria.SetJoin;
|
||||
import javax.persistence.metamodel.Attribute;
|
||||
import javax.persistence.metamodel.CollectionAttribute;
|
||||
|
@ -138,7 +139,22 @@ abstract class Joins {
|
|||
public Member<? extends Z, X> getMember() {
|
||||
return (Member<? extends Z, X>) _member;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Join<Z, X> on(Expression<Boolean> restriction) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Join<Z, X> on(Predicate... restrictions) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate getOn() {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the metamodel attribute corresponding to the join.
|
||||
* @return metamodel attribute type corresponding to the join
|
||||
|
@ -495,7 +511,22 @@ abstract class Joins {
|
|||
public Collection(FromImpl<?,Z> parent, Members.CollectionAttributeImpl<? super Z, E> member, JoinType jt) {
|
||||
super(parent, member, jt);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CollectionJoin<Z, E> on(Expression<Boolean> restriction) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollectionJoin<Z, E> on(Predicate... restrictions) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate getOn() {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
public CollectionAttribute<? super Z, E> getModel() {
|
||||
return (CollectionAttribute<? super Z, E>)_member;
|
||||
}
|
||||
|
@ -512,7 +543,22 @@ abstract class Joins {
|
|||
public Set(FromImpl<?,Z> parent, Members.SetAttributeImpl<? super Z, E> member, JoinType jt) {
|
||||
super(parent, member, jt);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SetJoin<Z, E> on(Expression<Boolean> restriction) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public SetJoin<Z, E> on(Predicate... restrictions) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate getOn() {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
public SetAttribute<? super Z, E> getModel() {
|
||||
return (SetAttribute<? super Z, E>)_member;
|
||||
}
|
||||
|
@ -531,7 +577,22 @@ abstract class Joins {
|
|||
public List(FromImpl<?,Z> parent, Members.ListAttributeImpl<? super Z, E> member, JoinType jt) {
|
||||
super(parent, member, jt);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ListJoin<Z, E> on(Expression<Boolean> restriction) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public ListJoin<Z, E> on(Predicate... restrictions) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate getOn() {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
public ListAttribute<? super Z, E> getModel() {
|
||||
return (ListAttribute<? super Z, E>)_member;
|
||||
}
|
||||
|
@ -556,7 +617,22 @@ abstract class Joins {
|
|||
public Map(FromImpl<?,Z> parent, Members.MapAttributeImpl<? super Z, K,V> member, JoinType jt) {
|
||||
super(parent, member, jt);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public MapJoin<Z, K, V> on(Expression<Boolean> restriction) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapJoin<Z, K, V> on(Predicate... restrictions) {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Predicate getOn() {
|
||||
throw new UnsupportedOperationException("JPA 2.1");
|
||||
}
|
||||
|
||||
public MapAttribute<? super Z, K,V> getModel() {
|
||||
return (MapAttribute<? super Z, K,V>) _member;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,7 @@ import java.util.concurrent.CopyOnWriteArraySet;
|
|||
|
||||
import javax.persistence.criteria.AbstractQuery;
|
||||
import javax.persistence.criteria.CollectionJoin;
|
||||
import javax.persistence.criteria.CommonAbstractCriteria;
|
||||
import javax.persistence.criteria.Expression;
|
||||
import javax.persistence.criteria.Join;
|
||||
import javax.persistence.criteria.ListJoin;
|
||||
|
@ -94,7 +95,12 @@ class SubqueryImpl<T> extends ExpressionImpl<T> implements Subquery<T> {
|
|||
public AbstractQuery<?> getParent() {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public CommonAbstractCriteria getContainingQuery() {
|
||||
return getParent();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the captive query to which this subquery delegates.
|
||||
*/
|
||||
|
|
|
@ -140,7 +140,7 @@
|
|||
<include>commons-dbcp:commons-dbcp</include>
|
||||
|
||||
<include>org.apache.geronimo.specs:geronimo-jta_1.1_spec</include>
|
||||
<include>org.apache.geronimo.specs:geronimo-jpa_2.0_spec</include>
|
||||
<include>org.apache.geronimo.specs:geronimo-jpa_2.1_spec</include>
|
||||
<include>org.apache.geronimo.specs:geronimo-jms_1.1_spec</include>
|
||||
<include>org.apache.geronimo.specs:geronimo-validation_1.0_spec</include>
|
||||
<include>org.apache.bval:org.apache.bval.bundle</include>
|
||||
|
|
|
@ -79,7 +79,7 @@
|
|||
<include>commons-dbcp:commons-dbcp</include>
|
||||
|
||||
<include>org.apache.geronimo.specs:geronimo-jta_1.1_spec</include>
|
||||
<include>org.apache.geronimo.specs:geronimo-jpa_2.0_spec</include>
|
||||
<include>org.apache.geronimo.specs:geronimo-jpa_2.1_spec</include>
|
||||
<include>org.apache.geronimo.specs:geronimo-jms_1.1_spec</include>
|
||||
<include>org.apache.geronimo.specs:geronimo-validation_1.0_spec</include>
|
||||
<include>org.apache.bval:org.apache.bval.bundle</include>
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
|
@ -115,7 +115,7 @@
|
|||
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
|
@ -43,7 +43,7 @@
|
|||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
|
@ -36,7 +36,7 @@
|
|||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
4
pom.xml
4
pom.xml
|
@ -524,8 +524,8 @@
|
|||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
<artifactId>geronimo-jpa_2.0_spec</artifactId>
|
||||
<version>1.1</version>
|
||||
<artifactId>geronimo-jpa_2.1_spec</artifactId>
|
||||
<version>1.0-SNAPSHOT</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.geronimo.specs</groupId>
|
||||
|
|
|
@ -40,7 +40,7 @@ set JAVAC=%JAVA_HOME%\bin\javac
|
|||
@rem Compiler classpath shown for a typical OpenJPA development environment in Windows.
|
||||
@rem The essential aspect is openjpa libraries must be in the compiler's classpath.
|
||||
set M_REPO="%USERPROFILE%\.m2\repository"
|
||||
set SPEC=geronimo-jpa_2.0_spec
|
||||
set SPEC=geronimo-jpa_2.1_spec
|
||||
set VERSION=1.0-EA9-SNAPSHOT
|
||||
set JPA_LIB=%M_REPO%\org\apache\geronimo\specs\%SPEC%\%VERSION%\%SPEC%-%VERSION%.jar
|
||||
|
||||
|
|
Loading…
Reference in New Issue