Search in sources :

Example 1 with ExtendedQuerySupport

use of com.blazebit.persistence.spi.ExtendedQuerySupport 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 ExtendedQuerySupport

use of com.blazebit.persistence.spi.ExtendedQuerySupport 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 ExtendedQuerySupport

use of com.blazebit.persistence.spi.ExtendedQuerySupport 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)

Example 4 with ExtendedQuerySupport

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

the class AbstractUpdateCollectionCriteriaBuilder 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;
    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();
    int joinTableIndex = SqlUtils.indexOfTableName(sql, joinTable.getTableName());
    String collectionAlias = SqlUtils.extractAlias(sql, joinTableIndex + joinTable.getTableName().length());
    String tableToUpdate = joinTable.getTableName();
    String tablePrefix;
    if (mainQuery.dbmsDialect.getUpdateJoinStyle() == UpdateJoinStyle.FROM_ALIAS) {
        tablePrefix = collectionAlias;
    } else if (mainQuery.dbmsDialect.getUpdateJoinStyle() == UpdateJoinStyle.FROM) {
        tablePrefix = null;
    } else {
        tablePrefix = tableToUpdate;
    }
    List<String> setColumns = getSetColumns();
    // 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<>();
    List<String> joinTableIdColumns = new ArrayList<>();
    String[] discriminatorColumnCheck = mainQuery.jpaProvider.getDiscriminatorColumnCheck(entityType);
    String discriminatorPredicate = "";
    if (discriminatorColumnCheck != null) {
        discriminatorPredicate = ownerAlias + "." + discriminatorColumnCheck[0] + "=" + discriminatorColumnCheck[1] + " and";
        columnExpressionRemappings.put(ownerAlias + "." + discriminatorColumnCheck[0] + "=" + discriminatorColumnCheck[1], "1=1");
    }
    if (joinTable.getKeyColumnMappings() != null) {
        for (Map.Entry<String, String> entry : joinTable.getKeyColumnMappings().entrySet()) {
            joinTableIdColumns.add(entry.getKey());
            String sourceExpression = CollectionDmlSupportFunction.FUNCTION_NAME + "(" + collectionAlias + "." + entry.getValue() + ")";
            if (tablePrefix == null) {
                columnExpressionRemappings.put(sourceExpression, collectionAlias + "." + entry.getValue());
            } else {
                columnExpressionRemappings.put(sourceExpression, tablePrefix + "." + entry.getKey());
            }
        }
    }
    for (Map.Entry<String, String> entry : joinTable.getIdColumnMappings().entrySet()) {
        joinTableIdColumns.add(entry.getKey());
        String sourceExpression = CollectionDmlSupportFunction.FUNCTION_NAME + "(" + ownerAlias + "." + entry.getValue() + ")";
        if (tablePrefix == null) {
            columnExpressionRemappings.put(sourceExpression, ownerAlias + "." + entry.getValue());
        } else {
            columnExpressionRemappings.put(sourceExpression, tablePrefix + "." + entry.getKey());
        }
    }
    for (Map.Entry<String, String> entry : joinTable.getTargetColumnMappings().entrySet()) {
        String sourceExpression = CollectionDmlSupportFunction.FUNCTION_NAME + "(" + targetAlias + "." + entry.getValue() + ")";
        if (tablePrefix == null) {
            columnExpressionRemappings.put(sourceExpression, targetAlias + "." + entry.getValue());
        } else {
            columnExpressionRemappings.put(sourceExpression, 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(", ");
            if (tablePrefix == null) {
                rightSb.append(ownerAlias).append('.').append(entry.getValue()).append(',');
            } else {
                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());
    }
    Map<String, String> aliasMapping = new TreeMap<>();
    if (mainQuery.dbmsDialect.getPhysicalRowId() != null) {
        joinTableIdColumns.clear();
        joinTableIdColumns.add(mainQuery.dbmsDialect.getPhysicalRowId());
    }
    for (String idColumn : joinTableIdColumns) {
        aliasMapping.put(collectionAlias + "." + idColumn, "tmp.c" + aliasMapping.size());
    }
    SqlUtils.buildAliasMappingForTopLevelSelects(extendedQuerySupport.getSql(em, baseQuery), "tmp", aliasMapping);
    return new CollectionUpdateModificationQuerySpecification(this, baseQuery, exampleQuery, parameterManager.getParameterImpls(), parameterListNames, mainQuery.cteManager.isRecursive(), ctes, shouldRenderCteNodes, isEmbedded, returningColumns, objectBuilder, includedModificationStates, returningAttributeBindingMap, mainQuery.getQueryConfiguration().isQueryPlanCacheEnabled(), tableToUpdate, collectionAlias, joinTableIdColumns.toArray(new String[0]), setColumns, getForeignKeyParticipatingQueries(), aliasMapping, getUpdateExampleQuery(), columnExpressionRemappings);
}
Also used : ReturningBuilder(com.blazebit.persistence.ReturningBuilder) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ArrayList(java.util.ArrayList) TreeMap(java.util.TreeMap) CollectionUpdateModificationQuerySpecification(com.blazebit.persistence.impl.query.CollectionUpdateModificationQuerySpecification) SingularAttribute(javax.persistence.metamodel.SingularAttribute) ExtendedQuerySupport(com.blazebit.persistence.spi.ExtendedQuerySupport) CTENode(com.blazebit.persistence.impl.query.CTENode) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Map(java.util.Map) TreeMap(java.util.TreeMap) JoinTable(com.blazebit.persistence.spi.JoinTable)

Aggregations

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