/******************************************************************************* * Copyright (c) 1998, 2015 Oracle and/or its affiliates, IBM Corporation. All rights reserved. * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v1.0 and Eclipse Distribution License v. 1.0 * which accompanies this distribution. * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html * and the Eclipse Distribution License is available at * http://www.eclipse.org/org/documents/edl-v10.php. * * 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 */ public 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); 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) { getArguments().add(argumentName); getArgumentTypes().add(type); getArgumentParameterTypes().add(argumentParameterType); getArgumentTypeNames().add(type.getName()); if (nullable) { getNullableArguments().add(new DatabaseField(argumentName)); } } /** * 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 */ 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. * * @param classLoader */ 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<String>(); } return this.arguments; } /** * INTERNAL: * Used to calculate parameter types in JPQL * @return */ public List<ParameterType> getArgumentParameterTypes(){ if (argumentParameterTypes == null){ this.argumentParameterTypes = new ArrayList<ParameterType>(); } 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<Class>(); // 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<Class>(arguments.size()); List<String> typeNames = new ArrayList<String>(arguments.size()); List<DatabaseField> typeFields = new ArrayList<DatabaseField>(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<Object>(); } 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 = Boolean.valueOf(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 = Boolean.valueOf(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.booleanValue(); } /** * 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); } 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<DatabaseField>(); } 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; } }