| /* |
| * Copyright (c) 1998, 2021 Oracle and/or its affiliates. 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 |
| package org.eclipse.persistence.queries; |
| |
| import org.eclipse.persistence.exceptions.*; |
| import org.eclipse.persistence.expressions.*; |
| import org.eclipse.persistence.internal.queries.DatabaseQueryMechanism; |
| import org.eclipse.persistence.internal.queries.ExpressionQueryMechanism; |
| import org.eclipse.persistence.internal.sessions.AbstractRecord; |
| import org.eclipse.persistence.internal.sessions.UnitOfWorkImpl; |
| import org.eclipse.persistence.internal.sessions.AbstractSession; |
| |
| /** |
| * PUBLIC: |
| * Query used to perform a bulk delete using the expression framework. |
| * |
| * @author Andrei Ilitchev |
| * @since August 18, 2005 |
| */ |
| public abstract class ModifyAllQuery extends ModifyQuery { |
| |
| /** Cache usage flags */ |
| public static final int NO_CACHE = 0; |
| public static final int INVALIDATE_CACHE = 1; |
| |
| private int m_cacheUsage = INVALIDATE_CACHE; |
| |
| protected Class<?> referenceClass; |
| protected String referenceClassName; |
| |
| /** Number of modified objects */ |
| protected transient Integer result; |
| |
| /** Indicates whether execution should be deferred in UOW */ |
| private boolean shouldDeferExecutionInUOW; |
| |
| /** Provide a default builder so that it's easier to be consistent */ |
| protected ExpressionBuilder defaultBuilder; |
| |
| /** Indicates whether the query was prepared so that it will execute using temp storage */ |
| protected boolean isPreparedUsingTempStorage; |
| |
| /** |
| * PUBLIC: |
| */ |
| protected ModifyAllQuery() { |
| super(); |
| shouldDeferExecutionInUOW = true; |
| } |
| |
| /** |
| * PUBLIC: |
| * Create a new update all query for the class specified. |
| */ |
| protected ModifyAllQuery(Class<?> referenceClass) { |
| this(); |
| setReferenceClass(referenceClass); |
| } |
| |
| /** |
| * PUBLIC: |
| * Create a new update all query for the class and the selection criteria |
| * specified. |
| */ |
| protected ModifyAllQuery(Class<?> referenceClass, Expression selectionCriteria) { |
| this(); |
| setReferenceClass(referenceClass); |
| setSelectionCriteria(selectionCriteria); |
| } |
| |
| /** |
| * PUBLIC: |
| * Return true if this is a modify all query. |
| */ |
| @Override |
| public boolean isModifyAllQuery() { |
| return true; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public void setIsPreparedUsingTempStorage(boolean isPreparedUsingTempStorage) { |
| this.isPreparedUsingTempStorage = isPreparedUsingTempStorage; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| public boolean isPreparedUsingTempStorage() { |
| return isPreparedUsingTempStorage; |
| } |
| |
| /** |
| * INTERNAL |
| * Used to give the subclasses opportunity to copy aspects of the cloned query |
| * to the original query. The clones of all the ModifyAllQueries will be added to modifyAllQueries for validation. |
| */ |
| @Override |
| protected void clonedQueryExecutionComplete(DatabaseQuery query, AbstractSession session) { |
| super.clonedQueryExecutionComplete(query, session); |
| |
| if (session.isUnitOfWork()) { |
| ((UnitOfWorkImpl)session).storeModifyAllQuery(query); |
| } |
| } |
| |
| /** |
| * 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. |
| */ |
| @Override |
| public Object executeInUnitOfWork(UnitOfWorkImpl unitOfWork, AbstractRecord translationRow) throws DatabaseException, OptimisticLockException { |
| if (unitOfWork.isNestedUnitOfWork()) { |
| throw ValidationException.nestedUOWNotSupportedForModifyAllQuery(); |
| } |
| |
| //Bug4607551 For UpdateAllQuery, if deferred, add the original query with a translation row to the deferredUpdateAllQueries for execution. |
| //No action for non-deferred. Later on the clones of all the UpdateAllQuery's will be added to modifyAllQueries for validation. |
| if(shouldDeferExecutionInUOW()) { |
| unitOfWork.storeDeferredModifyAllQuery(this, translationRow); |
| result = null; |
| } else { |
| if(!unitOfWork.isInTransaction()) { |
| unitOfWork.beginEarlyTransaction(); |
| } |
| unitOfWork.setWasNonObjectLevelModifyQueryExecuted(true); |
| result = (Integer)super.executeInUnitOfWork(unitOfWork, translationRow); |
| } |
| return result; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the cache usage for this query. |
| */ |
| public int getCacheUsage() { |
| return m_cacheUsage; |
| } |
| |
| /** |
| * PUBLIC: |
| * Get the expression builder which should be used for this query. |
| * This expression builder should be used to build all expressions used by this query. |
| */ |
| public ExpressionBuilder getExpressionBuilder() { |
| if (defaultBuilder == null) { |
| initializeDefaultBuilder(); |
| } |
| |
| return defaultBuilder; |
| } |
| |
| /** |
| * INTERNAL |
| * Sets the default expression builder for this query. |
| */ |
| public void setExpressionBuilder(ExpressionBuilder builder) { |
| this.defaultBuilder = builder; |
| } |
| |
| /** |
| * INTERNAL: |
| * Return the name of the reference class of the query. |
| * Used by the Mapping Workbench to avoid classpath dependencies |
| */ |
| @Override |
| public String getReferenceClassName() { |
| if ((referenceClassName == null) && (referenceClass != null)) { |
| referenceClassName = referenceClass.getName(); |
| } |
| return referenceClassName; |
| } |
| |
| /** |
| * PUBLIC: |
| * Return the reference class for this query. |
| */ |
| @Override |
| public Class<?> getReferenceClass() { |
| return referenceClass; |
| } |
| |
| /** |
| * INTERNAL: |
| * Invalid the cache, that is, those objects in the cache that were affected |
| * by the query. |
| */ |
| protected void invalidateCache() { |
| if(result != null && result == 0) { |
| // no rows modified in the db - nothing to invalidate |
| return; |
| } |
| getSession().getIdentityMapAccessor().invalidateObjects(getSelectionCriteria(), getReferenceClass(), getTranslationRow(), true); |
| } |
| |
| /** |
| * INTERNAL: |
| * After execution we need to merge the changes into the shared cache, |
| * unless the query has been tagged to bypass on the store. |
| */ |
| public void mergeChangesIntoSharedCache() { |
| if (shouldInvalidateCache() && ! shouldStoreBypassCache()) { |
| invalidateCache(); |
| } |
| } |
| |
| /** |
| * PUBLIC: |
| * Set the level of cache support for this query, either NONE or INVALIDATE. |
| */ |
| public void setCacheUsage(int cacheUsage) { |
| m_cacheUsage = cacheUsage; |
| } |
| |
| /** |
| * PUBLIC: |
| * Set the reference class this query. |
| */ |
| public void setReferenceClass(Class<?> referenceClass) { |
| if (this.referenceClass != referenceClass) { |
| setIsPrepared(false); |
| } |
| this.referenceClass = referenceClass; |
| } |
| |
| /** |
| * INTERNAL: |
| * Set the class name of the reference class of this query. |
| * Used by the Mapping Workbench to avoid classpath dependencies. |
| */ |
| public void setReferenceClassName(String className) { |
| referenceClassName = className; |
| } |
| |
| /** |
| * PUBLIC: |
| * Set a flag indicating whether execution should be deferred in UOW until commit. |
| */ |
| public void setShouldDeferExecutionInUOW(boolean shouldDeferExecutionInUOW) { |
| this.shouldDeferExecutionInUOW = shouldDeferExecutionInUOW; |
| } |
| |
| /** |
| * PUBLIC: |
| * Indicates whether execution should be deferred in UOW until commit. |
| */ |
| public boolean shouldDeferExecutionInUOW() { |
| return shouldDeferExecutionInUOW; |
| } |
| |
| /** |
| * INTERNAL: |
| */ |
| protected boolean shouldInvalidateCache() { |
| return m_cacheUsage == INVALIDATE_CACHE; |
| } |
| |
| /** |
| * INTERNAL: |
| * Initialize the expression builder which should be used for this query. If |
| * there is a where clause, use its expression builder, otherwise |
| * generate one and cache it. This helps avoid unnecessary rebuilds. |
| */ |
| protected void initializeDefaultBuilder() { |
| initializeQuerySpecificDefaultBuilder(); |
| if(defaultBuilder == null) { |
| defaultBuilder = new ExpressionBuilder(); |
| } |
| } |
| |
| /** |
| * INTERNAL: |
| * Initialize the expression builder which should be used for this query. If |
| * there is a where clause, use its expression builder. |
| * If after this method defaultBuilder is still null, |
| * then initializeDefaultBuilder method will generate and cache it. |
| */ |
| protected void initializeQuerySpecificDefaultBuilder() { |
| DatabaseQueryMechanism mech = getQueryMechanism(); |
| if (mech.isExpressionQueryMechanism() && ((ExpressionQueryMechanism)mech).getExpressionBuilder() != null) { |
| this.defaultBuilder = ((ExpressionQueryMechanism)mech).getExpressionBuilder(); |
| } |
| } |
| } |