use of org.hibernate.query.spi.NavigablePath 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);
}
}
}
use of org.hibernate.query.spi.NavigablePath in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitInsertSelectStatement.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Insert-select statement
@Override
public InsertStatement visitInsertSelectStatement(SqmInsertSelectStatement<?> sqmStatement) {
final CteContainer cteContainer = this.visitCteContainer(sqmStatement);
final String entityName = sqmStatement.getTarget().getEntityName();
final EntityPersister entityDescriptor = creationContext.getSessionFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(entityName);
assert entityDescriptor != null;
SqmQueryPart<?> selectQueryPart = sqmStatement.getSelectQueryPart();
pushProcessingState(new SqlAstProcessingStateImpl(null, this, r -> new SqmAliasedNodePositionTracker(r, selectQueryPart.getFirstQuerySpec().getSelectClause().getSelections()), getCurrentClauseStack()::getCurrent));
currentClauseStack.push(Clause.INSERT);
final InsertStatement insertStatement;
final AdditionalInsertValues additionalInsertValues;
try {
final NavigablePath rootPath = sqmStatement.getTarget().getNavigablePath();
final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup(true, rootPath, sqmStatement.getTarget().getExplicitAlias(), () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, predicate), this, getCreationContext());
getFromClauseAccess().registerTableGroup(rootPath, rootTableGroup);
insertStatement = new InsertStatement(cteContainer, (NamedTableReference) rootTableGroup.getPrimaryTableReference(), Collections.emptyList());
additionalInsertValues = visitInsertionTargetPaths((assigable, references) -> insertStatement.addTargetColumnReferences(references), sqmStatement, entityDescriptor, rootTableGroup);
if (!rootTableGroup.getTableReferenceJoins().isEmpty() || !rootTableGroup.getTableGroupJoins().isEmpty()) {
throw new SemanticException("Not expecting multiple table references for an SQM INSERT-SELECT");
}
} finally {
popProcessingStateStack();
currentClauseStack.pop();
}
insertStatement.setSourceSelectStatement(visitQueryPart(selectQueryPart));
insertStatement.getSourceSelectStatement().visitQuerySpecs(querySpec -> {
final boolean appliedRowNumber = additionalInsertValues.applySelections(querySpec, creationContext.getSessionFactory());
// If this requires the special row number handling, it should use the mutation strategy
assert !appliedRowNumber;
});
return insertStatement;
}
use of org.hibernate.query.spi.NavigablePath in project hibernate-orm by hibernate.
the class BaseSqmToSqlAstConverter method visitUpdateStatement.
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Update statement
@Override
public UpdateStatement visitUpdateStatement(SqmUpdateStatement<?> sqmStatement) {
final CteContainer cteContainer = this.visitCteContainer(sqmStatement);
final SqmRoot<?> sqmTarget = sqmStatement.getTarget();
final String entityName = sqmTarget.getEntityName();
final EntityPersister entityDescriptor = getCreationContext().getSessionFactory().getRuntimeMetamodels().getMappingMetamodel().getEntityDescriptor(entityName);
assert entityDescriptor != null;
pushProcessingState(new SqlAstProcessingStateImpl(getCurrentProcessingState(), this, getCurrentClauseStack()::getCurrent));
try {
final NavigablePath rootPath = sqmTarget.getNavigablePath();
final TableGroup rootTableGroup = entityDescriptor.createRootTableGroup(true, rootPath, sqmStatement.getRoot().getAlias(), () -> predicate -> additionalRestrictions = SqlAstTreeHelper.combinePredicates(additionalRestrictions, predicate), this, getCreationContext());
if (!rootTableGroup.getTableReferenceJoins().isEmpty()) {
throw new HibernateException("Not expecting multiple table references for an SQM UPDATE");
}
if (sqmTarget.hasJoins()) {
throw new HibernateException("SQM UPDATE does not support explicit joins");
}
getFromClauseAccess().registerTableGroup(rootPath, rootTableGroup);
final List<Assignment> assignments = visitSetClause(sqmStatement.getSetClause());
addVersionedAssignment(assignments::add, sqmStatement);
FilterHelper.applyBaseRestrictions((filterPredicate) -> additionalRestrictions = filterPredicate, entityDescriptor, rootTableGroup, AbstractSqlAstTranslator.rendersTableReferenceAlias(Clause.UPDATE), getLoadQueryInfluencers(), this);
Predicate suppliedPredicate = null;
final SqmWhereClause whereClause = sqmStatement.getWhereClause();
if (whereClause != null) {
suppliedPredicate = visitWhereClause(whereClause.getPredicate());
}
return new UpdateStatement(cteContainer, (NamedTableReference) rootTableGroup.getPrimaryTableReference(), assignments, SqlAstTreeHelper.combinePredicates(suppliedPredicate, additionalRestrictions), Collections.emptyList());
} finally {
popProcessingStateStack();
}
}
use of org.hibernate.query.spi.NavigablePath in project hibernate-orm by hibernate.
the class BasicValuedCollectionPart method resolveSqlSelection.
private SqlSelection resolveSqlSelection(NavigablePath navigablePath, TableGroup tableGroup, boolean allowFkOptimization, DomainResultCreationState creationState) {
final SqlExpressionResolver exprResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
final TableGroup targetTableGroup;
// into the element table group though because the element table group navigable path is not the parent of this navigable path
if (nature == Nature.INDEX && collectionDescriptor.getAttributeMapping().getIndexMetadata().getIndexPropertyName() != null) {
targetTableGroup = ((PluralTableGroup) tableGroup).getElementTableGroup();
} else {
targetTableGroup = tableGroup;
}
final TableReference tableReference = targetTableGroup.resolveTableReference(navigablePath, getContainingTableExpression(), allowFkOptimization);
return exprResolver.resolveSqlSelection(exprResolver.resolveSqlExpression(SqlExpressionResolver.createColumnReferenceKey(tableReference, selectableMapping.getSelectionExpression()), sqlAstProcessingState -> new ColumnReference(tableReference, selectableMapping, creationState.getSqlAstCreationState().getCreationContext().getSessionFactory())), getJavaType(), creationState.getSqlAstCreationState().getCreationContext().getSessionFactory().getTypeConfiguration());
}
use of org.hibernate.query.spi.NavigablePath in project hibernate-orm by hibernate.
the class BasicValuedCollectionPart method generateFetch.
@Override
public Fetch generateFetch(FetchParent fetchParent, NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, String resultVariable, DomainResultCreationState creationState) {
ResultsLogger.LOGGER.debugf("Generating Fetch for collection-part : `%s` -> `%s`", collectionDescriptor.getRole(), nature.getName());
NavigablePath parentNavigablePath = fetchablePath.getParent();
if (parentNavigablePath instanceof EntityIdentifierNavigablePath) {
parentNavigablePath = parentNavigablePath.getParent();
}
final TableGroup tableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().findTableGroup(parentNavigablePath);
final SqlSelection sqlSelection = resolveSqlSelection(fetchablePath, tableGroup, true, creationState);
return new BasicFetch<>(sqlSelection.getValuesArrayPosition(), fetchParent, fetchablePath, this, valueConverter, FetchTiming.IMMEDIATE, creationState);
}
Aggregations