Search in sources :

Example 1 with ReturningBuilder

use of com.blazebit.persistence.ReturningBuilder in project blaze-persistence by Blazebit.

the class AbstractDeleteCollectionCriteriaBuilder method getQuerySpecification.

private <R> QuerySpecification getQuerySpecification(Query baseQuery, Query exampleQuery, String[] returningColumns, ReturningObjectBuilder<R> objectBuilder, Map<DbmsModificationState, String> includedModificationStates) {
    Set<String> parameterListNames = parameterManager.getParameterListNames(baseQuery);
    boolean isEmbedded = this instanceof ReturningBuilder;
    boolean shouldRenderCteNodes = renderCteNodes(isEmbedded);
    List<CTENode> ctes = shouldRenderCteNodes ? getCteNodes(isEmbedded) : Collections.EMPTY_LIST;
    // Prepare a Map<EntityAlias.idColumnName, CollectionAlias.idColumnName>
    // This is used to replace references to id columns properly in the final sql query
    ExtendedQuerySupport extendedQuerySupport = getService(ExtendedQuerySupport.class);
    String sql = extendedQuerySupport.getSql(em, baseQuery);
    String ownerAlias = extendedQuerySupport.getSqlAlias(em, baseQuery, entityAlias);
    String targetAlias = extendedQuerySupport.getSqlAlias(em, baseQuery, JoinManager.COLLECTION_DML_BASE_QUERY_ALIAS);
    JoinTable joinTable = collectionAttribute.getJoinTable();
    if (joinTable == null) {
        throw new IllegalStateException("Deleting inverse collections is not supported!");
    }
    int joinTableIndex = SqlUtils.indexOfTableName(sql, joinTable.getTableName());
    String collectionAlias = SqlUtils.extractAlias(sql, joinTableIndex + joinTable.getTableName().length());
    String tableToDelete = joinTable.getTableName();
    String tablePrefix = mainQuery.dbmsDialect.getDeleteJoinStyle() == DeleteJoinStyle.FROM ? collectionAlias : tableToDelete;
    Map<String, String> columnExpressionRemappings = new HashMap<>(joinTable.getIdColumnMappings().size());
    List<String> joinTableIdColumns = new ArrayList<>();
    if (joinTable.getKeyColumnMappings() != null) {
        for (Map.Entry<String, String> entry : joinTable.getKeyColumnMappings().entrySet()) {
            joinTableIdColumns.add(entry.getKey());
            columnExpressionRemappings.put(CollectionDmlSupportFunction.FUNCTION_NAME + "(" + collectionAlias + "." + entry.getValue() + ")", tablePrefix + "." + entry.getKey());
        }
    }
    String[] discriminatorColumnCheck = mainQuery.jpaProvider.getDiscriminatorColumnCheck(entityType);
    if (discriminatorColumnCheck != null) {
        columnExpressionRemappings.put(ownerAlias + "." + discriminatorColumnCheck[0] + "=" + discriminatorColumnCheck[1], "1=1");
    }
    for (Map.Entry<String, String> entry : joinTable.getIdColumnMappings().entrySet()) {
        joinTableIdColumns.add(entry.getKey());
        columnExpressionRemappings.put(CollectionDmlSupportFunction.FUNCTION_NAME + "(" + ownerAlias + "." + entry.getValue() + ")", tablePrefix + "." + entry.getKey());
    }
    for (Map.Entry<String, String> entry : joinTable.getTargetColumnMappings().entrySet()) {
        columnExpressionRemappings.put(CollectionDmlSupportFunction.FUNCTION_NAME + "(" + targetAlias + "." + entry.getValue() + ")", tablePrefix + "." + entry.getKey());
    }
    // If the id attribute is an embedded type, there is the possibility that row value expressions are used which we need to handle as well
    Set<SingularAttribute<?, ?>> idAttributes = JpaMetamodelUtils.getIdAttributes(entityType);
    if (idAttributes.size() == 1 && idAttributes.iterator().next().getType() instanceof ManagedType<?>) {
        StringBuilder leftSb = new StringBuilder();
        StringBuilder rightSb = new StringBuilder();
        leftSb.append(CollectionDmlSupportFunction.FUNCTION_NAME).append("((");
        rightSb.append("(");
        for (Map.Entry<String, String> entry : joinTable.getIdColumnMappings().entrySet()) {
            leftSb.append(ownerAlias).append('.').append(entry.getValue()).append(", ");
            rightSb.append(tablePrefix).append('.').append(entry.getKey()).append(',');
        }
        leftSb.setLength(leftSb.length() - 2);
        leftSb.append("))");
        rightSb.setCharAt(rightSb.length() - 1, ')');
        columnExpressionRemappings.put(leftSb.toString(), rightSb.toString());
    }
    return new CollectionDeleteModificationQuerySpecification(this, baseQuery, exampleQuery, parameterManager.getParameterImpls(), parameterListNames, mainQuery.cteManager.isRecursive(), ctes, shouldRenderCteNodes, isEmbedded, returningColumns, objectBuilder, includedModificationStates, returningAttributeBindingMap, mainQuery.getQueryConfiguration().isQueryPlanCacheEnabled(), tableToDelete, collectionAlias, joinTableIdColumns.toArray(new String[0]), false, getDeleteExampleQuery(), columnExpressionRemappings);
}
Also used : ReturningBuilder(com.blazebit.persistence.ReturningBuilder) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) CollectionDeleteModificationQuerySpecification(com.blazebit.persistence.impl.query.CollectionDeleteModificationQuerySpecification) SingularAttribute(javax.persistence.metamodel.SingularAttribute) ExtendedQuerySupport(com.blazebit.persistence.spi.ExtendedQuerySupport) CTENode(com.blazebit.persistence.impl.query.CTENode) HashMap(java.util.HashMap) Map(java.util.Map) JoinTable(com.blazebit.persistence.spi.JoinTable)

