All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.blazebit.persistence.impl.BaseDeleteCriteriaBuilderImpl Maven / Gradle / Ivy

There is a newer version: 1.6.12
Show newest version
/*
 * Copyright 2014 - 2020 Blazebit.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.blazebit.persistence.impl;

import com.blazebit.persistence.BaseDeleteCriteriaBuilder;
import com.blazebit.persistence.ReturningBuilder;
import com.blazebit.persistence.ReturningObjectBuilder;
import com.blazebit.persistence.ReturningResult;
import com.blazebit.persistence.impl.function.entity.ValuesEntity;
import com.blazebit.persistence.impl.query.CTENode;
import com.blazebit.persistence.impl.query.CustomReturningSQLTypedQuery;
import com.blazebit.persistence.impl.query.CustomSQLQuery;
import com.blazebit.persistence.impl.query.DeleteModificationQuerySpecification;
import com.blazebit.persistence.impl.query.QuerySpecification;
import com.blazebit.persistence.impl.util.SqlUtils;
import com.blazebit.persistence.parser.expression.ExpressionCopyContext;
import com.blazebit.persistence.spi.DbmsModificationState;
import com.blazebit.persistence.spi.DbmsStatementType;
import com.blazebit.persistence.spi.DeleteJoinStyle;
import com.blazebit.persistence.spi.ExtendedManagedType;
import com.blazebit.persistence.spi.ExtendedQuerySupport;

import javax.persistence.Query;
import javax.persistence.TypedQuery;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 *
 * @param  The query result type
 * @author Christian Beikov
 * @since 1.1.0
 */
public abstract class BaseDeleteCriteriaBuilderImpl, Y> extends AbstractModificationCriteriaBuilder implements BaseDeleteCriteriaBuilder {

    public BaseDeleteCriteriaBuilderImpl(MainQuery mainQuery, QueryContext queryContext, boolean isMainQuery, Class clazz, String alias, CTEManager.CTEKey cteKey, Class cteClass, Y result, CTEBuilderListener listener) {
        super(mainQuery, queryContext, isMainQuery, DbmsStatementType.DELETE, clazz, alias, cteKey, cteClass, result, listener);
    }

    public BaseDeleteCriteriaBuilderImpl(AbstractModificationCriteriaBuilder builder, MainQuery mainQuery, QueryContext queryContext, Map joinManagerMapping, ExpressionCopyContext copyContext) {
        super(builder, mainQuery, queryContext, joinManagerMapping, copyContext);
    }

    @Override
    protected void buildBaseQueryString(StringBuilder sbSelectFrom, boolean externalRepresentation, JoinNode lateralJoinNode) {
        sbSelectFrom.append("DELETE FROM ");
        sbSelectFrom.append(entityType.getName()).append(' ');
        sbSelectFrom.append(entityAlias);
        JoinNode rootNode = joinManager.getRoots().get(0);
        if (joinManager.getRoots().size() > 1 || rootNode.hasChildNodes()) {
            if (externalRepresentation) {
                sbSelectFrom.append(" USING ");
                List whereClauseConjuncts = new ArrayList<>();
                List optionalWhereClauseConjuncts = new ArrayList<>();
                joinManager.buildClause(sbSelectFrom, Collections.emptySet(), null, false, externalRepresentation, false, false, optionalWhereClauseConjuncts, whereClauseConjuncts, explicitVersionEntities, nodesToFetch, Collections.emptySet(), null, false);
                appendWhereClause(sbSelectFrom, externalRepresentation);
            } else {
                if (!mainQuery.supportsAdvancedSql() || mainQuery.dbmsDialect.getDeleteJoinStyle() == DeleteJoinStyle.NONE || mainQuery.dbmsDialect.getDeleteJoinStyle() == DeleteJoinStyle.MERGE) {
                    sbSelectFrom.append(" WHERE EXISTS (SELECT 1");
                    List whereClauseConjuncts = new ArrayList<>();
                    List optionalWhereClauseConjuncts = new ArrayList<>();
                    joinManager.buildClause(sbSelectFrom, Collections.emptySet(), null, false, externalRepresentation, false, false, optionalWhereClauseConjuncts, whereClauseConjuncts, explicitVersionEntities, nodesToFetch, Collections.emptySet(), rootNode, true);
                    appendWhereClause(sbSelectFrom, externalRepresentation);
                    sbSelectFrom.append(')');
                } else {
                    sbSelectFrom.setLength(0);
                    sbSelectFrom.append("SELECT 1");
                    List whereClauseConjuncts = new ArrayList<>();
                    List optionalWhereClauseConjuncts = new ArrayList<>();
                    joinManager.buildClause(sbSelectFrom, Collections.emptySet(), null, false, externalRepresentation, false, false, optionalWhereClauseConjuncts, whereClauseConjuncts, explicitVersionEntities, nodesToFetch, Collections.emptySet(), null, true);
                    appendWhereClause(sbSelectFrom, externalRepresentation);
                }
            }
        } else {
            appendWhereClause(sbSelectFrom, externalRepresentation);
        }
    }

