use of org.hibernate.query.sqm.tree.update.SqmUpdateStatement in project hibernate-orm by hibernate.
the class SemanticQueryBuilder method visitUpdateStatement.
@Override
public SqmUpdateStatement<R> visitUpdateStatement(HqlParser.UpdateStatementContext ctx) {
final boolean versioned = !(ctx.getChild(1) instanceof HqlParser.TargetEntityContext);
final int dmlTargetIndex = versioned ? 2 : 1;
final HqlParser.TargetEntityContext dmlTargetContext = (HqlParser.TargetEntityContext) ctx.getChild(dmlTargetIndex);
final SqmRoot<R> root = visitTargetEntity(dmlTargetContext);
if (root.getReferencedPathSource() instanceof SqmPolymorphicRootDescriptor<?>) {
throw new SemanticException(String.format("Target type '%s' in update statement is not an entity", root.getReferencedPathSource().getHibernateEntityName()));
}
final SqmUpdateStatement<R> updateStatement = new SqmUpdateStatement<>(root, creationContext.getNodeBuilder());
parameterCollector = updateStatement;
final SqmDmlCreationProcessingState processingState = new SqmDmlCreationProcessingState(updateStatement, this);
processingStateStack.push(processingState);
processingState.getPathRegistry().register(root);
try {
updateStatement.versioned(versioned);
final HqlParser.SetClauseContext setClauseCtx = (HqlParser.SetClauseContext) ctx.getChild(dmlTargetIndex + 1);
for (ParseTree subCtx : setClauseCtx.children) {
if (subCtx instanceof HqlParser.AssignmentContext) {
final HqlParser.AssignmentContext assignmentContext = (HqlParser.AssignmentContext) subCtx;
updateStatement.applyAssignment(consumeDomainPath((HqlParser.SimplePathContext) assignmentContext.getChild(0)), (SqmExpression<?>) assignmentContext.getChild(2).accept(this));
}
}
if (dmlTargetIndex + 2 <= ctx.getChildCount()) {
updateStatement.applyPredicate(visitWhereClause((HqlParser.WhereClauseContext) ctx.getChild(dmlTargetIndex + 2)));
}
return updateStatement;
} finally {
processingStateStack.pop();
}
}
use of org.hibernate.query.sqm.tree.update.SqmUpdateStatement in project hibernate-orm by hibernate.
the class QuerySqmImpl method buildUpdateQueryPlan.
private NonSelectQueryPlan buildUpdateQueryPlan() {
// noinspection rawtypes
final SqmUpdateStatement sqmUpdate = (SqmUpdateStatement) getSqmStatement();
final String entityNameToUpdate = sqmUpdate.getTarget().getReferencedPathSource().getHibernateEntityName();
final EntityPersister entityDescriptor = getSessionFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(entityNameToUpdate);
final SqmMultiTableMutationStrategy multiTableStrategy = entityDescriptor.getSqmMultiTableMutationStrategy();
if (multiTableStrategy == null) {
return new SimpleUpdateQueryPlan(sqmUpdate, domainParameterXref);
} else {
return new MultiTableUpdateQueryPlan(sqmUpdate, domainParameterXref, multiTableStrategy);
}
}
use of org.hibernate.query.sqm.tree.update.SqmUpdateStatement in project hibernate-orm by hibernate.
the class CteUpdateHandler method addDmlCtes.
@Override
protected void addDmlCtes(CteContainer statement, CteStatement idSelectCte, MultiTableSqmMutationConverter sqmConverter, Map<SqmParameter, List<JdbcParameter>> parameterResolutions, SessionFactoryImplementor factory) {
final TableGroup updatingTableGroup = sqmConverter.getMutatingTableGroup();
final SqmUpdateStatement<?> updateStatement = (SqmUpdateStatement<?>) getSqmDeleteOrUpdateStatement();
final EntityMappingType entityDescriptor = getEntityDescriptor();
final EntityPersister entityPersister = entityDescriptor.getEntityPersister();
final String rootEntityName = entityPersister.getRootEntityName();
final EntityPersister rootEntityDescriptor = factory.getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(rootEntityName);
final String hierarchyRootTableName = ((Joinable) rootEntityDescriptor).getTableName();
final TableReference hierarchyRootTableReference = updatingTableGroup.resolveTableReference(updatingTableGroup.getNavigablePath(), hierarchyRootTableName);
assert hierarchyRootTableReference != null;
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// visit the set-clause using our special converter, collecting
// information about the assignments
final SqmSetClause setClause = updateStatement.getSetClause();
final List<Assignment> assignments = new ArrayList<>(setClause.getAssignments().size());
final Map<SqmParameter, MappingModelExpressible> paramTypeResolutions = new LinkedHashMap<>();
sqmConverter.visitSetClause(setClause, assignments::add, (sqmParam, mappingType, jdbcParameters) -> {
parameterResolutions.put(sqmParam, jdbcParameters);
paramTypeResolutions.put(sqmParam, mappingType);
});
sqmConverter.addVersionedAssignment(assignments::add, updateStatement);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// cross-reference the TableReference by alias. The TableGroup already
// cross-references it by name, but the ColumnReference only has the alias
final Map<String, TableReference> tableReferenceByAlias = CollectionHelper.mapOfSize(updatingTableGroup.getTableReferenceJoins().size() + 1);
collectTableReference(updatingTableGroup.getPrimaryTableReference(), tableReferenceByAlias::put);
for (int i = 0; i < updatingTableGroup.getTableReferenceJoins().size(); i++) {
collectTableReference(updatingTableGroup.getTableReferenceJoins().get(i), tableReferenceByAlias::put);
}
final Map<TableReference, List<Assignment>> assignmentsByTable = CollectionHelper.mapOfSize(updatingTableGroup.getTableReferenceJoins().size() + 1);
for (int i = 0; i < assignments.size(); i++) {
final Assignment assignment = assignments.get(i);
final List<ColumnReference> assignmentColumnRefs = assignment.getAssignable().getColumnReferences();
TableReference assignmentTableReference = null;
for (int c = 0; c < assignmentColumnRefs.size(); c++) {
final ColumnReference columnReference = assignmentColumnRefs.get(c);
final TableReference tableReference = resolveTableReference(columnReference, tableReferenceByAlias);
// TODO: this could be fixed by introducing joins to DML statements
if (assignmentTableReference != null && !assignmentTableReference.equals(tableReference)) {
throw new IllegalStateException("Assignment referred to columns from multiple tables");
}
assignmentTableReference = tableReference;
}
assert assignmentTableReference != null;
List<Assignment> assignmentsForTable = assignmentsByTable.get(assignmentTableReference);
if (assignmentsForTable == null) {
assignmentsForTable = new ArrayList<>();
assignmentsByTable.put(assignmentTableReference, assignmentsForTable);
}
assignmentsForTable.add(assignment);
}
getEntityDescriptor().visitConstraintOrderedTables((tableExpression, tableColumnsVisitationSupplier) -> {
final CteTable dmlResultCte = new CteTable(getCteTableName(tableExpression), idSelectCte.getCteTable().getCteColumns(), factory);
final TableReference updatingTableReference = updatingTableGroup.getTableReference(updatingTableGroup.getNavigablePath(), tableExpression, true, true);
final List<Assignment> assignmentList = assignmentsByTable.get(updatingTableReference);
if (assignmentList == null) {
return;
}
final NamedTableReference dmlTableReference = resolveUnionTableReference(updatingTableReference, tableExpression);
final List<ColumnReference> columnReferences = new ArrayList<>(idSelectCte.getCteTable().getCteColumns().size());
tableColumnsVisitationSupplier.get().accept((index, selectable) -> columnReferences.add(new ColumnReference(dmlTableReference, selectable, factory)));
final MutationStatement dmlStatement = new UpdateStatement(dmlTableReference, assignmentList, createIdSubQueryPredicate(columnReferences, idSelectCte, factory), columnReferences);
statement.addCteStatement(new CteStatement(dmlResultCte, dmlStatement));
});
}
use of org.hibernate.query.sqm.tree.update.SqmUpdateStatement in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitUpdateStatement.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Update statement
@Override
public UpdateStatement visitUpdateStatement(SqmUpdateStatement<?> sqmStatement) {
final CteContainer cteContainer = this.visitCteContainer(sqmStatement);
final SqmRoot<?> sqmTarget = sqmStatement.getTarget();
final String entityName = sqmTarget.getEntityName();
final EntityPersister entityDescriptor = getCreationContext().getSessionFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(entityName);
assert entityDescriptor != null;
pushProcessingState(new SqlAstProcessingStateImpl(getCurrentProcessingState(), this, getCurrentClauseStack()::getCurrent));
try {
final NavigablePath rootPath = sqmTarget.getNavigablePath();
final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup(true, rootPath, sqmStatement.getRoot().getAlias(), () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, predicate), this, getCreationContext());
if (!rootTableGroup.getTableReferenceJoins().isEmpty()) {
throw new HibernateException("Not expecting multiple table references for an SQM UPDATE");
}
if (sqmTarget.hasJoins()) {
throw new HibernateException("SQM UPDATE does not support explicit joins");
}
getFromClauseAccess().registerTableGroup(rootPath, rootTableGroup);
final List<Assignment> assignments = visitSetClause(sqmStatement.getSetClause());
addVersionedAssignment(assignments::add, sqmStatement);
FilterHelper.applyBaseRestrictions((filterPredicate) -> additionalRestrictions = filterPredicate, entityDescriptor, rootTableGroup, AbstractSqlAstTranslator.rendersTableReferenceAlias(Clause.UPDATE), getLoadQueryInfluencers(), this);
Predicate suppliedPredicate = null;
final SqmWhereClause whereClause = sqmStatement.getWhereClause();
if (whereClause != null) {
suppliedPredicate = visitWhereClause(whereClause.getPredicate());
}
return new UpdateStatement(cteContainer, (NamedTableReference) rootTableGroup.getPrimaryTableReference(), assignments, SqlAstTreeHelper.combinePredicates(suppliedPredicate, additionalRestrictions), Collections.emptyList());
} finally {
popProcessingStateStack();
}
}
Aggregations