Example 2 with ReturningBuilder

use of com.blazebit.persistence.ReturningBuilder in project blaze-persistence by Blazebit.

the class AbstractInsertCollectionCriteriaBuilder method getQuerySpecification.

private <R> QuerySpecification getQuerySpecification(Query baseQuery, Query exampleQuery, String[] returningColumns, ReturningObjectBuilder<R> objectBuilder, Map<DbmsModificationState, String> includedModificationStates) {
    Set<String> parameterListNames = parameterManager.getParameterListNames(baseQuery);
    Set<JoinNode> keyRestrictedLeftJoins = getKeyRestrictedLeftJoins();
    List<String> keyRestrictedLeftJoinAliases = getKeyRestrictedLeftJoinAliases(baseQuery, keyRestrictedLeftJoins, Collections.EMPTY_SET);
    List<EntityFunctionNode> entityFunctionNodes = getEntityFunctionNodes(baseQuery);
    boolean isEmbedded = this instanceof ReturningBuilder;
    boolean shouldRenderCteNodes = renderCteNodes(isEmbedded);
    List<CTENode> ctes = shouldRenderCteNodes ? getCteNodes(isEmbedded) : Collections.EMPTY_LIST;
    ExtendedQuerySupport extendedQuerySupport = getService(ExtendedQuerySupport.class);
    Query insertExampleQuery = getInsertExampleQuery();
    String insertExampleSql = extendedQuerySupport.getSql(em, insertExampleQuery);
    String ownerAlias = extendedQuerySupport.getSqlAlias(em, insertExampleQuery, entityAlias);
    String targetAlias = extendedQuerySupport.getSqlAlias(em, insertExampleQuery, JoinManager.COLLECTION_DML_BASE_QUERY_ALIAS);
    JoinTable joinTable = mainQuery.jpaProvider.getJoinTable(entityType, collectionName);
    int joinTableIndex = SqlUtils.indexOfTableName(insertExampleSql, joinTable.getTableName());
    String collectionAlias = SqlUtils.extractAlias(insertExampleSql, joinTableIndex + joinTable.getTableName().length());
    String[] selectItemExpressions = SqlUtils.getSelectItemExpressions(insertExampleSql, SqlUtils.indexOfSelect(insertExampleSql));
    // Prepare a Map<EntityAlias.idColumnName, CollectionAlias.idColumnName>
    // This is used to replace references to id columns properly in the final sql query
    Map<String, String> columnExpressionRemappings = new HashMap<>(selectItemExpressions.length);
    String[] discriminatorColumnCheck = mainQuery.jpaProvider.getDiscriminatorColumnCheck(entityType);
    if (discriminatorColumnCheck != null) {
        columnExpressionRemappings.put(ownerAlias + "." + discriminatorColumnCheck[0] + "=" + discriminatorColumnCheck[1], "1=1");
    }
    if (joinTable.getKeyColumnMappings() != null) {
        for (Map.Entry<String, String> entry : joinTable.getKeyColumnMappings().entrySet()) {
            columnExpressionRemappings.put(collectionAlias + "." + entry.getValue(), entry.getKey());
        }
    }
    for (Map.Entry<String, String> entry : joinTable.getIdColumnMappings().entrySet()) {
        columnExpressionRemappings.put(ownerAlias + "." + entry.getValue(), entry.getKey());
    }
    for (Map.Entry<String, String> entry : joinTable.getTargetColumnMappings().entrySet()) {
        columnExpressionRemappings.put(targetAlias + "." + entry.getValue(), entry.getKey());
    }
    int cutoffColumns = 0;
    StringBuilder insertSqlSb = new StringBuilder();
    insertSqlSb.append("insert into ").append(joinTable.getTableName()).append("(");
    for (String selectItemExpression : selectItemExpressions) {
        String columnExpression = columnExpressionRemappings.get(selectItemExpression.trim());
        // It should never be null, but the workaround for https://hibernate.atlassian.net/browse/HHH-13045 requires us to filter out the entity fetch columns
        if (columnExpression == null) {
            cutoffColumns++;
        } else {
            insertSqlSb.append(columnExpression).append(',');
        }
    }
    insertSqlSb.setCharAt(insertSqlSb.length() - 1, ')');
    return new CollectionInsertModificationQuerySpecification(this, baseQuery, exampleQuery, parameterManager.getParameterImpls(), parameterListNames, keyRestrictedLeftJoinAliases, entityFunctionNodes, mainQuery.cteManager.isRecursive(), ctes, shouldRenderCteNodes, isEmbedded, returningColumns, objectBuilder, includedModificationStates, returningAttributeBindingMap, getInsertExecutorQuery(), insertSqlSb.toString(), cutoffColumns, getForeignKeyParticipatingQueries(), mainQuery.getQueryConfiguration().isQueryPlanCacheEnabled());
}
Also used : ReturningBuilder(com.blazebit.persistence.ReturningBuilder) TypedQuery(javax.persistence.TypedQuery) CustomSQLQuery(com.blazebit.persistence.impl.query.CustomSQLQuery) Query(javax.persistence.Query) CustomReturningSQLTypedQuery(com.blazebit.persistence.impl.query.CustomReturningSQLTypedQuery) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) CollectionInsertModificationQuerySpecification(com.blazebit.persistence.impl.query.CollectionInsertModificationQuerySpecification) ExtendedQuerySupport(com.blazebit.persistence.spi.ExtendedQuerySupport) EntityFunctionNode(com.blazebit.persistence.impl.query.EntityFunctionNode) CTENode(com.blazebit.persistence.impl.query.CTENode) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) JoinTable(com.blazebit.persistence.spi.JoinTable)

