Search in sources :

Example 46 with TableGroup

use of org.hibernate.sql.ast.tree.from.TableGroup in project hibernate-orm by hibernate.

the class CteInsertHandler method addDmlCtes.

protected String addDmlCtes(CteContainer statement, CteStatement queryCte, List<Map.Entry<SqmCteTableColumn, Assignment>> assignments, boolean assignsId, MultiTableSqmMutationConverter sqmConverter, Map<SqmParameter<?>, List<List<JdbcParameter>>> parameterResolutions, SessionFactoryImplementor factory) {
    final TableGroup updatingTableGroup = sqmConverter.getMutatingTableGroup();
    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;
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // 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<Map.Entry<SqmCteTableColumn, Assignment>>> assignmentsByTable = CollectionHelper.mapOfSize(updatingTableGroup.getTableReferenceJoins().size() + 1);
    for (int i = 0; i < assignments.size(); i++) {
        final Map.Entry<SqmCteTableColumn, Assignment> entry = assignments.get(i);
        final Assignment assignment = entry.getValue();
        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, updatingTableGroup, 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<Map.Entry<SqmCteTableColumn, Assignment>> assignmentsForTable = assignmentsByTable.get(assignmentTableReference);
        if (assignmentsForTable == null) {
            assignmentsForTable = new ArrayList<>();
            assignmentsByTable.put(assignmentTableReference, assignmentsForTable);
        }
        assignmentsForTable.add(entry);
    }
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Add the root insert as cte
    final AbstractEntityPersister persister = (AbstractEntityPersister) entityDescriptor.getEntityPersister();
    final String rootTableName = persister.getTableName(0);
    final TableReference rootTableReference = updatingTableGroup.getTableReference(updatingTableGroup.getNavigablePath(), rootTableName, true, true);
    final IdentifierGenerator identifierGenerator = entityDescriptor.getEntityPersister().getIdentifierGenerator();
    final List<Map.Entry<SqmCteTableColumn, Assignment>> tableAssignments = assignmentsByTable.get(rootTableReference);
    if ((tableAssignments == null || tableAssignments.isEmpty()) && !(identifierGenerator instanceof PostInsertIdentifierGenerator)) {
        throw new IllegalStateException("There must be at least a single root table assignment");
    }
    final int tableSpan = persister.getTableSpan();
    final String[] rootKeyColumns = persister.getKeyColumns(0);
    final List<CteColumn> keyCteColumns = queryCte.getCteTable().getCteColumns().subList(0, rootKeyColumns.length);
    for (int i = 0; i < tableSpan; i++) {
        final String tableExpression = persister.getTableName(i);
        final TableReference updatingTableReference = updatingTableGroup.getTableReference(updatingTableGroup.getNavigablePath(), tableExpression, true, true);
        final List<Map.Entry<SqmCteTableColumn, Assignment>> assignmentList = assignmentsByTable.get(updatingTableReference);
        final NamedTableReference dmlTableReference = resolveUnionTableReference(updatingTableReference, tableExpression);
        final String[] keyColumns = persister.getKeyColumns(i);
        final List<ColumnReference> returningColumnReferences = new ArrayList<>(keyColumns.length + (assignmentList == null ? 0 : assignmentList.size()));
        final List<ColumnReference> insertColumnReferences;
        final QuerySpec insertSelectSpec = new QuerySpec(true);
        CteStatement finalCteStatement = null;
        final CteTable dmlResultCte;
        if (i == 0 && !assignsId && identifierGenerator instanceof PostInsertIdentifierGenerator) {
            // Special handling for identity generation
            final String baseTableName = "base_" + queryCte.getCteTable().getTableExpression();
            insertSelectSpec.getFromClause().addRoot(new CteTableGroup(new NamedTableReference(baseTableName, "e", false, factory)));
            final CteColumn rowNumberColumn = queryCte.getCteTable().getCteColumns().get(queryCte.getCteTable().getCteColumns().size() - 1);
            final ColumnReference rowNumberColumnReference = new ColumnReference("e", rowNumberColumn.getColumnExpression(), false, null, null, rowNumberColumn.getJdbcMapping(), factory);
            // Insert in the same order as the original tuples came
            insertSelectSpec.addSortSpecification(new SortSpecification(rowNumberColumnReference, SortOrder.ASCENDING));
            final List<CteColumn> returningColumns = new ArrayList<>(keyCteColumns.size() + 1);
            returningColumns.addAll(keyCteColumns);
            dmlResultCte = new CteTable(getCteTableName(tableExpression, "base_"), returningColumns, factory);
            for (int j = 0; j < keyColumns.length; j++) {
                returningColumnReferences.add(new ColumnReference(dmlTableReference, keyColumns[j], false, null, null, null, factory));
            }
            insertColumnReferences = Collections.emptyList();
            final SelectStatement queryStatement = (SelectStatement) queryCte.getCteDefinition();
            final QuerySpec querySpec = queryStatement.getQuerySpec();
            final NavigablePath navigablePath = new NavigablePath(baseTableName);
            final TableGroup baseTableGroup = new TableGroupImpl(navigablePath, null, new NamedTableReference(baseTableName, "e", false, factory), null);
            final TableGroup rootInsertCteTableGroup = new CteTableGroup(new NamedTableReference(getCteTableName(tableExpression), "t", false, factory));
            baseTableGroup.addTableGroupJoin(new TableGroupJoin(rootInsertCteTableGroup.getNavigablePath(), SqlAstJoinType.INNER, rootInsertCteTableGroup, new ComparisonPredicate(rowNumberColumnReference, ComparisonOperator.EQUAL, new ColumnReference("t", rowNumberColumn.getColumnExpression(), false, null, null, rowNumberColumn.getJdbcMapping(), factory))));
            querySpec.getFromClause().addRoot(baseTableGroup);
            final List<CteColumn> cteColumns = queryCte.getCteTable().getCteColumns();
            // The id column in this case comes from the dml CTE
            final CteColumn idCteColumn = cteColumns.get(0);
            querySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new ColumnReference("t", idCteColumn.getColumnExpression(), false, null, null, idCteColumn.getJdbcMapping(), factory)));
            // The other columns come from the base CTE
            for (int j = 1; j < cteColumns.size(); j++) {
                final CteColumn cteColumn = cteColumns.get(j);
                querySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new ColumnReference("e", cteColumn.getColumnExpression(), false, null, null, cteColumn.getJdbcMapping(), factory)));
            }
            // Now build the final CTE statement
            final List<CteColumn> finalReturningColumns = new ArrayList<>(keyCteColumns.size() + 1);
            finalReturningColumns.addAll(keyCteColumns);
            finalReturningColumns.add(rowNumberColumn);
            final CteTable finalResultCte = new CteTable(getCteTableName(tableExpression), finalReturningColumns, factory);
            final QuerySpec finalResultQuery = new QuerySpec(true);
            finalResultQuery.getFromClause().addRoot(new CteTableGroup(new NamedTableReference(dmlResultCte.getTableExpression(), "e", false, factory)));
            // The id column in this case comes from the dml CTE
            final ColumnReference idColumnReference = new ColumnReference("e", idCteColumn.getColumnExpression(), false, null, null, idCteColumn.getJdbcMapping(), factory);
            finalResultQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, idColumnReference));
            final BasicType<Integer> rowNumberType = sessionFactory.getTypeConfiguration().getBasicTypeForJavaType(Integer.class);
            finalResultQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new Over<>(new SelfRenderingFunctionSqlAstExpression("row_number", (appender, args, walker) -> appender.appendSql("row_number()"), Collections.emptyList(), rowNumberType, rowNumberType), Collections.emptyList(), Collections.emptyList())));
            finalResultQuery.addSortSpecification(new SortSpecification(idColumnReference, SortOrder.ASCENDING));
            final SelectStatement finalResultStatement = new SelectStatement(finalResultQuery);
            finalCteStatement = new CteStatement(finalResultCte, finalResultStatement);
        } else {
            insertSelectSpec.getFromClause().addRoot(new CteTableGroup(new NamedTableReference(queryCte.getCteTable().getTableExpression(), "e", false, factory)));
            dmlResultCte = new CteTable(getCteTableName(tableExpression), keyCteColumns, factory);
            for (int j = 0; j < keyColumns.length; j++) {
                returningColumnReferences.add(new ColumnReference(dmlTableReference, keyColumns[j], false, null, null, null, factory));
                insertSelectSpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new ColumnReference("e", rootKeyColumns[j], false, null, null, null, factory)));
            }
            insertColumnReferences = returningColumnReferences;
        }
        final InsertStatement dmlStatement = new InsertStatement(dmlTableReference, returningColumnReferences);
        dmlStatement.addTargetColumnReferences(insertColumnReferences);
        if (assignmentList != null) {
            for (Map.Entry<SqmCteTableColumn, Assignment> entry : assignmentList) {
                final Assignment assignment = entry.getValue();
                // Skip the id mapping here as we handled that already
                if (assignment.getAssignedValue().getExpressionType() instanceof EntityIdentifierMapping) {
                    continue;
                }
                final List<ColumnReference> assignmentReferences = assignment.getAssignable().getColumnReferences();
                dmlStatement.addTargetColumnReferences(assignmentReferences);
                final int size = assignmentReferences.size();
                for (int j = 0; j < size; j++) {
                    final ColumnReference columnReference = assignmentReferences.get(j);
                    final String columnName = size > 1 ? entry.getKey().getColumnName() + '_' + i : entry.getKey().getColumnName();
                    insertSelectSpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new ColumnReference("e", columnName, columnReference.isColumnExpressionFormula(), null, null, columnReference.getJdbcMapping(), factory)));
                }
            }
        }
        dmlStatement.setSourceSelectStatement(insertSelectSpec);
        statement.addCteStatement(new CteStatement(dmlResultCte, dmlStatement));
        if (finalCteStatement != null) {
            statement.addCteStatement(finalCteStatement);
        }
        if (i == 0 && !assignsId && identifierGenerator instanceof PostInsertIdentifierGenerator) {
            // Special handling for identity generation
            statement.addCteStatement(queryCte);
        }
    }
    return getCteTableName(rootTableName);
}
Also used : EntityPersister(org.hibernate.persister.entity.EntityPersister) AbstractEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister) CteColumn(org.hibernate.sql.ast.tree.cte.CteColumn) CollectionHelper(org.hibernate.internal.util.collections.CollectionHelper) Arrays(java.util.Arrays) EntityPersister(org.hibernate.persister.entity.EntityPersister) Statement(org.hibernate.sql.ast.tree.Statement) SqlExpressible(org.hibernate.metamodel.mapping.SqlExpressible) BasicType(org.hibernate.type.BasicType) SqmCteTable(org.hibernate.query.sqm.tree.cte.SqmCteTable) SqmInsertValuesStatement(org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement) TableGroupJoin(org.hibernate.sql.ast.tree.from.TableGroupJoin) CteStatement(org.hibernate.sql.ast.tree.cte.CteStatement) Joinable(org.hibernate.persister.entity.Joinable) EntityMappingType(org.hibernate.metamodel.mapping.EntityMappingType) SqmExpression(org.hibernate.query.sqm.tree.expression.SqmExpression) Identifier(org.hibernate.boot.model.naming.Identifier) SqmJdbcExecutionContextAdapter(org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) SqmUtil(org.hibernate.query.sqm.internal.SqmUtil) PostInsertIdentifierGenerator(org.hibernate.id.PostInsertIdentifierGenerator) Map(java.util.Map) ComparisonOperator(org.hibernate.query.sqm.ComparisonOperator) TableReferenceJoin(org.hibernate.sql.ast.tree.from.TableReferenceJoin) SessionFactoryImplementor(org.hibernate.engine.spi.SessionFactoryImplementor) SqmInsertSelectStatement(org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement) IdentifierGenerator(org.hibernate.id.IdentifierGenerator) Assignment(org.hibernate.sql.ast.tree.update.Assignment) IdentityHashMap(java.util.IdentityHashMap) SelfRenderingSqlFragmentExpression(org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) TypeConfiguration(org.hibernate.type.spi.TypeConfiguration) Optimizer(org.hibernate.id.enhanced.Optimizer) NavigablePath(org.hibernate.query.spi.NavigablePath) DomainResult(org.hibernate.sql.results.graph.DomainResult) BasicValuedMapping(org.hibernate.metamodel.mapping.BasicValuedMapping) Expression(org.hibernate.sql.ast.tree.expression.Expression) BaseSqmToSqlAstConverter(org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter) BasicResult(org.hibernate.sql.results.graph.basic.BasicResult) SqlAstProcessingState(org.hibernate.sql.ast.spi.SqlAstProcessingState) EntityIdentifierMapping(org.hibernate.metamodel.mapping.EntityIdentifierMapping) SelectStatement(org.hibernate.sql.ast.tree.select.SelectStatement) InsertHandler(org.hibernate.query.sqm.mutation.internal.InsertHandler) List(java.util.List) Over(org.hibernate.sql.ast.tree.expression.Over) SqmParameter(org.hibernate.query.sqm.tree.expression.SqmParameter) AbstractEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister) InsertStatement(org.hibernate.sql.ast.tree.insert.InsertStatement) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) MappingModelExpressible(org.hibernate.metamodel.mapping.MappingModelExpressible) TableGroupImpl(org.hibernate.query.results.TableGroupImpl) JdbcMapping(org.hibernate.metamodel.mapping.JdbcMapping) CteContainer(org.hibernate.sql.ast.tree.cte.CteContainer) CteMaterialization(org.hibernate.sql.ast.tree.cte.CteMaterialization) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference) OptimizableGenerator(org.hibernate.id.OptimizableGenerator) SemanticException(org.hibernate.query.SemanticException) SortOrder(org.hibernate.query.sqm.SortOrder) JdbcParameterBindings(org.hibernate.sql.exec.spi.JdbcParameterBindings) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) ArrayList(java.util.ArrayList) TableReference(org.hibernate.sql.ast.tree.from.TableReference) LinkedHashMap(java.util.LinkedHashMap) CteTable(org.hibernate.sql.ast.tree.cte.CteTable) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) MultiTableSqmMutationConverter(org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter) SqmParameterMappingModelResolutionAccess(org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess) CteColumn(org.hibernate.sql.ast.tree.cte.CteColumn) UnionTableReference(org.hibernate.sql.ast.tree.from.UnionTableReference) BiConsumer(java.util.function.BiConsumer) BinaryArithmeticExpression(org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression) BinaryArithmeticOperator(org.hibernate.query.sqm.BinaryArithmeticOperator) ValuesTableGroup(org.hibernate.sql.ast.tree.from.ValuesTableGroup) Values(org.hibernate.sql.ast.tree.insert.Values) BulkInsertionCapableIdentifierGenerator(org.hibernate.id.BulkInsertionCapableIdentifierGenerator) TemporaryTable(org.hibernate.dialect.temptable.TemporaryTable) ListResultsConsumer(org.hibernate.sql.results.spi.ListResultsConsumer) SqmStar(org.hibernate.query.sqm.tree.expression.SqmStar) CteTableGroup(org.hibernate.sql.ast.tree.cte.CteTableGroup) SqlAstTranslator(org.hibernate.sql.ast.SqlAstTranslator) JdbcServices(org.hibernate.engine.jdbc.spi.JdbcServices) QueryLiteral(org.hibernate.sql.ast.tree.expression.QueryLiteral) DomainQueryExecutionContext(org.hibernate.query.spi.DomainQueryExecutionContext) SqmCteTableColumn(org.hibernate.query.sqm.tree.cte.SqmCteTableColumn) AbstractMap(java.util.AbstractMap) JdbcParameter(org.hibernate.sql.ast.tree.expression.JdbcParameter) SqmInsertStatement(org.hibernate.query.sqm.tree.insert.SqmInsertStatement) QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) SqlAstJoinType(org.hibernate.sql.ast.SqlAstJoinType) SqlSelectionImpl(org.hibernate.sql.results.internal.SqlSelectionImpl) Stack(org.hibernate.internal.util.collections.Stack) DomainParameterXref(org.hibernate.query.sqm.internal.DomainParameterXref) Collections(java.util.Collections) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) JdbcSelect(org.hibernate.sql.exec.spi.JdbcSelect) SqmValues(org.hibernate.query.sqm.tree.insert.SqmValues) NavigablePath(org.hibernate.query.spi.NavigablePath) ArrayList(java.util.ArrayList) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) InsertStatement(org.hibernate.sql.ast.tree.insert.InsertStatement) SqmInsertStatement(org.hibernate.query.sqm.tree.insert.SqmInsertStatement) Assignment(org.hibernate.sql.ast.tree.update.Assignment) TableGroupJoin(org.hibernate.sql.ast.tree.from.TableGroupJoin) SqmInsertSelectStatement(org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement) SelectStatement(org.hibernate.sql.ast.tree.select.SelectStatement) Over(org.hibernate.sql.ast.tree.expression.Over) TableReference(org.hibernate.sql.ast.tree.from.TableReference) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) UnionTableReference(org.hibernate.sql.ast.tree.from.UnionTableReference) SqmCteTable(org.hibernate.query.sqm.tree.cte.SqmCteTable) CteTable(org.hibernate.sql.ast.tree.cte.CteTable) CteStatement(org.hibernate.sql.ast.tree.cte.CteStatement) List(java.util.List) ArrayList(java.util.ArrayList) TableGroupImpl(org.hibernate.query.results.TableGroupImpl) EntityMappingType(org.hibernate.metamodel.mapping.EntityMappingType) ValuesTableGroup(org.hibernate.sql.ast.tree.from.ValuesTableGroup) CteTableGroup(org.hibernate.sql.ast.tree.cte.CteTableGroup) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) PostInsertIdentifierGenerator(org.hibernate.id.PostInsertIdentifierGenerator) CteTableGroup(org.hibernate.sql.ast.tree.cte.CteTableGroup) SqmCteTableColumn(org.hibernate.query.sqm.tree.cte.SqmCteTableColumn) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) Joinable(org.hibernate.persister.entity.Joinable) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) EntityIdentifierMapping(org.hibernate.metamodel.mapping.EntityIdentifierMapping) SqlSelectionImpl(org.hibernate.sql.results.internal.SqlSelectionImpl) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) LinkedHashMap(java.util.LinkedHashMap) AbstractMap(java.util.AbstractMap) AbstractEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference) PostInsertIdentifierGenerator(org.hibernate.id.PostInsertIdentifierGenerator) IdentifierGenerator(org.hibernate.id.IdentifierGenerator) BulkInsertionCapableIdentifierGenerator(org.hibernate.id.BulkInsertionCapableIdentifierGenerator)

