use of org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement in project hibernate-orm by hibernate.
the class SemanticQueryBuilder method visitInsertStatement.
@Override
public SqmInsertStatement<R> visitInsertStatement(HqlParser.InsertStatementContext ctx) {
final int dmlTargetIndex;
if (ctx.getChild(1) instanceof HqlParser.TargetEntityContext) {
dmlTargetIndex = 1;
} else {
dmlTargetIndex = 2;
}
final HqlParser.TargetEntityContext dmlTargetContext = (HqlParser.TargetEntityContext) ctx.getChild(dmlTargetIndex);
final HqlParser.TargetFieldsContext targetFieldsSpecContext = (HqlParser.TargetFieldsContext) ctx.getChild(dmlTargetIndex + 1);
final SqmRoot<R> root = visitTargetEntity(dmlTargetContext);
if (root.getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor<?>) {
throw new SemanticException(String.format("Target type '%s' in insert statement is not an entity", root.getReferencedPathSource().getHibernateEntityName()));
}
final HqlParser.QueryExpressionContext queryExpressionContext = ctx.queryExpression();
if (queryExpressionContext != null) {
final SqmInsertSelectStatement<R> insertStatement = new SqmInsertSelectStatement<>(root, creationContext.getNodeBuilder());
parameterCollector = insertStatement;
final SqmDmlCreationProcessingState processingState = new SqmDmlCreationProcessingState(insertStatement, this);
processingStateStack.push(processingState);
try {
queryExpressionContext.accept(this);
final SqmCreationProcessingState stateFieldsProcessingState = new SqmCreationProcessingStateImpl(insertStatement, this);
stateFieldsProcessingState.getPathRegistry().register(root);
processingStateStack.push(stateFieldsProcessingState);
try {
for (HqlParser.SimplePathContext stateFieldCtx : targetFieldsSpecContext.simplePath()) {
final SqmPath<?> stateField = (SqmPath<?>) visitSimplePath(stateFieldCtx);
// todo : validate each resolved stateField...
insertStatement.addInsertTargetStateField(stateField);
}
} finally {
processingStateStack.pop();
}
return insertStatement;
} finally {
processingStateStack.pop();
}
} else {
final SqmInsertValuesStatement<R> insertStatement = new SqmInsertValuesStatement<>(root, creationContext.getNodeBuilder());
parameterCollector = insertStatement;
final SqmDmlCreationProcessingState processingState = new SqmDmlCreationProcessingState(insertStatement, this);
processingStateStack.push(processingState);
processingState.getPathRegistry().register(root);
try {
final HqlParser.ValuesListContext valuesListContext = ctx.valuesList();
for (int i = 1; i < valuesListContext.getChildCount(); i += 2) {
final ParseTree values = valuesListContext.getChild(i);
final SqmValues sqmValues = new SqmValues();
for (int j = 1; j < values.getChildCount(); j += 2) {
sqmValues.getExpressions().add((SqmExpression<?>) values.getChild(j).accept(this));
}
insertStatement.getValuesList().add(sqmValues);
}
for (HqlParser.SimplePathContext stateFieldCtx : targetFieldsSpecContext.simplePath()) {
final SqmPath<?> stateField = (SqmPath<?>) visitSimplePath(stateFieldCtx);
// todo : validate each resolved stateField...
insertStatement.addInsertTargetStateField(stateField);
}
return insertStatement;
} finally {
processingStateStack.pop();
}
}
}
use of org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement 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();
}
use of org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement in project hibernate-orm by hibernate.
the class TableBasedInsertHandler method resolveDelegate.
private ExecutionDelegate resolveDelegate(DomainQueryExecutionContext executionContext) {
final EntityPersister entityDescriptor = sessionFactory.getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(getSqmInsertStatement().getTarget().getEntityName());
final MultiTableSqmMutationConverter converterDelegate = new MultiTableSqmMutationConverter(entityDescriptor, getSqmInsertStatement(), getSqmInsertStatement().getTarget(), domainParameterXref, executionContext.getQueryOptions(), executionContext.getSession().getLoadQueryInfluencers(), executionContext.getQueryParameterBindings(), sessionFactory);
final TableGroup insertingTableGroup = converterDelegate.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 List<Assignment> targetPathColumns = new ArrayList<>();
final Map<SqmParameter<?>, MappingModelExpressible<?>> paramTypeResolutions = new LinkedHashMap<>();
final NamedTableReference entityTableReference = new NamedTableReference(entityTable.getTableExpression(), TemporaryTable.DEFAULT_ALIAS, true, sessionFactory);
final InsertStatement insertStatement = new InsertStatement(entityTableReference);
final BaseSqmToSqlAstConverter.AdditionalInsertValues additionalInsertValues = converterDelegate.visitInsertionTargetPaths((assigable, columnReferences) -> {
insertStatement.addTargetColumnReferences(columnReferences);
targetPathColumns.add(new Assignment(assigable, (Expression) assigable));
}, sqmInsertStatement, entityDescriptor, insertingTableGroup, (sqmParameter, mappingType, jdbcParameters) -> {
parameterResolutions.computeIfAbsent(sqmParameter, k -> new ArrayList<>(1)).add(jdbcParameters);
paramTypeResolutions.put(sqmParameter, mappingType);
});
if (sqmInsertStatement instanceof SqmInsertSelectStatement) {
final QueryPart queryPart = converterDelegate.visitQueryPart(((SqmInsertSelectStatement<?>) sqmInsertStatement).getSelectQueryPart());
queryPart.visitQuerySpecs(querySpec -> {
if (additionalInsertValues.applySelections(querySpec, sessionFactory)) {
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(entityTable.getColumns().size() - 1);
final ColumnReference columnReference = new ColumnReference((String) null, rowNumberColumn.getColumnName(), false, null, null, rowNumberColumn.getJdbcMapping(), sessionFactory);
insertStatement.getTargetColumnReferences().set(insertStatement.getTargetColumnReferences().size() - 1, columnReference);
targetPathColumns.set(targetPathColumns.size() - 1, new Assignment(columnReference, columnReference));
} else if (entityDescriptor.getIdentifierGenerator() instanceof OptimizableGenerator) {
final Optimizer optimizer = ((OptimizableGenerator) entityDescriptor.getIdentifierGenerator()).getOptimizer();
if (optimizer != null && optimizer.getIncrementSize() > 1) {
if (!sessionFactory.getJdbcServices().getDialect().supportsWindowFunctions()) {
return;
}
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(entityTable.getColumns().size() - 1);
final ColumnReference columnReference = new ColumnReference((String) null, rowNumberColumn.getColumnName(), false, null, null, rowNumberColumn.getJdbcMapping(), sessionFactory);
insertStatement.getTargetColumnReferences().add(columnReference);
targetPathColumns.add(new Assignment(columnReference, columnReference));
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())));
}
}
});
insertStatement.setSourceSelectStatement(queryPart);
} else {
// Add the row number column if there is one
final IdentifierGenerator generator = entityDescriptor.getIdentifierGenerator();
final BasicType<?> rowNumberType;
if (generator instanceof OptimizableGenerator) {
final Optimizer optimizer = ((OptimizableGenerator) generator).getOptimizer();
if (optimizer != null && optimizer.getIncrementSize() > 1) {
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(entityTable.getColumns().size() - 1);
rowNumberType = (BasicType<?>) rowNumberColumn.getJdbcMapping();
final ColumnReference columnReference = new ColumnReference((String) null, rowNumberColumn.getColumnName(), false, null, null, rowNumberColumn.getJdbcMapping(), sessionFactory);
insertStatement.getTargetColumnReferences().add(columnReference);
targetPathColumns.add(new Assignment(columnReference, columnReference));
} else {
rowNumberType = null;
}
} else {
rowNumberType = null;
}
final List<SqmValues> sqmValuesList = ((SqmInsertValuesStatement<?>) sqmInsertStatement).getValuesList();
final List<Values> valuesList = new ArrayList<>(sqmValuesList.size());
for (int i = 0; i < sqmValuesList.size(); i++) {
final Values values = converterDelegate.visitValues(sqmValuesList.get(i));
additionalInsertValues.applyValues(values);
if (rowNumberType != null) {
values.getExpressions().add(new QueryLiteral<>(i + 1, rowNumberType));
}
valuesList.add(values);
}
insertStatement.setValuesList(valuesList);
}
converterDelegate.pruneTableGroupJoins();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 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(insertingTableGroup.getTableReferenceJoins().size() + 1);
collectTableReference(insertingTableGroup.getPrimaryTableReference(), tableReferenceByAlias::put);
for (int i = 0; i < insertingTableGroup.getTableReferenceJoins().size(); i++) {
collectTableReference(insertingTableGroup.getTableReferenceJoins().get(i), tableReferenceByAlias::put);
}
return new InsertExecutionDelegate(sqmInsertStatement, converterDelegate, entityTable, afterUseAction, sessionUidAccess, domainParameterXref, insertingTableGroup, tableReferenceByAlias, targetPathColumns, insertStatement, parameterResolutions, paramTypeResolutions, executionContext);
}
use of org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitInsertSelectStatement.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Insert-select statement
@Override
public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement<?> sqmStatement) {
final CteContainer cteContainer = this.visitCteContainer(sqmStatement);
final String entityName = sqmStatement.getTarget().getEntityName();
final EntityPersister entityDescriptor = creationContext.getSessionFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(entityName);
assert entityDescriptor != null;
SqmQueryPart<?> selectQueryPart = sqmStatement.getSelectQueryPart();
pushProcessingState(new SqlAstProcessingStateImpl(null, this, r -> new SqmAliasedNodePositionTracker(r, selectQueryPart.getFirstQuerySpec().getSelectClause().getSelections()), getCurrentClauseStack()::getCurrent));
currentClauseStack.push(Clause.INSERT);
final InsertStatement insertStatement;
final AdditionalInsertValues additionalInsertValues;
try {
final NavigablePath rootPath = sqmStatement.getTarget().getNavigablePath();
final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup(true, rootPath, sqmStatement.getTarget().getExplicitAlias(), () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, predicate), this, getCreationContext());
getFromClauseAccess().registerTableGroup(rootPath, rootTableGroup);
insertStatement = new InsertStatement(cteContainer, (NamedTableReference) rootTableGroup.getPrimaryTableReference(), Collections.emptyList());
additionalInsertValues = visitInsertionTargetPaths((assigable, references) -> insertStatement.addTargetColumnReferences(references), sqmStatement, entityDescriptor, rootTableGroup);
if (!rootTableGroup.getTableReferenceJoins().isEmpty() || !rootTableGroup.getTableGroupJoins().isEmpty()) {
throw new SemanticException("Not expecting multiple table references for an SQM INSERT-SELECT");
}
} finally {
popProcessingStateStack();
currentClauseStack.pop();
}
insertStatement.setSourceSelectStatement(visitQueryPart(selectQueryPart));
insertStatement.getSourceSelectStatement().visitQuerySpecs(querySpec -> {
final boolean appliedRowNumber = additionalInsertValues.applySelections(querySpec, creationContext.getSessionFactory());
// If this requires the special row number handling, it should use the mutation strategy
assert !appliedRowNumber;
});
return insertStatement;
}
use of org.hibernate.query.sqm.tree.insert.SqmInsertSelectStatement in project hibernate-orm by hibernate.
the class QuerySqmImpl method verifyInsertTypesMatch.
private void verifyInsertTypesMatch(String hqlString, SqmInsertStatement<R> sqmStatement) {
final List<SqmPath<?>> insertionTargetPaths = sqmStatement.getInsertionTargetPaths();
if (sqmStatement instanceof SqmInsertValuesStatement<?>) {
final SqmInsertValuesStatement<R> statement = (SqmInsertValuesStatement<R>) sqmStatement;
for (SqmValues sqmValues : statement.getValuesList()) {
verifyInsertTypesMatch(hqlString, insertionTargetPaths, sqmValues.getExpressions());
}
} else {
final SqmInsertSelectStatement<R> statement = (SqmInsertSelectStatement<R>) sqmStatement;
final List<SqmSelection<?>> selections = statement.getSelectQueryPart().getFirstQuerySpec().getSelectClause().getSelections();
verifyInsertTypesMatch(hqlString, insertionTargetPaths, selections);
statement.getSelectQueryPart().validateQueryStructureAndFetchOwners();
}
}
Aggregations