Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* 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 java.io.Serializable;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Objects;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.openjpa.conf.OpenJPAConfiguration;
import org.apache.openjpa.enhance.PersistenceCapable;
import org.apache.openjpa.kernel.exps.AggregateListener;
import org.apache.openjpa.kernel.exps.Constant;
import org.apache.openjpa.kernel.exps.FilterListener;
import org.apache.openjpa.kernel.exps.Literal;
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.MergedResultObjectProvider;
import org.apache.openjpa.lib.rop.RangeResultObjectProvider;
import org.apache.openjpa.lib.rop.ResultList;
import org.apache.openjpa.lib.rop.ResultObjectProvider;
import org.apache.openjpa.lib.util.ClassUtil;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.lib.util.OrderedMap;
import org.apache.openjpa.lib.util.ReferenceHashSet;
import org.apache.openjpa.lib.util.StringUtil;
import org.apache.openjpa.lib.util.collections.AbstractReferenceMap;
import org.apache.openjpa.lib.util.collections.LinkedMap;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.meta.MetaDataRepository;
import org.apache.openjpa.util.GeneralException;
import org.apache.openjpa.util.ImplHelper;
import org.apache.openjpa.util.InvalidStateException;
import org.apache.openjpa.util.NoResultException;
import org.apache.openjpa.util.NonUniqueResultException;
import org.apache.openjpa.util.OpenJPAException;
import org.apache.openjpa.util.UnsupportedException;
import org.apache.openjpa.util.UserException;
/**
* Implementation of the {@link Query} interface.
*
* @author Abe White
*/
public class QueryImpl implements Query {
private static final long serialVersionUID = 1L;
private static final Localizer _loc = Localizer.forPackage(QueryImpl.class);
private final String _language;
private final StoreQuery _storeQuery;
private transient final BrokerImpl _broker;
private transient final Log _log;
private transient ClassLoader _loader = null;
// query has its own internal lock
private ReentrantLock _lock;
// unparsed state
private Class> _class = null;
private boolean _subclasses = true;
private boolean _readOnly = false;
private String _query = null;
private String _params = null;
// parsed state
private transient Compilation _compiled = null;
private transient boolean _compiling = false;
private transient ResultPacker _packer = null;
// candidates
private transient Collection> _collection = null;
private transient Extent _extent = null;
// listeners
private Map _filtListeners = null;
private Map _aggListeners = null;
// configuration for loading objects
private FetchConfiguration _fc = null;
private boolean _ignoreChanges = false;
private Class> _resultMappingScope = null;
private String _resultMappingName = null;
// these fields should only be used directly after we have a compilation,
// because their values may be encoded in the query string
private Boolean _unique = null;
private Class> _resultClass = null;
private transient long _startIdx = 0;
private transient long _endIdx = Long.MAX_VALUE;
private transient boolean _rangeSet = false;
// remember the list of all the results we have returned so we
// can free their resources when close or closeAll is called
private transient final Collection _resultLists =
new ReferenceHashSet(AbstractReferenceMap.ReferenceStrength.WEAK);
private boolean _printParameters = false;
/**
* Construct a query managed by the given broker.
*/
public QueryImpl(Broker broker, String language, StoreQuery storeQuery) {
_broker = (BrokerImpl) broker;
_language = language;
_storeQuery = storeQuery;
_fc = (FetchConfiguration) broker.getFetchConfiguration().clone();
_log = broker.getConfiguration().getLog(OpenJPAConfiguration.LOG_QUERY);
_storeQuery.setContext(this);
_printParameters = _broker.getPrintParameters();
if (_broker != null && _broker.getMultithreaded())
_lock = new ReentrantLock();
}
/**
* Internal store query.
*/
public StoreQuery getStoreQuery() {
return _storeQuery;
}
@Override
public Broker getBroker() {
return _broker;
}
@Override
public Query getQuery() {
return this;
}
@Override
public StoreContext getStoreContext() {
return _broker;
}
@Override
public String getLanguage() {
return _language;
}
@Override
public FetchConfiguration getFetchConfiguration() {
return _fc;
}
@Override
public String getQueryString() {
return _query;
}
@Override
public boolean getIgnoreChanges() {
assertOpen();
return _ignoreChanges;
}
@Override
public void setIgnoreChanges(boolean flag) {
lock();
try {
assertOpen();
// allowed modification: no read-only check
_ignoreChanges = flag;
} finally {
unlock();
}
}
@Override
public boolean isReadOnly() {
assertOpen();
return _readOnly;
}
@Override
public void setReadOnly(boolean flag) {
lock();
try {
assertOpen();
_readOnly = flag;
} finally {
unlock();
}
}
@Override
public void addFilterListener(FilterListener listener) {
lock();
try {
assertOpen();
assertNotReadOnly();
if (_filtListeners == null)
_filtListeners = new HashMap<>(5);
_filtListeners.put(listener.getTag(), listener);
} finally {
unlock();
}
}
@Override
public void removeFilterListener(FilterListener listener) {
lock();
try {
assertOpen();
assertNotReadOnly();
if (_filtListeners != null)
_filtListeners.remove(listener.getTag());
} finally {
unlock();
}
}
@Override
public Collection getFilterListeners() {
if (_filtListeners == null)
return Collections.emptyList();
else
return _filtListeners.values();
}
@Override
public FilterListener getFilterListener(String tag) {
// first check listeners for this query
if (_filtListeners != null) {
FilterListener listen = _filtListeners.get(tag);
if (listen != null)
return listen;
}
// check user-defined listeners from configuration
FilterListener[] confListeners = _broker.getConfiguration().
getFilterListenerInstances();
for (FilterListener confListener : confListeners)
if (confListener.getTag().equals(tag))
return confListener;
// check store listeners
return _storeQuery.getFilterListener(tag);
}
@Override
public void addAggregateListener(AggregateListener listener) {
lock();
try {
assertOpen();
assertNotReadOnly();
if (_aggListeners == null)
_aggListeners = new HashMap<>(5);
_aggListeners.put(listener.getTag(), listener);
} finally {
unlock();
}
}
@Override
public void removeAggregateListener(AggregateListener listener) {
lock();
try {
assertOpen();
assertNotReadOnly();
if (_aggListeners != null)
_aggListeners.remove(listener.getTag());
} finally {
unlock();
}
}
@Override
public Collection getAggregateListeners() {
if (_aggListeners == null)
return Collections.emptyList();
else
return _aggListeners.values();
}
@Override
public AggregateListener getAggregateListener(String tag) {
// first check listeners for this query
if (_aggListeners != null) {
AggregateListener listen = _aggListeners.
get(tag);
if (listen != null)
return listen;
}
// check user-defined listeners from configuration
AggregateListener[] confListeners = _broker.getConfiguration().
getAggregateListenerInstances();
for (AggregateListener confListener : confListeners)
if (confListener.getTag().equals(tag))
return confListener;
// check store listeners
return _storeQuery.getAggregateListener(tag);
}
@Override
public Extent getCandidateExtent() {
// if just the class is set, fetch the corresponding extent; if the
// extent is already set but its ignore cache setting is wrong,
// get a new extent with the correct setting (don't modify orig extent
// in case the user has a reference to it and might use it)
lock();
try {
Class> cls = getCandidateType();
if (_extent == null && _collection == null && _broker != null
&& cls != null) {
_extent = _broker.newExtent(cls, _subclasses);
_extent.setIgnoreChanges(_ignoreChanges);
} else if (_extent != null
&& _extent.getIgnoreChanges() != _ignoreChanges && cls != null){
_extent = _broker.newExtent(cls, _extent.hasSubclasses());
_extent.setIgnoreChanges(_ignoreChanges);
}
return _extent;
} finally {
unlock();
}
}
@Override
public void setCandidateExtent(Extent candidateExtent) {
lock();
try {
assertOpen();
assertNotReadOnly();
if (candidateExtent == _extent)
return;
if (candidateExtent == null) {
_extent = null;
return;
}
// if extent then not collection
_extent = candidateExtent;
_collection = null;
boolean invalidate = false;
if (_extent.getElementType() != _class) {
_class = _extent.getElementType();
_loader = null;
invalidate = true;
}
if (_extent.hasSubclasses() != _subclasses) {
_subclasses = _extent.hasSubclasses();
invalidate = true;
}
if (invalidate)
invalidateCompilation();
} finally {
unlock();
}
}
@Override
public Collection> getCandidateCollection() {
assertOpen();
return _collection;
}
@Override
public void setCandidateCollection(Collection> candidateCollection) {
if (!_storeQuery.supportsInMemoryExecution())
throw new UnsupportedException(_loc.get("query-nosupport",
_language));
lock();
try {
assertOpen();
// if collection then not extent
_collection = candidateCollection;
if (_collection != null)
_extent = null;
} finally {
unlock();
}
}
@Override
public Class getCandidateType() {
lock();
try {
assertOpen();
if (_class != null || _compiled != null || _query == null
|| _broker == null)
return _class;
// check again after compilation; maybe encoded in string
compileForCompilation();
return _class;
} finally {
unlock();
}
}
@Override
public void setCandidateType(Class candidateClass, boolean subs) {
lock();
try {
assertOpen();
assertNotReadOnly();
_class = candidateClass;
_subclasses = subs;
_loader = null;
invalidateCompilation();
} finally {
unlock();
}
}
@Override
public boolean hasSubclasses() {
return _subclasses;
}
@Override
public String getResultMappingName() {
assertOpen();
return _resultMappingName;
}
@Override
public Class getResultMappingScope() {
assertOpen();
return _resultMappingScope;
}
@Override
public void setResultMapping(Class> scope, String name) {
lock();
try {
assertOpen();
_resultMappingScope = scope;
_resultMappingName = name;
_packer = null;
} finally {
unlock();
}
}
@Override
public boolean isUnique() {
lock();
try {
assertOpen();
if (_unique != null)
return _unique;
if ((_query == null && _language.endsWith("JPQL")) || _compiling || _broker == null)
return false;
// check again after compilation; maybe encoded in string
if (_compiled == null) {
compileForCompilation();
if (_unique != null)
return _unique;
}
// no explicit setting; default
StoreQuery.Executor ex = compileForExecutor();
if (!ex.isAggregate(_storeQuery))
return false;
return !ex.hasGrouping(_storeQuery);
} finally {
unlock();
}
}
/**
* Affirms if this query has originated by parsing a string-based query.
*/
public boolean isParsedQuery() {
return getQueryString() != null;
}
@Override
public void setUnique(boolean unique) {
lock();
try {
assertOpen();
assertNotReadOnly();
_unique = (unique) ? Boolean.TRUE : Boolean.FALSE;
} finally {
unlock();
}
}
@Override
public Class getResultType() {
lock();
try {
assertOpen();
if (_resultClass != null || _compiled != null || _query == null
|| _broker == null)
return _resultClass;
// check again after compilation; maybe encoded in string
compileForCompilation();
return _resultClass;
} finally {
unlock();
}
}
@Override
public void setResultType(Class cls) {
lock();
try {
assertOpen();
// allowed modification: no read-only check
_resultClass = cls;
_packer = null;
} finally {
unlock();
}
}
@Override
public long getStartRange() {
assertOpen();
return _startIdx;
}
@Override
public long getEndRange() {
assertOpen();
return _endIdx;
}
@Override
public void setRange(long start, long end) {
if (start < 0 || end < 0)
throw new UserException(_loc.get("invalid-range",
String.valueOf(start), String.valueOf(end)));
if (end - start > Integer.MAX_VALUE && end != Long.MAX_VALUE)
throw new UserException(_loc.get("range-too-big",
String.valueOf(start), String.valueOf(end)));
lock();
try {
assertOpen();
// allowed modification: no read-only check
_startIdx = start;
_endIdx = end;
_rangeSet = true;
} finally {
unlock();
}
}
@Override
public String getParameterDeclaration() {
lock();
try {
assertOpen();
if (_params != null || _compiled != null || _compiling
|| _broker == null)
return _params;
// check again after compilation; maybe encoded in string
compileForCompilation();
return _params;
} finally {
unlock();
}
}
@Override
public void declareParameters(String params) {
if (!_storeQuery.supportsParameterDeclarations())
throw new UnsupportedException(_loc.get("query-nosupport",
_language));
lock();
try {
assertOpen();
assertNotReadOnly();
_params = StringUtil.trimToNull(params);
invalidateCompilation();
} finally {
unlock();
}
}
@Override
public void compile() {
lock();
try {
assertOpen();
StoreQuery.Executor ex = compileForExecutor();
getResultPacker(_storeQuery, ex);
ex.validate(_storeQuery);
} finally {
unlock();
}
}
@Override
public Object getCompilation() {
lock();
try {
return compileForCompilation().storeData;
} finally {
unlock();
}
}
/**
* Compile query properties.
*/
private Compilation compileForCompilation() {
if (_compiled != null || _compiling)
return _compiled;
assertNotSerialized();
assertOpen();
boolean readOnly = _readOnly;
_readOnly = false;
_compiling = true;
try {
_compiled = compilationFromCache();
return _compiled;
} catch (OpenJPAException ke) {
throw ke;
} catch (RuntimeException re) {
throw new GeneralException(re);
} finally {
_compiling = false;
_readOnly = readOnly;
}
}
/**
* Find the cached compilation for the current query, creating one if it
* does not exist.
*/
@SuppressWarnings("unchecked")
protected Compilation compilationFromCache() {
Map compCache = _broker.getConfiguration().getQueryCompilationCacheInstance();
if (compCache == null || !isParsedQuery()) {
return newCompilation();
} else {
CompilationKey key = new CompilationKey();
key.queryType = _storeQuery.getClass();
key.candidateType = getCandidateType();
key.subclasses = hasSubclasses();
key.query = getQueryString();
key.language = getLanguage();
key.storeKey = _storeQuery.newCompilationKey();
Compilation comp = (Compilation) compCache.get(key);
// parse declarations if needed
if (comp == null) {
comp = newCompilation();
// only cache those queries that can be compiled
if (comp.storeData != null) {
synchronized (compCache) {
Compilation existingComp = (Compilation) compCache.get(key);
if (existingComp == null) {
compCache.put(key, comp);
} else {
comp = existingComp;
}
}
}
} else {
_storeQuery.populateFromCompilation(comp.storeData);
}
return comp;
}
}
/**
* Create and populate a new compilation.
*/
private Compilation newCompilation() {
Compilation comp = new Compilation();
comp.storeData = _storeQuery.newCompilation();
_storeQuery.populateFromCompilation(comp.storeData);
return comp;
}
/**
* Compile for execution, choosing between datastore and in-mem
* compilation based on what we support and our settings.
*/
private StoreQuery.Executor compileForExecutor() {
Compilation comp = compileForCompilation();
if (_collection == null) {
if (comp.datastore != null)
return comp.datastore;
if (comp.memory != null)
return comp.memory;
if (_storeQuery.supportsDataStoreExecution())
return compileForDataStore(comp);
return compileForInMemory(comp);
}
if (comp.memory != null)
return comp.memory;
if (comp.datastore != null)
return comp.datastore;
if (_storeQuery.supportsInMemoryExecution())
return compileForInMemory(comp);
return compileForDataStore(comp);
}
/**
* Create an expression tree for datastore execution.
*/
private StoreQuery.Executor compileForDataStore(Compilation comp) {
if (comp.datastore == null)
comp.datastore = createExecutor(false);
return comp.datastore;
}
/**
* Create an expression tree for in-memory execution.
*/
private StoreQuery.Executor compileForInMemory(Compilation comp) {
if (comp.memory == null)
comp.memory = createExecutor(true);
return comp.memory;
}
/**
* Return a query executor of the proper type.
*/
private StoreQuery.Executor createExecutor(boolean inMem) {
assertCandidateType();
MetaDataRepository repos = _broker.getConfiguration().
getMetaDataRepositoryInstance();
ClassMetaData meta = repos.getMetaData(_class,
_broker.getClassLoader(), false);
ClassMetaData[] metas;
if (_class == null || _storeQuery.supportsAbstractExecutors())
metas = new ClassMetaData[]{ meta };
else if (_subclasses && (meta == null || meta.isManagedInterface()))
metas = repos.getImplementorMetaDatas(_class,
_broker.getClassLoader(), true);
else if (meta != null && (_subclasses || meta.isMapped()))
metas = new ClassMetaData[]{ meta };
else
metas = StoreQuery.EMPTY_METAS;
if (metas.length == 0)
throw new UserException(_loc.get("no-impls", _class));
try {
if (metas.length == 1) {
if (inMem)
return _storeQuery.newInMemoryExecutor(metas[0],
_subclasses);
return _storeQuery.newDataStoreExecutor(metas[0], _subclasses);
}
// multiple implementors
StoreQuery.Executor[] es = new StoreQuery.Executor[metas.length];
for (int i = 0; i < es.length; i++) {
if (inMem)
es[i] = _storeQuery.newInMemoryExecutor(metas[i], true);
else
es[i] = _storeQuery.newDataStoreExecutor(metas[i], true);
}
return new MergedExecutor(es);
} catch (OpenJPAException ke) {
throw ke;
} catch (RuntimeException re) {
throw new GeneralException(re);
}
}
/**
* Clear any compilation, forcing this query to be recompiled
* next time it's executed. This should be invoked whenever any
* state changes that would cause the underlying query
* representation to change.
*
* @since 0.3.0
*/
private boolean invalidateCompilation() {
if (_compiling)
return false;
_storeQuery.invalidateCompilation();
_compiled = null;
_packer = null;
return true;
}
@Override
public Object execute() {
return execute((Object[]) null);
}
@Override
public Object execute(Object[] params) {
return execute(OP_SELECT, params);
}
@Override
public Object execute(Map params) {
return execute(OP_SELECT, params);
}
private Object execute(int operation, Object[] params) {
if (params == null)
params = StoreQuery.EMPTY_OBJECTS;
lock();
try {
assertNotSerialized();
_broker.beginOperation(true);
try {
assertOpen();
_broker.assertNontransactionalRead();
// get executor
Compilation comp = compileForCompilation();
StoreQuery.Executor ex = (isInMemory(operation))
? compileForInMemory(comp) : compileForDataStore(comp);
assertParameters(_storeQuery, ex, params);
if (_log.isTraceEnabled())
logExecution(operation, ex.getOrderedParameterTypes(_storeQuery),
params);
if (operation == OP_SELECT)
return execute(_storeQuery, ex, params);
if (operation == OP_DELETE)
return delete(_storeQuery, ex, params);
if (operation == OP_UPDATE)
return update(_storeQuery, ex, params);
throw new UnsupportedException();
} catch (OpenJPAException ke) {
throw ke;
} catch (Exception e) {
throw new UserException(e);
} finally {
_broker.endOperation();
}
}
finally {
unlock();
}
}
private Object execute(int operation, Map params) {
if (params == null)
params = Collections.EMPTY_MAP;
lock();
try {
_broker.beginOperation(true);
try {
assertNotSerialized();
assertOpen();
_broker.assertNontransactionalRead();
// get executor
Compilation comp = compileForCompilation();
StoreQuery.Executor ex = (isInMemory(operation))
? compileForInMemory(comp) : compileForDataStore(comp);
assertParameters(_storeQuery, ex, params);
Object[] arr = (params.isEmpty()) ? StoreQuery.EMPTY_OBJECTS :
ex.toParameterArray(_storeQuery, params);
if (_log.isTraceEnabled())
logExecution(operation, params);
if (operation == OP_SELECT)
return execute(_storeQuery, ex, arr);
if (operation == OP_DELETE)
return delete(_storeQuery, ex, arr);
if (operation == OP_UPDATE)
return update(_storeQuery, ex, arr);
throw new UnsupportedException();
} catch (OpenJPAException ke) {
throw ke;
} catch (Exception e) {
throw new UserException(_loc.get("query-execution-error",
_query), e);
} finally {
_broker.endOperation();
}
}
finally {
unlock();
}
}
@Override
public long deleteAll() {
return deleteAll((Object[]) null);
}
@Override
public long deleteAll(Object[] params) {
return ((Number) execute(OP_DELETE, params)).longValue();
}
@Override
public long deleteAll(Map params) {
return ((Number) execute(OP_DELETE, params)).longValue();
}
@Override
public long updateAll() {
return updateAll((Object[]) null);
}
@Override
public long updateAll(Object[] params) {
return ((Number) execute(OP_UPDATE, params)).longValue();
}
@Override
public long updateAll(Map params) {
return ((Number) execute(OP_UPDATE, params)).longValue();
}
/**
* Converts the values of given params Map into an array in
* consultation of the paramTypes Map.
*
* The indexing of the resultant array is significant for following
* interrelated but tacit assumptions:
* The values in the returned Object[] is consumed by {@link Parameter}
* expressions. Query parsing creates these Parameters and sets their
* key and index. The index set on the Parameter by the parser is the
* same index used to access the Object[] elements returned by this method.
*
* {@link JPQLExpressionBuilder} creates and populates parameters as
* follows:
* The parameter key is not the token encountered by the parser, but
* converted to Integer or String based on the context in which the token
* appeared.
* The index for positional (Integer) parameter is the value of the key
* minus 1.
* The index for named (String) parameter is the order in which the
* token appeared to parser during scanning.
*
*
* The first LinkedMap argument to this method is the result of parsing.
* This LinkedMap contains the parameter key and their expected
* (if determinable) value types. That it is a LinkedMap points to the
* fact that an ordering is implicit. The ordering of the keys in this Map
* is the same as the order in which parser encountered the parameter
* tokens.
*
* For example, parsing result of the following two JPQL queries
* a) UPDATE CompUser e SET e.name= ?1, e.age = ?2 WHERE e.userid = ?3
* b) UPDATE CompUser e SET e.name= :name, e.age = :age WHERE e.userid =
* :id
* The parameter keys will appear in the order (3,2,1) or (:id, :name, :age)
* in the given LinkedMap because WHERE clause is parsed before SET clause.
* The corresponding Parameter Expressions created by the parser will have
* following key and index:
* a) 1:0, 2:1, 3:2
* b) name:1, age:2, id:0
*
* The purpose of this method is to produce an Object[] with an indexing
* scheme that matches the indexing of the Parameter Expression.
* The user map (the second argument) should produce the following Object[]
* in two above-mentioned cases
* a) {1:"Shannon",2:29,3:5032} --> ["Shannon", 29, 5032]
* b) {"name":"Shannon", "age":29, "id":5032} --> [5032, "Shannon", 29]
*
*/
/**
* Return whether we should execute this query in memory.
*/
private boolean isInMemory(int operation) {
// if there are any dirty instances in the current trans that are
// involved in this query, we have to execute in memory or flush
boolean inMem = !_storeQuery.supportsDataStoreExecution()
|| _collection != null;
if (!inMem && (!_ignoreChanges || operation != OP_SELECT)
&& _broker.isActive() && isAccessPathDirty()) {
int flush = _fc.getFlushBeforeQueries();
if ((flush == FLUSH_TRUE
|| (flush == FLUSH_WITH_CONNECTION && _broker.hasConnection())
|| operation != OP_SELECT
|| !_storeQuery.supportsInMemoryExecution())
&& _broker.getConfiguration().supportedOptions().
contains(OpenJPAConfiguration.OPTION_INC_FLUSH)) {
_broker.flush();
} else {
if (_log.isInfoEnabled())
_log.info(_loc.get("force-in-mem", _class));
inMem = true;
}
}
if (inMem && !_storeQuery.supportsInMemoryExecution())
throw new InvalidStateException(_loc.get("cant-exec-inmem",
_language));
return inMem;
}
/**
* Execute the query using the given compilation, executor, and parameter
* values. All other execute methods delegate to this one or to
* {@link #execute(int, Map)} after validation and locking.
*/
private Object execute(StoreQuery q, StoreQuery.Executor ex,
Object[] params)
throws Exception {
// if this is an impossible result range, return null / empty list
StoreQuery.Range range = new StoreQuery.Range(_startIdx, _endIdx);
if (!_rangeSet)
ex.getRange(q, params, range);
if (range.start >= range.end)
return emptyResult(q, ex);
// execute; if we have a result class or we have only one result
// and so need to remove it from its array, wrap in a packing rop
range.lrs = isLRS(range.start, range.end);
ResultObjectProvider rop = ex.executeQuery(q, params, range);
try {
return toResult(q, ex, rop, range);
} catch (Exception e) {
if (rop != null)
try { rop.close(); } catch (Exception e2) {}
throw e;
}
}
/**
* Delete the query using the given executor, and parameter
* values. All other execute methods delegate to this one or to
* {@link #delete(StoreQuery, StoreQuery.Executor, Object[])} after validation and locking.
* The return value will be a Number indicating the number of
* instances deleted.
*/
private Number delete(StoreQuery q, StoreQuery.Executor ex, Object[] params)
throws Exception {
assertBulkModify(q, ex, params);
return ex.executeDelete(q, params);
}
@Override
public Number deleteInMemory(StoreQuery q, StoreQuery.Executor executor,
Object[] params) {
try {
Object o = execute(q, executor, params);
if (!(o instanceof Collection))
o = Collections.singleton(o);
int size = 0;
for (Iterator i = ((Collection) o).iterator(); i.hasNext(); size++)
_broker.delete(i.next(), null);
return size;
} catch (OpenJPAException ke) {
throw ke;
} catch (Exception e) {
throw new UserException(e);
}
}
/**
* Update the query using the given compilation, executor, and parameter
* values. All other execute methods delegate to this one or to
* {@link #update(StoreQuery, StoreQuery.Executor, Object[])} after validation and locking.
* The return value will be a Number indicating the number of
* instances updated.
*/
private Number update(StoreQuery q, StoreQuery.Executor ex, Object[] params)
throws Exception {
assertBulkModify(q, ex, params);
return ex.executeUpdate(q, params);
}
@Override
public Number updateInMemory(StoreQuery q, StoreQuery.Executor executor,
Object[] params) {
try {
Object o = execute(q, executor, params);
if (!(o instanceof Collection))
o = Collections.singleton(o);
int size = 0;
for (Iterator i = ((Collection) o).iterator(); i.hasNext(); size++)
updateInMemory(i.next(), params, q);
return size;
} catch (OpenJPAException ke) {
throw ke;
} catch (Exception e) {
throw new UserException(e);
}
}
/**
* Set the values for the updates in memory.
*
* @param ob the persistent instance to change
* @param params the parameters passed to the query
*/
private void updateInMemory(Object ob, Object[] params, StoreQuery q) {
for (Object o : getUpdates().entrySet()) {
Entry e = (Entry) o;
Path path = (Path) e.getKey();
FieldMetaData fmd = path.last();
OpenJPAStateManager sm = _broker.getStateManager(ob);
Object val;
Object value = e.getValue();
if (value instanceof Val) {
val = ((Val) value).
evaluate(ob, null, getStoreContext(), params);
}
else if (value instanceof Literal) {
val = ((Literal) value).getValue();
}
else if (value instanceof Constant) {
val = ((Constant) value).getValue(params);
}
else {
try {
val = q.evaluate(value, ob, params, sm);
}
catch (UnsupportedException e1) {
throw new UserException(
_loc.get("fail-to-get-update-value"));
}
}
int i = fmd.getIndex();
PersistenceCapable into = ImplHelper.toPersistenceCapable(ob,
_broker.getConfiguration());
// set the actual field in the instance
int set = OpenJPAStateManager.SET_USER;
switch (fmd.getDeclaredTypeCode()) {
case JavaTypes.BOOLEAN:
sm.settingBooleanField(into, i, sm.fetchBooleanField(i),
val == null ? false : (Boolean) val,
set);
break;
case JavaTypes.BYTE:
sm.settingByteField(into, i, sm.fetchByteField(i),
val == null ? 0 : ((Number) val).byteValue(), set);
break;
case JavaTypes.CHAR:
sm.settingCharField(into, i, sm.fetchCharField(i),
val == null ? 0 : val.toString().charAt(0), set);
break;
case JavaTypes.DOUBLE:
sm.settingDoubleField(into, i, sm.fetchDoubleField(i),
val == null ? 0 : ((Number) val).doubleValue(), set);
break;
case JavaTypes.FLOAT:
sm.settingFloatField(into, i, sm.fetchFloatField(i),
val == null ? 0 : ((Number) val).floatValue(), set);
break;
case JavaTypes.INT:
sm.settingIntField(into, i, sm.fetchIntField(i),
val == null ? 0 : ((Number) val).intValue(), set);
break;
case JavaTypes.LONG:
sm.settingLongField(into, i, sm.fetchLongField(i),
val == null ? 0 : ((Number) val).longValue(), set);
break;
case JavaTypes.SHORT:
sm.settingShortField(into, i, sm.fetchShortField(i),
val == null ? 0 : ((Number) val).shortValue(), set);
break;
case JavaTypes.STRING:
sm.settingStringField(into, i, sm.fetchStringField(i),
val == null ? null : val.toString(), set);
break;
case JavaTypes.DATE:
case JavaTypes.NUMBER:
case JavaTypes.BOOLEAN_OBJ:
case JavaTypes.BYTE_OBJ:
case JavaTypes.CHAR_OBJ:
case JavaTypes.DOUBLE_OBJ:
case JavaTypes.FLOAT_OBJ:
case JavaTypes.INT_OBJ:
case JavaTypes.LONG_OBJ:
case JavaTypes.SHORT_OBJ:
case JavaTypes.BIGDECIMAL:
case JavaTypes.BIGINTEGER:
case JavaTypes.LOCALE:
case JavaTypes.OBJECT:
case JavaTypes.OID:
case JavaTypes.ENUM:
sm.settingObjectField(into, i, sm.fetchObjectField(i), val,
set);
break;
default:
throw new UserException(_loc.get("only-update-primitives"));
}
}
}
/**
* Trace log that the query is executing.
*/
private void logExecution(int op, OrderedMap