Example 47 with TableGroup

use of org.hibernate.sql.ast.tree.from.TableGroup in project hibernate-orm by hibernate.

the class CteInsertHandler method execute.

@Override
public int execute(DomainQueryExecutionContext executionContext) {
    final SqmInsertStatement<?> sqmInsertStatement = getSqmStatement();
    final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
    final EntityPersister entityDescriptor = getEntityDescriptor().getEntityPersister();
    final String explicitDmlTargetAlias;
    if (sqmInsertStatement.getTarget().getExplicitAlias() == null) {
        explicitDmlTargetAlias = "dml_target";
    } else {
        explicitDmlTargetAlias = sqmInsertStatement.getTarget().getExplicitAlias();
    }
    final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter(entityDescriptor, sqmInsertStatement, sqmInsertStatement.getTarget(), explicitDmlTargetAlias, domainParameterXref, executionContext.getQueryOptions(), executionContext.getSession().getLoadQueryInfluencers(), executionContext.getQueryParameterBindings(), factory);
    final TableGroup insertingTableGroup = sqmConverter.getMutatingTableGroup();
    final Map<SqmParameter<?>, List<List<JdbcParameter>>> parameterResolutions;
    if (domainParameterXref.getSqmParameterCount() == 0) {
        parameterResolutions = Collections.emptyMap();
    } else {
        parameterResolutions = new IdentityHashMap<>();
    }
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // visit the insertion target using our special converter, collecting
    // information about the target paths
    final int size = sqmStatement.getInsertionTargetPaths().size();
    final List<Map.Entry<SqmCteTableColumn, Assignment>> targetPathColumns = new ArrayList<>(size);
    final List<SqmCteTableColumn> targetPathSqmCteColumns = new ArrayList<>(size);
    final Map<SqmParameter<?>, MappingModelExpressible<?>> paramTypeResolutions = new LinkedHashMap<>();
    final NamedTableReference entityTableReference = new NamedTableReference(cteTable.getCteName(), TemporaryTable.DEFAULT_ALIAS, true, sessionFactory);
    final InsertStatement insertStatement = new InsertStatement(entityTableReference);
    final BaseSqmToSqlAstConverter.AdditionalInsertValues additionalInsertValues = sqmConverter.visitInsertionTargetPaths((assignable, columnReferences) -> {
        // Find a matching cte table column and set that at the current index
        for (SqmCteTableColumn column : cteTable.getColumns()) {
            if (column.getType() == ((Expression) assignable).getExpressionType()) {
                insertStatement.addTargetColumnReferences(columnReferences);
                targetPathSqmCteColumns.add(column);
                targetPathColumns.add(new AbstractMap.SimpleEntry<>(column, new Assignment(assignable, (Expression) assignable)));
                return;
            }
        }
        throw new IllegalStateException("Couldn't find matching cte column for: " + ((Expression) assignable).getExpressionType());
    }, sqmInsertStatement, entityDescriptor, insertingTableGroup, (sqmParameter, mappingType, jdbcParameters) -> {
        parameterResolutions.computeIfAbsent(sqmParameter, k -> new ArrayList<>(1)).add(jdbcParameters);
        paramTypeResolutions.put(sqmParameter, mappingType);
    });
    final boolean assignsId = targetPathSqmCteColumns.contains(cteTable.getColumns().get(0));
    // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    // Create the statement that represent the source for the entity cte
    final Stack<SqlAstProcessingState> processingStateStack = sqmConverter.getProcessingStateStack();
    final SqlAstProcessingState oldState = processingStateStack.pop();
    final Statement queryStatement;
    if (sqmInsertStatement instanceof SqmInsertSelectStatement) {
        final QueryPart queryPart = sqmConverter.visitQueryPart(((SqmInsertSelectStatement<?>) sqmInsertStatement).getSelectQueryPart());
        queryPart.visitQuerySpecs(querySpec -> {
            // in which case we will fill the row_number column instead of the id column
            if (additionalInsertValues.applySelections(querySpec, sessionFactory)) {
                final SqmCteTableColumn rowNumberColumn = cteTable.getColumns().get(cteTable.getColumns().size() - 1);
                final ColumnReference columnReference = new ColumnReference((String) null, rowNumberColumn.getColumnName(), false, null, null, (JdbcMapping) rowNumberColumn.getType(), sessionFactory);
                insertStatement.getTargetColumnReferences().set(insertStatement.getTargetColumnReferences().size() - 1, columnReference);
                targetPathSqmCteColumns.set(targetPathSqmCteColumns.size() - 1, rowNumberColumn);
            }
            if (!assignsId && entityDescriptor.getIdentifierGenerator() instanceof PostInsertIdentifierGenerator) {
                final BasicType<Integer> rowNumberType = sessionFactory.getTypeConfiguration().getBasicTypeForJavaType(Integer.class);
                querySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new Over<>(new SelfRenderingFunctionSqlAstExpression("row_number", (appender, args, walker) -> appender.appendSql("row_number()"), Collections.emptyList(), rowNumberType, rowNumberType), Collections.emptyList(), Collections.emptyList())));
            }
        });
        queryStatement = new SelectStatement(queryPart);
    } else {
        final List<SqmValues> sqmValuesList = ((SqmInsertValuesStatement<?>) sqmInsertStatement).getValuesList();
        final List<Values> valuesList = new ArrayList<>(sqmValuesList.size());
        for (SqmValues sqmValues : sqmValuesList) {
            final Values values = sqmConverter.visitValues(sqmValues);
            additionalInsertValues.applyValues(values);
            valuesList.add(values);
        }
        final QuerySpec querySpec = new QuerySpec(true);
        final NavigablePath navigablePath = new NavigablePath(entityDescriptor.getRootPathName());
        final List<String> columnNames = new ArrayList<>(targetPathColumns.size());
        for (Map.Entry<SqmCteTableColumn, Assignment> entry : targetPathColumns) {
            for (ColumnReference columnReference : entry.getValue().getAssignable().getColumnReferences()) {
                columnNames.add(columnReference.getColumnExpression());
                querySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, columnReference));
            }
        }
        final ValuesTableGroup valuesTableGroup = new ValuesTableGroup(navigablePath, entityDescriptor.getEntityPersister(), valuesList, insertingTableGroup.getPrimaryTableReference().getIdentificationVariable(), columnNames, true, factory);
        querySpec.getFromClause().addRoot(valuesTableGroup);
        queryStatement = new SelectStatement(querySpec);
    }
    processingStateStack.push(oldState);
    sqmConverter.pruneTableGroupJoins();
    if (!assignsId && entityDescriptor.getIdentifierGenerator() instanceof PostInsertIdentifierGenerator) {
        // Add the row number to the assignments
        final SqmCteTableColumn rowNumberColumn = cteTable.getColumns().get(cteTable.getColumns().size() - 1);
        final ColumnReference columnReference = new ColumnReference((String) null, rowNumberColumn.getColumnName(), false, null, null, (JdbcMapping) rowNumberColumn.getType(), sessionFactory);
        insertStatement.getTargetColumnReferences().add(columnReference);
        targetPathSqmCteColumns.add(rowNumberColumn);
    }
    final CteTable entityCteTable = BaseSqmToSqlAstConverter.createCteTable(getCteTable(), targetPathSqmCteColumns, factory);
    // Create the main query spec that will return the count of rows
    final QuerySpec querySpec = new QuerySpec(true, 1);
    final List<DomainResult<?>> domainResults = new ArrayList<>(1);
    final SelectStatement statement = new SelectStatement(querySpec, domainResults);
    final CteStatement entityCte;
    if (additionalInsertValues.requiresRowNumberIntermediate()) {
        final CteTable fullEntityCteTable = BaseSqmToSqlAstConverter.createCteTable(getCteTable(), factory);
        final String baseTableName = "base_" + entityCteTable.getTableExpression();
        final CteStatement baseEntityCte = new CteStatement(entityCteTable.withName(baseTableName), queryStatement, // The query cte will be reused multiple times
        CteMaterialization.MATERIALIZED);
        statement.addCteStatement(baseEntityCte);
        final CteColumn rowNumberColumn = fullEntityCteTable.getCteColumns().get(fullEntityCteTable.getCteColumns().size() - 1);
        final ColumnReference rowNumberColumnReference = new ColumnReference("e", rowNumberColumn.getColumnExpression(), false, null, null, rowNumberColumn.getJdbcMapping(), factory);
        final CteColumn idColumn = fullEntityCteTable.getCteColumns().get(0);
        final BasicValuedMapping idType = (BasicValuedMapping) idColumn.getJdbcMapping();
        final Optimizer optimizer = ((OptimizableGenerator) entityDescriptor.getIdentifierGenerator()).getOptimizer();
        final BasicValuedMapping integerType = (BasicValuedMapping) rowNumberColumn.getJdbcMapping();
        final Expression rowNumberMinusOneModuloIncrement = new BinaryArithmeticExpression(new BinaryArithmeticExpression(rowNumberColumnReference, BinaryArithmeticOperator.SUBTRACT, new QueryLiteral<>(1, (BasicValuedMapping) rowNumberColumn.getJdbcMapping()), integerType), BinaryArithmeticOperator.MODULO, new QueryLiteral<>(optimizer.getIncrementSize(), integerType), integerType);
        // Create the CTE that fetches a new sequence value for the row numbers that need it
        {
            final QuerySpec rowsWithSequenceQuery = new QuerySpec(true);
            rowsWithSequenceQuery.getFromClause().addRoot(new CteTableGroup(new NamedTableReference(baseTableName, "e", false, factory)));
            rowsWithSequenceQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, rowNumberColumnReference));
            final String fragment = ((BulkInsertionCapableIdentifierGenerator) entityDescriptor.getIdentifierGenerator()).determineBulkInsertionIdentifierGenerationSelectFragment(sessionFactory.getSqlStringGenerationContext());
            rowsWithSequenceQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(2, 1, new SelfRenderingSqlFragmentExpression(fragment)));
            rowsWithSequenceQuery.applyPredicate(new ComparisonPredicate(rowNumberMinusOneModuloIncrement, ComparisonOperator.EQUAL, new QueryLiteral<>(0, integerType)));
            final CteTable rowsWithSequenceCteTable = new CteTable(ROW_NUMBERS_WITH_SEQUENCE_VALUE, Arrays.asList(rowNumberColumn, idColumn), sessionFactory);
            final SelectStatement rowsWithSequenceStatement = new SelectStatement(rowsWithSequenceQuery);
            final CteStatement rowsWithSequenceCte = new CteStatement(rowsWithSequenceCteTable, rowsWithSequenceStatement, // The query cte will be reused multiple times
            CteMaterialization.MATERIALIZED);
            statement.addCteStatement(rowsWithSequenceCte);
        }
        // Create the CTE that represents the entity cte
        {
            final QuerySpec entityQuery = new QuerySpec(true);
            final NavigablePath navigablePath = new NavigablePath(baseTableName);
            final TableGroup baseTableGroup = new TableGroupImpl(navigablePath, null, new NamedTableReference(baseTableName, "e", false, factory), null);
            final TableGroup rowsWithSequenceTableGroup = new CteTableGroup(new NamedTableReference(ROW_NUMBERS_WITH_SEQUENCE_VALUE, "t", false, factory));
            baseTableGroup.addTableGroupJoin(new TableGroupJoin(rowsWithSequenceTableGroup.getNavigablePath(), SqlAstJoinType.LEFT, rowsWithSequenceTableGroup, new ComparisonPredicate(new BinaryArithmeticExpression(rowNumberColumnReference, BinaryArithmeticOperator.SUBTRACT, rowNumberMinusOneModuloIncrement, integerType), ComparisonOperator.EQUAL, new ColumnReference("t", rowNumberColumn.getColumnExpression(), false, null, null, rowNumberColumn.getJdbcMapping(), factory))));
            entityQuery.getFromClause().addRoot(baseTableGroup);
            entityQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new BinaryArithmeticExpression(new ColumnReference("t", idColumn.getColumnExpression(), false, null, null, idColumn.getJdbcMapping(), factory), BinaryArithmeticOperator.ADD, new BinaryArithmeticExpression(rowNumberColumnReference, BinaryArithmeticOperator.SUBTRACT, new ColumnReference("t", rowNumberColumn.getColumnExpression(), false, null, null, rowNumberColumn.getJdbcMapping(), factory), integerType), idType)));
            final CteTable finalEntityCteTable;
            if (targetPathSqmCteColumns.contains(getCteTable().getColumns().get(0))) {
                finalEntityCteTable = entityCteTable;
            } else {
                targetPathSqmCteColumns.add(0, getCteTable().getColumns().get(0));
                finalEntityCteTable = BaseSqmToSqlAstConverter.createCteTable(getCteTable(), targetPathSqmCteColumns, factory);
            }
            final List<CteColumn> cteColumns = finalEntityCteTable.getCteColumns();
            for (int i = 1; i < cteColumns.size(); i++) {
                final CteColumn cteColumn = cteColumns.get(i);
                entityQuery.getSelectClause().addSqlSelection(new SqlSelectionImpl(i + 1, i, new ColumnReference("e", cteColumn.getColumnExpression(), false, null, null, cteColumn.getJdbcMapping(), factory)));
            }
            final SelectStatement entityStatement = new SelectStatement(entityQuery);
            entityCte = new CteStatement(finalEntityCteTable, entityStatement, // The query cte will be reused multiple times
            CteMaterialization.MATERIALIZED);
            statement.addCteStatement(entityCte);
        }
    } else if (!assignsId && entityDescriptor.getIdentifierGenerator() instanceof PostInsertIdentifierGenerator) {
        final String baseTableName = "base_" + entityCteTable.getTableExpression();
        final CteStatement baseEntityCte = new CteStatement(entityCteTable.withName(baseTableName), queryStatement, // The query cte will be reused multiple times
        CteMaterialization.MATERIALIZED);
        statement.addCteStatement(baseEntityCte);
        targetPathSqmCteColumns.add(0, cteTable.getColumns().get(0));
        final CteTable finalEntityCteTable = BaseSqmToSqlAstConverter.createCteTable(getCteTable(), targetPathSqmCteColumns, factory);
        final QuerySpec finalQuerySpec = new QuerySpec(true);
        final SelectStatement finalQueryStatement = new SelectStatement(finalQuerySpec);
        entityCte = new CteStatement(finalEntityCteTable, finalQueryStatement, // The query cte will be reused multiple times
        CteMaterialization.MATERIALIZED);
    } else {
        entityCte = new CteStatement(entityCteTable, queryStatement, // The query cte will be reused multiple times
        CteMaterialization.MATERIALIZED);
        statement.addCteStatement(entityCte);
    }
    // Add all CTEs
    final String baseInsertCte = addDmlCtes(statement, entityCte, targetPathColumns, assignsId, sqmConverter, parameterResolutions, factory);
    final Expression count = createCountStar(factory, sqmConverter);
    domainResults.add(new BasicResult(0, null, ((SqlExpressible) count).getJdbcMapping().getJavaTypeDescriptor()));
    querySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, count));
    querySpec.getFromClause().addRoot(new CteTableGroup(new NamedTableReference(// We want to return the insertion count of the base table
    baseInsertCte, CTE_TABLE_IDENTIFIER, false, factory)));
    // Execute the statement
    final JdbcServices jdbcServices = factory.getJdbcServices();
    final SqlAstTranslator<JdbcSelect> translator = jdbcServices.getJdbcEnvironment().getSqlAstTranslatorFactory().buildSelectTranslator(factory, statement);
    final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(executionContext.getQueryParameterBindings(), domainParameterXref, SqmUtil.generateJdbcParamsXref(domainParameterXref, sqmConverter), factory.getRuntimeMetamodels().getMappingMetamodel(), navigablePath -> sqmConverter.getMutatingTableGroup(), new SqmParameterMappingModelResolutionAccess() {

        @Override
        @SuppressWarnings("unchecked")
        public <T> MappingModelExpressible<T> getResolvedMappingModelType(SqmParameter<T> parameter) {
            return (MappingModelExpressible<T>) paramTypeResolutions.get(parameter);
        }
    }, executionContext.getSession());
    final JdbcSelect select = translator.translate(jdbcParameterBindings, executionContext.getQueryOptions());
    executionContext.getSession().autoFlushIfRequired(select.getAffectedTableNames());
    List<Object> list = jdbcServices.getJdbcSelectExecutor().list(select, jdbcParameterBindings, SqmJdbcExecutionContextAdapter.omittingLockingAndPaging(executionContext), row -> row[0], ListResultsConsumer.UniqueSemantic.NONE);
    return ((Number) list.get(0)).intValue();
}
Also used : CollectionHelper(org.hibernate.internal.util.collections.CollectionHelper) Arrays(java.util.Arrays) EntityPersister(org.hibernate.persister.entity.EntityPersister) Statement(org.hibernate.sql.ast.tree.Statement) SqlExpressible(org.hibernate.metamodel.mapping.SqlExpressible) BasicType(org.hibernate.type.BasicType) SqmCteTable(org.hibernate.query.sqm.tree.cte.SqmCteTable) SqmInsertValuesStatement(org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement) TableGroupJoin(org.hibernate.sql.ast.tree.from.TableGroupJoin) CteStatement(org.hibernate.sql.ast.tree.cte.CteStatement) Joinable(org.hibernate.persister.entity.Joinable) EntityMappingType(org.hibernate.metamodel.mapping.EntityMappingType) SqmExpression(org.hibernate.query.sqm.tree.expression.SqmExpression) Identifier(org.hibernate.boot.model.naming.Identifier) SqmJdbcExecutionContextAdapter(org.hibernate.query.sqm.internal.SqmJdbcExecutionContextAdapter) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) SqmUtil(org.hibernate.query.sqm.internal.SqmUtil) PostInsertIdentifierGenerator(org.hibernate.id.PostInsertIdentifierGenerator) Map(java.util.Map) ComparisonOperator(org.hibernate.query.sqm.ComparisonOperator) TableReferenceJoin(org.hibernate.sql.ast.tree.from.TableReferenceJoin) SessionFactoryImplementor(org.hibernate.engine.spi.SessionFactoryImplementor) SqmInsertSelectStatement(org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement) IdentifierGenerator(org.hibernate.id.IdentifierGenerator) Assignment(org.hibernate.sql.ast.tree.update.Assignment) IdentityHashMap(java.util.IdentityHashMap) SelfRenderingSqlFragmentExpression(org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) TypeConfiguration(org.hibernate.type.spi.TypeConfiguration) Optimizer(org.hibernate.id.enhanced.Optimizer) NavigablePath(org.hibernate.query.spi.NavigablePath) DomainResult(org.hibernate.sql.results.graph.DomainResult) BasicValuedMapping(org.hibernate.metamodel.mapping.BasicValuedMapping) Expression(org.hibernate.sql.ast.tree.expression.Expression) BaseSqmToSqlAstConverter(org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter) BasicResult(org.hibernate.sql.results.graph.basic.BasicResult) SqlAstProcessingState(org.hibernate.sql.ast.spi.SqlAstProcessingState) EntityIdentifierMapping(org.hibernate.metamodel.mapping.EntityIdentifierMapping) SelectStatement(org.hibernate.sql.ast.tree.select.SelectStatement) InsertHandler(org.hibernate.query.sqm.mutation.internal.InsertHandler) List(java.util.List) Over(org.hibernate.sql.ast.tree.expression.Over) SqmParameter(org.hibernate.query.sqm.tree.expression.SqmParameter) AbstractEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister) InsertStatement(org.hibernate.sql.ast.tree.insert.InsertStatement) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) MappingModelExpressible(org.hibernate.metamodel.mapping.MappingModelExpressible) TableGroupImpl(org.hibernate.query.results.TableGroupImpl) JdbcMapping(org.hibernate.metamodel.mapping.JdbcMapping) CteContainer(org.hibernate.sql.ast.tree.cte.CteContainer) CteMaterialization(org.hibernate.sql.ast.tree.cte.CteMaterialization) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference) OptimizableGenerator(org.hibernate.id.OptimizableGenerator) SemanticException(org.hibernate.query.SemanticException) SortOrder(org.hibernate.query.sqm.SortOrder) JdbcParameterBindings(org.hibernate.sql.exec.spi.JdbcParameterBindings) SortSpecification(org.hibernate.sql.ast.tree.select.SortSpecification) ArrayList(java.util.ArrayList) TableReference(org.hibernate.sql.ast.tree.from.TableReference) LinkedHashMap(java.util.LinkedHashMap) CteTable(org.hibernate.sql.ast.tree.cte.CteTable) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) MultiTableSqmMutationConverter(org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter) SqmParameterMappingModelResolutionAccess(org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess) CteColumn(org.hibernate.sql.ast.tree.cte.CteColumn) UnionTableReference(org.hibernate.sql.ast.tree.from.UnionTableReference) BiConsumer(java.util.function.BiConsumer) BinaryArithmeticExpression(org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression) BinaryArithmeticOperator(org.hibernate.query.sqm.BinaryArithmeticOperator) ValuesTableGroup(org.hibernate.sql.ast.tree.from.ValuesTableGroup) Values(org.hibernate.sql.ast.tree.insert.Values) BulkInsertionCapableIdentifierGenerator(org.hibernate.id.BulkInsertionCapableIdentifierGenerator) TemporaryTable(org.hibernate.dialect.temptable.TemporaryTable) ListResultsConsumer(org.hibernate.sql.results.spi.ListResultsConsumer) SqmStar(org.hibernate.query.sqm.tree.expression.SqmStar) CteTableGroup(org.hibernate.sql.ast.tree.cte.CteTableGroup) SqlAstTranslator(org.hibernate.sql.ast.SqlAstTranslator) JdbcServices(org.hibernate.engine.jdbc.spi.JdbcServices) QueryLiteral(org.hibernate.sql.ast.tree.expression.QueryLiteral) DomainQueryExecutionContext(org.hibernate.query.spi.DomainQueryExecutionContext) SqmCteTableColumn(org.hibernate.query.sqm.tree.cte.SqmCteTableColumn) AbstractMap(java.util.AbstractMap) JdbcParameter(org.hibernate.sql.ast.tree.expression.JdbcParameter) SqmInsertStatement(org.hibernate.query.sqm.tree.insert.SqmInsertStatement) QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) SqlAstJoinType(org.hibernate.sql.ast.SqlAstJoinType) SqlSelectionImpl(org.hibernate.sql.results.internal.SqlSelectionImpl) Stack(org.hibernate.internal.util.collections.Stack) DomainParameterXref(org.hibernate.query.sqm.internal.DomainParameterXref) Collections(java.util.Collections) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) JdbcSelect(org.hibernate.sql.exec.spi.JdbcSelect) SqmValues(org.hibernate.query.sqm.tree.insert.SqmValues) CteColumn(org.hibernate.sql.ast.tree.cte.CteColumn) QueryPart(org.hibernate.sql.ast.tree.select.QueryPart) OptimizableGenerator(org.hibernate.id.OptimizableGenerator) ArrayList(java.util.ArrayList) Values(org.hibernate.sql.ast.tree.insert.Values) SqmValues(org.hibernate.query.sqm.tree.insert.SqmValues) InsertStatement(org.hibernate.sql.ast.tree.insert.InsertStatement) SqmInsertStatement(org.hibernate.query.sqm.tree.insert.SqmInsertStatement) LinkedHashMap(java.util.LinkedHashMap) ValuesTableGroup(org.hibernate.sql.ast.tree.from.ValuesTableGroup) AbstractMap(java.util.AbstractMap) Assignment(org.hibernate.sql.ast.tree.update.Assignment) CteStatement(org.hibernate.sql.ast.tree.cte.CteStatement) List(java.util.List) ArrayList(java.util.ArrayList) ValuesTableGroup(org.hibernate.sql.ast.tree.from.ValuesTableGroup) CteTableGroup(org.hibernate.sql.ast.tree.cte.CteTableGroup) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) SqmParameterMappingModelResolutionAccess(org.hibernate.query.sqm.spi.SqmParameterMappingModelResolutionAccess) SessionFactoryImplementor(org.hibernate.engine.spi.SessionFactoryImplementor) DomainResult(org.hibernate.sql.results.graph.DomainResult) CteTableGroup(org.hibernate.sql.ast.tree.cte.CteTableGroup) BinaryArithmeticExpression(org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) Map(java.util.Map) IdentityHashMap(java.util.IdentityHashMap) LinkedHashMap(java.util.LinkedHashMap) AbstractMap(java.util.AbstractMap) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference) EntityPersister(org.hibernate.persister.entity.EntityPersister) AbstractEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister) NavigablePath(org.hibernate.query.spi.NavigablePath) MappingModelExpressible(org.hibernate.metamodel.mapping.MappingModelExpressible) Optimizer(org.hibernate.id.enhanced.Optimizer) JdbcServices(org.hibernate.engine.jdbc.spi.JdbcServices) ComparisonPredicate(org.hibernate.sql.ast.tree.predicate.ComparisonPredicate) TableGroupJoin(org.hibernate.sql.ast.tree.from.TableGroupJoin) SqlAstProcessingState(org.hibernate.sql.ast.spi.SqlAstProcessingState) Over(org.hibernate.sql.ast.tree.expression.Over) SqmInsertSelectStatement(org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement) SelectStatement(org.hibernate.sql.ast.tree.select.SelectStatement) SqmCteTable(org.hibernate.query.sqm.tree.cte.SqmCteTable) CteTable(org.hibernate.sql.ast.tree.cte.CteTable) QueryLiteral(org.hibernate.sql.ast.tree.expression.QueryLiteral) BasicResult(org.hibernate.sql.results.graph.basic.BasicResult) SqmValues(org.hibernate.query.sqm.tree.insert.SqmValues) TableGroupImpl(org.hibernate.query.results.TableGroupImpl) SqmInsertSelectStatement(org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement) BaseSqmToSqlAstConverter(org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter) SelfRenderingSqlFragmentExpression(org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression) JdbcSelect(org.hibernate.sql.exec.spi.JdbcSelect) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) JdbcParameter(org.hibernate.sql.ast.tree.expression.JdbcParameter) Statement(org.hibernate.sql.ast.tree.Statement) SqmInsertValuesStatement(org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement) CteStatement(org.hibernate.sql.ast.tree.cte.CteStatement) SqmInsertSelectStatement(org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement) SelectStatement(org.hibernate.sql.ast.tree.select.SelectStatement) InsertStatement(org.hibernate.sql.ast.tree.insert.InsertStatement) SqmInsertStatement(org.hibernate.query.sqm.tree.insert.SqmInsertStatement) SqmInsertValuesStatement(org.hibernate.query.sqm.tree.insert.SqmInsertValuesStatement) PostInsertIdentifierGenerator(org.hibernate.id.PostInsertIdentifierGenerator) BasicValuedMapping(org.hibernate.metamodel.mapping.BasicValuedMapping) SqmCteTableColumn(org.hibernate.query.sqm.tree.cte.SqmCteTableColumn) SqmExpression(org.hibernate.query.sqm.tree.expression.SqmExpression) SelfRenderingSqlFragmentExpression(org.hibernate.sql.ast.tree.expression.SelfRenderingSqlFragmentExpression) SelfRenderingFunctionSqlAstExpression(org.hibernate.query.sqm.function.SelfRenderingFunctionSqlAstExpression) Expression(org.hibernate.sql.ast.tree.expression.Expression) BinaryArithmeticExpression(org.hibernate.sql.ast.tree.expression.BinaryArithmeticExpression) SqlSelectionImpl(org.hibernate.sql.results.internal.SqlSelectionImpl) SqmParameter(org.hibernate.query.sqm.tree.expression.SqmParameter) MultiTableSqmMutationConverter(org.hibernate.query.sqm.mutation.internal.MultiTableSqmMutationConverter) JdbcParameterBindings(org.hibernate.sql.exec.spi.JdbcParameterBindings)

