use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class DynamicFetchBuilderLegacy method buildFetch.
@Override
public Fetch buildFetch(FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver, DomainResultCreationState domainResultCreationState) {
final DomainResultCreationStateImpl creationState = ResultsHelper.impl(domainResultCreationState);
final TableGroup ownerTableGroup = creationState.getFromClauseAccess().findByAlias(ownerTableAlias);
final AttributeMapping attributeMapping = parent.getReferencedMappingContainer().findContainingEntityMapping().findDeclaredAttributeMapping(fetchableName);
final TableGroup tableGroup;
if (attributeMapping instanceof TableGroupJoinProducer) {
final SqlAliasBase sqlAliasBase = new SqlAliasBaseConstant(tableAlias);
final TableGroupJoin tableGroupJoin = ((TableGroupJoinProducer) attributeMapping).createTableGroupJoin(fetchPath, ownerTableGroup, tableAlias, SqlAstJoinType.INNER, true, false, s -> sqlAliasBase, creationState.getSqlExpressionResolver(), creationState.getFromClauseAccess(), creationState.getCreationContext());
ownerTableGroup.addTableGroupJoin(tableGroupJoin);
creationState.getFromClauseAccess().registerTableGroup(fetchPath, tableGroup = tableGroupJoin.getJoinedGroup());
} else {
tableGroup = ownerTableGroup;
}
if (columnNames != null) {
final ForeignKeyDescriptor keyDescriptor;
if (attributeMapping instanceof PluralAttributeMapping) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) attributeMapping;
keyDescriptor = pluralAttributeMapping.getKeyDescriptor();
} else {
// Not sure if this fetch builder can also be used with other attribute mappings
assert attributeMapping instanceof ToOneAttributeMapping;
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) attributeMapping;
keyDescriptor = toOneAttributeMapping.getForeignKeyDescriptor();
}
if (!columnNames.isEmpty()) {
keyDescriptor.forEachSelectable((selectionIndex, selectableMapping) -> {
resolveSqlSelection(columnNames.get(selectionIndex), createColumnReferenceKey(tableGroup.resolveTableReference(selectableMapping.getContainingTableExpression()), selectableMapping.getSelectionExpression()), selectableMapping.getJdbcMapping(), jdbcResultsMetadata, domainResultCreationState);
});
}
// We process the fetch builder such that it contains a resultBuilderEntity before calling this method in ResultSetMappingProcessor
if (resultBuilderEntity != null) {
return resultBuilderEntity.buildFetch(parent, attributeMapping, jdbcResultsMetadata, creationState);
}
}
try {
final NavigablePath currentRelativePath = creationState.getCurrentRelativePath();
final String prefix;
if (currentRelativePath == null) {
prefix = "";
} else {
prefix = currentRelativePath.getFullPath().replace(ELEMENT_PREFIX, "").replace(INDEX_PREFIX, "") + ".";
}
creationState.pushExplicitFetchMementoResolver(relativePath -> {
if (relativePath.startsWith(prefix)) {
return findFetchBuilder(relativePath.substring(prefix.length()));
}
return null;
});
return parent.generateFetchableFetch(attributeMapping, parent.resolveNavigablePath(attributeMapping), FetchTiming.IMMEDIATE, true, null, domainResultCreationState);
} finally {
creationState.popExplicitFetchMementoResolver();
}
}
use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method createTableGroup.
private TableGroup createTableGroup(TableGroup parentTableGroup, SqmPath<?> joinedPath) {
final TableGroup actualParentTableGroup = findActualTableGroup(parentTableGroup, joinedPath);
final SqmPath<?> lhsPath = joinedPath.getLhs();
final FromClauseIndex fromClauseIndex = getFromClauseIndex();
final ModelPart subPart = actualParentTableGroup.getModelPart().findSubPart(joinedPath.getReferencedPathSource().getPathName(), lhsPath instanceof SqmTreatedPath ? resolveEntityPersister(((SqmTreatedPath<?, ?>) lhsPath).getTreatTarget()) : null);
final TableGroup tableGroup;
if (subPart instanceof TableGroupJoinProducer) {
final TableGroupJoinProducer joinProducer = (TableGroupJoinProducer) subPart;
if (fromClauseIndex.findTableGroup(actualParentTableGroup.getNavigablePath()) == null) {
final QuerySpec querySpec = currentQuerySpec();
// The parent table group is on a parent query, so we need a root table group
tableGroup = joinProducer.createRootTableGroupJoin(joinedPath.getNavigablePath(), actualParentTableGroup, null, null, false, querySpec::applyPredicate, this);
// Force initialization of a possible lazy table group
tableGroup.getPrimaryTableReference();
querySpec.getFromClause().addRoot(tableGroup);
} else {
// Check if we can reuse a table group join of the parent
final TableGroup compatibleTableGroup = findCompatibleJoinedGroup(actualParentTableGroup, joinProducer, SqlAstJoinType.INNER);
if (compatibleTableGroup == null) {
final TableGroupJoin tableGroupJoin = joinProducer.createTableGroupJoin(joinedPath.getNavigablePath(), actualParentTableGroup, null, null, false, false, this);
// Implicit joins in the ON clause of attribute joins need to be added as nested table group joins
// We don't have to do that for entity joins etc. as these do not have an inherent dependency on the lhs.
// We can just add the implicit join before the currently processing join
// See consumeEntityJoin for details
final boolean nested = currentClauseStack.getCurrent() == Clause.FROM && currentlyProcessingJoin instanceof SqmAttributeJoin<?, ?>;
if (nested) {
actualParentTableGroup.addNestedTableGroupJoin(tableGroupJoin);
} else {
actualParentTableGroup.addTableGroupJoin(tableGroupJoin);
}
tableGroup = tableGroupJoin.getJoinedGroup();
} else {
tableGroup = compatibleTableGroup;
}
}
fromClauseIndex.register(joinedPath, tableGroup);
registerPluralTableGroupParts(tableGroup);
} else {
tableGroup = null;
}
return tableGroup;
}
use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method consumeCrossJoin.
private TableGroup consumeCrossJoin(SqmCrossJoin<?> sqmJoin, TableGroup lhsTableGroup, boolean transitive) {
final EntityPersister entityDescriptor = resolveEntityPersister(sqmJoin.getReferencedPathSource());
final TableGroup tableGroup = entityDescriptor.createRootTableGroup(true, sqmJoin.getNavigablePath(), sqmJoin.getExplicitAlias(), () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, predicate), this, getCreationContext());
final TableGroupJoin tableGroupJoin = new TableGroupJoin(sqmJoin.getNavigablePath(), SqlAstJoinType.CROSS, tableGroup);
lhsTableGroup.addTableGroupJoin(tableGroupJoin);
getFromClauseIndex().register(sqmJoin, tableGroup);
if (transitive) {
consumeExplicitJoins(sqmJoin, tableGroupJoin.getJoinedGroup());
}
return tableGroup;
}
use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method consumeFromClauseCorrelatedRoot.
protected void consumeFromClauseCorrelatedRoot(SqmRoot<?> sqmRoot) {
log.tracef("Resolving SqmRoot [%s] to TableGroup", sqmRoot);
final FromClauseIndex fromClauseIndex = getFromClauseIndex();
if (fromClauseIndex.isResolved(sqmRoot)) {
log.tracef("Already resolved SqmRoot [%s] to TableGroup", sqmRoot);
}
final QuerySpec currentQuerySpec = currentQuerySpec();
final TableGroup tableGroup;
if (!sqmRoot.isCorrelated()) {
return;
}
final SessionFactoryImplementor sessionFactory = creationContext.getSessionFactory();
if (sqmRoot.containsOnlyInnerJoins()) {
// If we have just inner joins against a correlated root, we can render the joins as references
final SqmFrom<?, ?> from;
// It will always contain just a single correlated join though, which is what is actually correlated
if (sqmRoot instanceof SqmCorrelatedRootJoin<?>) {
assert sqmRoot.getSqmJoins().size() == 1;
assert sqmRoot.getSqmJoins().get(0).isCorrelated();
from = sqmRoot.getSqmJoins().get(0);
} else {
from = sqmRoot;
}
final TableGroup parentTableGroup = fromClauseIndex.findTableGroupOnParents(from.getCorrelationParent().getNavigablePath());
final SqlAliasBase sqlAliasBase = sqlAliasBaseManager.createSqlAliasBase(parentTableGroup.getGroupAlias());
if (parentTableGroup instanceof PluralTableGroup) {
final PluralTableGroup pluralTableGroup = (PluralTableGroup) parentTableGroup;
final CorrelatedPluralTableGroup correlatedPluralTableGroup = new CorrelatedPluralTableGroup(parentTableGroup, sqlAliasBase, currentQuerySpec, predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, predicate), sessionFactory);
final TableGroup elementTableGroup = pluralTableGroup.getElementTableGroup();
if (elementTableGroup != null) {
final TableGroup correlatedElementTableGroup = new CorrelatedTableGroup(elementTableGroup, sqlAliasBase, currentQuerySpec, predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, predicate), sessionFactory);
final TableGroupJoin tableGroupJoin = new TableGroupJoin(elementTableGroup.getNavigablePath(), SqlAstJoinType.INNER, correlatedElementTableGroup);
correlatedPluralTableGroup.registerElementTableGroup(tableGroupJoin);
}
final TableGroup indexTableGroup = pluralTableGroup.getIndexTableGroup();
if (indexTableGroup != null) {
final TableGroup correlatedIndexTableGroup = new CorrelatedTableGroup(indexTableGroup, sqlAliasBase, currentQuerySpec, predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, predicate), sessionFactory);
final TableGroupJoin tableGroupJoin = new TableGroupJoin(indexTableGroup.getNavigablePath(), SqlAstJoinType.INNER, correlatedIndexTableGroup);
correlatedPluralTableGroup.registerIndexTableGroup(tableGroupJoin);
}
tableGroup = correlatedPluralTableGroup;
} else {
tableGroup = new CorrelatedTableGroup(parentTableGroup, sqlAliasBase, currentQuerySpec, predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, predicate), sessionFactory);
}
fromClauseIndex.register(from, tableGroup);
registerPluralTableGroupParts(tableGroup);
log.tracef("Resolved SqmRoot [%s] to correlated TableGroup [%s]", sqmRoot, tableGroup);
consumeExplicitJoins(from, tableGroup);
return;
} else {
final EntityPersister entityDescriptor = resolveEntityPersister(sqmRoot.getReferencedPathSource());
final TableGroup parentTableGroup = fromClauseIndex.findTableGroupOnParents(sqmRoot.getCorrelationParent().getNavigablePath());
// If we have non-inner joins against a correlated root, we must render the root with a correlation predicate
tableGroup = entityDescriptor.createRootTableGroup(true, sqmRoot.getNavigablePath(), sqmRoot.getExplicitAlias(), () -> predicate -> {
}, this, creationContext);
final EntityIdentifierMapping identifierMapping = entityDescriptor.getIdentifierMapping();
final NavigablePath navigablePath = sqmRoot.getNavigablePath().append(identifierMapping.getNavigableRole().getNavigableName());
final int jdbcTypeCount = identifierMapping.getJdbcTypeCount();
if (jdbcTypeCount == 1) {
identifierMapping.forEachSelectable((index, selectable) -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, new ComparisonPredicate(new ColumnReference(parentTableGroup.resolveTableReference(navigablePath, selectable.getContainingTableExpression()), selectable, sessionFactory), ComparisonOperator.EQUAL, new ColumnReference(tableGroup.resolveTableReference(navigablePath, selectable.getContainingTableExpression()), selectable, sessionFactory))));
} else {
final List<Expression> lhs = new ArrayList<>(jdbcTypeCount);
final List<Expression> rhs = new ArrayList<>(jdbcTypeCount);
identifierMapping.forEachSelectable((index, selectable) -> {
lhs.add(new ColumnReference(parentTableGroup.resolveTableReference(navigablePath, selectable.getContainingTableExpression()), selectable, sessionFactory));
rhs.add(new ColumnReference(tableGroup.resolveTableReference(navigablePath, selectable.getContainingTableExpression()), selectable, sessionFactory));
});
additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, new ComparisonPredicate(new SqlTuple(lhs, identifierMapping), ComparisonOperator.EQUAL, new SqlTuple(rhs, identifierMapping)));
}
}
log.tracef("Resolved SqmRoot [%s] to new TableGroup [%s]", sqmRoot, tableGroup);
fromClauseIndex.register(sqmRoot, tableGroup);
currentQuerySpec.getFromClause().addRoot(tableGroup);
consumeJoins(sqmRoot, fromClauseIndex, tableGroup);
}
use of org.hibernate.sql.ast.tree.from.TableGroupJoin in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method addFetch.
public void addFetch(List<Fetch> fetches, FetchParent fetchParent, Fetchable fetchable, Boolean isKeyFetchable) {
final NavigablePath resolvedNavigablePath = fetchParent.resolveNavigablePath(fetchable);
final String alias;
FetchTiming fetchTiming = fetchable.getMappedFetchOptions().getTiming();
boolean joined = false;
EntityGraphTraversalState.TraversalResult traversalResult = null;
final FromClauseIndex fromClauseIndex = getFromClauseIndex();
final SqmAttributeJoin<?, ?> fetchedJoin = fromClauseIndex.findFetchedJoinByPath(resolvedNavigablePath);
boolean explicitFetch = false;
final NavigablePath fetchablePath;
if (fetchedJoin != null) {
fetchablePath = fetchedJoin.getNavigablePath();
// there should be a TableGroupJoin registered for this `fetchablePath` already
assert fromClauseIndex.getTableGroup(fetchedJoin.getNavigablePath()) != null;
if (fetchedJoin.isFetched()) {
fetchTiming = FetchTiming.IMMEDIATE;
}
joined = true;
alias = fetchedJoin.getExplicitAlias();
explicitFetch = true;
} else {
fetchablePath = resolvedNavigablePath;
// there was not an explicit fetch in the SQM
alias = null;
if (!(fetchable instanceof CollectionPart)) {
if (entityGraphTraversalState != null) {
traversalResult = entityGraphTraversalState.traverse(fetchParent, fetchable, isKeyFetchable);
fetchTiming = traversalResult.getFetchTiming();
joined = traversalResult.isJoined();
explicitFetch = true;
} else if (getLoadQueryInfluencers().hasEnabledFetchProfiles()) {
// There is no point in checking the fetch profile if it can't affect this fetchable
if (fetchTiming != FetchTiming.IMMEDIATE || fetchable.incrementFetchDepth()) {
final String fetchableRole = fetchable.getNavigableRole().getFullPath();
for (String enabledFetchProfileName : getLoadQueryInfluencers().getEnabledFetchProfileNames()) {
final FetchProfile enabledFetchProfile = getCreationContext().getSessionFactory().getFetchProfile(enabledFetchProfileName);
final org.hibernate.engine.profile.Fetch profileFetch = enabledFetchProfile.getFetchByRole(fetchableRole);
if (profileFetch != null) {
fetchTiming = FetchTiming.IMMEDIATE;
joined = joined || profileFetch.getStyle() == org.hibernate.engine.profile.Fetch.Style.JOIN;
explicitFetch = true;
if (currentBagRole != null && fetchable instanceof PluralAttributeMapping) {
final CollectionClassification collectionClassification = ((PluralAttributeMapping) fetchable).getMappedType().getCollectionSemantics().getCollectionClassification();
if (collectionClassification == CollectionClassification.BAG) {
// To avoid a MultipleBagFetchException due to fetch profiles in a circular model,
// we skip join fetching in case we encounter an existing bag role
joined = false;
}
}
}
}
}
}
}
// final TableGroup existingJoinedGroup = fromClauseIndex.findTableGroup( fetchablePath );
// if ( existingJoinedGroup != null ) {
// we can use this to trigger the fetch from the joined group.
// todo (6.0) : do we want to do this though?
// On the positive side it would allow EntityGraph to use the existing TableGroup. But that ties in
// to the discussion above regarding how to handle eager and EntityGraph (JOIN versus SELECT).
// Can be problematic if the existing one is restricted
// fetchTiming = FetchTiming.IMMEDIATE;
// }
// lastly, account for any app-defined max-fetch-depth
final Integer maxDepth = getCreationContext().getMaximumFetchDepth();
if (maxDepth != null) {
if (fetchDepth >= maxDepth) {
joined = false;
}
}
if (joined && fetchable instanceof TableGroupJoinProducer) {
TableGroupJoinProducer tableGroupJoinProducer = (TableGroupJoinProducer) fetchable;
fromClauseIndex.resolveTableGroup(fetchablePath, np -> {
// generate the join
final TableGroup lhs = fromClauseIndex.getTableGroup(fetchParent.getNavigablePath());
final TableGroupJoin tableGroupJoin = ((TableGroupJoinProducer) fetchable).createTableGroupJoin(fetchablePath, lhs, alias, tableGroupJoinProducer.getDefaultSqlAstJoinType(lhs), true, false, BaseSqmToSqlAstConverter.this);
lhs.addTableGroupJoin(tableGroupJoin);
return tableGroupJoin.getJoinedGroup();
});
}
}
final boolean incrementFetchDepth = fetchable.incrementFetchDepth();
try {
if (incrementFetchDepth) {
fetchDepth++;
}
// There is no need to check for circular fetches if this is an explicit fetch
if (!explicitFetch && !isResolvingCircularFetch()) {
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(fetchablePath, fetchParent, fetchTiming, this);
if (biDirectionalFetch != null) {
fetches.add(biDirectionalFetch);
return;
}
}
final Fetch fetch = buildFetch(fetchablePath, fetchParent, fetchable, fetchTiming, joined, alias);
if (fetch != null) {
if (fetch.getTiming() == FetchTiming.IMMEDIATE && fetchable instanceof PluralAttributeMapping) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) fetchable;
final CollectionClassification collectionClassification = pluralAttributeMapping.getMappedType().getCollectionSemantics().getCollectionClassification();
if (collectionClassification == CollectionClassification.BAG) {
if (currentBagRole != null) {
throw new MultipleBagFetchException(Arrays.asList(currentBagRole, fetchable.getNavigableRole().getNavigableName()));
}
currentBagRole = fetchable.getNavigableRole().getNavigableName();
}
}
fetches.add(fetch);
}
} finally {
if (incrementFetchDepth) {
fetchDepth--;
}
if (entityGraphTraversalState != null && traversalResult != null) {
entityGraphTraversalState.backtrack(traversalResult);
}
}
}
Aggregations