use of org.hibernate.sql.ast.tree.update.UpdateStatement in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method translate.
@Override
public T translate(JdbcParameterBindings jdbcParameterBindings, QueryOptions queryOptions) {
try {
this.jdbcParameterBindings = jdbcParameterBindings;
this.lockOptions = queryOptions.getLockOptions().makeCopy();
this.limit = queryOptions.getLimit() == null ? null : queryOptions.getLimit().makeCopy();
final JdbcOperation jdbcOperation;
if (statement instanceof DeleteStatement) {
jdbcOperation = translateDelete((DeleteStatement) statement);
} else if (statement instanceof UpdateStatement) {
jdbcOperation = translateUpdate((UpdateStatement) statement);
} else if (statement instanceof InsertStatement) {
jdbcOperation = translateInsert((InsertStatement) statement);
} else if (statement instanceof SelectStatement) {
jdbcOperation = translateSelect((SelectStatement) statement);
} else {
throw new IllegalArgumentException("Unexpected statement!");
}
if (jdbcParameterBindings != null && CollectionHelper.isNotEmpty(getFilterJdbcParameters())) {
for (FilterJdbcParameter filterJdbcParameter : getFilterJdbcParameters()) {
jdbcParameterBindings.addBinding(filterJdbcParameter.getParameter(), filterJdbcParameter.getBinding());
}
}
return (T) jdbcOperation;
} finally {
cleanup();
}
}
use of org.hibernate.sql.ast.tree.update.UpdateStatement in project hibernate-orm by hibernate.
the class SimpleUpdateQueryPlan method createUpdateTranslator.
private SqlAstTranslator<JdbcUpdate> createUpdateTranslator(DomainQueryExecutionContext executionContext) {
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
final QueryEngine queryEngine = factory.getQueryEngine();
final SqmTranslatorFactory translatorFactory = queryEngine.getSqmTranslatorFactory();
final SqmTranslator<UpdateStatement> translator = translatorFactory.createSimpleUpdateTranslator(sqmUpdate, executionContext.getQueryOptions(), domainParameterXref, executionContext.getQueryParameterBindings(), executionContext.getSession().getLoadQueryInfluencers(), factory);
final SqmTranslation<UpdateStatement> sqmInterpretation = translator.translate();
tableGroupAccess = sqmInterpretation.getFromClauseAccess();
this.jdbcParamsXref = SqmUtil.generateJdbcParamsXref(domainParameterXref, sqmInterpretation::getJdbcParamsBySqmParam);
this.sqmParamMappingTypeResolutions = sqmInterpretation.getSqmParameterMappingModelTypeResolutions();
return factory.getJdbcServices().getJdbcEnvironment().getSqlAstTranslatorFactory().buildUpdateTranslator(factory, sqmInterpretation.getSqlAst());
}
use of org.hibernate.sql.ast.tree.update.UpdateStatement in project hibernate-orm by hibernate.
the class InsertExecutionDelegate method insertRootTable.
private void insertRootTable(String tableExpression, int rows, String[] keyColumns, ExecutionContext executionContext) {
final TableReference updatingTableReference = updatingTableGroup.getTableReference(updatingTableGroup.getNavigablePath(), tableExpression, true, true);
final IdentifierGenerator identifierGenerator = entityDescriptor.getEntityPersister().getIdentifierGenerator();
final List<Assignment> assignments = assignmentsByTable.get(updatingTableReference);
if ((assignments == null || assignments.isEmpty()) && !(identifierGenerator instanceof PostInsertIdentifierGenerator)) {
throw new IllegalStateException("There must be at least a single root table assignment");
}
final NamedTableReference dmlTableReference = resolveUnionTableReference(updatingTableReference, tableExpression);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create the SQL AST and convert it into a JdbcOperation
final QuerySpec querySpec = new QuerySpec(true);
final NamedTableReference temporaryTableReference = new NamedTableReference(insertStatement.getTargetTable().getTableExpression(), updatingTableReference.getIdentificationVariable(), false, sessionFactory);
final TableGroupImpl temporaryTableGroup = new TableGroupImpl(updatingTableGroup.getNavigablePath(), null, temporaryTableReference, entityDescriptor);
querySpec.getFromClause().addRoot(temporaryTableGroup);
final InsertStatement insertStatement = new InsertStatement(dmlTableReference);
insertStatement.setSourceSelectStatement(querySpec);
for (Assignment assignment : assignments) {
insertStatement.addTargetColumnReferences(assignment.getAssignable().getColumnReferences());
for (ColumnReference columnReference : assignment.getAssignable().getColumnReferences()) {
querySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new ColumnReference(updatingTableReference.getIdentificationVariable(), columnReference.getColumnExpression(), false, null, null, columnReference.getJdbcMapping(), sessionFactory)));
}
}
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
final Map<Object, Object> entityTableToRootIdentity;
if (identifierGenerator instanceof PostInsertIdentifierGenerator) {
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
final QuerySpec idSelectQuerySpec = new QuerySpec(true);
idSelectQuerySpec.getFromClause().addRoot(temporaryTableGroup);
final ColumnReference columnReference = new ColumnReference((String) null, TemporaryTable.ENTITY_TABLE_IDENTITY_COLUMN, false, null, null, identifierMapping.getJdbcMapping(), sessionFactory);
idSelectQuerySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, columnReference));
idSelectQuerySpec.addSortSpecification(new SortSpecification(columnReference, SortOrder.ASCENDING));
final SelectStatement selectStatement = new SelectStatement(idSelectQuerySpec, Collections.singletonList(new BasicFetch<>(0, null, null, identifierMapping, null, FetchTiming.IMMEDIATE, null)));
final JdbcSelect jdbcSelect = jdbcServices.getJdbcEnvironment().getSqlAstTranslatorFactory().buildSelectTranslator(sessionFactory, selectStatement).translate(null, executionContext.getQueryOptions());
final List<Object> list = jdbcServices.getJdbcSelectExecutor().list(jdbcSelect, JdbcParameterBindings.NO_BINDINGS, executionContext, null, ListResultsConsumer.UniqueSemantic.NONE);
entityTableToRootIdentity = new LinkedHashMap<>(list.size());
for (Object o : list) {
entityTableToRootIdentity.put(o, null);
}
querySpec.applyPredicate(new ComparisonPredicate(columnReference, ComparisonOperator.EQUAL, new JdbcParameterImpl(identifierMapping.getJdbcMapping())));
} else {
entityTableToRootIdentity = null;
if (identifierGenerator instanceof OptimizableGenerator) {
final Optimizer optimizer = ((OptimizableGenerator) identifierGenerator).getOptimizer();
// but only if the target paths don't already contain the id
if (optimizer != null && optimizer.getIncrementSize() > 1 && insertStatement.getTargetColumnReferences().stream().noneMatch(c -> keyColumns[0].equals(c.getColumnExpression()))) {
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
final JdbcParameter rowNumber = new JdbcParameterImpl(identifierMapping.getJdbcMapping());
final JdbcParameter rootIdentity = new JdbcParameterImpl(identifierMapping.getJdbcMapping());
final List<Assignment> temporaryTableAssignments = new ArrayList<>(1);
final ColumnReference idColumnReference = new ColumnReference((String) null, identifierMapping, sessionFactory);
temporaryTableAssignments.add(new Assignment(idColumnReference, rootIdentity));
final TemporaryTableColumn rowNumberColumn = entityTable.getColumns().get(entityTable.getColumns().size() - 1);
final UpdateStatement updateStatement = new UpdateStatement(temporaryTableReference, temporaryTableAssignments, new ComparisonPredicate(new ColumnReference((String) null, rowNumberColumn.getColumnName(), false, null, null, rowNumberColumn.getJdbcMapping(), sessionFactory), ComparisonOperator.EQUAL, rowNumber));
final JdbcUpdate jdbcUpdate = jdbcServices.getJdbcEnvironment().getSqlAstTranslatorFactory().buildUpdateTranslator(sessionFactory, updateStatement).translate(null, executionContext.getQueryOptions());
final JdbcParameterBindings updateBindings = new JdbcParameterBindingsImpl(2);
for (int i = 0; i < rows; i++) {
updateBindings.addBinding(rowNumber, new JdbcParameterBindingImpl(rowNumberColumn.getJdbcMapping(), i + 1));
updateBindings.addBinding(rootIdentity, new JdbcParameterBindingImpl(identifierMapping.getJdbcMapping(), identifierGenerator.generate(executionContext.getSession(), null)));
jdbcServices.getJdbcMutationExecutor().execute(jdbcUpdate, updateBindings, sql -> executionContext.getSession().getJdbcCoordinator().getStatementPreparer().prepareStatement(sql), (integer, preparedStatement) -> {
}, executionContext);
}
insertStatement.addTargetColumnReferences(new ColumnReference((String) null, keyColumns[0], false, null, null, identifierMapping.getJdbcMapping(), sessionFactory));
querySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, new ColumnReference(updatingTableReference.getIdentificationVariable(), idColumnReference.getColumnExpression(), false, null, null, idColumnReference.getJdbcMapping(), sessionFactory)));
}
}
}
final JdbcInsert jdbcInsert = jdbcServices.getJdbcEnvironment().getSqlAstTranslatorFactory().buildInsertTranslator(sessionFactory, insertStatement).translate(null, executionContext.getQueryOptions());
if (identifierGenerator instanceof PostInsertIdentifierGenerator) {
final PostInsertIdentifierGenerator generator = (PostInsertIdentifierGenerator) identifierGenerator;
final boolean generatedKeysEnabled = sessionFactory.getSessionFactoryOptions().isGetGeneratedKeysEnabled();
final InsertGeneratedIdentifierDelegate identifierDelegate = generator.getInsertGeneratedIdentifierDelegate((PostInsertIdentityPersister) entityDescriptor.getEntityPersister(), jdbcServices.getDialect(), generatedKeysEnabled);
final String finalSql = identifierDelegate.prepareIdentifierGeneratingInsert(jdbcInsert.getSql());
final BasicEntityIdentifierMapping identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
final ValueBinder jdbcValueBinder = identifierMapping.getJdbcMapping().getJdbcValueBinder();
for (Map.Entry<Object, Object> entry : entityTableToRootIdentity.entrySet()) {
final Object rootIdentity = identifierDelegate.performInsert(finalSql, executionContext.getSession(), new Binder() {
@Override
public void bindValues(PreparedStatement ps) throws SQLException {
jdbcValueBinder.bind(ps, entry.getKey(), 1, executionContext.getSession());
}
@Override
public Object getEntity() {
return null;
}
});
entry.setValue(rootIdentity);
}
final JdbcParameter entityIdentity = new JdbcParameterImpl(identifierMapping.getJdbcMapping());
final JdbcParameter rootIdentity = new JdbcParameterImpl(identifierMapping.getJdbcMapping());
final List<Assignment> temporaryTableAssignments = new ArrayList<>(1);
temporaryTableAssignments.add(new Assignment(new ColumnReference((String) null, identifierMapping, sessionFactory), rootIdentity));
final UpdateStatement updateStatement = new UpdateStatement(temporaryTableReference, temporaryTableAssignments, new ComparisonPredicate(new ColumnReference((String) null, TemporaryTable.ENTITY_TABLE_IDENTITY_COLUMN, false, null, null, identifierMapping.getJdbcMapping(), sessionFactory), ComparisonOperator.EQUAL, entityIdentity));
final JdbcUpdate jdbcUpdate = jdbcServices.getJdbcEnvironment().getSqlAstTranslatorFactory().buildUpdateTranslator(sessionFactory, updateStatement).translate(null, executionContext.getQueryOptions());
final JdbcParameterBindings updateBindings = new JdbcParameterBindingsImpl(2);
for (Map.Entry<Object, Object> entry : entityTableToRootIdentity.entrySet()) {
updateBindings.addBinding(entityIdentity, new JdbcParameterBindingImpl(identifierMapping.getJdbcMapping(), entry.getKey()));
updateBindings.addBinding(rootIdentity, new JdbcParameterBindingImpl(identifierMapping.getJdbcMapping(), entry.getValue()));
jdbcServices.getJdbcMutationExecutor().execute(jdbcUpdate, updateBindings, sql -> executionContext.getSession().getJdbcCoordinator().getStatementPreparer().prepareStatement(sql), (integer, preparedStatement) -> {
}, executionContext);
}
} else {
jdbcServices.getJdbcMutationExecutor().execute(jdbcInsert, JdbcParameterBindings.NO_BINDINGS, sql -> executionContext.getSession().getJdbcCoordinator().getStatementPreparer().prepareStatement(sql), (integer, preparedStatement) -> {
}, executionContext);
}
}
use of org.hibernate.sql.ast.tree.update.UpdateStatement 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.sql.ast.tree.update.UpdateStatement in project hibernate-orm by hibernate.
the class UpdateExecutionDelegate method updateTable.
private void updateTable(String tableExpression, Supplier<Consumer<SelectableConsumer>> tableKeyColumnVisitationSupplier, QuerySpec idTableSubQuery, ExecutionContext executionContext) {
final TableReference updatingTableReference = updatingTableGroup.getTableReference(updatingTableGroup.getNavigablePath(), tableExpression, true, true);
final List<Assignment> assignments = assignmentsByTable.get(updatingTableReference);
if (assignments == null || assignments.isEmpty()) {
// no assignments for this table - skip it
return;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// create the in-subquery predicate to restrict the updates to just
// matching ids
final TableKeyExpressionCollector keyColumnCollector = new TableKeyExpressionCollector(entityDescriptor);
tableKeyColumnVisitationSupplier.get().accept((columnIndex, selection) -> {
assert selection.getContainingTableExpression().equals(tableExpression);
keyColumnCollector.apply(new ColumnReference((String) null, selection, sessionFactory));
});
final InSubQueryPredicate idTableSubQueryPredicate = new InSubQueryPredicate(keyColumnCollector.buildKeyExpression(), idTableSubQuery, false);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Create the SQL AST and convert it into a JdbcOperation
final UpdateStatement sqlAst = new UpdateStatement(resolveUnionTableReference(updatingTableReference, tableExpression), assignments, idTableSubQueryPredicate);
final JdbcServices jdbcServices = sessionFactory.getJdbcServices();
final JdbcUpdate jdbcUpdate = jdbcServices.getJdbcEnvironment().getSqlAstTranslatorFactory().buildUpdateTranslator(sessionFactory, sqlAst).translate(jdbcParameterBindings, executionContext.getQueryOptions());
jdbcServices.getJdbcMutationExecutor().execute(jdbcUpdate, jdbcParameterBindings, sql -> executionContext.getSession().getJdbcCoordinator().getStatementPreparer().prepareStatement(sql), (integer, preparedStatement) -> {
}, executionContext);
}
Aggregations