Example 48 with TableGroup

use of org.hibernate.sql.ast.tree.from.TableGroup in project hibernate-orm by hibernate.

the class CteDeleteHandler 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 SelectStatement idSelectStatement = (SelectStatement) idSelectCte.getCteDefinition();
    sqmConverter.getProcessingStateStack().push(new SqlAstQueryPartProcessingStateImpl(idSelectStatement.getQuerySpec(), sqmConverter.getCurrentProcessingState(), sqmConverter.getSqlAstCreationState(), sqmConverter.getCurrentClauseStack()::getCurrent, false));
    getEntityDescriptor().visitSubTypeAttributeMappings(attribute -> {
        if (attribute instanceof PluralAttributeMapping) {
            final PluralAttributeMapping pluralAttribute = (PluralAttributeMapping) attribute;
            if (pluralAttribute.getSeparateCollectionTable() != null) {
                // Ensure that the FK target columns are available
                final boolean useFkTarget = !(pluralAttribute.getKeyDescriptor().getTargetPart() instanceof EntityIdentifierMapping);
                if (useFkTarget) {
                    final TableGroup mutatingTableGroup = sqmConverter.getMutatingTableGroup();
                    pluralAttribute.getKeyDescriptor().getTargetPart().applySqlSelections(mutatingTableGroup.getNavigablePath(), mutatingTableGroup, sqmConverter, (selection, jdbcMapping) -> {
                        idSelectStatement.getDomainResultDescriptors().add(new BasicResult<>(selection.getValuesArrayPosition(), null, jdbcMapping.getJavaTypeDescriptor()));
                    });
                }
                // this collection has a separate collection table, meaning it is one of:
                // 1) element-collection
                // 2) many-to-many
                // 3) one-to many using a dedicated join-table
                // 
                // in all of these cases, we should clean up the matching rows in the
                // collection table
                final String tableExpression = pluralAttribute.getSeparateCollectionTable();
                final CteTable dmlResultCte = new CteTable(getCteTableName(pluralAttribute), idSelectCte.getCteTable().getCteColumns(), factory);
                final NamedTableReference dmlTableReference = new NamedTableReference(tableExpression, DeleteStatement.DEFAULT_ALIAS, true, factory);
                final List<ColumnReference> columnReferences = new ArrayList<>(idSelectCte.getCteTable().getCteColumns().size());
                pluralAttribute.getKeyDescriptor().visitKeySelectables((index, selectable) -> columnReferences.add(new ColumnReference(dmlTableReference, selectable, factory)));
                final MutationStatement dmlStatement = new DeleteStatement(dmlTableReference, createIdSubQueryPredicate(columnReferences, idSelectCte, useFkTarget ? pluralAttribute.getKeyDescriptor().getTargetPart() : null, factory), columnReferences);
                statement.addCteStatement(new CteStatement(dmlResultCte, dmlStatement));
            }
        }
    });
    sqmConverter.getProcessingStateStack().pop();
    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 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 DeleteStatement(dmlTableReference, createIdSubQueryPredicate(columnReferences, idSelectCte, factory), columnReferences);
        statement.addCteStatement(new CteStatement(dmlResultCte, dmlStatement));
    });
}
Also used : TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) PluralAttributeMapping(org.hibernate.metamodel.mapping.PluralAttributeMapping) ArrayList(java.util.ArrayList) SqmDeleteStatement(org.hibernate.query.sqm.tree.delete.SqmDeleteStatement) DeleteStatement(org.hibernate.sql.ast.tree.delete.DeleteStatement) SelectStatement(org.hibernate.sql.ast.tree.select.SelectStatement) SqlAstQueryPartProcessingStateImpl(org.hibernate.query.sqm.sql.internal.SqlAstQueryPartProcessingStateImpl) SqmCteTable(org.hibernate.query.sqm.tree.cte.SqmCteTable) CteTable(org.hibernate.sql.ast.tree.cte.CteTable) MutationStatement(org.hibernate.sql.ast.tree.MutationStatement) TableReference(org.hibernate.sql.ast.tree.from.TableReference) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) EntityIdentifierMapping(org.hibernate.metamodel.mapping.EntityIdentifierMapping) CteStatement(org.hibernate.sql.ast.tree.cte.CteStatement) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference)

