Search in sources :

Example 1 with SqmSetClause

use of org.hibernate.query.sqm.tree.update.SqmSetClause in project hibernate-orm by hibernate.

the class CteUpdateHandler method addDmlCtes.

@Override
protected void addDmlCtes(CteContainer statement, CteStatement idSelectCte, MultiTableSqmMutationConverter sqmConverter, Map<SqmParameter, List<JdbcParameter>> parameterResolutions, SessionFactoryImplementor factory) {
    final TableGroup updatingTableGroup = sqmConverter.getMutatingTableGroup();
    final SqmUpdateStatement<?> updateStatement = (SqmUpdateStatement<?>) getSqmDeleteOrUpdateStatement();
    final EntityMappingType entityDescriptor = getEntityDescriptor();
    final EntityPersister entityPersister = entityDescriptor.getEntityPersister();
    final String rootEntityName = entityPersister.getRootEntityName();
    final EntityPersister rootEntityDescriptor = factory.getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(rootEntityName);
    final String hierarchyRootTableName = ((Joinable) rootEntityDescriptor).getTableName();
    final TableReference hierarchyRootTableReference = updatingTableGroup.resolveTableReference(updatingTableGroup.getNavigablePath(), hierarchyRootTableName);
    assert hierarchyRootTableReference != null;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // visit the set-clause using our special converter, collecting
    // information about the assignments
    final SqmSetClause setClause = updateStatement.getSetClause();
    final List<Assignment> assignments = new ArrayList<>(setClause.getAssignments().size());
    final Map<SqmParameter, MappingModelExpressible> paramTypeResolutions = new LinkedHashMap<>();
    sqmConverter.visitSetClause(setClause, assignments::add, (sqmParam, mappingType, jdbcParameters) -> {
        parameterResolutions.put(sqmParam, jdbcParameters);
        paramTypeResolutions.put(sqmParam, mappingType);
    });
    sqmConverter.addVersionedAssignment(assignments::add, updateStatement);
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // cross-reference the TableReference by alias.  The TableGroup already
    // cross-references it by name, but the ColumnReference only has the alias
    final Map<String, TableReference> tableReferenceByAlias = CollectionHelper.mapOfSize(updatingTableGroup.getTableReferenceJoins().size() + 1);
    collectTableReference(updatingTableGroup.getPrimaryTableReference(), tableReferenceByAlias::put);
    for (int i = 0; i < updatingTableGroup.getTableReferenceJoins().size(); i++) {
        collectTableReference(updatingTableGroup.getTableReferenceJoins().get(i), tableReferenceByAlias::put);
    }
    final Map<TableReference, List<Assignment>> assignmentsByTable = CollectionHelper.mapOfSize(updatingTableGroup.getTableReferenceJoins().size() + 1);
    for (int i = 0; i < assignments.size(); i++) {
        final Assignment assignment = assignments.get(i);
        final List<ColumnReference> assignmentColumnRefs = assignment.getAssignable().getColumnReferences();
        TableReference assignmentTableReference = null;
        for (int c = 0; c < assignmentColumnRefs.size(); c++) {
            final ColumnReference columnReference = assignmentColumnRefs.get(c);
            final TableReference tableReference = resolveTableReference(columnReference, tableReferenceByAlias);
            // TODO: this could be fixed by introducing joins to DML statements
            if (assignmentTableReference != null && !assignmentTableReference.equals(tableReference)) {
                throw new IllegalStateException("Assignment referred to columns from multiple tables");
            }
            assignmentTableReference = tableReference;
        }
        assert assignmentTableReference != null;
        List<Assignment> assignmentsForTable = assignmentsByTable.get(assignmentTableReference);
        if (assignmentsForTable == null) {
            assignmentsForTable = new ArrayList<>();
            assignmentsByTable.put(assignmentTableReference, assignmentsForTable);
        }
        assignmentsForTable.add(assignment);
    }
    getEntityDescriptor().visitConstraintOrderedTables((tableExpression, tableColumnsVisitationSupplier) -> {
        final CteTable dmlResultCte = new CteTable(getCteTableName(tableExpression), idSelectCte.getCteTable().getCteColumns(), factory);
        final TableReference updatingTableReference = updatingTableGroup.getTableReference(updatingTableGroup.getNavigablePath(), tableExpression, true, true);
        final List<Assignment> assignmentList = assignmentsByTable.get(updatingTableReference);
        if (assignmentList == null) {
            return;
        }
        final NamedTableReference dmlTableReference = resolveUnionTableReference(updatingTableReference, tableExpression);
        final List<ColumnReference> columnReferences = new ArrayList<>(idSelectCte.getCteTable().getCteColumns().size());
        tableColumnsVisitationSupplier.get().accept((index, selectable) -> columnReferences.add(new ColumnReference(dmlTableReference, selectable, factory)));
        final MutationStatement dmlStatement = new UpdateStatement(dmlTableReference, assignmentList, createIdSubQueryPredicate(columnReferences, idSelectCte, factory), columnReferences);
        statement.addCteStatement(new CteStatement(dmlResultCte, dmlStatement));
    });
}
Also used : EntityPersister(org.hibernate.persister.entity.EntityPersister) MappingModelExpressible(org.hibernate.metamodel.mapping.MappingModelExpressible) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) Assignment(org.hibernate.sql.ast.tree.update.Assignment) TableReference(org.hibernate.sql.ast.tree.from.TableReference) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) SqmCteTable(org.hibernate.query.sqm.tree.cte.SqmCteTable) CteTable(org.hibernate.sql.ast.tree.cte.CteTable) CteStatement(org.hibernate.sql.ast.tree.cte.CteStatement) ArrayList(java.util.ArrayList) List(java.util.List) SqmSetClause(org.hibernate.query.sqm.tree.update.SqmSetClause) EntityMappingType(org.hibernate.metamodel.mapping.EntityMappingType) SqmUpdateStatement(org.hibernate.query.sqm.tree.update.SqmUpdateStatement) UpdateStatement(org.hibernate.sql.ast.tree.update.UpdateStatement) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) SqmUpdateStatement(org.hibernate.query.sqm.tree.update.SqmUpdateStatement) MutationStatement(org.hibernate.sql.ast.tree.MutationStatement) Joinable(org.hibernate.persister.entity.Joinable) SqmParameter(org.hibernate.query.sqm.tree.expression.SqmParameter) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference)

