use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitTableGroup.
private Expression visitTableGroup(TableGroup tableGroup, SqmFrom<?, ?> path) {
final ModelPartContainer modelPart;
final MappingModelExpressible<?> inferredValueMapping = getInferredValueMapping();
// For plain SqmFrom node uses, prefer the mapping type from the context if possible
if (!(inferredValueMapping instanceof ModelPartContainer)) {
modelPart = tableGroup.getModelPart();
} else {
modelPart = (ModelPartContainer) inferredValueMapping;
}
final ModelPart resultModelPart;
final ModelPart interpretationModelPart;
final TableGroup parentGroupToUse;
if (modelPart instanceof ToOneAttributeMapping) {
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) modelPart;
final ModelPart targetPart = toOneAttributeMapping.getForeignKeyDescriptor().getPart(toOneAttributeMapping.getSideNature().inverse());
if (tableGroup.getModelPart().getPartMappingType() == modelPart.getPartMappingType()) {
resultModelPart = targetPart;
} else {
// If the table group is for a different mapping type i.e. an inheritance subtype,
// lookup the target part on that mapping type
resultModelPart = tableGroup.getModelPart().findSubPart(targetPart.getPartName(), null);
}
interpretationModelPart = modelPart;
parentGroupToUse = null;
} else if (modelPart instanceof PluralAttributeMapping) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) modelPart;
final CollectionPart elementDescriptor = pluralAttributeMapping.getElementDescriptor();
if (elementDescriptor instanceof EntityCollectionPart) {
// Usually, we need to resolve to the PK for visitTableGroup
final EntityCollectionPart collectionPart = (EntityCollectionPart) elementDescriptor;
final ModelPart collectionTargetPart = collectionPart.getForeignKeyDescriptor().getPart(collectionPart.getSideNature().inverse());
final EntityIdentifierMapping identifierMapping = collectionPart.getEntityMappingType().getIdentifierMapping();
// If the FK points to the PK, we can use the FK part though, if this is not a root
if (collectionTargetPart == identifierMapping && !(path instanceof SqmRoot<?>)) {
resultModelPart = collectionPart.getForeignKeyDescriptor().getPart(collectionPart.getSideNature());
} else {
resultModelPart = identifierMapping;
}
} else {
resultModelPart = elementDescriptor;
}
interpretationModelPart = elementDescriptor;
parentGroupToUse = null;
} else if (modelPart instanceof EntityCollectionPart) {
// Usually, we need to resolve to the PK for visitTableGroup
final EntityCollectionPart collectionPart = (EntityCollectionPart) modelPart;
final ModelPart collectionTargetPart = collectionPart.getForeignKeyDescriptor().getPart(collectionPart.getSideNature().inverse());
final EntityIdentifierMapping identifierMapping = collectionPart.getEntityMappingType().getIdentifierMapping();
// If the FK points to the PK, we can use the FK part though, if this is not a root
if (collectionTargetPart == identifierMapping && !(path instanceof SqmRoot<?>)) {
resultModelPart = collectionPart.getForeignKeyDescriptor().getPart(collectionPart.getSideNature());
} else {
resultModelPart = identifierMapping;
}
interpretationModelPart = modelPart;
parentGroupToUse = findTableGroup(tableGroup.getNavigablePath().getParent());
} else if (modelPart instanceof EntityMappingType) {
resultModelPart = ((EntityMappingType) modelPart).getIdentifierMapping();
interpretationModelPart = modelPart;
// todo: I think this will always be null anyways because EntityMappingType will only be the model part
// of a TableGroup if that is a root TableGroup, so check if we can just switch to null
parentGroupToUse = findTableGroup(tableGroup.getNavigablePath().getParent());
} else {
resultModelPart = modelPart;
interpretationModelPart = modelPart;
parentGroupToUse = null;
}
final NavigablePath navigablePath;
if (interpretationModelPart == modelPart) {
navigablePath = tableGroup.getNavigablePath();
} else {
navigablePath = tableGroup.getNavigablePath().append(interpretationModelPart.getPartName());
}
final Expression result;
if (interpretationModelPart instanceof EntityValuedModelPart) {
final boolean expandToAllColumns;
if (currentClauseStack.getCurrent() == Clause.GROUP) {
// When the table group is known to be fetched i.e. a fetch join
// but also when the from clause is part of the select clause
// we need to expand to all columns, as we also expand this to all columns in the select clause
expandToAllColumns = tableGroup.isFetched() || selectClauseContains(path);
} else {
expandToAllColumns = false;
}
final EntityValuedModelPart mapping = (EntityValuedModelPart) interpretationModelPart;
EntityMappingType mappingType;
if (path instanceof SqmTreatedPath) {
mappingType = creationContext.getSessionFactory().getRuntimeMetamodels().getMappingMetamodel().findEntityDescriptor(((SqmTreatedPath<?, ?>) path).getTreatTarget().getHibernateEntityName());
} else {
mappingType = mapping.getEntityMappingType();
}
result = EntityValuedPathInterpretation.from(navigablePath, parentGroupToUse == null ? tableGroup : parentGroupToUse, expandToAllColumns ? null : resultModelPart, (EntityValuedModelPart) interpretationModelPart, mappingType, this);
} else if (interpretationModelPart instanceof EmbeddableValuedModelPart) {
final EmbeddableValuedModelPart mapping = (EmbeddableValuedModelPart) resultModelPart;
result = new EmbeddableValuedPathInterpretation<>(mapping.toSqlExpression(tableGroup, currentClauseStack.getCurrent(), this, getSqlAstCreationState()), navigablePath, (EmbeddableValuedModelPart) interpretationModelPart, tableGroup);
} else {
assert interpretationModelPart instanceof BasicValuedModelPart;
final BasicValuedModelPart mapping = (BasicValuedModelPart) resultModelPart;
final TableReference tableReference = tableGroup.resolveTableReference(navigablePath.append(resultModelPart.getPartName()), mapping.getContainingTableExpression());
final Expression expression = getSqlExpressionResolver().resolveSqlExpression(SqlExpressionResolver.createColumnReferenceKey(tableReference, mapping.getSelectionExpression()), sacs -> new ColumnReference(tableReference.getIdentificationVariable(), mapping, getCreationContext().getSessionFactory()));
final ColumnReference columnReference;
if (expression instanceof ColumnReference) {
columnReference = (ColumnReference) expression;
} else if (expression instanceof SqlSelectionExpression) {
final Expression selectedExpression = ((SqlSelectionExpression) expression).getSelection().getExpression();
assert selectedExpression instanceof ColumnReference;
columnReference = (ColumnReference) selectedExpression;
} else {
throw new UnsupportedOperationException("Unsupported basic-valued path expression : " + expression);
}
result = new BasicValuedPathInterpretation<>(columnReference, navigablePath, (BasicValuedModelPart) interpretationModelPart, tableGroup);
}
return withTreatRestriction(result, path);
}
use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method createLateralJoinExpression.
protected Expression createLateralJoinExpression(AbstractSqmSpecificPluralPartPath<?> pluralPartPath, boolean index, String functionName) {
prepareReusablePath(pluralPartPath.getLhs(), () -> null);
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) determineValueMapping(pluralPartPath.getPluralDomainPath());
final FromClauseAccess parentFromClauseAccess = getFromClauseAccess();
final TableGroup parentTableGroup = parentFromClauseAccess.findTableGroup(pluralPartPath.getNavigablePath().getParent());
final CollectionPart collectionPart = index ? pluralAttributeMapping.getIndexDescriptor() : pluralAttributeMapping.getElementDescriptor();
final ModelPart modelPart;
if (collectionPart instanceof EntityAssociationMapping) {
modelPart = ((EntityAssociationMapping) collectionPart).getKeyTargetMatchPart();
} else {
modelPart = collectionPart;
}
final int jdbcTypeCount = modelPart.getJdbcTypeCount();
final String pathName = functionName + (index ? "_index" : "_element");
final String identifierVariable = parentTableGroup.getPrimaryTableReference().getIdentificationVariable() + "_" + pathName;
final NavigablePath queryPath = new NavigablePath(parentTableGroup.getNavigablePath(), pathName, identifierVariable);
TableGroup lateralTableGroup = parentFromClauseAccess.findTableGroup(queryPath);
if (lateralTableGroup == null) {
final QuerySpec subQuerySpec = new QuerySpec(false);
pushProcessingState(new SqlAstQueryPartProcessingStateImpl(subQuerySpec, getCurrentProcessingState(), this, currentClauseStack::getCurrent, false));
try {
final TableGroup tableGroup = pluralAttributeMapping.createRootTableGroup(true, pluralPartPath.getNavigablePath(), null, () -> subQuerySpec::applyPredicate, this, creationContext);
pluralAttributeMapping.applyBaseRestrictions(subQuerySpec::applyPredicate, tableGroup, true, getLoadQueryInfluencers().getEnabledFilters(), null, this);
getFromClauseAccess().registerTableGroup(pluralPartPath.getNavigablePath(), tableGroup);
registerPluralTableGroupParts(tableGroup);
subQuerySpec.getFromClause().addRoot(tableGroup);
final List<String> columnNames = new ArrayList<>(jdbcTypeCount);
final List<ColumnReference> resultColumnReferences = new ArrayList<>(jdbcTypeCount);
final NavigablePath navigablePath = pluralPartPath.getNavigablePath();
final Boolean max = functionName.equalsIgnoreCase("max") ? Boolean.TRUE : (functionName.equalsIgnoreCase("min") ? Boolean.FALSE : null);
final AbstractSqmSelfRenderingFunctionDescriptor functionDescriptor = (AbstractSqmSelfRenderingFunctionDescriptor) creationContext.getSessionFactory().getQueryEngine().getSqmFunctionRegistry().findFunctionDescriptor(functionName);
final List<ColumnReference> subQueryColumns = new ArrayList<>(jdbcTypeCount);
modelPart.forEachSelectable((selectionIndex, selectionMapping) -> {
final ColumnReference columnReference = new ColumnReference(tableGroup.resolveTableReference(navigablePath, selectionMapping.getContainingTableExpression()), selectionMapping, creationContext.getSessionFactory());
final String columnName;
if (selectionMapping.isFormula()) {
columnName = "col" + columnNames.size();
} else {
columnName = selectionMapping.getSelectionExpression();
}
columnNames.add(columnName);
subQueryColumns.add(columnReference);
if (max != null) {
subQuerySpec.addSortSpecification(new SortSpecification(columnReference, max ? SortOrder.DESCENDING : SortOrder.ASCENDING));
}
});
if (max != null) {
for (int i = 0; i < subQueryColumns.size(); i++) {
subQuerySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(i + 1, i, subQueryColumns.get(i)));
resultColumnReferences.add(new ColumnReference(identifierVariable, columnNames.get(i), false, null, null, subQueryColumns.get(i).getJdbcMapping(), creationContext.getSessionFactory()));
}
subQuerySpec.setFetchClauseExpression(new QueryLiteral<>(1, basicType(Integer.class)), FetchClauseType.ROWS_ONLY);
} else {
final List<? extends SqlAstNode> arguments;
if (jdbcTypeCount == 1) {
arguments = subQueryColumns;
} else {
arguments = Collections.singletonList(new SqlTuple(subQueryColumns, modelPart));
}
final Expression expression = new SelfRenderingAggregateFunctionSqlAstExpression(functionDescriptor.getName(), functionDescriptor, arguments, null, (ReturnableType<?>) functionDescriptor.getReturnTypeResolver().resolveFunctionReturnType(() -> null, arguments).getJdbcMapping(), modelPart);
subQuerySpec.getSelectClause().addSqlSelection(new SqlSelectionImpl(1, 0, expression));
resultColumnReferences.add(new ColumnReference(identifierVariable, columnNames.get(0), false, null, null, expression.getExpressionType().getJdbcMappings().get(0), creationContext.getSessionFactory()));
}
subQuerySpec.applyPredicate(pluralAttributeMapping.getKeyDescriptor().generateJoinPredicate(parentFromClauseAccess.findTableGroup(pluralPartPath.getPluralDomainPath().getNavigablePath().getParent()), tableGroup, getSqlExpressionResolver(), creationContext));
final String compatibleTableExpression;
if (modelPart instanceof BasicValuedModelPart) {
compatibleTableExpression = ((BasicValuedModelPart) modelPart).getContainingTableExpression();
} else if (modelPart instanceof EmbeddableValuedModelPart) {
compatibleTableExpression = ((EmbeddableValuedModelPart) modelPart).getContainingTableExpression();
} else {
compatibleTableExpression = null;
}
lateralTableGroup = new QueryPartTableGroup(queryPath, null, subQuerySpec, identifierVariable, columnNames, compatibleTableExpression, true, false, creationContext.getSessionFactory());
if (currentlyProcessingJoin == null) {
parentTableGroup.addTableGroupJoin(new TableGroupJoin(lateralTableGroup.getNavigablePath(), SqlAstJoinType.LEFT, lateralTableGroup));
} else {
// In case this is used in the ON condition, we must prepend this lateral join
final TableGroup targetTableGroup;
if (currentlyProcessingJoin.getLhs() == null) {
targetTableGroup = parentFromClauseAccess.getTableGroup(currentlyProcessingJoin.findRoot().getNavigablePath());
} else {
targetTableGroup = parentFromClauseAccess.getTableGroup(currentlyProcessingJoin.getLhs().getNavigablePath());
}
// Many databases would support modelling this as nested table group join,
// but at least SQL Server doesn't like that, saying that the correlated columns can't be "bound"
// Since there is no dependency on the currentlyProcessingJoin, we can safely prepend this join
targetTableGroup.prependTableGroupJoin(currentlyProcessingJoin.getNavigablePath(), new TableGroupJoin(lateralTableGroup.getNavigablePath(), SqlAstJoinType.LEFT, lateralTableGroup));
}
parentFromClauseAccess.registerTableGroup(lateralTableGroup.getNavigablePath(), lateralTableGroup);
if (jdbcTypeCount == 1) {
return new SelfRenderingFunctionSqlAstExpression(pathName, (sqlAppender, sqlAstArguments, walker) -> {
sqlAstArguments.get(0).accept(walker);
}, resultColumnReferences, (ReturnableType<?>) resultColumnReferences.get(0).getJdbcMapping(), resultColumnReferences.get(0).getJdbcMapping());
} else {
return new SqlTuple(resultColumnReferences, modelPart);
}
} finally {
popProcessingStateStack();
}
}
final QueryPartTableReference tableReference = (QueryPartTableReference) lateralTableGroup.getPrimaryTableReference();
if (jdbcTypeCount == 1) {
final List<SqlSelection> sqlSelections = tableReference.getQueryPart().getFirstQuerySpec().getSelectClause().getSqlSelections();
return new SelfRenderingFunctionSqlAstExpression(pathName, (sqlAppender, sqlAstArguments, walker) -> {
sqlAstArguments.get(0).accept(walker);
}, Collections.singletonList(new ColumnReference(identifierVariable, tableReference.getColumnNames().get(0), false, null, null, sqlSelections.get(0).getExpressionType().getJdbcMappings().get(0), creationContext.getSessionFactory())), (ReturnableType<?>) sqlSelections.get(0).getExpressionType().getJdbcMappings().get(0), sqlSelections.get(0).getExpressionType());
} else {
final List<ColumnReference> resultColumnReferences = new ArrayList<>(jdbcTypeCount);
modelPart.forEachSelectable((selectionIndex, selectionMapping) -> resultColumnReferences.add(new ColumnReference(identifierVariable, tableReference.getColumnNames().get(selectionIndex), false, null, null, selectionMapping.getJdbcMapping(), creationContext.getSessionFactory())));
return new SqlTuple(resultColumnReferences, modelPart);
}
}
use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitSimpleCaseExpression.
@Override
public CaseSimpleExpression visitSimpleCaseExpression(SqmCaseSimple<?, ?> expression) {
final List<CaseSimpleExpression.WhenFragment> whenFragments = new ArrayList<>(expression.getWhenFragments().size());
final Supplier<MappingModelExpressible<?>> inferenceSupplier = inferrableTypeAccessStack.getCurrent();
inferrableTypeAccessStack.push(() -> {
for (SqmCaseSimple.WhenFragment<?, ?> whenFragment : expression.getWhenFragments()) {
final MappingModelExpressible<?> resolved = determineCurrentExpressible(whenFragment.getCheckValue());
if (resolved != null) {
return resolved;
}
}
return null;
});
final Expression fixture = (Expression) expression.getFixture().accept(this);
final MappingModelExpressible<?> fixtureType = (MappingModelExpressible<?>) fixture.getExpressionType();
inferrableTypeAccessStack.pop();
MappingModelExpressible<?> resolved = determineCurrentExpressible(expression);
Expression otherwise = null;
for (SqmCaseSimple.WhenFragment<?, ?> whenFragment : expression.getWhenFragments()) {
inferrableTypeAccessStack.push(() -> fixtureType);
final Expression checkValue = (Expression) whenFragment.getCheckValue().accept(this);
inferrableTypeAccessStack.pop();
final MappingModelExpressible<?> alreadyKnown = resolved;
inferrableTypeAccessStack.push(() -> alreadyKnown == null && inferenceSupplier != null ? inferenceSupplier.get() : alreadyKnown);
final Expression resultExpression = (Expression) whenFragment.getResult().accept(this);
inferrableTypeAccessStack.pop();
resolved = (MappingModelExpressible<?>) highestPrecedence(resolved, resultExpression.getExpressionType());
whenFragments.add(new CaseSimpleExpression.WhenFragment(checkValue, resultExpression));
}
if (expression.getOtherwise() != null) {
final MappingModelExpressible<?> alreadyKnown = resolved;
inferrableTypeAccessStack.push(() -> alreadyKnown == null && inferenceSupplier != null ? inferenceSupplier.get() : alreadyKnown);
otherwise = (Expression) expression.getOtherwise().accept(this);
inferrableTypeAccessStack.pop();
resolved = (MappingModelExpressible<?>) highestPrecedence(resolved, otherwise.getExpressionType());
}
return new CaseSimpleExpression(resolved, fixture, whenFragments, otherwise);
}
use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitInsertionTargetPaths.
public AdditionalInsertValues visitInsertionTargetPaths(BiConsumer<Assignable, List<ColumnReference>> targetColumnReferenceConsumer, SqmInsertStatement<?> sqmStatement, EntityPersister entityDescriptor, TableGroup rootTableGroup) {
final List<SqmPath<?>> targetPaths = sqmStatement.getInsertionTargetPaths();
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping();
IdentifierGenerator identifierGenerator = entityDescriptor.getIdentifierGenerator();
Expression versionExpression = null;
Expression discriminatorExpression = null;
BasicEntityIdentifierMapping identifierMapping = null;
// We use the id property name to null the identifier generator variable if the target paths contain the id
final String identifierPropertyName;
if (identifierGenerator != null) {
identifierPropertyName = entityDescriptor.getIdentifierPropertyName();
} else {
identifierPropertyName = null;
}
final String versionAttributeName;
boolean needsVersionInsert;
if (entityDescriptor.isVersioned()) {
versionAttributeName = entityDescriptor.getVersionMapping().getVersionAttribute().getAttributeName();
needsVersionInsert = true;
} else {
versionAttributeName = null;
needsVersionInsert = false;
}
// Go through all target paths and remember if the target paths contain the version or id attributes
for (int i = 0; i < targetPaths.size(); i++) {
final SqmPath<?> path = targetPaths.get(i);
final String localName = path.getNavigablePath().getLocalName();
if (localName.equals(identifierPropertyName)) {
identifierGenerator = null;
} else if (localName.equals(versionAttributeName)) {
needsVersionInsert = false;
}
final Assignable assignable = (Assignable) path.accept(this);
targetColumnReferenceConsumer.accept(assignable, assignable.getColumnReferences());
}
if (needsVersionInsert) {
final BasicValuedPathInterpretation<?> versionPath = BasicValuedPathInterpretation.from((SqmBasicValuedSimplePath<?>) sqmStatement.getTarget().get(versionAttributeName), this, this, jpaQueryComplianceEnabled);
final List<ColumnReference> targetColumnReferences = versionPath.getColumnReferences();
assert targetColumnReferences.size() == 1;
targetColumnReferenceConsumer.accept(versionPath, targetColumnReferences);
versionExpression = new VersionTypeSeedParameterSpecification(entityDescriptor.getVersionMapping().getJdbcMapping(), entityDescriptor.getVersionJavaType());
}
if (discriminatorMapping != null && discriminatorMapping.isPhysical()) {
final BasicValuedPathInterpretation<?> discriminatorPath = new BasicValuedPathInterpretation<>(new ColumnReference(rootTableGroup.resolveTableReference(discriminatorMapping.getContainingTableExpression()), discriminatorMapping, getCreationContext().getSessionFactory()), rootTableGroup.getNavigablePath().append(discriminatorMapping.getPartName()), discriminatorMapping, rootTableGroup);
targetColumnReferenceConsumer.accept(discriminatorPath, discriminatorPath.getColumnReferences());
discriminatorExpression = new QueryLiteral<>(entityDescriptor.getDiscriminatorValue(), discriminatorMapping);
}
// This uses identity generation, so we don't need to list the column
if (identifierGenerator instanceof PostInsertIdentifierGenerator || identifierGenerator instanceof CompositeNestedGeneratedValueGenerator) {
identifierGenerator = null;
} else if (identifierGenerator != null) {
identifierMapping = (BasicEntityIdentifierMapping) entityDescriptor.getIdentifierMapping();
final BasicValuedPathInterpretation<?> identifierPath = new BasicValuedPathInterpretation<>(new ColumnReference(rootTableGroup.resolveTableReference(identifierMapping.getContainingTableExpression()), identifierMapping, getCreationContext().getSessionFactory()), rootTableGroup.getNavigablePath().append(identifierMapping.getPartName()), identifierMapping, rootTableGroup);
targetColumnReferenceConsumer.accept(identifierPath, identifierPath.getColumnReferences());
}
return new AdditionalInsertValues(versionExpression, discriminatorExpression, identifierGenerator, identifierMapping);
}
use of org.hibernate.sql.ast.tree.expression.Expression in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitQuerySpec.
@Override
public QuerySpec visitQuerySpec(SqmQuerySpec<?> sqmQuerySpec) {
final boolean topLevel = getProcessingStateStack().isEmpty();
final QuerySpec sqlQuerySpec = new QuerySpec(topLevel, sqmQuerySpec.getFromClause().getNumberOfRoots());
final SqmSelectClause selectClause = sqmQuerySpec.getSelectClause();
final Predicate originalAdditionalRestrictions = additionalRestrictions;
additionalRestrictions = null;
final boolean trackAliasedNodePositions;
if (trackSelectionsForGroup) {
trackAliasedNodePositions = true;
} else if (sqmQuerySpec.getOrderByClause() != null && sqmQuerySpec.getOrderByClause().hasPositionalSortItem()) {
trackAliasedNodePositions = true;
} else if (sqmQuerySpec.hasPositionalGroupItem()) {
trackAliasedNodePositions = true;
} else {
// Since JPA Criteria queries can use the same expression object in order or group by items,
// we need to track the positions to be able to replace the expression in the items with alias references
// Also see #resolveGroupOrOrderByExpression for more details
trackAliasedNodePositions = statement.getQuerySource() == SqmQuerySource.CRITERIA && (sqmQuerySpec.getOrderByClause() != null || !sqmQuerySpec.getGroupByClauseExpressions().isEmpty());
}
final SqlAstProcessingState processingState;
if (trackAliasedNodePositions) {
processingState = new SqlAstQueryPartProcessingStateImpl(sqlQuerySpec, getCurrentProcessingState(), this, r -> new SqmAliasedNodePositionTracker(r, selectClause.getSelections()), currentClauseStack::getCurrent, deduplicateSelectionItems);
} else {
processingState = new SqlAstQueryPartProcessingStateImpl(sqlQuerySpec, getCurrentProcessingState(), this, currentClauseStack::getCurrent, deduplicateSelectionItems);
}
final SqmQueryPart<?> sqmQueryPart = currentSqmQueryPart;
final boolean originalDeduplicateSelectionItems = deduplicateSelectionItems;
currentSqmQueryPart = sqmQuerySpec;
// In sub-queries, we can never deduplicate the selection items as that might change semantics
deduplicateSelectionItems = false;
pushProcessingState(processingState);
queryTransformers.push(new ArrayList<>());
try {
// we want to visit the from-clause first
visitFromClause(sqmQuerySpec.getFromClause());
visitSelectClause(selectClause);
final SqmWhereClause whereClause = sqmQuerySpec.getWhereClause();
if (whereClause != null) {
sqlQuerySpec.applyPredicate(visitWhereClause(whereClause.getPredicate()));
}
sqlQuerySpec.setGroupByClauseExpressions(visitGroupByClause(sqmQuerySpec.getGroupByClauseExpressions()));
if (sqmQuerySpec.getHavingClausePredicate() != null) {
sqlQuerySpec.setHavingClauseRestrictions(visitHavingClause(sqmQuerySpec.getHavingClausePredicate()));
}
visitOrderByOffsetAndFetch(sqmQuerySpec, sqlQuerySpec);
if (topLevel && statement instanceof SqmSelectStatement<?>) {
if (orderByFragments != null) {
orderByFragments.forEach(entry -> entry.getKey().apply(sqlQuerySpec, entry.getValue(), this));
orderByFragments = null;
}
applyCollectionFilterPredicates(sqlQuerySpec);
}
QuerySpec finalQuerySpec = sqlQuerySpec;
for (QueryTransformer transformer : queryTransformers.getCurrent()) {
finalQuerySpec = transformer.transform(cteContainer, finalQuerySpec, this);
}
return finalQuerySpec;
} finally {
if (additionalRestrictions != null) {
sqlQuerySpec.applyPredicate(additionalRestrictions);
}
additionalRestrictions = originalAdditionalRestrictions;
popProcessingStateStack();
queryTransformers.pop();
currentSqmQueryPart = sqmQueryPart;
deduplicateSelectionItems = originalDeduplicateSelectionItems;
}
}
Aggregations