Example 49 with TableGroup

use of org.hibernate.sql.ast.tree.from.TableGroup in project hibernate-orm by hibernate.

the class ExecuteWithTemporaryTableHelper method saveMatchingIdsIntoIdTable.

public static int saveMatchingIdsIntoIdTable(MultiTableSqmMutationConverter sqmConverter, Predicate suppliedPredicate, TemporaryTable idTable, Function<SharedSessionContractImplementor, String> sessionUidAccess, JdbcParameterBindings jdbcParameterBindings, ExecutionContext executionContext) {
    final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
    final TableGroup mutatingTableGroup = sqmConverter.getMutatingTableGroup();
    assert mutatingTableGroup.getModelPart() instanceof EntityMappingType;
    final EntityMappingType mutatingEntityDescriptor = (EntityMappingType) mutatingTableGroup.getModelPart();
    final NamedTableReference idTableReference = new NamedTableReference(idTable.getTableExpression(), InsertStatement.DEFAULT_ALIAS, false, factory);
    final InsertStatement idTableInsert = new InsertStatement(idTableReference);
    for (int i = 0; i < idTable.getColumns().size(); i++) {
        final TemporaryTableColumn column = idTable.getColumns().get(i);
        idTableInsert.addTargetColumnReferences(new ColumnReference(idTableReference, column.getColumnName(), // id columns cannot be formulas and cannot have custom read and write expressions
        false, null, null, column.getJdbcMapping(), factory));
    }
    final QuerySpec matchingIdSelection = new QuerySpec(true, 1);
    idTableInsert.setSourceSelectStatement(matchingIdSelection);
    matchingIdSelection.getFromClause().addRoot(mutatingTableGroup);
    mutatingEntityDescriptor.getIdentifierMapping().forEachSelectable((jdbcPosition, selection) -> {
        final TableReference tableReference = mutatingTableGroup.resolveTableReference(mutatingTableGroup.getNavigablePath(), selection.getContainingTableExpression());
        matchingIdSelection.getSelectClause().addSqlSelection(new SqlSelectionImpl(jdbcPosition, jdbcPosition + 1, sqmConverter.getSqlExpressionResolver().resolveSqlExpression(SqlExpressionResolver.createColumnReferenceKey(tableReference, selection.getSelectionExpression()), sqlAstProcessingState -> new ColumnReference(tableReference, selection, factory))));
    });
    if (idTable.getSessionUidColumn() != null) {
        final int jdbcPosition = matchingIdSelection.getSelectClause().getSqlSelections().size();
        matchingIdSelection.getSelectClause().addSqlSelection(new SqlSelectionImpl(jdbcPosition, jdbcPosition + 1, new QueryLiteral<>(sessionUidAccess.apply(executionContext.getSession()), (BasicValuedMapping) idTable.getSessionUidColumn().getJdbcMapping())));
    }
    matchingIdSelection.applyPredicate(suppliedPredicate);
    return saveIntoTemporaryTable(idTableInsert, jdbcParameterBindings, executionContext);
}
Also used : TableReference(org.hibernate.sql.ast.tree.from.TableReference) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) QueryLiteral(org.hibernate.sql.ast.tree.expression.QueryLiteral) StandardTableGroup(org.hibernate.sql.ast.tree.from.StandardTableGroup) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) NamedTableReference(org.hibernate.sql.ast.tree.from.NamedTableReference) SessionFactoryImplementor(org.hibernate.engine.spi.SessionFactoryImplementor) SqlSelectionImpl(org.hibernate.sql.results.internal.SqlSelectionImpl) TemporaryTableColumn(org.hibernate.dialect.temptable.TemporaryTableColumn) QuerySpec(org.hibernate.sql.ast.tree.select.QuerySpec) EntityMappingType(org.hibernate.metamodel.mapping.EntityMappingType) InsertStatement(org.hibernate.sql.ast.tree.insert.InsertStatement) ColumnReference(org.hibernate.sql.ast.tree.expression.ColumnReference)

