use of org.hibernate.query.sqm.tree.domain.SqmPath in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method withTreatRestriction.
private Expression withTreatRestriction(Expression expression, SqmPath<?> path) {
final SqmPath<?> lhs;
if (path instanceof SqmTreatedPath<?, ?>) {
lhs = path;
} else {
lhs = path.getLhs();
}
if (lhs instanceof SqmTreatedPath<?, ?>) {
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) lhs;
final Class<?> treatTargetJavaType = treatedPath.getTreatTarget().getJavaType();
final Class<?> originalJavaType = treatedPath.getWrappedPath().getJavaType();
if (treatTargetJavaType.isAssignableFrom(originalJavaType)) {
// Treating a node to a super type can be ignored
return expression;
}
if (!(expression.getExpressionType() instanceof BasicValuedMapping)) {
// A case wrapper for non-basic paths is not possible,
// because a case expression must return a scalar value,
// so we instead add the type restriction predicate as conjunct
final MappingMetamodel domainModel = creationContext.getSessionFactory().getRuntimeMetamodels().getMappingMetamodel();
final EntityPersister entityDescriptor = domainModel.findEntityDescriptor(treatedPath.getTreatTarget().getHibernateEntityName());
conjunctTreatUsages.computeIfAbsent(treatedPath.getWrappedPath(), p -> new HashSet<>(1)).addAll(entityDescriptor.getSubclassEntityNames());
return expression;
}
// Note: If the columns that are accessed are not shared with other entities, we could avoid this wrapping
return createCaseExpression(treatedPath.getWrappedPath(), treatedPath.getTreatTarget(), expression);
}
return expression;
}
use of org.hibernate.query.sqm.tree.domain.SqmPath in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitDynamicInstantiation.
@Override
public DynamicInstantiation<?> visitDynamicInstantiation(SqmDynamicInstantiation<?> sqmDynamicInstantiation) {
final SqmDynamicInstantiationTarget<?> instantiationTarget = sqmDynamicInstantiation.getInstantiationTarget();
final DynamicInstantiationNature instantiationNature = instantiationTarget.getNature();
final JavaType<Object> targetTypeDescriptor = interpretInstantiationTarget(instantiationTarget);
final DynamicInstantiation<?> dynamicInstantiation = new DynamicInstantiation<>(instantiationNature, targetTypeDescriptor);
for (SqmDynamicInstantiationArgument<?> sqmArgument : sqmDynamicInstantiation.getArguments()) {
final SqmSelectableNode<?> selectableNode = sqmArgument.getSelectableNode();
if (selectableNode instanceof SqmPath<?>) {
prepareForSelection((SqmPath<?>) selectableNode);
}
final DomainResultProducer<?> argumentResultProducer = (DomainResultProducer<?>) selectableNode.accept(this);
dynamicInstantiation.addArgument(sqmArgument.getAlias(), argumentResultProducer, this);
}
dynamicInstantiation.complete();
return dynamicInstantiation;
}
use of org.hibernate.query.sqm.tree.domain.SqmPath in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitOrPredicate.
@Override
public Junction visitOrPredicate(SqmOrPredicate predicate) {
final Junction disjunction = new Junction(Junction.Nature.DISJUNCTION, getBooleanType());
final Predicate predicate1 = (Predicate) predicate.getLeftHandPredicate().accept(this);
final Map<SqmPath<?>, Set<String>> conjunctTreatUsages1;
if (conjunctTreatUsages.isEmpty()) {
conjunctTreatUsages1 = null;
} else {
conjunctTreatUsages1 = new IdentityHashMap<>(conjunctTreatUsages);
conjunctTreatUsages.clear();
}
final Predicate predicate2 = (Predicate) predicate.getRightHandPredicate().accept(this);
if (conjunctTreatUsages.isEmpty() || conjunctTreatUsages1 == null) {
disjunction.add(SqlAstTreeHelper.combinePredicates(consumeConjunctTreatTypeRestrictions(conjunctTreatUsages1), predicate1));
disjunction.add(predicate2);
} else {
// If both disjunctions have treat type restrictions build the intersection of the two,
// so that we can push that up and infer during pruning, which entity subclasses can be omitted
final Map<SqmPath<?>, Set<String>> conjunctTreatUsages2 = new IdentityHashMap<>(conjunctTreatUsages);
final Iterator<Map.Entry<SqmPath<?>, Set<String>>> iterator = conjunctTreatUsages.entrySet().iterator();
while (iterator.hasNext()) {
final Map.Entry<SqmPath<?>, Set<String>> entry = iterator.next();
final Set<String> entityNames1 = conjunctTreatUsages1.get(entry.getKey());
if (entityNames1 == null) {
iterator.remove();
continue;
}
// Intersect the two sets and transfer the common elements to the intersection
final Set<String> entityNames2 = entry.getValue();
final Set<String> intersected = new HashSet<>(entityNames1);
intersected.retainAll(entityNames2);
if (intersected.isEmpty()) {
iterator.remove();
continue;
}
entry.setValue(intersected);
entityNames1.removeAll(intersected);
entityNames2.removeAll(intersected);
if (entityNames1.isEmpty()) {
conjunctTreatUsages1.remove(entry.getKey());
}
if (entityNames2.isEmpty()) {
conjunctTreatUsages2.remove(entry.getKey());
}
}
disjunction.add(SqlAstTreeHelper.combinePredicates(consumeConjunctTreatTypeRestrictions(conjunctTreatUsages1), predicate1));
disjunction.add(SqlAstTreeHelper.combinePredicates(consumeConjunctTreatTypeRestrictions(conjunctTreatUsages2), predicate2));
}
return disjunction;
}
use of org.hibernate.query.sqm.tree.domain.SqmPath in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitSelection.
@Override
public Void visitSelection(SqmSelection<?> sqmSelection) {
final List<Map.Entry<String, DomainResultProducer<?>>> resultProducers;
final SqmSelectableNode<?> selectionNode = sqmSelection.getSelectableNode();
if (selectionNode instanceof SqmJpaCompoundSelection<?>) {
final SqmJpaCompoundSelection<?> selectableNode = (SqmJpaCompoundSelection<?>) selectionNode;
resultProducers = new ArrayList<>(selectableNode.getSelectionItems().size());
for (SqmSelectableNode<?> selectionItem : selectableNode.getSelectionItems()) {
if (selectionItem instanceof SqmPath<?>) {
prepareForSelection((SqmPath<?>) selectionItem);
}
resultProducers.add(new AbstractMap.SimpleEntry<>(selectionItem.getAlias(), (DomainResultProducer<?>) selectionItem.accept(this)));
}
} else {
if (selectionNode instanceof SqmPath<?>) {
prepareForSelection((SqmPath<?>) selectionNode);
}
resultProducers = Collections.singletonList(new AbstractMap.SimpleEntry<>(sqmSelection.getAlias(), (DomainResultProducer<?>) selectionNode.accept(this)));
}
final Stack<SqlAstProcessingState> processingStateStack = getProcessingStateStack();
final boolean needsDomainResults = domainResults != null && currentClauseContributesToTopLevelSelectClause();
final boolean collectDomainResults;
if (processingStateStack.depth() == 1) {
collectDomainResults = needsDomainResults;
} else {
final SqlAstProcessingState current = processingStateStack.getCurrent();
// Since we only want to create domain results for the first/left-most query spec within query groups,
// we have to check if the current query spec is the left-most.
// This is the case when all upper level in-flight query groups are still empty
collectDomainResults = needsDomainResults && processingStateStack.findCurrentFirst(processingState -> {
if (!(processingState instanceof SqlAstQueryPartProcessingState)) {
return Boolean.FALSE;
}
if (processingState == current) {
return null;
}
final QueryPart part = ((SqlAstQueryPartProcessingState) processingState).getInflightQueryPart();
if (part instanceof QueryGroup) {
if (((QueryGroup) part).getQueryParts().isEmpty()) {
return null;
}
}
return Boolean.FALSE;
}) == null;
}
// arguments
if (collectDomainResults) {
resultProducers.forEach(entry -> {
if (!(entry.getValue() instanceof DynamicInstantiation<?>)) {
currentSqlSelectionCollector().next();
}
domainResults.add(entry.getValue().createDomainResult(entry.getKey(), this));
});
} else if (needsDomainResults) {
// We just create domain results for the purpose of creating selections
// This is necessary for top-level query specs within query groups to avoid cycles
resultProducers.forEach(entry -> {
if (!(entry.getValue() instanceof DynamicInstantiation<?>)) {
currentSqlSelectionCollector().next();
}
entry.getValue().createDomainResult(entry.getKey(), this);
});
} else {
resultProducers.forEach(entry -> {
if (!(entry.getValue() instanceof DynamicInstantiation<?>)) {
currentSqlSelectionCollector().next();
}
entry.getValue().applySqlSelections(this);
});
}
return null;
}
use of org.hibernate.query.sqm.tree.domain.SqmPath in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method consumeConjunctTreatTypeRestrictions.
private Predicate consumeConjunctTreatTypeRestrictions(Map<SqmPath<?>, Set<String>> conjunctTreatUsages) {
if (conjunctTreatUsages == null || conjunctTreatUsages.isEmpty()) {
return null;
}
Predicate predicate = null;
for (Map.Entry<SqmPath<?>, Set<String>> entry : conjunctTreatUsages.entrySet()) {
predicate = SqlAstTreeHelper.combinePredicates(predicate, createTreatTypeRestriction(entry.getKey(), entry.getValue()));
}
conjunctTreatUsages.clear();
return predicate;
}
Aggregations