| /* |
| * 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.DataRecord; |
| import org.eclipse.persistence.sessions.remote.*; |
| import org.eclipse.persistence.sessions.DatabaseRecord; |
| 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<String> args = this.argumentTypeNames.iterator(); |
| while (args.hasNext()) { |
| String argumentTypeName = 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, DataRecord) 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, DataRecord) 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); |
| } |
| @SuppressWarnings({"unchecked"}) |
| Hashtable<String, String> sensorNames = (Hashtable<String, String>) getProperty("DMSSensorNames"); |
| if (sensorNames == null) { |
| sensorNames = new Hashtable<>(); |
| setProperty("DMSSensorNames", sensorNames); |
| } |
| String 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 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, DataRecord) 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, DataRecord) 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, DataRecord) |
| */ |
| public String getTranslatedSQLString(org.eclipse.persistence.sessions.Session session, DataRecord 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, DataRecord) prepareCall(Session, Record) |
| */ |
| public List getTranslatedSQLStrings(org.eclipse.persistence.sessions.Session session, DataRecord 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, |
| * DataRecord) |
| */ |
| public void prepareCall(org.eclipse.persistence.sessions.Session session, DataRecord 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<String> arguments = getArguments(); |
| List<Class<?>> argumentTypes = getArgumentTypes(); |
| List<DatabaseField> argumentFields = new ArrayList<>(arguments.size()); |
| int size = arguments.size(); |
| for (int index = 0; index < size; index++) { |
| DatabaseField argumentField = new DatabaseField(arguments.get(index)); |
| argumentField.setType(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. |
| */ |
| @SuppressWarnings({"unchecked"}) |
| 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; |
| } |
| } |