Example 3 with ReturningBuilder

use of com.blazebit.persistence.ReturningBuilder in project blaze-persistence by Blazebit.

the class AbstractModificationCriteriaBuilder method getQuery.

@Override
protected Query getQuery(Map<DbmsModificationState, String> includedModificationStates) {
    Query query;
    // We use this to make these features only available to Hibernate as it is the only provider that supports sql replace yet
    if (hasLimit() || mainQuery.cteManager.hasCtes() || returningAttributeBindingMap.size() > 0) {
        // We need to change the underlying sql when doing a limit with hibernate since it does not support limiting insert ... select statements
        // For CTEs we will also need to change the underlying sql
        query = em.createQuery(getBaseQueryStringWithCheck(null, null));
        Set<String> parameterListNames = parameterManager.getParameterListNames(query);
        boolean isEmbedded = this instanceof ReturningBuilder;
        String[] returningColumns = getReturningColumns();
        boolean shouldRenderCteNodes = renderCteNodes(isEmbedded);
        List<CTENode> ctes = shouldRenderCteNodes ? getCteNodes(isEmbedded) : Collections.EMPTY_LIST;
        QuerySpecification querySpecification = new ModificationQuerySpecification(this, query, getCountExampleQuery(), parameterManager.getParameterImpls(), parameterListNames, mainQuery.cteManager.isRecursive(), ctes, shouldRenderCteNodes, isEmbedded, returningColumns, null, includedModificationStates, returningAttributeBindingMap, mainQuery.getQueryConfiguration().isQueryPlanCacheEnabled());
        query = new CustomSQLQuery(querySpecification, query, parameterManager.getCriteriaNameMapping(), parameterManager.getTransformers(), parameterManager.getValuesParameters(), parameterManager.getValuesBinders());
    } else {
        query = em.createQuery(getBaseQueryStringWithCheck(null, null));
        if (parameterManager.getCriteriaNameMapping() != null) {
            query = new QueryWrapper(query, parameterManager.getCriteriaNameMapping());
        }
    }
    parameterManager.parameterizeQuery(query);
    return query;
}
Also used : ReturningBuilder(com.blazebit.persistence.ReturningBuilder) SimpleReturningBuilder(com.blazebit.persistence.SimpleReturningBuilder) QuerySpecification(com.blazebit.persistence.impl.query.QuerySpecification) ModificationQuerySpecification(com.blazebit.persistence.impl.query.ModificationQuerySpecification) TypedQuery(javax.persistence.TypedQuery) CustomSQLQuery(com.blazebit.persistence.impl.query.CustomSQLQuery) Query(javax.persistence.Query) CustomReturningSQLTypedQuery(com.blazebit.persistence.impl.query.CustomReturningSQLTypedQuery) CustomSQLQuery(com.blazebit.persistence.impl.query.CustomSQLQuery) QueryWrapper(com.blazebit.persistence.impl.query.QueryWrapper) CTENode(com.blazebit.persistence.impl.query.CTENode) ModificationQuerySpecification(com.blazebit.persistence.impl.query.ModificationQuerySpecification)

