use of org.hibernate.sql.ast.tree.predicate.Predicate in project hibernate-orm by hibernate.
the class AbstractSqlAstTranslator method visitHavingClause.
protected final void visitHavingClause(QuerySpec querySpec) {
final Predicate havingClauseRestrictions = querySpec.getHavingClauseRestrictions();
if (havingClauseRestrictions != null && !havingClauseRestrictions.isEmpty()) {
appendSql(" having ");
clauseStack.push(Clause.HAVING);
try {
havingClauseRestrictions.accept(this);
} finally {
clauseStack.pop();
}
}
}
use of org.hibernate.sql.ast.tree.predicate.Predicate in project hibernate-orm by hibernate.
the class AbstractCteMutationHandler method execute.
@Override
public int execute(DomainQueryExecutionContext executionContext) {
final SqmDeleteOrUpdateStatement sqmMutationStatement = getSqmDeleteOrUpdateStatement();
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
final EntityMappingType entityDescriptor = getEntityDescriptor();
final String explicitDmlTargetAlias;
// We need an alias because we try to acquire a WRITE lock for these rows in the CTE
if (sqmMutationStatement.getTarget().getExplicitAlias() == null) {
explicitDmlTargetAlias = "dml_target";
} else {
explicitDmlTargetAlias = sqmMutationStatement.getTarget().getExplicitAlias();
}
final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter(entityDescriptor, sqmMutationStatement, sqmMutationStatement.getTarget(), explicitDmlTargetAlias, domainParameterXref, executionContext.getQueryOptions(), executionContext.getSession().getLoadQueryInfluencers(), executionContext.getQueryParameterBindings(), factory);
final Map<SqmParameter, List<JdbcParameter>> parameterResolutions;
if (domainParameterXref.getSqmParameterCount() == 0) {
parameterResolutions = Collections.emptyMap();
} else {
parameterResolutions = new IdentityHashMap<>();
}
final Map<SqmParameter, MappingModelExpressible> paramTypeResolutions = new LinkedHashMap<>();
final Predicate restriction = sqmConverter.visitWhereClause(sqmMutationStatement.getWhereClause(), columnReference -> {
}, (sqmParam, mappingType, jdbcParameters) -> paramTypeResolutions.put(sqmParam, mappingType));
sqmConverter.pruneTableGroupJoins();
final CteStatement idSelectCte = new CteStatement(BaseSqmToSqlAstConverter.createCteTable(getCteTable(), factory), MatchingIdSelectionHelper.generateMatchingIdSelectStatement(entityDescriptor, sqmMutationStatement, false, restriction, sqmConverter, executionContext, factory), // The id-select cte will be reused multiple times
CteMaterialization.MATERIALIZED);
// Create the main query spec that will return the count of
final QuerySpec querySpec = new QuerySpec(true, 1);
final List<DomainResult<?>> domainResults = new ArrayList<>(1);
final SelectStatement statement = new SelectStatement(querySpec, domainResults);
final JdbcServices jdbcServices = factory.getJdbcServices();
final SqlAstTranslator<JdbcSelect> translator = jdbcServices.getJdbcEnvironment().getSqlAstTranslatorFactory().buildSelectTranslator(factory, statement);
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(idSelectCte.getCteTable().getTableExpression(), CTE_TABLE_IDENTIFIER, false, factory)));
// Add all CTEs
statement.addCteStatement(idSelectCte);
addDmlCtes(statement, idSelectCte, sqmConverter, parameterResolutions, factory);
final JdbcParameterBindings jdbcParameterBindings = SqmUtil.createJdbcParameterBindings(executionContext.getQueryParameterBindings(), domainParameterXref, SqmUtil.generateJdbcParamsXref(domainParameterXref, sqmConverter), factory.getRuntimeMetamodels().getMappingMetamodel(), navigablePath -> sqmConverter.getMutatingTableGroup(), paramTypeResolutions::get, executionContext.getSession());
final LockOptions lockOptions = executionContext.getQueryOptions().getLockOptions();
final LockMode lockMode = lockOptions.getAliasSpecificLockMode(explicitDmlTargetAlias);
// Acquire a WRITE lock for the rows that are about to be modified
lockOptions.setAliasSpecificLockMode(explicitDmlTargetAlias, LockMode.WRITE);
final JdbcSelect select = translator.translate(jdbcParameterBindings, executionContext.getQueryOptions());
lockOptions.setAliasSpecificLockMode(explicitDmlTargetAlias, lockMode);
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.sql.ast.tree.predicate.Predicate in project hibernate-orm by hibernate.
the class InlineDeleteHandler method executeDelete.
private void executeDelete(String targetTableExpression, EntityMappingType entityDescriptor, Supplier<Consumer<SelectableConsumer>> tableKeyColumnsVisitationSupplier, List<Object> ids, int valueIndex, ModelPart valueModelPart, JdbcParameterBindings jdbcParameterBindings, DomainQueryExecutionContext executionContext) {
final NamedTableReference targetTableReference = new NamedTableReference(targetTableExpression, DeleteStatement.DEFAULT_ALIAS, false, sessionFactory);
final SqmJdbcExecutionContextAdapter executionContextAdapter = SqmJdbcExecutionContextAdapter.omittingLockingAndPaging(executionContext);
final Predicate matchingIdsPredicate = matchingIdsPredicateProducer.produceRestriction(ids, entityDescriptor, valueIndex, valueModelPart, targetTableReference, tableKeyColumnsVisitationSupplier, executionContextAdapter);
final DeleteStatement deleteStatement = new DeleteStatement(targetTableReference, matchingIdsPredicate);
final JdbcDelete jdbcOperation = sqlAstTranslatorFactory.buildDeleteTranslator(sessionFactory, deleteStatement).translate(jdbcParameterBindings, executionContext.getQueryOptions());
jdbcMutationExecutor.execute(jdbcOperation, jdbcParameterBindings, this::prepareQueryStatement, (integer, preparedStatement) -> {
}, executionContextAdapter);
}
use of org.hibernate.sql.ast.tree.predicate.Predicate in project hibernate-orm by hibernate.
the class MatchingIdSelectionHelper method selectMatchingIds.
/**
* Centralized selection of ids matching the restriction of the DELETE
* or UPDATE SQM query
*/
public static List<Object> selectMatchingIds(SqmDeleteOrUpdateStatement sqmMutationStatement, DomainParameterXref domainParameterXref, DomainQueryExecutionContext executionContext) {
final SessionFactoryImplementor factory = executionContext.getSession().getFactory();
final EntityMappingType entityDescriptor = factory.getRuntimeMetamodels().getEntityMappingType(sqmMutationStatement.getTarget().getModel().getHibernateEntityName());
final MultiTableSqmMutationConverter sqmConverter = new MultiTableSqmMutationConverter(entityDescriptor, sqmMutationStatement, sqmMutationStatement.getTarget(), domainParameterXref, executionContext.getQueryOptions(), executionContext.getSession().getLoadQueryInfluencers(), executionContext.getQueryParameterBindings(), factory);
final Map<SqmParameter, List<JdbcParameter>> parameterResolutions;
if (domainParameterXref.getSqmParameterCount() == 0) {
parameterResolutions = Collections.emptyMap();
} else {
parameterResolutions = new IdentityHashMap<>();
}
final Predicate restriction = sqmConverter.visitWhereClause(sqmMutationStatement.getWhereClause(), columnReference -> {
}, (sqmParam, mappingType, jdbcParameters) -> parameterResolutions.put(sqmParam, jdbcParameters));
final SelectStatement matchingIdSelection = generateMatchingIdSelectStatement(entityDescriptor, sqmMutationStatement, true, restriction, sqmConverter, executionContext, factory);
sqmConverter.getProcessingStateStack().push(new SqlAstQueryPartProcessingStateImpl(matchingIdSelection.getQuerySpec(), sqmConverter.getCurrentProcessingState(), sqmConverter.getSqlAstCreationState(), sqmConverter.getCurrentClauseStack()::getCurrent, true));
entityDescriptor.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) -> {
matchingIdSelection.getDomainResultDescriptors().add(new BasicResult<>(selection.getValuesArrayPosition(), null, jdbcMapping.getJavaTypeDescriptor()));
});
}
}
}
});
sqmConverter.getProcessingStateStack().pop();
final JdbcServices jdbcServices = factory.getJdbcServices();
final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment();
final SqlAstTranslator<JdbcSelect> sqlAstSelectTranslator = jdbcEnvironment.getSqlAstTranslatorFactory().buildSelectTranslator(factory, matchingIdSelection);
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>) sqmConverter.getSqmParameterMappingModelExpressibleResolutions().get(parameter);
}
}, executionContext.getSession());
final LockOptions lockOptions = executionContext.getQueryOptions().getLockOptions();
final LockMode lockMode = lockOptions.getLockMode();
// Acquire a WRITE lock for the rows that are about to be modified
lockOptions.setLockMode(LockMode.WRITE);
// Visit the table joins and reset the lock mode if we encounter OUTER joins that are not supported
if (!jdbcEnvironment.getDialect().supportsOuterJoinForUpdate()) {
matchingIdSelection.getQuerySpec().getFromClause().visitTableJoins(tableJoin -> {
if (tableJoin.getJoinType() != SqlAstJoinType.INNER) {
lockOptions.setLockMode(lockMode);
}
});
}
final JdbcSelect idSelectJdbcOperation = sqlAstSelectTranslator.translate(jdbcParameterBindings, executionContext.getQueryOptions());
lockOptions.setLockMode(lockMode);
return jdbcServices.getJdbcSelectExecutor().list(idSelectJdbcOperation, jdbcParameterBindings, SqmJdbcExecutionContextAdapter.omittingLockingAndPaging(executionContext), row -> row[0], ListResultsConsumer.UniqueSemantic.FILTER);
}
use of org.hibernate.sql.ast.tree.predicate.Predicate in project hibernate-orm by hibernate.
the class AggregateWindowEmulationQueryTransformer method transform.
@Override
public QuerySpec transform(CteContainer cteContainer, QuerySpec querySpec, SqmToSqlAstConverter converter) {
final SessionFactoryImplementor factory = converter.getCreationContext().getSessionFactory();
final QuerySpec outerQuerySpec = new QuerySpec(querySpec.isRoot());
final String identifierVariable = "hhh_";
final NavigablePath navigablePath = new NavigablePath(identifierVariable, identifierVariable);
final SelectClause selectClause = outerQuerySpec.getSelectClause();
final QuerySpec subQuerySpec = querySpec.asSubQuery();
final SelectClause subSelectClause = subQuerySpec.getSelectClause();
final List<SqlSelection> subSelections = subSelectClause.getSqlSelections();
final List<String> columnNames = new ArrayList<>(subSelections.size());
// A map to find the select item position for an expression
// which is needed to decide if we need to introduce synthetic select items
// for group by items, since these group by items are migrated to the outer query
final Map<Expression, Integer> selectionMapping = new HashMap<>(subSelections.size());
// for the QueryPartTableGroup within which the sub query spec is embedded
for (int i = 0; i < subSelections.size(); i++) {
final BasicValuedMapping mapping = (BasicValuedMapping) subSelections.get(i).getExpressionType();
final String columnName = "col" + i;
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, mapping.getJdbcMapping(), factory);
final Expression expression = subSelections.get(i).getExpression();
final Expression finalExpression;
if (expression == windowFunction) {
finalExpression = new SelfRenderingAggregateFunctionSqlAstExpression("min", (sqlAppender, sqlAstArguments, walker1) -> {
sqlAppender.appendSql("min(");
sqlAstArguments.get(0).accept(walker1);
sqlAppender.append(')');
}, Collections.singletonList(columnReference), null, (ReturnableType<?>) mapping.getMappedType(), expression.getExpressionType());
} else {
finalExpression = columnReference;
selectionMapping.put(expression, i);
}
columnNames.add(columnName);
selectClause.addSqlSelection(new ResolvedSqlSelection(i + 1, i, finalExpression, (BasicType<Object>) mapping.getJdbcMapping()));
}
// Migrate the group by clause to the outer query
// and push group by expressions into the partition by clause of the window function
final List<Expression> groupByExpressions = new ArrayList<>(subQuerySpec.getGroupByClauseExpressions().size());
for (Expression groupByClauseExpression : subQuerySpec.getGroupByClauseExpressions()) {
final Expression realExpression;
final Expression outerGroupByExpression;
if (groupByClauseExpression instanceof SqlSelectionExpression) {
final SqlSelection selection = ((SqlSelectionExpression) groupByClauseExpression).getSelection();
outerGroupByExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(selection.getValuesArrayPosition()));
realExpression = selection.getExpression();
} else {
if (groupByClauseExpression instanceof SqmPathInterpretation<?>) {
realExpression = ((SqmPathInterpretation<?>) groupByClauseExpression).getSqlExpression();
} else {
realExpression = groupByClauseExpression;
}
final Integer position = selectionMapping.get(realExpression);
if (position == null) {
// Group by something that has no corresponding selection item,
// so we need to introduce an intermediate selection item
final int valuesPosition = selectClause.getSqlSelections().size();
final String columnName = "col" + valuesPosition;
final JdbcMapping jdbcMapping = realExpression.getExpressionType().getJdbcMappings().get(0);
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, jdbcMapping, factory);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(subValuesPosition + 1, subValuesPosition, realExpression, (BasicType<Object>) jdbcMapping);
columnNames.add(columnName);
subSelectClause.addSqlSelection(subSelection);
outerGroupByExpression = columnReference;
selectionMapping.put(realExpression, subValuesPosition);
} else {
outerGroupByExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(position));
}
}
windowFunction.getPartitions().add(realExpression);
groupByExpressions.add(outerGroupByExpression);
}
outerQuerySpec.setGroupByClauseExpressions(groupByExpressions);
subQuerySpec.setGroupByClauseExpressions(null);
// Migrate the having clause to the outer query
if (subQuerySpec.getHavingClauseRestrictions() != null) {
final Predicate predicate = new ExpressionReplacementWalker() {
@Override
protected <X extends SqlAstNode> X replaceExpression(X expression) {
if (expression instanceof Literal || expression instanceof JdbcParameter) {
return expression;
}
final Expression outerExpression;
if (expression instanceof SqlSelectionExpression) {
final SqlSelection selection = ((SqlSelectionExpression) expression).getSelection();
outerExpression = selectClause.getSqlSelections().get(selection.getValuesArrayPosition()).getExpression();
} else {
final Expression realExpression;
if (expression instanceof SqmPathInterpretation<?>) {
realExpression = ((SqmPathInterpretation<?>) expression).getSqlExpression();
} else {
realExpression = (Expression) expression;
}
final Integer position = selectionMapping.get(realExpression);
if (position == null) {
// An expression that has no corresponding selection item,
// so we need to introduce an intermediate selection item
final int valuesPosition = selectClause.getSqlSelections().size();
final String columnName = "col" + valuesPosition;
final JdbcMapping jdbcMapping = realExpression.getExpressionType().getJdbcMappings().get(0);
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, jdbcMapping, factory);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(subValuesPosition + 1, subValuesPosition, realExpression, (BasicType<Object>) jdbcMapping);
columnNames.add(columnName);
subSelectClause.addSqlSelection(subSelection);
outerExpression = columnReference;
selectionMapping.put(realExpression, subValuesPosition);
} else {
outerExpression = selectClause.getSqlSelections().get(position).getExpression();
}
}
return (X) outerExpression;
}
}.replaceExpressions(subQuerySpec.getHavingClauseRestrictions());
outerQuerySpec.setHavingClauseRestrictions(predicate);
subQuerySpec.setHavingClauseRestrictions(null);
}
// Migrate the order by clause to the outer query
if (subQuerySpec.hasSortSpecifications()) {
for (SortSpecification sortSpecification : subQuerySpec.getSortSpecifications()) {
final Expression sortExpression = sortSpecification.getSortExpression();
final Expression outerSortExpression;
if (sortExpression instanceof SqlSelectionExpression) {
final SqlSelection selection = ((SqlSelectionExpression) sortExpression).getSelection();
outerSortExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(selection.getValuesArrayPosition()));
} else {
final Expression realExpression;
if (sortExpression instanceof SqmPathInterpretation<?>) {
realExpression = ((SqmPathInterpretation<?>) sortExpression).getSqlExpression();
} else {
realExpression = sortExpression;
}
final Integer position = selectionMapping.get(realExpression);
if (position == null) {
// Group by something that has no corresponding selection item,
// so we need to introduce an intermediate selection item
final int valuesPosition = selectClause.getSqlSelections().size();
final String columnName = "col" + valuesPosition;
final JdbcMapping jdbcMapping = realExpression.getExpressionType().getJdbcMappings().get(0);
final ColumnReference columnReference = new ColumnReference(identifierVariable, columnName, false, null, null, jdbcMapping, factory);
final int subValuesPosition = subSelectClause.getSqlSelections().size();
final SqlSelection subSelection = new ResolvedSqlSelection(subValuesPosition + 1, subValuesPosition, realExpression, (BasicType<Object>) jdbcMapping);
columnNames.add(columnName);
subSelectClause.addSqlSelection(subSelection);
outerSortExpression = columnReference;
selectionMapping.put(realExpression, subValuesPosition);
} else {
outerSortExpression = new SqlSelectionExpression(selectClause.getSqlSelections().get(position));
}
}
outerQuerySpec.addSortSpecification(new SortSpecification(outerSortExpression, sortSpecification.getSortOrder(), sortSpecification.getNullPrecedence()));
}
subQuerySpec.getSortSpecifications().clear();
}
// We need to add selection items for the expressions we order by to the sub query spec.
final int selectionOffset = columnNames.size();
// Collect the sorting column references so we can apply the filter later
final List<ColumnReference> sortingColumns = new ArrayList<>(withinGroup.size());
for (int i = 0; i < withinGroup.size(); i++) {
final int valueIndex = selectionOffset + i;
final Expression sortExpression = withinGroup.get(i).getSortExpression();
final BasicValuedMapping mapping = (BasicValuedMapping) sortExpression.getExpressionType();
final String columnName = "col" + valueIndex;
final int oldValueIndex = subSelectClause.getSqlSelections().size();
columnNames.add(columnName);
subSelectClause.addSqlSelection(new ResolvedSqlSelection(oldValueIndex + 1, oldValueIndex, sortExpression, (BasicType<Object>) mapping.getJdbcMapping()));
sortingColumns.add(new ColumnReference(identifierVariable, columnName, false, null, null, mapping.getJdbcMapping(), factory));
}
if (arguments != null) {
// So we add a filter to the outer query so we can extract the rank
switch(arguments.size()) {
case 0:
break;
case 1:
outerQuerySpec.applyPredicate(new ComparisonPredicate(sortingColumns.get(0), ComparisonOperator.EQUAL, (Expression) arguments.get(0)));
break;
default:
outerQuerySpec.applyPredicate(new ComparisonPredicate(new SqlTuple(sortingColumns, null), ComparisonOperator.EQUAL, new SqlTuple((List<? extends Expression>) (List<?>) arguments, null)));
}
}
final QueryPartTableGroup queryPartTableGroup = new QueryPartTableGroup(navigablePath, null, subQuerySpec, identifierVariable, columnNames, false, true, factory);
outerQuerySpec.getFromClause().addRoot(queryPartTableGroup);
// Migrate the offset/fetch clause
outerQuerySpec.setOffsetClauseExpression(subQuerySpec.getOffsetClauseExpression());
outerQuerySpec.setFetchClauseExpression(subQuerySpec.getFetchClauseExpression(), subQuerySpec.getFetchClauseType());
subQuerySpec.setOffsetClauseExpression(null);
subQuerySpec.setFetchClauseExpression(null, null);
return outerQuerySpec;
}
Aggregations