Aggregations

ArrayList (java.util.ArrayList)1 LinkedHashMap (java.util.LinkedHashMap)1 List (java.util.List)1 EntityMappingType (org.hibernate.metamodel.mapping.EntityMappingType)1 MappingModelExpressible (org.hibernate.metamodel.mapping.MappingModelExpressible)1 EntityPersister (org.hibernate.persister.entity.EntityPersister)1 Joinable (org.hibernate.persister.entity.Joinable)1 SqmCteTable (org.hibernate.query.sqm.tree.cte.SqmCteTable)1 SqmParameter (org.hibernate.query.sqm.tree.expression.SqmParameter)1 SqmSetClause (org.hibernate.query.sqm.tree.update.SqmSetClause)1 SqmUpdateStatement (org.hibernate.query.sqm.tree.update.SqmUpdateStatement)1 MutationStatement (org.hibernate.sql.ast.tree.MutationStatement)1 CteStatement (org.hibernate.sql.ast.tree.cte.CteStatement)1 CteTable (org.hibernate.sql.ast.tree.cte.CteTable)1 ColumnReference (org.hibernate.sql.ast.tree.expression.ColumnReference)1 NamedTableReference (org.hibernate.sql.ast.tree.from.NamedTableReference)1 TableGroup (org.hibernate.sql.ast.tree.from.TableGroup)1 TableReference (org.hibernate.sql.ast.tree.from.TableReference)1 Assignment (org.hibernate.sql.ast.tree.update.Assignment)1 UpdateStatement (org.hibernate.sql.ast.tree.update.UpdateStatement)1