Example 4 with ReturningBuilder

use of com.blazebit.persistence.ReturningBuilder in project blaze-persistence by Blazebit.

the class BaseInsertCriteriaBuilderImpl method getQuery.

@Override
protected Query getQuery(Map<DbmsModificationState, String> includedModificationStates) {
    // We need to change the underlying sql when doing a limit with hibernate since it does not support limiting insert ... select statements
    Query baseQuery = em.createQuery(getBaseQueryStringWithCheck(null, null));
    Set<String> parameterListNames = parameterManager.getParameterListNames(baseQuery);
    Set<JoinNode> keyRestrictedLeftJoins = getKeyRestrictedLeftJoins();
    List<String> keyRestrictedLeftJoinAliases = getKeyRestrictedLeftJoinAliases(baseQuery, keyRestrictedLeftJoins, Collections.EMPTY_SET);
    List<EntityFunctionNode> entityFunctionNodes = getEntityFunctionNodes(baseQuery);
    boolean isEmbedded = this instanceof ReturningBuilder;
    String[] returningColumns = getReturningColumns();
    boolean shouldRenderCteNodes = renderCteNodes(isEmbedded);
    List<CTENode> ctes = shouldRenderCteNodes ? getCteNodes(isEmbedded) : Collections.EMPTY_LIST;
    QuerySpecification querySpecification = new ModificationQuerySpecification(this, baseQuery, getCountExampleQuery(), parameterManager.getParameterImpls(), parameterListNames, keyRestrictedLeftJoinAliases, entityFunctionNodes, mainQuery.cteManager.isRecursive(), ctes, shouldRenderCteNodes, isEmbedded, returningColumns, null, includedModificationStates, returningAttributeBindingMap, mainQuery.getQueryConfiguration().isQueryPlanCacheEnabled());
    CustomSQLQuery query = new CustomSQLQuery(querySpecification, baseQuery, parameterManager.getCriteriaNameMapping(), parameterManager.getTransformers(), parameterManager.getValuesParameters(), parameterManager.getValuesBinders());
    parameterManager.parameterizeQuery(query);
    query.setFirstResult(firstResult);
    query.setMaxResults(maxResults);
    return query;
}
Also used : ReturningBuilder(com.blazebit.persistence.ReturningBuilder) Query(javax.persistence.Query) CustomSQLQuery(com.blazebit.persistence.impl.query.CustomSQLQuery) CustomSQLQuery(com.blazebit.persistence.impl.query.CustomSQLQuery) QuerySpecification(com.blazebit.persistence.impl.query.QuerySpecification) ModificationQuerySpecification(com.blazebit.persistence.impl.query.ModificationQuerySpecification) EntityFunctionNode(com.blazebit.persistence.impl.query.EntityFunctionNode) CTENode(com.blazebit.persistence.impl.query.CTENode) ModificationQuerySpecification(com.blazebit.persistence.impl.query.ModificationQuerySpecification)

Example 5 with ReturningBuilder

use of com.blazebit.persistence.ReturningBuilder in project blaze-persistence by Blazebit.

the class BaseUpdateCriteriaBuilderImpl method getQuerySpecification.