Example 50 with TableGroup

use of org.hibernate.sql.ast.tree.from.TableGroup in project hibernate-orm by hibernate.

the class SqmMappingModelHelper method resolveSqmPath.

private static ModelPart resolveSqmPath(SqmPath<?> sqmPath, MappingMetamodel domainModel, Function<NavigablePath, TableGroup> tableGroupLocator) {
    if (sqmPath instanceof SqmTreatedPath) {
        final SqmTreatedPath treatedPath = (SqmTreatedPath) sqmPath;
        final EntityDomainType treatTargetType = treatedPath.getTreatTarget();
        return domainModel.findEntityDescriptor(treatTargetType.getHibernateEntityName());
    }
    // see if the LHS is treated
    if (sqmPath.getLhs() instanceof SqmTreatedPath) {
        final SqmTreatedPath treatedPath = (SqmTreatedPath) sqmPath.getLhs();
        final EntityDomainType treatTargetType = treatedPath.getTreatTarget();
        final EntityPersister container = domainModel.findEntityDescriptor(treatTargetType.getHibernateEntityName());
        return container.findSubPart(sqmPath.getNavigablePath().getLocalName(), container);
    }
    // Plural path parts are not joined and thus also have no table group
    if (sqmPath instanceof AbstractSqmSpecificPluralPartPath<?>) {
        final TableGroup lhsTableGroup = tableGroupLocator.apply(sqmPath.getLhs().getLhs().getNavigablePath());
        final ModelPartContainer pluralPart = (ModelPartContainer) lhsTableGroup.getModelPart().findSubPart(sqmPath.getLhs().getReferencedPathSource().getPathName(), null);
        final CollectionPart collectionPart = (CollectionPart) pluralPart.findSubPart(sqmPath.getReferencedPathSource().getPathName(), null);
        // as that is the mapping type of the expression
        if (collectionPart instanceof EntityCollectionPart) {
            return ((EntityCollectionPart) collectionPart).getEntityMappingType();
        }
        return collectionPart;
    }
    if (sqmPath.getLhs() == null) {
        final EntityDomainType<?> entityDomainType = (EntityDomainType<?>) sqmPath.getReferencedPathSource();
        return domainModel.findEntityDescriptor(entityDomainType.getHibernateEntityName());
    }
    final TableGroup lhsTableGroup = tableGroupLocator.apply(sqmPath.getLhs().getNavigablePath());
    final ModelPartContainer modelPart;
    if (lhsTableGroup == null) {
        modelPart = (ModelPartContainer) resolveSqmPath(sqmPath.getLhs(), domainModel, tableGroupLocator);
    } else {
        modelPart = lhsTableGroup.getModelPart();
    }
    return modelPart.findSubPart(sqmPath.getReferencedPathSource().getPathName(), null);
}
Also used : EntityPersister(org.hibernate.persister.entity.EntityPersister) EntityCollectionPart(org.hibernate.metamodel.mapping.internal.EntityCollectionPart) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) AbstractSqmSpecificPluralPartPath(org.hibernate.query.sqm.tree.domain.AbstractSqmSpecificPluralPartPath) SqmTreatedPath(org.hibernate.query.sqm.tree.domain.SqmTreatedPath) EntityDomainType(org.hibernate.metamodel.model.domain.EntityDomainType) EntityCollectionPart(org.hibernate.metamodel.mapping.internal.EntityCollectionPart) CollectionPart(org.hibernate.metamodel.mapping.CollectionPart) ModelPartContainer(org.hibernate.metamodel.mapping.ModelPartContainer)

