blob: 0584e1145b4154974fab7d434f68bdb8e39f7f6c [file] [log] [blame]
/*
* Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 1998, 2018 IBM Corporation. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0,
* or the Eclipse Distribution License v. 1.0 which is available at
* http://www.eclipse.org/org/documents/edl-v10.php.
*
* SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
*/
// Contributors:
// Oracle - initial API and implementation from Oracle TopLink
// 07/16/2009-2.0 Guy Pelletier
// - 277039: JPA 2.0 Cache Usage Settings
// 10/15/2010-2.2 Guy Pelletier
// - 322008: Improve usability of additional criteria applied to queries at the session/EM
// 10/29/2010-2.2 Michael O'Brien
// - 325167: Make reserved # bind parameter char generic to enable native SQL pass through
// 04/01/2011-2.3 Guy Pelletier
// - 337323: Multi-tenant with shared schema support (part 2)
// 05/24/2011-2.3 Guy Pelletier
// - 345962: Join fetch query when using tenant discriminator column fails.
// 06/30/2011-2.3.1 Guy Pelletier
// - 341940: Add disable/enable allowing native queries
// 07/13/2012-2.5 Guy Pelletier
// - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls
// 11/05/2012-2.5 Guy Pelletier
// - 350487: JPA 2.1 Specification defined support for Stored Procedure Calls
// 08/11/2012-2.5 Guy Pelletier
// - 393867: Named queries do not work when using EM level Table Per Tenant Multitenancy.
// 08/11/2014-2.5 Rick Curtis
// - 440594: Tolerate invalid NamedQuery at EntityManager creation.
// 09/03/2015 - Will Dazey
// - 456067 : Added support for defining query timeout units
package org.eclipse.persistence.queries;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.io.*;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.config.ParameterDelimiterType;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.descriptors.DescriptorQueryManager;
import org.eclipse.persistence.descriptors.partitioning.PartitioningPolicy;
import org.eclipse.persistence.expressions.*;
import org.eclipse.persistence.internal.expressions.*;
import org.eclipse.persistence.internal.databaseaccess.*;
import org.eclipse.persistence.internal.queries.*;
import org.eclipse.persistence.exceptions.*;
import org.eclipse.persistence.internal.sessions.remote.*;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;
import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl;
import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.sessions.remote.*;
import org.eclipse.persistence.sessions.DatabaseRecord;
import org.eclipse.persistence.sessions.Record;
import org.eclipse.persistence.sessions.SessionProfiler;
/**
* <p>
* <b>Purpose</b>: Abstract class for all database query objects. DatabaseQuery
* is a visible class to the EclipseLink user. Users create an appropriate query
* by creating an instance of a concrete subclasses of DatabaseQuery.
*
* <p>
* <b>Responsibilities</b>:
* <ul>
* <li>Provide a common protocol for query objects.
* <li>Defines a generic execution interface.
* <li>Provides query property values
* <li>Holds arguments to the query
* </ul>
*
* @author Yvon Lavoie
* @since TOPLink/Java 1.0
*/
public abstract class DatabaseQuery implements Cloneable, Serializable {
/** INTERNAL: Property used for batch fetching in non object queries. */
public static final String BATCH_FETCH_PROPERTY = "BATCH_FETCH_PROPERTY";
/**
* Queries can be given a name and registered with a descriptor to allow
* common queries to be reused.
*/
protected String name;
/**
* Arguments can be given and specified to predefined queries to allow
* reuse.
*/
protected List<String> arguments;
/**
* PERF: Argument fields are cached in prepare to avoid rebuilding on each
* execution.
*/
protected List<DatabaseField> argumentFields;
/**
* Arguments values can be given and specified to predefined queries to
* allow reuse.
*/
protected List<Object> argumentValues;
/** Needed to differentiate queries with the same name. */
protected List<Class> argumentTypes;
/** Used to build a list of argumentTypes by name pre-initialization */
protected List<String> argumentTypeNames;
/** Used for parameter retreival in JPQL **/
public enum ParameterType {POSITIONAL, NAMED}
protected List<ParameterType> argumentParameterTypes;
/** The descriptor cached on the prepare for object level queries. */
protected transient ClassDescriptor descriptor;
/** The list of descriptors this query deals with. Set via JPA processing for table per tenant queries */
protected List<ClassDescriptor> descriptors;
/**
* The query mechanism determines the mechanism on how the database will be
* accessed.
*/
protected DatabaseQueryMechanism queryMechanism;
/**
* A redirector allows for a queries execution to be the execution of a
* piece of code.
*/
protected QueryRedirector redirector;
/**
* Can be set to true in the case there is a redirector or a default
* redirector but the user does not want the query redirected.
*/
protected boolean doNotRedirect = false;
/** Flag used for a query to bypass the identitymap and unit of work. */
// Bug#3476483 - Restore shouldMaintainCache to previous state after reverse
// of bug fix 3240668
protected boolean shouldMaintainCache;
/** JPA flags to control the shared cache */
protected boolean shouldRetrieveBypassCache = false;
protected boolean shouldStoreBypassCache = false;
/**
* Property used to override a persistence unit level that disallows native
* SQL queries.
* @see org.eclipse.persistence.sessions.Project#setAllowNativeSQLQueries(boolean) Project.setAllowNativeSQLQueries(boolean)
*/
protected Boolean allowNativeSQLQuery;
/** Internally used by the mappings as a temporary store. */
protected Map<Object, Object> properties;
/**
* Only used after the query is cloned for execution to store the session
* under which the query was executed.
*/
protected transient AbstractSession session;
/**
* Only used after the query is cloned for execution to store the execution
* session under which the query was executed.
*/
protected transient AbstractSession executionSession;
/**
* Connection to use for database access, required for server session
* connection pooling.
* There can be multiple connections with partitioning and replication.
*/
protected transient Collection<Accessor> accessors;
/**
* Mappings and the descriptor use parameterized mechanisms that will be
* translated with the data from the row.
*/
protected AbstractRecord translationRow;
/**
* Internal flag used to bypass user define queries when executing one for
* custom sql/query support.
*/
protected boolean isUserDefined;
/**
* Internal flag used to bypass user define queries when executing one for
* custom sql/query support.
*/
protected boolean isUserDefinedSQLCall;
/** Policy that determines how the query will cascade to its object's parts. */
protected int cascadePolicy;
/** Used to override the default session in the session broker. */
protected String sessionName;
/** Queries prepare common stated in themselves. */
protected boolean isPrepared;
/** Used to indicate whether or not the call needs to be cloned. */
protected boolean shouldCloneCall;
/**
* Allow for the prepare of queries to be turned off, this allow for dynamic
* non-pre SQL generated queries.
*/
protected boolean shouldPrepare;
/**
* List of arguments to check for null.
* If any are null, the query needs to be re-prepared.
*/
protected List<DatabaseField> nullableArguments;
/** Bind all arguments to the SQL statement. */
// Has False, Undefined or True value. In case of Undefined -
// Session's shouldBindAllParameters() defines whether to bind or not.
protected Boolean shouldBindAllParameters;
/**
* Cache the prepared statement, this requires full parameter binding as
* well.
*/
// Has False, Undefined or True value. In case of Undefined -
// Session's shouldCacheAllStatements() defines whether to cache or not.
protected Boolean shouldCacheStatement;
/** Use the WrapperPolicy for the objects returned by the query */
protected boolean shouldUseWrapperPolicy;
/**
* Table per class requires multiple query executions. Internally we prepare
* those queries and cache them against the source mapping's selection
* query. When queries are executed they are cloned so we need a mechanism
* to keep a reference back to the actual selection query so that we can
* successfully look up and chain query executions within a table per class
* inheritance hierarchy.
*/
protected DatabaseMapping sourceMapping;
/**
* queryTimeout has three possible settings: DefaultTimeout, NoTimeout, and
* 1..N This applies to both DatabaseQuery.queryTimeout and
* DescriptorQueryManager.queryTimeout
*
* DatabaseQuery.queryTimeout: - DefaultTimeout: get queryTimeout from
* DescriptorQueryManager - NoTimeout, 1..N: overrides queryTimeout in
* DescriptorQueryManager
*
* DescriptorQueryManager.queryTimeout: - DefaultTimeout: get queryTimeout
* from parent DescriptorQueryManager. If there is no parent, default to
* NoTimeout - NoTimeout, 1..N: overrides parent queryTimeout
*/
protected int queryTimeout;
protected TimeUnit queryTimeoutUnit;
/* Used as default for read, means shallow write for modify. */
public static final int NoCascading = 1;
/*
* Used as default for write, used for refreshing to refresh the whole
* object.
*/
public static final int CascadePrivateParts = 2;
/*
* Currently not supported, used for deep write/refreshes/reads in the
* future.
*/
public static final int CascadeAllParts = 3;
/* Used by the unit of work. */
public static final int CascadeDependentParts = 4;
/*
* Used by aggregate Collections: As aggregates delete at update time,
* cascaded deletes must know to stop when entering postDelete for a
* particular mapping. Only used by the aggregate collection when update is
* occurring in a UnitOfWork CR 2811
*/
public static final int CascadeAggregateDelete = 5;
/*
* Used when refreshing should check the mappings to determine if a
* particular mapping should be cascaded.
*/
public static final int CascadeByMapping = 6;
/** Used for adding hints to the query string in oracle */
protected String hintString;
/*
* Stores the FlushMode of this Query. This is only applicable when executed
* in a flushable UnitOfWork and will be ignored otherwise.
*/
protected Boolean flushOnExecute;
/**
* PERF: Determines if the query has already been cloned for execution, to
* avoid duplicate cloning.
*/
protected boolean isExecutionClone;
/** PERF: Store if this query will use the descriptor custom query. */
protected volatile Boolean isCustomQueryUsed;
/** Allow connection unwrapping to be configured. */
protected boolean isNativeConnectionRequired;
/**
* Return the name to use for the query in performance monitoring.
*/
protected transient String monitorName;
/** Allow additional validation to be performed before using the update call cache */
protected boolean shouldValidateUpdateCallCacheUse;
/** Allow queries to be targeted at specific connection pools. */
protected PartitioningPolicy partitioningPolicy;
/** Allow the reserved pound char used to delimit bind parameters to be overridden */
protected String parameterDelimiter;
/**
* PUBLIC: Initialize the state of the query
*/
protected DatabaseQuery() {
this.shouldMaintainCache = true;
// bug 3524620: lazy-init query mechanism
// this.queryMechanism = new ExpressionQueryMechanism(this);
this.isUserDefined = false;
this.cascadePolicy = NoCascading;
this.isPrepared = false;
this.shouldUseWrapperPolicy = true;
this.queryTimeout = DescriptorQueryManager.DefaultTimeout;
this.queryTimeoutUnit = DescriptorQueryManager.DefaultTimeoutUnit;
this.shouldPrepare = true;
this.shouldCloneCall = false;
this.shouldBindAllParameters = null;
this.shouldCacheStatement = null;
this.isExecutionClone = false;
this.shouldValidateUpdateCallCacheUse = false;
this.parameterDelimiter = ParameterDelimiterType.DEFAULT;
}
/**
* PUBLIC:
* Return the query's partitioning policy.
*/
public PartitioningPolicy getPartitioningPolicy() {
return partitioningPolicy;
}
/**
* PUBLIC:
* Set the query's partitioning policy.
* A PartitioningPolicy is used to partition, load-balance or replicate data across multiple difference databases
* or across a database cluster such as Oracle RAC.
* Partitioning can provide improved scalability by allowing multiple database machines to service requests.
* Setting a policy on a query will override the descriptor and session defaults.
*/
public void setPartitioningPolicy(PartitioningPolicy partitioningPolicy) {
this.partitioningPolicy = partitioningPolicy;
}
/**
* INTERNAL:
* Return the name to use for the query in performance monitoring.
*/
public String getMonitorName() {
if (monitorName == null) {
resetMonitorName();
}
return monitorName;
}
/**
* INTERNAL:
* Return the name to use for the query in performance monitoring.
*/
public void resetMonitorName() {
if (getReferenceClassName() == null) {
this.monitorName = getClass().getSimpleName() + ":" + getName();
} else {
this.monitorName = getClass().getSimpleName() + ":" + getReferenceClassName() + ":" + getName();
}
}
/**
* PUBLIC: Add the argument named argumentName. This will cause the
* translation of references of argumentName in the receiver's expression,
* with the value of the argument as supplied to the query in order from
* executeQuery()
*/
public void addArgument(String argumentName) {
addArgument(argumentName, Object.class);
}
/**
* PUBLIC: Add the argument named argumentName and its class type. This will
* cause the translation of references of argumentName in the receiver's
* expression, with the value of the argument as supplied to the query in
* order from executeQuery(). Specifying the class type is important if
* identically named queries are used but with different argument lists.
*/
public void addArgument(String argumentName, Class type) {
addArgument(argumentName, type, false);
}
/**
* INTERNAL: Add the argument named argumentName. This method was added to maintain
* information about whether parameters are positional or named for JPQL query introspeciton
* API
*/
public void addArgument(String argumentName, Class type, ParameterType parameterType) {
addArgument(argumentName, type, parameterType, false);
}
/**
* PUBLIC: Add the argument named argumentName and its class type. This will
* cause the translation of references of argumentName in the receiver's
* expression, with the value of the argument as supplied to the query in
* order from executeQuery(). Specifying the class type is important if
* identically named queries are used but with different argument lists.
* If the argument can be null, and null must be treated differently in the
* generated SQL, then nullable should be set to true.
*/
public void addArgument(String argumentName, Class type, boolean nullable) {
getArguments().add(argumentName);
getArgumentTypes().add(type);
if(type != null) {
getArgumentTypeNames().add(type.getName());
}
if (nullable) {
getNullableArguments().add(new DatabaseField(argumentName));
}
}
/**
* INTERNAL: Add the argument named argumentName. This method was added to maintain
* information about whether parameters are positional or named for JPQL query introspeciton
* API
*/
public void addArgument(String argumentName, Class type, ParameterType argumentParameterType, boolean nullable) {
addArgument(argumentName, type, nullable);
getArgumentParameterTypes().add(argumentParameterType);
}
/**
* PUBLIC: Add the argument named argumentName and its class type. This will
* cause the translation of references of argumentName in the receiver's
* expression, with the value of the argument as supplied to the query in
* order from executeQuery(). Specifying the class type is important if
* identically named queries are used but with different argument lists.
*/
public void addArgument(String argumentName, String typeAsString) {
getArguments().add(argumentName);
// bug 3197587
getArgumentTypes().add(Helper.getObjectClass(ConversionManager.loadClass(typeAsString)));
getArgumentTypeNames().add(typeAsString);
}
/**
* INTERNAL: Add an argument to the query, but do not resolve the class yet.
* This is useful for building a query without putting the domain classes on
* the classpath for the Mapping Workbench.
*/
public void addArgumentByTypeName(String argumentName, String typeAsString) {
getArguments().add(argumentName);
getArgumentTypeNames().add(typeAsString);
}
/**
* PUBLIC: Add the argumentValue. Argument values must be added in the same
* order the arguments are defined.
*/
public void addArgumentValue(Object argumentValue) {
getArgumentValues().add(argumentValue);
}
/**
* PUBLIC: Add the argumentValues to the query. Argument values must be
* added in the same order the arguments are defined.
*/
public void addArgumentValues(List theArgumentValues) {
getArgumentValues().addAll(theArgumentValues);
}
/**
* PUBLIC: Used to define a store procedure or SQL query. This may be used
* for multiple SQL executions to be mapped to a single query. This cannot
* be used for cursored selects, delete alls or does exists.
*/
public void addCall(Call call) {
setQueryMechanism(call.buildQueryMechanism(this, getQueryMechanism()));
// Must un-prepare is prepare as the SQL may change.
setIsPrepared(false);
}
/**
* PUBLIC: Used to define a statement level query. This may be used for
* multiple SQL executions to be mapped to a single query. This cannot be
* used for cursored selects, delete all(s) or does exists.
*/
public void addStatement(SQLStatement statement) {
// bug 3524620: lazy-init query mechanism
if (!hasQueryMechanism()) {
setQueryMechanism(new StatementQueryMechanism(this));
} else if (!getQueryMechanism().isStatementQueryMechanism()) {
setQueryMechanism(new StatementQueryMechanism(this));
}
((StatementQueryMechanism) getQueryMechanism()).getSQLStatements().addElement(statement);
// Must un-prepare is prepare as the SQL may change.
setIsPrepared(false);
}
/**
* PUBLIC: Bind all arguments to any SQL statement.
*/
public void bindAllParameters() {
setShouldBindAllParameters(true);
}
/**
* INTERNAL: In the case of EJBQL, an expression needs to be generated.
* Build the required expression.
*/
protected void buildSelectionCriteria(AbstractSession session) {
this.getQueryMechanism().buildSelectionCriteria(session);
}
/**
* PUBLIC: Cache the prepared statements, this requires full parameter
* binding as well.
*/
public void cacheStatement() {
setShouldCacheStatement(true);
}
/**
* PUBLIC: Cascade the query and its properties on the queries object(s) and
* all objects related to the queries object(s). This includes private and
* independent relationships, but not read-only relationships. This will
* still stop on uninstantiated indirection objects except for deletion.
* Great caution should be used in using the property as the query may
* effect a large number of objects. This policy is used by the unit of work
* to ensure persistence by reachability.
*/
public void cascadeAllParts() {
setCascadePolicy(CascadeAllParts);
}
/**
* PUBLIC: Cascade the query and its properties on the queries object(s) and
* all related objects where the mapping has been set to cascade the merge.
*/
public void cascadeByMapping() {
setCascadePolicy(CascadeByMapping);
}
/**
* INTERNAL: Used by unit of work, only cascades constraint dependencies.
*/
public void cascadeOnlyDependentParts() {
setCascadePolicy(CascadeDependentParts);
}
/**
* PUBLIC: Cascade the query and its properties on the queries object(s) and
* all privately owned objects related to the queries object(s). This is the
* default for write and delete queries. This policy should normally be used
* for refreshing, otherwise you could refresh half of any object.
*/
public void cascadePrivateParts() {
setCascadePolicy(CascadePrivateParts);
}
/**
* INTERNAL: Ensure that the descriptor has been set.
*/
public void checkDescriptor(AbstractSession session) throws QueryException {
}
/**
* INTERNAL: Check to see if this query already knows the return value
* without performing any further work.
*/
public Object checkEarlyReturn(AbstractSession session, AbstractRecord translationRow) {
return null;
}
/**
* INTERNAL: Check to see if a custom query should be used for this query.
* This is done before the query is copied and prepared/executed. null means
* there is none.
*/
protected DatabaseQuery checkForCustomQuery(AbstractSession session, AbstractRecord translationRow) {
return null;
}
/**
* INTERNAL: Check to see if this query needs to be prepare and prepare it.
* The prepare is done on the original query to ensure that the work is not
* repeated.
*/
public void checkPrepare(AbstractSession session, AbstractRecord translationRow) {
this.checkPrepare(session, translationRow, false);
}
/**
* INTERNAL: Call the prepare on the query.
*/
public void prepareInternal(AbstractSession session) {
setSession(session);
try {
prepare();
} finally {
setSession(null);
}
}
/**
* INTERNAL: Check to see if this query needs to be prepare and prepare it.
* The prepare is done on the original query to ensure that the work is not
* repeated.
*/
public void checkPrepare(AbstractSession session, AbstractRecord translationRow, boolean force) {
try {
// This query is first prepared for global common state, this must be synced.
if (!this.isPrepared) {// Avoid the monitor is already prepare, must
// If this query will use the custom query, do not prepare.
if ((!force) && (!this.shouldPrepare || !((DatasourcePlatform)session.getDatasourcePlatform()).shouldPrepare(this)
|| (checkForCustomQuery(session, translationRow) != null))) {
return;
}
// check again for concurrency.
// Profile the query preparation time.
session.startOperationProfile(SessionProfiler.QueryPreparation, this, SessionProfiler.ALL);
// Prepared queries cannot be custom as then they would never have
// been prepared.
synchronized (this) {
if (!isPrepared()) {
// When custom SQL is used there is a possibility that the
// SQL contains the # token (for stored procedures or temporary tables).
// Avoid this by telling the call if this is custom SQL with parameters.
// This must not be called for SDK calls.
if ((isReadQuery() || isDataModifyQuery()) && isCallQuery() && (getQueryMechanism() instanceof CallQueryMechanism)
&& ((translationRow == null) || (translationRow.isEmpty() && !translationRow.hasSopObject()))) {
// Must check for read object queries as the row will be
// empty until the prepare.
if (isReadObjectQuery() || isUserDefined()) {
((CallQueryMechanism) getQueryMechanism()).setCallHasCustomSQLArguments();
}
} else if (isCallQuery() && (getQueryMechanism() instanceof CallQueryMechanism)) {
((CallQueryMechanism) getQueryMechanism()).setCallHasCustomSQLArguments();
}
setSession(session);// Session is required for some init stuff.
prepare();
setSession(null);
setIsPrepared(true);// MUST not set prepare until done as
// other thread may hit before finishing the prepare.
}
}
// Profile the query preparation time.
session.endOperationProfile(SessionProfiler.QueryPreparation, this, SessionProfiler.ALL);
}
} catch (QueryException knownFailure) {
// Set the query, as prepare can be called directly.
if (knownFailure.getQuery() == null) {
knownFailure.setQuery(this);
knownFailure.setSession(session);
}
throw knownFailure;
} catch (EclipseLinkException knownFailure) {
throw knownFailure;
} catch (RuntimeException unexpectedFailure) {
throw QueryException.prepareFailed(unexpectedFailure, this);
}
}
/**
* INTERNAL: Clone the query
*/
@Override
public Object clone() {
try {
DatabaseQuery cloneQuery = (DatabaseQuery) super.clone();
// partial fix for 3054240
// need to pay attention to other components of the query, too MWN
if (cloneQuery.properties != null) {
if (cloneQuery.properties.isEmpty()) {
cloneQuery.properties = null;
} else {
cloneQuery.properties = new HashMap(this.properties);
}
}
// bug 3524620: now that the query mechanism is lazy-init'd,
// only clone the query mechanism if we have one.
if (this.queryMechanism != null) {
cloneQuery.queryMechanism = this.queryMechanism.clone(cloneQuery);
}
cloneQuery.isPrepared = this.isPrepared; // Setting some things may trigger unprepare.
return cloneQuery;
} catch (CloneNotSupportedException e) {
return null;
}
}
/**
* INTERNAL Used to give the subclasses opportunity to copy aspects of the
* cloned query to the original query.
*/
protected void clonedQueryExecutionComplete(DatabaseQuery query, AbstractSession session) {
// no-op for this class
}
/**
* INTERNAL: Convert all the class-name-based settings in this query to
* actual class-based settings This method is implemented by subclasses as
* necessary.
*
*/
public void convertClassNamesToClasses(ClassLoader classLoader) {
// note: normally we would fix the argument types here, but they are
// already
// lazily instantiated
}
/**
* PUBLIC: Do not Bind all arguments to any SQL statement.
*/
public void dontBindAllParameters() {
setShouldBindAllParameters(false);
}
/**
* PUBLIC: Don't cache the prepared statements, this requires full parameter
* binding as well.
*/
public void dontCacheStatement() {
setShouldCacheStatement(false);
}
/**
* PUBLIC: Do not cascade the query and its properties on the queries
* object(s) relationships. This does not effect the queries private parts
* but only the object(s) direct row-level attributes. This is the default
* for read queries and can be used in writing if it is known that only
* row-level attributes changed, or to resolve circular foreign key
* dependencies.
*/
public void dontCascadeParts() {
setCascadePolicy(NoCascading);
}
/**
* PUBLIC: Set for the identity map (cache) to be ignored completely. The
* cache check will be skipped and the result will not be put into the
* identity map. This can be used to retrieve the exact state of an object
* on the database. By default the identity map is always maintained.
*/
public void dontMaintainCache() {
setShouldMaintainCache(false);
}
/**
* INTERNAL: Execute the query
*
* @exception DatabaseException
* - an error has occurred on the database.
* @exception OptimisticLockException
* - an error has occurred using the optimistic lock feature.
* @return - the result of executing the query.
*/
public abstract Object executeDatabaseQuery() throws DatabaseException, OptimisticLockException;
/**
* INTERNAL: Override query execution where Session is a UnitOfWork.
* <p>
* If there are objects in the cache return the results of the cache lookup.
*
* @param unitOfWork
* - the session in which the receiver will be executed.
* @param translationRow
* - the arguments
* @exception DatabaseException
* - an error has occurred on the database.
* @exception OptimisticLockException
* - an error has occurred using the optimistic lock feature.
* @return An object, the result of executing the query.
*/
public Object executeInUnitOfWork(UnitOfWorkImpl unitOfWork, AbstractRecord translationRow) throws DatabaseException, OptimisticLockException {
return execute(unitOfWork, translationRow);
}
/**
* INTERNAL: Execute the query. If there are objects in the cache return the
* results of the cache lookup.
*
* @param session
* - the session in which the receiver will be executed.
* @exception DatabaseException
* - an error has occurred on the database.
* @exception OptimisticLockException
* - an error has occurred using the optimistic lock feature.
* @return An object, the result of executing the query.
*/
public Object execute(AbstractSession session, AbstractRecord translationRow) throws DatabaseException, OptimisticLockException {
DatabaseQuery queryToExecute = this;
// JPQL call may not have defined the reference class yet, so need to use prepare.
if (isJPQLCallQuery() && isObjectLevelReadQuery()) {
((ObjectLevelReadQuery)this).checkPrePrepare(session);
} else {
checkDescriptor(session);
}
QueryRedirector localRedirector = getRedirectorForQuery();
// refactored redirection for bug 3241138
if (localRedirector != null) {
return redirectQuery(localRedirector, queryToExecute, session, translationRow);
}
// Bug 5529564 - If this is a user defined selection query (custom SQL),
// prepare the query before hand so that we may look up the correct fk
// values from the query parameters when checking early return.
if (queryToExecute.isCustomSelectionQuery() && queryToExecute.shouldPrepare()) {
queryToExecute.checkPrepare(session, translationRow);
}
// This allows the query to check the cache or return early without
// doing any work.
Object earlyReturn = queryToExecute.checkEarlyReturn(session, translationRow);
// If know not to exist (checkCacheOnly, deleted, null primary key),
// return null.
if (earlyReturn == InvalidObject.instance) {
return null;
}
if (earlyReturn != null) {
return earlyReturn;
}
boolean hasCustomQuery = false;
if (!isPrepared() && shouldPrepare()) {
// Prepared queries cannot be custom as then they would never have
// been prepared.
DatabaseQuery customQuery = checkForCustomQuery(session, translationRow);
if (customQuery != null) {
hasCustomQuery = true;
// The custom query will be used not the original.
queryToExecute = customQuery;
}
}
// PERF: Queries need to be cloned for execution as they may be
// concurrently reused, and execution specific state is stored in the
// clone.
// In some case the query is known to be a one off, or cloned elsewhere
// so the query keeps track if it has been cloned already.
queryToExecute = session.prepareDatabaseQuery(queryToExecute);
boolean prepare = queryToExecute.shouldPrepare(translationRow, session);
if (prepare) {
queryToExecute.checkPrepare(session, translationRow);
}
// Then cloned for concurrency and repeatable execution.
if (!queryToExecute.isExecutionClone()) {
queryToExecute = (DatabaseQuery) queryToExecute.clone();
}
// Check for query argument values.
if ((this.argumentValues != null) && (!this.argumentValues.isEmpty()) && translationRow.isEmpty()) {
translationRow = rowFromArguments(this.argumentValues, session);
}
queryToExecute.setTranslationRow(translationRow);
// If the prepare has been disable the clone is prepare dynamically to
// not parameterize the SQL.
if (!prepare) {
queryToExecute.setIsPrepared(false);
queryToExecute.setTranslationRow(translationRow);
queryToExecute.checkPrepare(session, translationRow, true);
}
queryToExecute.setSession(session);
if (hasCustomQuery) {
prepareCustomQuery(queryToExecute);
localRedirector = queryToExecute.getRedirector();
// refactored redirection for bug 3241138
if (localRedirector != null) {
return redirectQuery(localRedirector, queryToExecute, session, queryToExecute.getTranslationRow());
}
}
queryToExecute.prepareForExecution();
// Then executed.
Object result = queryToExecute.executeDatabaseQuery();
// Give the subclasses the opportunity to retrieve aspects of the cloned
// query.
clonedQueryExecutionComplete(queryToExecute, session);
return result;
}
/**
* INTERNAL: Extract the correct query result from the transporter.
*/
public Object extractRemoteResult(Transporter transporter) {
return transporter.getObject();
}
/**
* INTERNAL: Return the accessor.
*/
public Accessor getAccessor() {
if ((this.accessors == null) || (this.accessors.size() == 0)) {
return null;
}
if (this.accessors instanceof List) {
return ((List<Accessor>)this.accessors).get(0);
}
return this.accessors.iterator().next();
}
/**
* INTERNAL: Return the accessors.
*/
public Collection<Accessor> getAccessors() {
return this.accessors;
}
/**
* INTERNAL: Return the arguments for use with the pre-defined query option
*/
public List<String> getArguments() {
if (this.arguments == null) {
this.arguments = new ArrayList<>();
}
return this.arguments;
}
/**
* INTERNAL:
* Used to calculate parameter types in JPQL
*/
public List<ParameterType> getArgumentParameterTypes(){
if (argumentParameterTypes == null){
this.argumentParameterTypes = new ArrayList<>();
}
return this.argumentParameterTypes;
}
/**
* INTERNAL: Return the argumentTypes for use with the pre-defined query
* option
*/
public List<Class> getArgumentTypes() {
if ((this.argumentTypes == null) || (this.argumentTypes.isEmpty() && (this.argumentTypeNames != null) && !this.argumentTypeNames.isEmpty())) {
this.argumentTypes = new ArrayList<>();
// Bug 3256198 - lazily initialize the argument types from their
// class names
if (this.argumentTypeNames != null) {
Iterator args = this.argumentTypeNames.iterator();
while (args.hasNext()) {
String argumentTypeName = (String) args.next();
this.argumentTypes.add(Helper.getObjectClass(ConversionManager.loadClass(argumentTypeName)));
}
}
}
return this.argumentTypes;
}
/**
* INTERNAL: Return the argumentTypeNames for use with the pre-defined query
* option These are used pre-initialization to construct the argumentTypes
* list.
*/
public List<String> getArgumentTypeNames() {
if (argumentTypeNames == null) {
argumentTypeNames = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance();
}
return argumentTypeNames;
}
/**
* INTERNAL: Set the argumentTypes for use with the pre-defined query option
*/
public void setArgumentTypes(List<Class> argumentTypes) {
this.argumentTypes = argumentTypes;
// bug 3256198 - ensure the list of type names matches the argument
// types.
getArgumentTypeNames().clear();
for (Class type : argumentTypes) {
this.argumentTypeNames.add(type.getName());
}
}
/**
* INTERNAL: Set the argumentTypes for use with the pre-defined query option
*/
public void setArgumentTypeNames(List<String> argumentTypeNames) {
this.argumentTypeNames = argumentTypeNames;
}
/**
* INTERNAL: Set the arguments for use with the pre-defined query option.
* Maintain the argumentTypes as well.
*/
public void setArguments(List<String> arguments) {
List<Class> types = new ArrayList<>(arguments.size());
List<String> typeNames = new ArrayList<>(arguments.size());
List<DatabaseField> typeFields = new ArrayList<>(arguments.size());
int size = arguments.size();
for (int index = 0; index < size; index++) {
types.add(Object.class);
typeNames.add("java.lang.Object");
DatabaseField field = new DatabaseField(arguments.get(index));
typeFields.add(field);
}
this.arguments = arguments;
this.argumentTypes = types;
this.argumentTypeNames = typeNames;
this.argumentFields = typeFields;
}
/**
* INTERNAL: Return the argumentValues for use with argumented queries.
*/
public List<Object> getArgumentValues() {
if (this.argumentValues == null) {
this.argumentValues = new ArrayList<>();
}
return this.argumentValues;
}
/**
* INTERNAL: Set the argumentValues for use with argumented queries.
*/
public void setArgumentValues(List<Object> theArgumentValues) {
this.argumentValues = theArgumentValues;
}
/**
* OBSOLETE: Return the call for this query. This call contains the SQL and
* argument list.
*
* @see #getDatasourceCall()
*/
public DatabaseCall getCall() {
Call call = getDatasourceCall();
if (call instanceof DatabaseCall) {
return (DatabaseCall) call;
} else {
return null;
}
}
/**
* ADVANCED: Return the call for this query. This call contains the SQL and
* argument list.
*
* @see #prepareCall(org.eclipse.persistence.sessions.Session, org.eclipse.persistence.sessions.Record) prepareCall(Session, Record)
*/
public Call getDatasourceCall() {
Call call = null;
if (this.queryMechanism instanceof DatasourceCallQueryMechanism) {
DatasourceCallQueryMechanism mechanism = (DatasourceCallQueryMechanism) this.queryMechanism;
call = mechanism.getCall();
// If has multiple calls return the first one.
if ((call == null) && mechanism.hasMultipleCalls()) {
call = (Call) mechanism.getCalls().get(0);
}
}
if ((call == null) && (this.queryMechanism != null) && this.queryMechanism.isJPQLCallQueryMechanism()) {
call = ((JPQLCallQueryMechanism) this.queryMechanism).getJPQLCall();
}
return call;
}
/**
* ADVANCED: Return the calls for this query. This method can be called for
* queries with multiple calls This call contains the SQL and argument list.
*
* @see #prepareCall(org.eclipse.persistence.sessions.Session, org.eclipse.persistence.sessions.Record) prepareCall(Session, Record)
*/
public List getDatasourceCalls() {
List calls = new Vector();
if (getQueryMechanism() instanceof DatasourceCallQueryMechanism) {
DatasourceCallQueryMechanism mechanism = (DatasourceCallQueryMechanism) getQueryMechanism();
// If has multiple calls return the first one.
if (mechanism.hasMultipleCalls()) {
calls = mechanism.getCalls();
} else {
calls.add(mechanism.getCall());
}
}
if ((calls.isEmpty()) && getQueryMechanism().isJPQLCallQueryMechanism()) {
calls.add(((JPQLCallQueryMechanism) getQueryMechanism()).getJPQLCall());
}
return calls;
}
/**
* INTERNAL: Return the cascade policy.
*/
public int getCascadePolicy() {
return cascadePolicy;
}
/**
* INTERNAL: Return the descriptor assigned with the reference class
*/
public ClassDescriptor getDescriptor() {
return descriptor;
}
/**
* INTERNAL:
* This is here only for JPA queries and currently only populated for JPA
* queries. JPAQuery is a jpa class and currently not part of the core.
*/
public List<ClassDescriptor> getDescriptors() {
return null;
}
/**
* INTERNAL:
* TopLink_sessionName_domainClass. Cached in properties
*/
public String getDomainClassNounName(String sessionName) {
if (getProperty("DMSDomainClassNounName") == null) {
StringBuilder buffer = new StringBuilder("EclipseLink");
if (sessionName != null) {
buffer.append(sessionName);
}
if (getReferenceClassName() != null) {
buffer.append("_");
buffer.append(getReferenceClassName());
}
setProperty("DMSDomainClassNounName", buffer.toString());
}
return (String)getProperty("DMSDomainClassNounName");
}
/**
* PUBLIC: Return the name of the query
*/
public String getName() {
return name;
}
/**
* INTERNAL:
* Return the String used to delimit an SQL parameter.
*/
public String getParameterDelimiter() {
if(null == parameterDelimiter || parameterDelimiter.length() == 0) {
parameterDelimiter = ParameterDelimiterType.DEFAULT;
}
return parameterDelimiter;
}
/**
* INTERNAL:
* Return the char used to delimit an SQL parameter.
*/
public char getParameterDelimiterChar() {
return getParameterDelimiter().charAt(0);
}
/**
* INTERNAL: Property support for use by mappings.
*/
public Map<Object, Object> getProperties() {
if (this.properties == null) {
// Lazy initialize to conserve space and allocation time.
this.properties = new HashMap();
}
return this.properties;
}
/**
* INTERNAL: Property support used by mappings to store temporary stuff in
* the query.
*/
public synchronized Object getProperty(Object property) {
if (this.properties == null) {
return null;
}
return this.properties.get(property);
}
/**
* INTERNAL:
* TopLink_sessionName_domainClass_queryClass_queryName (if exist). Cached in properties
*/
public String getQueryNounName(String sessionName) {
if (getProperty("DMSQueryNounName") == null) {
StringBuilder buffer = new StringBuilder(getDomainClassNounName(sessionName));
buffer.append("_");
buffer.append(getClass().getSimpleName());
if (getName() != null) {
buffer.append("_");
buffer.append(getName());
}
setProperty("DMSQueryNounName", buffer.toString());
}
return (String)getProperty("DMSQueryNounName");
}
/**
* INTERNAL: Return the mechanism assigned to the query
*/
public DatabaseQueryMechanism getQueryMechanism() {
// Bug 3524620 - lazy init
if (this.queryMechanism == null) {
this.queryMechanism = new ExpressionQueryMechanism(this);
}
return this.queryMechanism;
}
/**
* INTERNAL: Check if the mechanism has been set yet, used for lazy init.
*/
public boolean hasQueryMechanism() {
return (this.queryMechanism != null);
}
/**
* PUBLIC: Return the number of seconds the driver will wait for a Statement
* to execute to the given number of seconds.
*
* @see DescriptorQueryManager#getQueryTimeout()
*/
public int getQueryTimeout() {
return queryTimeout;
}
/**
* PUBLIC: Return the unit of time the driver will wait for a Statement to
* execute.
*
* @see DescriptorQueryManager#getQueryTimeoutUnit()
*/
public TimeUnit getQueryTimeoutUnit() {
return queryTimeoutUnit;
}
/**
* INTERNAL: Returns the specific default redirector for this query type.
* There are numerous default query redirectors. See ClassDescriptor for
* their types.
*/
protected QueryRedirector getDefaultRedirector() {
return this.descriptor.getDefaultQueryRedirector();
}
/**
* PUBLIC: Return the query redirector. A redirector can be used in a query
* to replace its execution with the execution of code. This can be used for
* named or parameterized queries to allow dynamic configuration of the
* query base on the query arguments.
*
* @see QueryRedirector
*/
public QueryRedirector getRedirectorForQuery() {
if (doNotRedirect) {
return null;
}
if (redirector != null) {
return redirector;
}
if (descriptor != null) {
return getDefaultRedirector();
}
return null;
}
/**
* PUBLIC: Return the query redirector. A redirector can be used in a query
* to replace its execution with the execution of code. This can be used for
* named or parameterized queries to allow dynamic configuration of the
* query base on the query arguments.
*
* @see QueryRedirector
*/
public QueryRedirector getRedirector() {
if (doNotRedirect) {
return null;
}
return redirector;
}
/**
* PUBLIC: Return the domain class associated with this query. By default
* this is null, but should be overridden in subclasses.
*/
public Class getReferenceClass() {
return null;
}
/**
* INTERNAL: return the name of the reference class. Added for Mapping
* Workbench removal of classpath dependency. Overridden by subclasses.
*/
public String getReferenceClassName() {
return null;
}
/**
* PUBLIC: Return the selection criteria of the query. This should only be
* used with expression queries, null will be returned for others.
*/
public Expression getSelectionCriteria() {
if (this.queryMechanism == null) {
return null;
}
return this.queryMechanism.getSelectionCriteria();
}
/**
* INTERNAL:
* TopLink_sessionName_domainClass_queryClass_queryName (if exist)_operationName (if exist). Cached in properties
*/
public String getSensorName(String operationName, String sessionName) {
if (operationName == null) {
return getQueryNounName(sessionName);
}
Hashtable sensorNames = (Hashtable)getProperty("DMSSensorNames");
if (sensorNames == null) {
sensorNames = new Hashtable();
setProperty("DMSSensorNames", sensorNames);
}
Object sensorName = sensorNames.get(operationName);
if (sensorName == null) {
StringBuilder buffer = new StringBuilder(getQueryNounName(sessionName));
buffer.append("_");
buffer.append(operationName);
sensorName = buffer.toString();
sensorNames.put(operationName, sensorName);
}
return (String)sensorName;
}
/**
* INTERNAL: Return the current session.
*/
public AbstractSession getSession() {
return session;
}
/**
* INTERNAL: Return the execution session. This is the session used to build
* objects returned by the query.
*/
public AbstractSession getExecutionSession() {
if (this.executionSession == null) {
if (getSession() != null) {
this.executionSession = getSession().getExecutionSession(this);
}
}
return this.executionSession;
}
/**
* INTERNAL: Set the execution session. This is the session used to build
* objects returned by the query.
*/
protected void setExecutionSession(AbstractSession executionSession) {
this.executionSession = executionSession;
}
/**
* PUBLIC: Return the name of the session that the query should be executed
* under. This can be with the session broker to override the default
* session.
*/
public String getSessionName() {
return sessionName;
}
/**
* PUBLIC: Return the SQL statement of the query. This can only be used with
* statement queries.
*/
public SQLStatement getSQLStatement() {
return ((StatementQueryMechanism) getQueryMechanism()).getSQLStatement();
}
/**
* PUBLIC: Return the JPQL string of the query.
*/
public String getJPQLString() {
return getEJBQLString();
}
/**
* PUBLIC: Return the EJBQL string of the query.
*/
public String getEJBQLString() {
if (!(getQueryMechanism().isJPQLCallQueryMechanism())) {
return null;
}
JPQLCall call = ((JPQLCallQueryMechanism) getQueryMechanism()).getJPQLCall();
return call.getEjbqlString();
}
/**
* PUBLIC: Return the current database hint string of the query.
*/
public String getHintString() {
return hintString;
}
/**
* ADVANCED: Return the SQL string of the query. This can be used for SQL
* queries. This can also be used for normal queries if they have been
* prepared, (i.e. query.prepareCall()).
*
* @see #prepareCall(org.eclipse.persistence.sessions.Session, org.eclipse.persistence.sessions.Record) prepareCall(Session, Record)
*/
public String getSQLString() {
Call call = getDatasourceCall();
if (call == null) {
return null;
}
if (!(call instanceof SQLCall)) {
return null;
}
return ((SQLCall) call).getSQLString();
}
/**
* ADVANCED: Return the SQL strings of the query. Used for queries with
* multiple calls This can be used for SQL queries. This can also be used
* for normal queries if they have been prepared, (i.e.
* query.prepareCall()).
*
* @see #prepareCall(org.eclipse.persistence.sessions.Session, org.eclipse.persistence.sessions.Record) prepareCall(Session, Record)
*/
public List getSQLStrings() {
List calls = getDatasourceCalls();
if ((calls == null) || calls.isEmpty()) {
return null;
}
Vector returnSQL = new Vector(calls.size());
Iterator iterator = calls.iterator();
while (iterator.hasNext()) {
Call call = (Call) iterator.next();
if (!(call instanceof SQLCall)) {
return null;
}
returnSQL.addElement(((SQLCall) call).getSQLString());
}
return returnSQL;
}
/**
* INTERNAL: Returns the internal tri-state value of shouldBindParameters
* used far cascading these settings
*/
public Boolean getShouldBindAllParameters() {
return this.shouldBindAllParameters;
}
/**
* INTERNAL:
*/
public DatabaseMapping getSourceMapping() {
return sourceMapping;
}
/**
* ADVANCED: This can be used to access a queries translated SQL if they
* have been prepared, (i.e. query.prepareCall()). The Record argument is
* one of (Record, XMLRecord) that contains the query arguments.
*
* @see #prepareCall(org.eclipse.persistence.sessions.Session, Record)
*/
public String getTranslatedSQLString(org.eclipse.persistence.sessions.Session session, Record translationRow) {
prepareCall(session, translationRow);
// CR#2859559 fix to use Session and Record interfaces not impl classes.
CallQueryMechanism queryMechanism = (CallQueryMechanism) getQueryMechanism();
if (queryMechanism.getCall() == null) {
return null;
}
SQLCall call = (SQLCall) queryMechanism.getCall().clone();
call.setUsesBinding(false);
call.translate((AbstractRecord) translationRow, queryMechanism.getModifyRow(), (AbstractSession) session);
return call.getSQLString();
}
/**
* ADVANCED: This can be used to access a queries translated SQL if they
* have been prepared, (i.e. query.prepareCall()). This method can be used
* for queries with multiple calls.
*
* @see #prepareCall(org.eclipse.persistence.sessions.Session, org.eclipse.persistence.sessions.Record) prepareCall(Session, Record)
*/
public List getTranslatedSQLStrings(org.eclipse.persistence.sessions.Session session, Record translationRow) {
prepareCall(session, translationRow);
CallQueryMechanism queryMechanism = (CallQueryMechanism) getQueryMechanism();
if ((queryMechanism.getCalls() == null) || queryMechanism.getCalls().isEmpty()) {
return null;
}
Vector calls = new Vector(queryMechanism.getCalls().size());
Iterator iterator = queryMechanism.getCalls().iterator();
while (iterator.hasNext()) {
SQLCall call = (SQLCall) iterator.next();
call = (SQLCall) call.clone();
call.setUsesBinding(false);
call.translate((AbstractRecord) translationRow, queryMechanism.getModifyRow(), (AbstractSession) session);
calls.add(call.getSQLString());
}
return calls;
}
/**
* INTERNAL: Return the row for translation
*/
public AbstractRecord getTranslationRow() {
return translationRow;
}
/**
* INTERNAL: returns true if the accessor has already been set. The
* getAccessor() will attempt to lazily initialize it.
*/
public boolean hasAccessor() {
return this.accessors != null;
}
/**
* INTERNAL: Return if any properties exist in the query.
*/
public boolean hasProperties() {
return (properties != null) && (!properties.isEmpty());
}
/**
* INTERNAL: Return if any arguments exist in the query.
*/
public boolean hasArguments() {
return (arguments != null) && (!arguments.isEmpty());
}
/**
* PUBLIC: Return if a name of the session that the query should be executed
* under has been specified. This can be with the session broker to override
* the default session.
*/
public boolean hasSessionName() {
return sessionName != null;
}
/**
* PUBLIC: Session's shouldBindAllParameters() defines whether to bind or
* not (default setting)
*/
public void ignoreBindAllParameters() {
this.shouldBindAllParameters = null;
}
/**
* PUBLIC: Session's shouldCacheAllStatements() defines whether to cache or
* not (default setting)
*/
public void ignoreCacheStatement() {
this.shouldCacheStatement = null;
}
/**
* PUBLIC: Return true if this query uses SQL, a stored procedure, or SDK
* call.
*/
public boolean isCallQuery() {
return (this.queryMechanism != null) && this.queryMechanism.isCallQueryMechanism();
}
/**
* INTERNAL: Returns true if this query has been created as the result of
* cascading a delete of an aggregate collection in a UnitOfWork CR 2811
*/
public boolean isCascadeOfAggregateDelete() {
return this.cascadePolicy == CascadeAggregateDelete;
}
/**
* PUBLIC: Return if this is a data modify query.
*/
public boolean isDataModifyQuery() {
return false;
}
/**
* PUBLIC: Return if this is a data read query.
*/
public boolean isDataReadQuery() {
return false;
}
/**
* PUBLIC: Return if this is a value read query.
*/
public boolean isValueReadQuery() {
return false;
}
/**
* PUBLIC: Return if this is a direct read query.
*/
public boolean isDirectReadQuery() {
return false;
}
/**
* PUBLIC: Return if this is a delete all query.
*/
public boolean isDeleteAllQuery() {
return false;
}
/**
* PUBLIC: Return if this is a delete object query.
*/
public boolean isDeleteObjectQuery() {
return false;
}
/**
* PUBLIC: Return true if this query uses an expression query mechanism
*/
public boolean isExpressionQuery() {
return (this.queryMechanism == null) || this.queryMechanism.isExpressionQueryMechanism();
}
/**
* PUBLIC: Return true if this is a modify all query.
*/
public boolean isModifyAllQuery() {
return false;
}
/**
* PUBLIC: Return true if this is a modify query.
*/
public boolean isModifyQuery() {
return false;
}
/**
* PUBLIC: Return true if this is an update all query.
*/
public boolean isUpdateAllQuery() {
return false;
}
/**
* PUBLIC: Return true if this is an update object query.
*/
public boolean isUpdateObjectQuery() {
return false;
}
/**
* PUBLIC: If executed against a RepeatableWriteUnitOfWork if this attribute
* is true EclipseLink will write changes to the database before executing
* the query.
*/
public Boolean getFlushOnExecute() {
return this.flushOnExecute;
}
/**
* PUBLIC: Return true if this is an insert object query.
*/
public boolean isInsertObjectQuery() {
return false;
}
/**
* PUBLIC: Return true if this is an object level modify query.
*/
public boolean isObjectLevelModifyQuery() {
return false;
}
/**
* PUBLIC: Return true if this is an object level read query.
*/
public boolean isObjectLevelReadQuery() {
return false;
}
/**
* PUBLIC: Return if this is an object building query.
*/
public boolean isObjectBuildingQuery() {
return false;
}
/**
* INTERNAL: Queries are prepared when they are executed and then do not
* need to be prepared on subsequent executions. This method returns true if
* this query has been prepared. Updating the settings on a query will
* 'un-prepare' the query.
*/
public boolean isPrepared() {
return isPrepared;
}
/**
* PUBLIC: Return true if this is a read all query.
*/
public boolean isReadAllQuery() {
return false;
}
/**
* PUBLIC: Return true if this is a read object query.
*/
public boolean isReadObjectQuery() {
return false;
}
/**
* PUBLIC: Return true if this is a read query.
*/
public boolean isReadQuery() {
return false;
}
/**
* PUBLIC: Return true if this is a report query.
*/
public boolean isReportQuery() {
return false;
}
/**
* PUBLIC: Return true if this is a result set mapping query.
*/
public boolean isResultSetMappingQuery() {
return false;
}
/**
* PUBLIC: Return true if this query uses an SQL query mechanism .
*/
public boolean isSQLCallQuery() {
// BUG#2669342 CallQueryMechanism and isCallQueryMechanism have
// different meaning as SDK return true but isn't.
Call call = getDatasourceCall();
return (call != null) && (call instanceof SQLCall);
}
/**
* PUBLIC: Return true if this query uses an JPQL query mechanism .
*/
public boolean isJPQLCallQuery() {
return ((this.queryMechanism != null)
&& this.queryMechanism.isJPQLCallQueryMechanism()
&& ((JPQLCallQueryMechanism)this.queryMechanism).getJPQLCall() != null);
}
/**
* INTERNAL: Return true if the query is a custom user defined query.
*/
public boolean isUserDefined() {
return isUserDefined;
}
/**
* INTERNAL: Return true if the query is a custom user defined SQL call query.
*/
public boolean isUserDefinedSQLCall() {
return this.isUserDefinedSQLCall;
}
/**
* INTERNAL: Return true if the query uses default properties. This is used
* to determine if this query is cacheable. i.e. does not use any properties
* that may conflict with another query with the same EJBQL or selection
* criteria.
*/
public boolean isDefaultPropertiesQuery() {
return (!this.isUserDefined) && (this.shouldPrepare) && (this.queryTimeout == DescriptorQueryManager.DefaultTimeout)
&& (this.hintString == null) && (this.shouldBindAllParameters == null) && (this.shouldCacheStatement == null) && (this.shouldUseWrapperPolicy);
}
/**
* PUBLIC: Return true if this is a write object query.
*/
public boolean isWriteObjectQuery() {
return false;
}
/**
* PUBLIC: Set for the identity map (cache) to be maintained. This is the
* default.
*/
public void maintainCache() {
setShouldMaintainCache(true);
}
/**
* INTERNAL: This is different from 'prepareForExecution' in that this is
* called on the original query, and the other is called on the copy of the
* query. This query is copied for concurrency so this prepare can only
* setup things that will apply to any future execution of this query.
*
* Resolve the queryTimeout using the DescriptorQueryManager if required.
*/
protected void prepare() throws QueryException {
// If the queryTimeout is DefaultTimeout, resolve using the
// DescriptorQueryManager.
if (this.queryTimeout == DescriptorQueryManager.DefaultTimeout) {
if (this.descriptor == null) {
setQueryTimeout(this.session.getQueryTimeoutDefault());
if(this.session.getQueryTimeoutUnitDefault() == null) {
this.session.setQueryTimeoutUnitDefault(DescriptorQueryManager.DefaultTimeoutUnit);
}
setQueryTimeoutUnit(this.session.getQueryTimeoutUnitDefault());
} else {
int timeout = this.descriptor.getQueryManager().getQueryTimeout();
// No timeout means none set, so use the session default.
if ((timeout == DescriptorQueryManager.DefaultTimeout) || (timeout == DescriptorQueryManager.NoTimeout)) {
timeout = this.session.getQueryTimeoutDefault();
}
setQueryTimeout(timeout);
//Bug #456067
TimeUnit timeoutUnit = this.descriptor.getQueryManager().getQueryTimeoutUnit();
if(timeoutUnit == DescriptorQueryManager.DefaultTimeoutUnit) {
timeoutUnit = this.session.getQueryTimeoutUnitDefault();
}
setQueryTimeoutUnit(timeoutUnit);
}
}
this.argumentFields = buildArgumentFields();
getQueryMechanism().prepare();
resetMonitorName();
}
/**
* INTERNAL: Copy all setting from the query. This is used to morph queries
* from one type to the other. By default this calls prepareFromQuery, but
* additional properties may be required to be copied as prepareFromQuery
* only copies properties that affect the SQL.
*/
public void copyFromQuery(DatabaseQuery query) {
prepareFromQuery(query);
this.cascadePolicy = query.cascadePolicy;
this.flushOnExecute = query.flushOnExecute;
this.arguments = query.arguments;
this.nullableArguments = query.nullableArguments;
this.argumentTypes = query.argumentTypes;
this.argumentTypeNames = query.argumentTypeNames;
this.argumentValues = query.argumentValues;
this.queryTimeout = query.queryTimeout;
this.redirector = query.redirector;
this.sessionName = query.sessionName;
this.shouldBindAllParameters = query.shouldBindAllParameters;
this.shouldCacheStatement = query.shouldCacheStatement;
this.shouldMaintainCache = query.shouldMaintainCache;
this.shouldPrepare = query.shouldPrepare;
this.shouldUseWrapperPolicy = query.shouldUseWrapperPolicy;
this.properties = query.properties;
this.doNotRedirect = query.doNotRedirect;
this.shouldRetrieveBypassCache = query.shouldRetrieveBypassCache;
this.shouldStoreBypassCache = query.shouldStoreBypassCache;
this.parameterDelimiter = query.parameterDelimiter;
this.shouldCloneCall = query.shouldCloneCall;
this.partitioningPolicy = query.partitioningPolicy;
}
/**
* INTERNAL: Prepare the query from the prepared query. This allows a
* dynamic query to prepare itself directly from a prepared query instance.
* This is used in the JPQL parse cache to allow preparsed queries to be
* used to prepare dynamic queries. This only copies over properties that
* are configured through JPQL.
*/
public void prepareFromQuery(DatabaseQuery query) {
setQueryMechanism((DatabaseQueryMechanism) query.getQueryMechanism().clone());
getQueryMechanism().setQuery(this);
this.descriptor = query.descriptor;
this.hintString = query.hintString;
this.isCustomQueryUsed = query.isCustomQueryUsed;
this.argumentFields = query.argumentFields;
// this.properties = query.properties; - Cannot set properties and CMP
// stores finders there.
}
/**
* ADVANCED: Pre-generate the call/SQL for the query. This method takes a
* Session and an implementor of Record (DatebaseRow or XMLRecord). This can
* be used to access the SQL for a query without executing it. To access the
* call use, query.getCall(), or query.getSQLString() for the SQL. Note the
* SQL will have argument markers in it (i.e. "?"). To translate these use
* query.getTranslatedSQLString(session, translationRow).
*
* @see #getCall()
* @see #getSQLString()
* @see #getTranslatedSQLString(org.eclipse.persistence.sessions.Session,
* Record)
*/
public void prepareCall(org.eclipse.persistence.sessions.Session session, Record translationRow) throws QueryException {
// CR#2859559 fix to use Session and Record interfaces not impl classes.
checkPrepare((AbstractSession) session, (AbstractRecord) translationRow, true);
}
/**
* INTERNAL: Set the properties needed to be cascaded into the custom query.
*/
protected void prepareCustomQuery(DatabaseQuery customQuery) {
// Nothing by default.
}
/**
* INTERNAL: Prepare the receiver for execution in a session. In particular,
* set the descriptor of the receiver to the ClassDescriptor for the
* appropriate class for the receiver's object.
*/
public void prepareForExecution() throws QueryException {
}
protected void prepareForRemoteExecution() {
}
/**
* INTERNAL: Use a EclipseLink redirector to redirect this query to a
* method. Added for bug 3241138
*
*/
public Object redirectQuery(QueryRedirector redirector, DatabaseQuery queryToRedirect, AbstractSession session, AbstractRecord translationRow) {
if (redirector == null) {
return null;
}
DatabaseQuery queryToExecute = (DatabaseQuery) queryToRedirect.clone();
queryToExecute.setRedirector(null);
// since we deal with a clone when using a redirector, the descriptor
// will
// get set on the clone, but not on the original object. So before
// returning
// the results, set the descriptor from the clone onto this object
// (original
// query) - GJPP, BUG# 2692956
Object toReturn = redirector.invokeQuery(queryToExecute, translationRow, session);
setDescriptor(queryToExecute.getDescriptor());
return toReturn;
}
protected Object remoteExecute() {
this.session.startOperationProfile(SessionProfiler.Remote, this, SessionProfiler.ALL);
Transporter transporter = ((DistributedSession) this.session).getRemoteConnection().remoteExecute((DatabaseQuery) this.clone());
this.session.endOperationProfile(SessionProfiler.Remote, this, SessionProfiler.ALL);
return extractRemoteResult(transporter);
}
/**
* INTERNAL:
*/
public Object remoteExecute(AbstractSession session) {
setSession(session);
prepareForRemoteExecution();
return remoteExecute();
}
/**
* INTERNAL: Property support used by mappings.
*/
public void removeProperty(Object property) {
getProperties().remove(property);
}
/**
* INTERNAL: replace the value holders in the specified result object(s)
*/
public Map replaceValueHoldersIn(Object object, RemoteSessionController controller) {
// by default, do nothing
return null;
}
/**
* ADVANCED: JPA flag used to control the behavior of the shared cache. This
* flag specifies the behavior when data is retrieved by the find methods
* and by the execution of queries. Calling this method will set a retrieve
* bypass to true.
*/
public void retrieveBypassCache() {
setShouldRetrieveBypassCache(true);
}
/**
* INTERNAL: Build the list of arguments fields from the argument names and
* types.
*/
public List<DatabaseField> buildArgumentFields() {
List arguments = getArguments();
List argumentTypes = getArgumentTypes();
List argumentFields = new ArrayList(arguments.size());
int size = arguments.size();
for (int index = 0; index < size; index++) {
DatabaseField argumentField = new DatabaseField((String) arguments.get(index));
argumentField.setType((Class) argumentTypes.get(index));
argumentFields.add(argumentField);
}
return argumentFields;
}
/**
* INTERNAL: Translate argumentValues into a database row.
*/
public AbstractRecord rowFromArguments(List argumentValues, AbstractSession session) throws QueryException {
List<DatabaseField> argumentFields = this.argumentFields;
// PERF: argumentFields are set in prepare, but need to be built if
// query is not prepared.
if (!isPrepared() || (argumentFields == null)) {
argumentFields = buildArgumentFields();
}
if (argumentFields.size() != argumentValues.size()) {
throw QueryException.argumentSizeMismatchInQueryAndQueryDefinition(this);
}
int argumentsSize = argumentFields.size();
AbstractRecord row = new DatabaseRecord(argumentsSize);
for (int index = 0; index < argumentsSize; index++) {
row.put(argumentFields.get(index), argumentValues.get(index));
}
return row;
}
/**
* INTERNAL:
* Set the list of connection accessors to execute the query on.
*/
public void setAccessors(Collection<Accessor> accessors) {
this.accessors = accessors;
}
/**
* INTERNAL: Set the accessor, the query must always use the same accessor
* for database access. This is required to support connection pooling.
*/
public void setAccessor(Accessor accessor) {
if (accessor == null) {
this.accessors = null;
return;
}
List<Accessor> accessors = new ArrayList(1);
accessors.add(accessor);
this.accessors = accessors;
}
/**
* PUBLIC: Used to define a store procedure or SQL query.
*/
public void setDatasourceCall(Call call) {
if (call == null) {
return;
}
setQueryMechanism(call.buildNewQueryMechanism(this));
}
/**
* PUBLIC: Used to define a store procedure or SQL query.
*/
public void setCall(Call call) {
setDatasourceCall(call);
isUserDefinedSQLCall = true;
}
/**
* INTERNAL: Set the cascade policy.
*/
public void setCascadePolicy(int policyConstant) {
cascadePolicy = policyConstant;
}
/**
* INTERNAL: Set the descriptor for the query.
*/
public void setDescriptor(ClassDescriptor descriptor) {
// If the descriptor changed must unprepare as the SQL may change.
if (this.descriptor != descriptor) {
setIsPrepared(false);
}
this.descriptor = descriptor;
}
/**
* PUBLIC: Set the JPQL string of the query. If arguments are required in
* the string they will be preceded by ":" then the argument name. The JPQL
* arguments must also be added as argument to the query.
*/
public void setJPQLString(String jpqlString) {
setEJBQLString(jpqlString);
}
/**
* PUBLIC: Set the EJBQL string of the query. If arguments are required in
* the string they will be preceded by "?" then the argument number.
*/
public void setEJBQLString(String ejbqlString) {
// Added the check for when we are building the query from the
// deployment XML
if ((ejbqlString != null) && (!ejbqlString.equals(""))) {
JPQLCallQueryMechanism mechanism = new JPQLCallQueryMechanism(this, new JPQLCall(ejbqlString));
setQueryMechanism(mechanism);
}
}
/**
* PUBLIC: If executed against a RepeatableWriteUnitOfWork if this attribute
* is true EclipseLink will write changes to the database before executing
* the query.
*/
public void setFlushOnExecute(Boolean flushMode) {
this.flushOnExecute = flushMode;
}
/**
* Used to set a database hint string on the query. This should be the full
* hint string including the comment delimiters. The hint string will be
* generated into the SQL string after the SELECT/INSERT/UPDATE/DELETE
* instruction.
* <p>
* <b>Example:</b>
* <pre>
* readAllQuery.setHintString("/*+ index(scott.emp ix_emp) * /");
* </pre>
* would result in SQL like:
* <pre>select /*+ index(scott.emp ix_emp) * / from scott.emp emp_alias</pre>
* <p>
* This method will cause a query to re-prepare if it has already been
* executed.
*
* @param newHintString
* the hint string to be added into the SQL call.
*/
public void setHintString(String newHintString) {
hintString = newHintString;
setIsPrepared(false);
}
/**
* INTERNAL: If changes are made to the query that affect the derived SQL or
* Call parameters the query needs to be prepared again.
* <p>
* Automatically called internally.
*/
public void setIsPrepared(boolean isPrepared) {
this.isPrepared = isPrepared;
if (!isPrepared) {
this.isCustomQueryUsed = null;
if (this.queryMechanism != null) {
this.queryMechanism.unprepare();
}
}
}
/**
* INTERNAL: PERF: Return if the query is an execution clone. This allow the
* clone during execution to be avoided in the cases when the query has
* already been clone elsewhere.
*/
public boolean isExecutionClone() {
return isExecutionClone;
}
/**
* INTERNAL: PERF: Set if the query is an execution clone. This allow the
* clone during execution to be avoided in the cases when the query has
* already been clone elsewhere.
*/
public void setIsExecutionClone(boolean isExecutionClone) {
this.isExecutionClone = isExecutionClone;
}
/**
* INTERNAL: PERF: Return if this query will use the descriptor custom query
* instead of executing itself.
*/
public Boolean isCustomQueryUsed() {
return this.isCustomQueryUsed;
}
/**
* INTERNAL: If the query mechanism is a call query mechanism and there are
* no arguments on the query then it must be a foreign reference custom
* selection query.
*/
protected boolean isCustomSelectionQuery() {
return getQueryMechanism().isCallQueryMechanism() && getArguments().isEmpty();
}
/**
* INTERNAL: PERF: Set if this query will use the descriptor custom query
* instead of executing itself.
* @param isCustomQueryUsed Custom query flag as {@code boolean}.
*/
protected void setIsCustomQueryUsed(final boolean isCustomQueryUsed) {
this.isCustomQueryUsed = isCustomQueryUsed;
}
/**
* INTERNAL: Set if the query is a custom user defined query.
*/
public void setIsUserDefined(boolean isUserDefined) {
this.isUserDefined = isUserDefined;
}
/**
* INTERNAL: Set if the query is a custom user defined sql call query.
*/
public void setIsUserDefinedSQLCall(boolean isUserDefinedSQLCall) {
this.isUserDefinedSQLCall = isUserDefinedSQLCall;
}
/**
* PUBLIC: Set the query's name. Queries can be named and added to a
* descriptor or the session and then referenced by name.
*/
public void setName(String queryName) {
name = queryName;
}
/**
* INTERNAL:
* Set the String char used to delimit an SQL parameter.
*/
public void setParameterDelimiter(String aParameterDelimiter) {
// 325167: if the parameterDelimiter is invalid - use the default # symbol
if(null == aParameterDelimiter || aParameterDelimiter.length() == 0) {
aParameterDelimiter = ParameterDelimiterType.DEFAULT;
}
parameterDelimiter = aParameterDelimiter;
}
/**
* INTERNAL: Property support used by mappings.
*/
public void setProperties(Map<Object, Object> properties) {
this.properties = properties;
}
/**
* INTERNAL: Property support used by mappings to store temporary stuff.
*/
public synchronized void setProperty(Object property, Object value) {
getProperties().put(property, value);
}
/**
* Set the query mechanism for the query.
*/
protected void setQueryMechanism(DatabaseQueryMechanism queryMechanism) {
this.queryMechanism = queryMechanism;
// Must un-prepare is prepare as the SQL may change.
setIsPrepared(false);
}
/**
* PUBLIC: Set the number of seconds the driver will wait for a Statement to
* execute to the given number of seconds. If the limit is exceeded, a
* DatabaseException is thrown.
*
* queryTimeout - the new query timeout limit in seconds; DefaultTimeout is
* the default, which redirects to DescriptorQueryManager's queryTimeout.
*
* @see DescriptorQueryManager#setQueryTimeout(int)
*
*/
public void setQueryTimeout(int queryTimeout) {
this.queryTimeout = queryTimeout;
this.shouldCloneCall = true;
}
public void setQueryTimeoutUnit(TimeUnit queryTimeoutUnit) {
this.queryTimeoutUnit = queryTimeoutUnit;
this.shouldCloneCall = true;
}
/**
* PUBLIC: Set the query redirector. A redirector can be used in a query to
* replace its execution with the execution of code. This can be used for
* named or parameterized queries to allow dynamic configuration of the
* query base on the query arguments.
*
* @see QueryRedirector
*/
public void setRedirector(QueryRedirector redirector) {
this.redirector = redirector;
this.doNotRedirect = false;
this.setIsPrepared(false);
}
/**
* PUBLIC: To any user of this object. Set the selection criteria of the
* query. This method be used when dealing with expressions.
*/
public void setSelectionCriteria(Expression expression) {
// Do not overwrite the call if the expression is null.
if ((expression == null) && (!getQueryMechanism().isExpressionQueryMechanism())) {
return;
}
if (!getQueryMechanism().isExpressionQueryMechanism()) {
setQueryMechanism(new ExpressionQueryMechanism(this, expression));
} else {
((ExpressionQueryMechanism) getQueryMechanism()).setSelectionCriteria(expression);
}
// Must un-prepare is prepare as the SQL may change.
setIsPrepared(false);
}
/**
* INTERNAL: Set the session for the query
*/
public void setSession(AbstractSession session) {
this.session = session;
this.executionSession = null;
}
/**
* PUBLIC: Set the name of the session that the query should be executed
* under. This can be with the session broker to override the default
* session.
*/
public void setSessionName(String sessionName) {
this.sessionName = sessionName;
}
/**
* PUBLIC: Bind all arguments to any SQL statement.
*/
public void setShouldBindAllParameters(boolean shouldBindAllParameters) {
this.shouldBindAllParameters = shouldBindAllParameters;
setIsPrepared(false);
}
/**
* INTERNAL: Sets the internal tri-state value of shouldBindAllParams Used
* to cascade this value to other queries
*/
public void setShouldBindAllParameters(Boolean bindAllParams) {
this.shouldBindAllParameters = bindAllParams;
}
/**
* PUBLIC: Cache the prepared statements, this requires full parameter
* binding as well.
*/
public void setShouldCacheStatement(boolean shouldCacheStatement) {
this.shouldCacheStatement = shouldCacheStatement;
setIsPrepared(false);
}
/**
* PUBLIC: Set if the identity map (cache) should be used or not. If not the
* cache check will be skipped and the result will not be put into the
* identity map. By default the identity map is always maintained.
*/
public void setShouldMaintainCache(boolean shouldMaintainCache) {
this.shouldMaintainCache = shouldMaintainCache;
}
/**
* PUBLIC: Set if the query should be prepared. EclipseLink automatically
* prepares queries to generate their SQL only once, one each execution of
* the query the SQL does not need to be generated again only the arguments
* need to be translated. This option is provide to disable this
* optimization as in can cause problems with certain types of queries that
* require dynamic SQL based on their arguments.
* <p>
* These queries include:
* <ul>
* <li>Expressions that make use of 'equal' where the argument value has the
* potential to be null, this can cause problems on databases that require
* IS NULL, instead of = NULL.
* <li>Expressions that make use of 'in' and that use parameter binding,
* this will cause problems as the in values must be bound individually.
* </ul>
*/
public void setShouldPrepare(boolean shouldPrepare) {
this.shouldPrepare = shouldPrepare;
setIsPrepared(false);
}
/**
* ADVANCED: JPA flag used to control the behavior of the shared cache. This
* flag specifies the behavior when data is retrieved by the find methods
* and by the execution of queries.
*/
public void setShouldRetrieveBypassCache(boolean shouldRetrieveBypassCache) {
this.shouldRetrieveBypassCache = shouldRetrieveBypassCache;
}
/**
* ADVANCED: JPA flag used to control the behavior of the shared cache. This
* flag specifies the behavior when data is read from the database and when
* data is committed into the database.
*/
public void setShouldStoreBypassCache(boolean shouldStoreBypassCache) {
this.shouldStoreBypassCache = shouldStoreBypassCache;
}
/**
* INTERNAL:
* Set if additional validation should be performed before the query uses
* the update call cache.
*/
public void setShouldValidateUpdateCallCacheUse(boolean shouldCheckUpdateCallCacheUse) {
this.shouldValidateUpdateCallCacheUse = shouldCheckUpdateCallCacheUse;
}
/**
* ADVANCED: The wrapper policy can be enable on a query.
*/
public void setShouldUseWrapperPolicy(boolean shouldUseWrapperPolicy) {
this.shouldUseWrapperPolicy = shouldUseWrapperPolicy;
}
/**
* INTERNAL:
*/
public void setSourceMapping(DatabaseMapping sourceMapping) {
this.sourceMapping = sourceMapping;
}
/**
* PUBLIC: To any user of this object. Set the SQL statement of the query.
* This method should only be used when dealing with statement objects.
*/
public void setSQLStatement(SQLStatement sqlStatement) {
setQueryMechanism(new StatementQueryMechanism(this, sqlStatement));
}
/**
* PUBLIC: To any user of this object. Set the SQL string of the query. This
* method should only be used when dealing with user defined SQL strings. If
* arguments are required in the string they will be preceded by "#" then
* the argument name. Warning: Allowing an unverified SQL string to be
* passed into this method makes your application vulnerable to SQL
* injection attacks.
*/
public void setSQLString(String sqlString) {
// Added the check for when we are building the query from the
// deployment XML
if ((sqlString != null) && (!sqlString.equals(""))) {
setCall(new SQLCall(sqlString));
}
}
/**
* INTERNAL: Set the row for translation
*/
public void setTranslationRow(AbstractRecord translationRow) {
this.translationRow = translationRow;
}
/**
* PUBLIC: Bind all arguments to any SQL statement.
*/
public boolean shouldBindAllParameters() {
return Boolean.TRUE.equals(shouldBindAllParameters);
}
/**
* INTERNAL:
* Return true if this individual query should allow native a SQL call
* to be issued.
*/
public boolean shouldAllowNativeSQLQuery(boolean projectAllowsNativeQueries) {
// If allow native SQL query is undefined, use the project setting
// otherwise use the allow native SQL setting.
return (allowNativeSQLQuery == null) ? projectAllowsNativeQueries : allowNativeSQLQuery;
}
/**
* PUBLIC: Cache the prepared statements, this requires full parameter
* binding as well.
*/
public boolean shouldCacheStatement() {
return Boolean.TRUE.equals(shouldCacheStatement);
}
/**
* PUBLIC: Flag used to determine if all parts should be cascaded
*/
public boolean shouldCascadeAllParts() {
return this.cascadePolicy == CascadeAllParts;
}
/**
* PUBLIC: Mappings should be checked to determined if the current operation
* should be cascaded to the objects referenced.
*/
public boolean shouldCascadeByMapping() {
return this.cascadePolicy == CascadeByMapping;
}
/**
* INTERNAL: Flag used for unit of works cascade policy.
*/
public boolean shouldCascadeOnlyDependentParts() {
return this.cascadePolicy == CascadeDependentParts;
}
/**
* PUBLIC: Flag used to determine if any parts should be cascaded
*/
public boolean shouldCascadeParts() {
return this.cascadePolicy != NoCascading;
}
/**
* PUBLIC: Flag used to determine if any private parts should be cascaded
*/
public boolean shouldCascadePrivateParts() {
return (this.cascadePolicy == CascadePrivateParts) || (this.cascadePolicy == CascadeAllParts);
}
/**
* INTERNAL: Flag used to determine if the call needs to be cloned.
*/
public boolean shouldCloneCall() {
return shouldCloneCall;
}
/**
* PUBLIC: Local shouldBindAllParameters() should be ignored, Session's
* shouldBindAllParameters() should be used.
*/
public boolean shouldIgnoreBindAllParameters() {
return shouldBindAllParameters == null;
}
/**
* PUBLIC: Local shouldCacheStatement() should be ignored, Session's
* shouldCacheAllStatements() should be used.
*/
public boolean shouldIgnoreCacheStatement() {
return shouldCacheStatement == null;
}
/**
* PUBLIC: Return if the identity map (cache) should be used or not. If not
* the cache check will be skipped and the result will not be put into the
* identity map. By default the identity map is always maintained.
*/
public boolean shouldMaintainCache() {
return shouldMaintainCache;
}
/**
* PUBLIC: Return if the query should be prepared. EclipseLink automatically
* prepares queries to generate their SQL only once, one each execution of
* the query the SQL does not need to be generated again only the arguments
* need to be translated. This option is provide to disable this
* optimization as in can cause problems with certain types of queries that
* require dynamic SQL based on their arguments.
* <p>
* These queries include:
* <ul>
* <li>Expressions that make use of 'equal' where the argument value has the
* potential to be null, this can cause problems on databases that require
* IS NULL, instead of = NULL.
* <li>Expressions that make use of 'in' and that use parameter binding,
* this will cause problems as the in values must be bound individually.
* </ul>
*/
public boolean shouldPrepare() {
return shouldPrepare;
}
/**
* INTERNAL:
* Check if the query should be prepared, or dynamic, depending on the arguments.
* This allows null parameters to affect the SQL, such as stored procedure default values,
* or IS NULL, or insert defaults.
*/
public boolean shouldPrepare(AbstractRecord translationRow, AbstractSession session) {
if (!this.shouldPrepare) {
return false;
}
if (!((DatasourcePlatform)session.getDatasourcePlatform()).shouldPrepare(this)) {
this.shouldPrepare = false;
return false;
}
if (this.nullableArguments != null) {
for (DatabaseField argument : this.nullableArguments) {
if (translationRow.get(argument) == null) {
return false;
}
}
}
return true;
}
/**
* ADVANCED: JPA flag used to control the behavior of the shared cache. This
* flag specifies the behavior when data is retrieved by the find methods
* and by the execution of queries.
*/
public boolean shouldRetrieveBypassCache() {
return this.shouldRetrieveBypassCache;
}
/**
* ADVANCED: JPA flag used to control the behavior of the shared cache. This
* flag specifies the behavior when data is read from the database and when
* data is committed into the database.
*/
public boolean shouldStoreBypassCache() {
return this.shouldStoreBypassCache;
}
/**
* ADVANCED: The wrapper policy can be enabled on a query.
*/
public boolean shouldUseWrapperPolicy() {
return shouldUseWrapperPolicy;
}
/**
* ADVANCED:
* Return true if additional validation should be performed before the query uses
* the update call cache, false otherwise.
*/
public boolean shouldValidateUpdateCallCacheUse() {
return shouldValidateUpdateCallCacheUse;
}
/**
* ADVANCED: JPA flag used to control the behavior of the shared cache. This
* flag specifies the behavior when data is read from the database and when
* data is committed into the database. Calling this method will set a store
* bypass to true.
*
* Note: For a cache store mode of REFRESH, see refreshIdentityMapResult()
* from ObjectLevelReadQuery.
*/
public void storeBypassCache() {
setShouldStoreBypassCache(true);
}
@Override
public String toString() {
String referenceClassString = "";
String nameString = "";
String queryString = "";
if (getReferenceClass() != null) {
referenceClassString = "referenceClass=" + getReferenceClass().getSimpleName() + " ";
}
if ((getName() != null) && (!getName().equals(""))) {
nameString = "name=\"" + getName() + "\" ";
}
if (isSQLCallQuery()) {
queryString = "sql=\"" + getSQLString() + "\"";
} else if (isJPQLCallQuery()) {
queryString = "jpql=\"" + getJPQLString() + "\"";
}
return getClass().getSimpleName() + "(" + nameString + referenceClassString + queryString + ")";
}
/**
* ADVANCED: Set if the descriptor requires usage of a native (unwrapped)
* JDBC connection. This may be required for some Oracle JDBC support when a
* wrapping DataSource is used.
*/
public void setIsNativeConnectionRequired(boolean isNativeConnectionRequired) {
this.isNativeConnectionRequired = isNativeConnectionRequired;
}
/**
* ADVANCED: Return if the descriptor requires usage of a native (unwrapped)
* JDBC connection. This may be required for some Oracle JDBC support when a
* wrapping DataSource is used.
*/
public boolean isNativeConnectionRequired() {
return isNativeConnectionRequired;
}
/**
* This method is used in combination with redirected queries. If a
* redirector is set on the query or there is a default redirector on the
* Descriptor setting this value to true will force EclipseLink to ignore
* the redirector during execution. This setting will be used most often
* when reexecuting the query within a redirector.
*/
public boolean getDoNotRedirect() {
return doNotRedirect;
}
/**
* This method is used in combination with redirected queries. If a
* redirector is set on the query or there is a default redirector on the
* Descriptor setting this value to true will force EclipseLink to ignore
* the redirector during execution. This setting will be used most often
* when reexecuting the query within a redirector.
*/
public void setDoNotRedirect(boolean doNotRedirect) {
this.doNotRedirect = doNotRedirect;
}
/**
* INTERNAL:
* Return temporary map of batched objects.
*/
public Map<Object, Object> getBatchObjects() {
return (Map<Object, Object>)getProperty(BATCH_FETCH_PROPERTY);
}
/**
* INTERNAL:
* Set temporary map of batched objects.
*/
public void setBatchObjects(Map<Object, Object> batchObjects) {
setProperty(BATCH_FETCH_PROPERTY, batchObjects);
}
/**
* INTERNAL:
* Set to true if this individual query should be marked to bypass a
* persistence unit level disallow SQL queries flag.
*/
public void setAllowNativeSQLQuery(Boolean allowNativeSQLQuery) {
this.allowNativeSQLQuery = allowNativeSQLQuery;
}
/**
* INTERNAL:
* Return if the query has any nullable arguments.
*/
public boolean hasNullableArguments() {
return (this.nullableArguments != null) && !this.nullableArguments.isEmpty();
}
/**
* INTERNAL:
* Return the list of arguments to check for null.
* If any are null, the query needs to be re-prepared.
*/
public List<DatabaseField> getNullableArguments() {
if (this.nullableArguments == null) {
this.nullableArguments = new ArrayList<>();
}
return nullableArguments;
}
/**
* INTERNAL:
* Set the list of arguments to check for null.
* If any are null, the query needs to be re-prepared.
*/
public void setNullableArguments(List<DatabaseField> nullableArguments) {
this.nullableArguments = nullableArguments;
}
}