private <R> QuerySpecification getQuerySpecification(Query baseQuery, Query exampleQuery, String[] returningColumns, ReturningObjectBuilder<R> objectBuilder, Map<DbmsModificationState, String> includedModificationStates) {
    Set<String> parameterListNames = parameterManager.getParameterListNames(baseQuery);
    boolean isEmbedded = this instanceof ReturningBuilder;
    boolean shouldRenderCteNodes = renderCteNodes(isEmbedded);
    List<CTENode> ctes = shouldRenderCteNodes ? getCteNodes(isEmbedded) : Collections.EMPTY_LIST;
    List<String> setColumns = getSetColumns();
    ExtendedQuerySupport extendedQuerySupport = getService(ExtendedQuerySupport.class);
    Map<String, String> aliasMapping = new TreeMap<>();
    JoinNode rootNode = joinManager.getRoots().get(0);
    String[] idColumns = null;
    String tableToUpdate = null;
    String tableAlias = null;
    if ((joinManager.getRoots().size() > 1 || rootNode.hasChildNodes()) && mainQuery.dbmsDialect.getUpdateJoinStyle() != UpdateJoinStyle.NONE) {
        String sql = getService(ExtendedQuerySupport.class).getSql(em, baseQuery);
        if (SqlUtils.indexOfSelect(sql) != -1) {
            idColumns = getIdColumns(getMetamodel().getManagedType(ExtendedManagedType.class, entityType));
            int fromIndex = SqlUtils.indexOfFrom(sql);
            int tableStartIndex = fromIndex + SqlUtils.FROM.length();
            int tableEndIndex = sql.indexOf(" ", tableStartIndex);
            tableToUpdate = sql.substring(tableStartIndex, tableEndIndex);
            tableAlias = extendedQuerySupport.getSqlAlias(em, baseQuery, entityAlias);
            for (String idColumn : idColumns) {
                aliasMapping.put(tableAlias + "." + idColumn, "tmp.c" + aliasMapping.size());
            }
            SqlUtils.buildAliasMappingForTopLevelSelects(extendedQuerySupport.getSql(em, baseQuery), "tmp", aliasMapping);
        }
    }
    return new UpdateModificationQuerySpecification(this, baseQuery, exampleQuery, parameterManager.getParameterImpls(), parameterListNames, mainQuery.cteManager.isRecursive(), ctes, shouldRenderCteNodes, isEmbedded, returningColumns, objectBuilder, includedModificationStates, returningAttributeBindingMap, mainQuery.getQueryConfiguration().isQueryPlanCacheEnabled(), tableToUpdate, tableAlias, idColumns, setColumns, getForeignKeyParticipatingQueries(), aliasMapping, getUpdateExampleQuery());
}
Also used : ReturningBuilder(com.blazebit.persistence.ReturningBuilder) TreeMap(java.util.TreeMap) ExtendedQuerySupport(com.blazebit.persistence.spi.ExtendedQuerySupport) UpdateModificationQuerySpecification(com.blazebit.persistence.impl.query.UpdateModificationQuerySpecification) CTENode(com.blazebit.persistence.impl.query.CTENode)

Aggregations

ReturningBuilder (com.blazebit.persistence.ReturningBuilder)6 CTENode (com.blazebit.persistence.impl.query.CTENode)6 ExtendedQuerySupport (com.blazebit.persistence.spi.ExtendedQuerySupport)4 CustomSQLQuery (com.blazebit.persistence.impl.query.CustomSQLQuery)3 JoinTable (com.blazebit.persistence.spi.JoinTable)3 HashMap (java.util.HashMap)3 Map (java.util.Map)3 Query (javax.persistence.Query)3 CustomReturningSQLTypedQuery (com.blazebit.persistence.impl.query.CustomReturningSQLTypedQuery)2 EntityFunctionNode (com.blazebit.persistence.impl.query.EntityFunctionNode)2 ModificationQuerySpecification (com.blazebit.persistence.impl.query.ModificationQuerySpecification)2 QuerySpecification (com.blazebit.persistence.impl.query.QuerySpecification)2 ArrayList (java.util.ArrayList)2 LinkedHashMap (java.util.LinkedHashMap)2 TreeMap (java.util.TreeMap)2 TypedQuery (javax.persistence.TypedQuery)2 SingularAttribute (javax.persistence.metamodel.SingularAttribute)2 SimpleReturningBuilder (com.blazebit.persistence.SimpleReturningBuilder)1 CollectionDeleteModificationQuerySpecification (com.blazebit.persistence.impl.query.CollectionDeleteModificationQuerySpecification)1 CollectionInsertModificationQuerySpecification (com.blazebit.persistence.impl.query.CollectionInsertModificationQuerySpecification)1