Aggregations

TableGroup (org.hibernate.sql.ast.tree.from.TableGroup)144 NavigablePath (org.hibernate.query.spi.NavigablePath)56 LazyTableGroup (org.hibernate.sql.ast.tree.from.LazyTableGroup)56 PluralTableGroup (org.hibernate.sql.ast.tree.from.PluralTableGroup)46 TableGroupJoin (org.hibernate.sql.ast.tree.from.TableGroupJoin)41 TableReference (org.hibernate.sql.ast.tree.from.TableReference)40 PluralAttributeMapping (org.hibernate.metamodel.mapping.PluralAttributeMapping)37 ColumnReference (org.hibernate.sql.ast.tree.expression.ColumnReference)35 CorrelatedTableGroup (org.hibernate.sql.ast.tree.from.CorrelatedTableGroup)33 QueryPartTableGroup (org.hibernate.sql.ast.tree.from.QueryPartTableGroup)31 VirtualTableGroup (org.hibernate.sql.ast.tree.from.VirtualTableGroup)31 EntityMappingType (org.hibernate.metamodel.mapping.EntityMappingType)30 SqlExpressionResolver (org.hibernate.sql.ast.spi.SqlExpressionResolver)29 SqlSelection (org.hibernate.sql.ast.spi.SqlSelection)29 QuerySpec (org.hibernate.sql.ast.tree.select.QuerySpec)29 Fetch (org.hibernate.sql.results.graph.Fetch)29 Expression (org.hibernate.sql.ast.tree.expression.Expression)28 CorrelatedPluralTableGroup (org.hibernate.sql.ast.tree.from.CorrelatedPluralTableGroup)28 SessionFactoryImplementor (org.hibernate.engine.spi.SessionFactoryImplementor)27 SelectStatement (org.hibernate.sql.ast.tree.select.SelectStatement)27