    @Override
    protected Query getQuery(Map includedModificationStates) {
        prepareAndCheck();
        JoinNode rootNode = joinManager.getRoots().get(0);
        if (joinManager.getRoots().size() > 1 || rootNode.hasChildNodes()) {
            // Prefer an exists subquery instead of MERGE
            if (!mainQuery.supportsAdvancedSql() || mainQuery.dbmsDialect.getDeleteJoinStyle() == DeleteJoinStyle.NONE || mainQuery.dbmsDialect.getDeleteJoinStyle() == DeleteJoinStyle.MERGE) {
                return super.getQuery(includedModificationStates);
            }
            Query baseQuery = em.createQuery(getBaseQueryStringWithCheck(null, null));
            QuerySpecification querySpecification = getQuerySpecification(baseQuery, getCountExampleQuery(), getReturningColumns(), null, includedModificationStates);

            Query query = new CustomSQLQuery(
                    querySpecification,
                    baseQuery,
                    parameterManager.getTransformers(),
                    parameterManager.getValuesParameters(),
                    parameterManager.getValuesBinders()
            );

            parameterManager.parameterizeQuery(query);

            return query;
        } else {
            return super.getQuery(includedModificationStates);
        }
    }

    @Override
    protected  TypedQuery> getExecuteWithReturningQuery(TypedQuery exampleQuery, Query baseQuery, String[] returningColumns, ReturningObjectBuilder objectBuilder) {
        QuerySpecification querySpecification = getQuerySpecification(baseQuery, exampleQuery, returningColumns, objectBuilder, null);

        CustomReturningSQLTypedQuery query = new CustomReturningSQLTypedQuery(
                querySpecification,
                exampleQuery,
                parameterManager.getTransformers(),
                parameterManager.getValuesParameters(),
                parameterManager.getValuesBinders()
        );

        query.setFirstResult(firstResult);
        query.setMaxResults(maxResults);
        parameterManager.parameterizeQuery(query);
        return query;
    }

    private  QuerySpecification getQuerySpecification(Query baseQuery, Query exampleQuery, String[] returningColumns, ReturningObjectBuilder objectBuilder, Map includedModificationStates) {
        Set parameterListNames = parameterManager.getParameterListNames(baseQuery);

        boolean isEmbedded = this instanceof ReturningBuilder;
        boolean shouldRenderCteNodes = renderCteNodes(isEmbedded);
        List ctes = shouldRenderCteNodes ? getCteNodes(isEmbedded) : Collections.EMPTY_LIST;

        String sql = getService(ExtendedQuerySupport.class).getSql(em, baseQuery);
        String[] idColumns = null;
        String tableToDelete = null;
        String tableAlias = null;
        boolean innerJoinOnly = false;
        if (SqlUtils.indexOfSelect(sql) != -1) {
            idColumns = getIdColumns(getMetamodel().getManagedType(ExtendedManagedType.class, entityType));
            innerJoinOnly = joinManager.getRoots().size() == 1 && !joinManager.getRootNodeOrFail(null).accept(InnerJoinOnlyAbortableResultJoinNodeVisitor.INSTANCE);
            int fromIndex = SqlUtils.indexOfFrom(sql);
            int tableStartIndex = fromIndex + SqlUtils.FROM.length();
            int tableEndIndex = sql.indexOf(" ", tableStartIndex);
            int tableAliasEndIndex = sql.indexOf(" ", tableEndIndex + 1);
            tableToDelete = sql.substring(tableStartIndex, tableEndIndex);
            tableAlias = sql.substring(tableEndIndex + 1, tableAliasEndIndex);
        }

        return new DeleteModificationQuerySpecification(
                this,
                baseQuery,
                exampleQuery,
                parameterManager.getParameters(),
                parameterListNames,
                mainQuery.cteManager.isRecursive(),
                ctes,
                shouldRenderCteNodes,
                isEmbedded,
                returningColumns,
                objectBuilder,
                includedModificationStates,
                returningAttributeBindingMap,
                mainQuery.getQueryConfiguration().isQueryPlanCacheEnabled(),
                tableToDelete,
                tableAlias,
                idColumns,
                innerJoinOnly,
                getDeleteExampleQuery()
        );
    }

    protected Query getDeleteExampleQuery() {
        // This is the query we use as "hull" to put other sqls into
        // We chose ValuesEntity as deletion base because it is known to be non-polymorphic
        // We could have used the owner entity type as well, but at the time of writing,
        // it wasn't clear if problems might arise when the entity type were polymorphic
        String exampleQueryString = "DELETE FROM " + ValuesEntity.class.getSimpleName();
        return em.createQuery(exampleQueryString);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy