Fix missing table reference issues by translating all SqmRoots and SqmJoins to proper path interpretations
This commit is contained in:
parent
e8d337828b
commit
07f6d31d2b
|
@ -182,6 +182,7 @@ xjc {
|
|||
|
||||
|
||||
task copyBundleResources (type: Copy) {
|
||||
inputs.property( "db", db )
|
||||
ext {
|
||||
bundlesTargetDir = file( "${buildDir}/bundles" )
|
||||
bundleTokens = dbBundle[db]
|
||||
|
|
|
@ -916,6 +916,10 @@ public class ToOneAttributeMapping
|
|||
if ( !canUseParentTableGroup ) {
|
||||
return false;
|
||||
}
|
||||
// Special case for resolving the table group for entity valued paths
|
||||
if ( np == navigablePath ) {
|
||||
return true;
|
||||
}
|
||||
NavigablePath path = np.getParent();
|
||||
// Fast path
|
||||
if ( path != null && navigablePath.equals( path ) ) {
|
||||
|
|
|
@ -47,6 +47,7 @@ import org.hibernate.metamodel.MappingMetamodel;
|
|||
import org.hibernate.metamodel.mapping.Association;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedMapping;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.Bindable;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.ConvertibleModelPart;
|
||||
|
@ -67,6 +68,7 @@ import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
|||
import org.hibernate.metamodel.mapping.ValueMapping;
|
||||
import org.hibernate.metamodel.mapping.internal.EmbeddedCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
||||
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
|
||||
import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
|
||||
|
@ -269,6 +271,7 @@ import org.hibernate.sql.ast.tree.from.LazyTableGroup;
|
|||
import org.hibernate.sql.ast.tree.from.TableGroup;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
|
||||
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
|
||||
import org.hibernate.sql.ast.tree.from.TableReference;
|
||||
import org.hibernate.sql.ast.tree.from.VirtualTableGroup;
|
||||
import org.hibernate.sql.ast.tree.insert.InsertStatement;
|
||||
import org.hibernate.sql.ast.tree.insert.Values;
|
||||
|
@ -464,6 +467,20 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
lastPoppedProcessingState = processingStateStack.pop();
|
||||
}
|
||||
|
||||
private QuerySpec currentQuerySpec() {
|
||||
return currentQueryPart().getLastQuerySpec();
|
||||
}
|
||||
|
||||
private QueryPart currentQueryPart() {
|
||||
final SqlAstQueryPartProcessingState processingState = (SqlAstQueryPartProcessingState) getProcessingStateStack()
|
||||
.getCurrent();
|
||||
return processingState.getInflightQueryPart();
|
||||
}
|
||||
|
||||
protected SqmAliasedNodeCollector currentSqlSelectionCollector() {
|
||||
return (SqmAliasedNodeCollector) getCurrentProcessingState().getSqlExpressionResolver();
|
||||
}
|
||||
|
||||
protected SqmStatement<?> getStatement() {
|
||||
return statement;
|
||||
}
|
||||
|
@ -1732,47 +1749,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return new SqlTuple( expressions, null );
|
||||
}
|
||||
|
||||
final Expression expression = (Expression) groupByClauseExpression.accept( this );
|
||||
// When a join alias is put into the GROUP BY or ORDER BY clause, we have to transform this to interpretations
|
||||
if ( expression instanceof TableGroup ) {
|
||||
final TableGroup tableGroup = (TableGroup) expression;
|
||||
if ( tableGroup.getModelPart() instanceof EmbeddableValuedModelPart ) {
|
||||
final EmbeddableValuedModelPart mapping = (EmbeddableValuedModelPart) tableGroup.getModelPart();
|
||||
return new EmbeddableValuedPathInterpretation<>(
|
||||
mapping.toSqlExpression(
|
||||
tableGroup,
|
||||
getCurrentClauseStack().getCurrent(),
|
||||
this,
|
||||
this
|
||||
),
|
||||
tableGroup.getNavigablePath(),
|
||||
mapping,
|
||||
tableGroup
|
||||
);
|
||||
}
|
||||
else if ( tableGroup.getModelPart() instanceof EntityValuedModelPart ) {
|
||||
final EntityValuedModelPart mapping = (EntityValuedModelPart) tableGroup.getModelPart();
|
||||
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()
|
||||
|| groupByClauseExpression instanceof SqmFrom<?, ?> && selectClauseContains( (SqmFrom<?, ?>) groupByClauseExpression );
|
||||
}
|
||||
else {
|
||||
expandToAllColumns = false;
|
||||
}
|
||||
return EntityValuedPathInterpretation.from(
|
||||
tableGroup.getNavigablePath(),
|
||||
tableGroup,
|
||||
mapping,
|
||||
expandToAllColumns,
|
||||
this
|
||||
);
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
return (Expression) groupByClauseExpression.accept( this );
|
||||
}
|
||||
|
||||
private int indexOfExpression(List<? extends SqmAliasedNode<?>> selections, SqmExpression<?> node) {
|
||||
|
@ -2365,72 +2342,168 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
// handled during `#visitFromClause`
|
||||
|
||||
@Override
|
||||
public TableGroup visitRootPath(SqmRoot<?> sqmRoot) {
|
||||
public Expression visitRootPath(SqmRoot<?> sqmRoot) {
|
||||
final TableGroup resolved = getFromClauseAccess().findTableGroup( sqmRoot.getNavigablePath() );
|
||||
if ( resolved != null ) {
|
||||
log.tracef( "SqmRoot [%s] resolved to existing TableGroup [%s]", sqmRoot, resolved );
|
||||
return resolved;
|
||||
return visitTableGroup( resolved, sqmRoot );
|
||||
}
|
||||
|
||||
throw new InterpretationException( "SqmRoot not yet resolved to TableGroup" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableGroup visitQualifiedAttributeJoin(SqmAttributeJoin<?, ?> sqmJoin) {
|
||||
public Expression visitQualifiedAttributeJoin(SqmAttributeJoin<?, ?> sqmJoin) {
|
||||
// todo (6.0) : have this resolve to TableGroup instead?
|
||||
// - trying to remove tracking of TableGroupJoin in the x-refs
|
||||
|
||||
final TableGroup existing = getFromClauseAccess().findTableGroup( sqmJoin.getNavigablePath() );
|
||||
if ( existing != null ) {
|
||||
log.tracef( "SqmAttributeJoin [%s] resolved to existing TableGroup [%s]", sqmJoin, existing );
|
||||
return existing;
|
||||
return visitTableGroup( existing, sqmJoin );
|
||||
}
|
||||
|
||||
throw new InterpretationException( "SqmAttributeJoin not yet resolved to TableGroup" );
|
||||
}
|
||||
|
||||
private QuerySpec currentQuerySpec() {
|
||||
return currentQueryPart().getLastQuerySpec();
|
||||
}
|
||||
|
||||
private QueryPart currentQueryPart() {
|
||||
final SqlAstQueryPartProcessingState processingState = (SqlAstQueryPartProcessingState) getProcessingStateStack()
|
||||
.getCurrent();
|
||||
return processingState.getInflightQueryPart();
|
||||
}
|
||||
|
||||
protected SqmAliasedNodeCollector currentSqlSelectionCollector() {
|
||||
return (SqmAliasedNodeCollector) getCurrentProcessingState().getSqlExpressionResolver();
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableGroup visitCrossJoin(SqmCrossJoin<?> sqmJoin) {
|
||||
public Expression visitCrossJoin(SqmCrossJoin<?> sqmJoin) {
|
||||
// todo (6.0) : have this resolve to TableGroup instead?
|
||||
// - trying to remove tracking of TableGroupJoin in the x-refs
|
||||
|
||||
final TableGroup existing = getFromClauseAccess().findTableGroup( sqmJoin.getNavigablePath() );
|
||||
if ( existing != null ) {
|
||||
log.tracef( "SqmCrossJoin [%s] resolved to existing TableGroup [%s]", sqmJoin, existing );
|
||||
return existing;
|
||||
return visitTableGroup( existing, sqmJoin );
|
||||
}
|
||||
|
||||
throw new InterpretationException( "SqmCrossJoin not yet resolved to TableGroup" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableGroup visitQualifiedEntityJoin(SqmEntityJoin sqmJoin) {
|
||||
public Expression visitQualifiedEntityJoin(SqmEntityJoin sqmJoin) {
|
||||
// todo (6.0) : have this resolve to TableGroup instead?
|
||||
// - trying to remove tracking of TableGroupJoin in the x-refs
|
||||
|
||||
final TableGroup existing = getFromClauseAccess().findTableGroup( sqmJoin.getNavigablePath() );
|
||||
if ( existing != null ) {
|
||||
log.tracef( "SqmEntityJoin [%s] resolved to existing TableGroup [%s]", sqmJoin, existing );
|
||||
return existing;
|
||||
return visitTableGroup( existing, sqmJoin );
|
||||
}
|
||||
|
||||
throw new InterpretationException( "SqmEntityJoin not yet resolved to TableGroup" );
|
||||
}
|
||||
|
||||
private Expression visitTableGroup(TableGroup tableGroup, SqmFrom<?, ?> path) {
|
||||
final ModelPartContainer modelPart = tableGroup.getModelPart();
|
||||
final ModelPart keyPart;
|
||||
final ModelPart resultPart;
|
||||
if ( modelPart instanceof ToOneAttributeMapping ) {
|
||||
final ToOneAttributeMapping toOneAttributeMapping = (ToOneAttributeMapping) modelPart;
|
||||
keyPart = toOneAttributeMapping.findSubPart( toOneAttributeMapping.getTargetKeyPropertyName() );
|
||||
resultPart = toOneAttributeMapping;
|
||||
}
|
||||
else if ( modelPart instanceof PluralAttributeMapping ) {
|
||||
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) modelPart;
|
||||
final CollectionPart elementDescriptor = pluralAttributeMapping.getElementDescriptor();
|
||||
if ( elementDescriptor instanceof EntityCollectionPart ) {
|
||||
keyPart = ( (EntityCollectionPart) elementDescriptor ).getKeyTargetMatchPart();
|
||||
}
|
||||
else {
|
||||
keyPart = elementDescriptor;
|
||||
}
|
||||
resultPart = elementDescriptor;
|
||||
}
|
||||
else if ( modelPart instanceof EntityCollectionPart ) {
|
||||
keyPart = ( (EntityCollectionPart) modelPart ).getKeyTargetMatchPart();
|
||||
resultPart = modelPart;
|
||||
}
|
||||
else if ( modelPart instanceof EntityMappingType ) {
|
||||
keyPart = ( (EntityMappingType) modelPart ).getIdentifierMapping();
|
||||
resultPart = modelPart;
|
||||
}
|
||||
else {
|
||||
keyPart = modelPart;
|
||||
resultPart = modelPart;
|
||||
}
|
||||
|
||||
final Expression result;
|
||||
if ( resultPart instanceof EntityValuedModelPart ) {
|
||||
final EntityValuedModelPart mapping = (EntityValuedModelPart) tableGroup.getModelPart();
|
||||
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;
|
||||
}
|
||||
result = EntityValuedPathInterpretation.from(
|
||||
tableGroup.getNavigablePath(),
|
||||
tableGroup,
|
||||
mapping,
|
||||
expandToAllColumns,
|
||||
this
|
||||
);
|
||||
}
|
||||
else if ( resultPart instanceof EmbeddableValuedModelPart ) {
|
||||
final EmbeddableValuedModelPart mapping = (EmbeddableValuedModelPart) keyPart;
|
||||
result = new EmbeddableValuedPathInterpretation<>(
|
||||
mapping.toSqlExpression(
|
||||
tableGroup,
|
||||
currentClauseStack.getCurrent(),
|
||||
this,
|
||||
getSqlAstCreationState()
|
||||
),
|
||||
tableGroup.getNavigablePath(),
|
||||
(EmbeddableValuedModelPart) resultPart,
|
||||
tableGroup
|
||||
);
|
||||
}
|
||||
else {
|
||||
assert resultPart instanceof BasicValuedModelPart;
|
||||
final BasicValuedModelPart mapping = (BasicValuedModelPart) keyPart;
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
tableGroup.getNavigablePath().append( keyPart.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,
|
||||
tableGroup.getNavigablePath(),
|
||||
(BasicValuedModelPart) resultPart,
|
||||
tableGroup
|
||||
);
|
||||
}
|
||||
|
||||
return withTreatRestriction( result, path );
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// SqmPath
|
||||
|
|
|
@ -43,7 +43,8 @@ public class BasicValuedPathInterpretation<T> extends AbstractSqmPathInterpretat
|
|||
SqlAstCreationState sqlAstCreationState,
|
||||
SemanticQueryWalker sqmWalker,
|
||||
boolean jpaQueryComplianceEnabled) {
|
||||
TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup( sqmPath.getLhs().getNavigablePath() );
|
||||
final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess()
|
||||
.getTableGroup( sqmPath.getLhs().getNavigablePath() );
|
||||
|
||||
EntityMappingType treatTarget = null;
|
||||
if ( jpaQueryComplianceEnabled ) {
|
||||
|
@ -114,7 +115,7 @@ public class BasicValuedPathInterpretation<T> extends AbstractSqmPathInterpretat
|
|||
|
||||
private final ColumnReference columnReference;
|
||||
|
||||
private BasicValuedPathInterpretation(
|
||||
public BasicValuedPathInterpretation(
|
||||
ColumnReference columnReference,
|
||||
NavigablePath navigablePath,
|
||||
BasicValuedModelPart mapping,
|
||||
|
|
|
@ -37,7 +37,6 @@ import org.hibernate.sql.ast.tree.cte.CteMaterialization;
|
|||
import org.hibernate.sql.ast.tree.cte.CteSearchClauseKind;
|
||||
import org.hibernate.query.FetchClauseType;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.NotYetImplementedFor6Exception;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.AbstractDelegatingWrapperOptions;
|
||||
|
@ -49,16 +48,10 @@ import org.hibernate.internal.util.StringHelper;
|
|||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.internal.util.collections.Stack;
|
||||
import org.hibernate.internal.util.collections.StandardStack;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.SqlExpressable;
|
||||
import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.persister.entity.AbstractEntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.query.ComparisonOperator;
|
||||
|
@ -3500,53 +3493,13 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
@Override
|
||||
public void visitTableGroup(TableGroup tableGroup) {
|
||||
// TableGroup and TableGroup handling should be performed as part of `#visitFromClause`...
|
||||
|
||||
// todo (6.0) : what is the correct behavior here?
|
||||
appendSql( tableGroup.getPrimaryTableReference().getIdentificationVariable() );
|
||||
appendSql( '.' );
|
||||
//TODO: pretty sure the typecast to Loadable is quite wrong here
|
||||
|
||||
ModelPartContainer modelPart = tableGroup.getModelPart();
|
||||
if ( modelPart instanceof Loadable ) {
|
||||
appendSql( ( (Loadable) tableGroup.getModelPart() ).getIdentifierColumnNames()[0] );
|
||||
}
|
||||
else if ( modelPart instanceof PluralAttributeMapping ) {
|
||||
final CollectionPart elementDescriptor = ( (PluralAttributeMapping) modelPart ).getElementDescriptor();
|
||||
if ( elementDescriptor instanceof BasicValuedCollectionPart ) {
|
||||
String mappedColumnExpression = ( (BasicValuedCollectionPart) elementDescriptor ).getSelectionExpression();
|
||||
appendSql( mappedColumnExpression );
|
||||
}
|
||||
else if ( elementDescriptor instanceof EntityCollectionPart ) {
|
||||
final ForeignKeyDescriptor foreignKeyDescriptor = ( (EntityCollectionPart) elementDescriptor ).getForeignKeyDescriptor();
|
||||
if ( foreignKeyDescriptor instanceof SimpleForeignKeyDescriptor ) {
|
||||
foreignKeyDescriptor.visitTargetSelectables(
|
||||
(selectionIndex, selectionMapping) -> appendSql( selectionMapping.getSelectionExpression() )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ( modelPart instanceof ToOneAttributeMapping ) {
|
||||
final ForeignKeyDescriptor foreignKeyDescriptor = ( (ToOneAttributeMapping) modelPart ).getForeignKeyDescriptor();
|
||||
if ( foreignKeyDescriptor instanceof SimpleForeignKeyDescriptor ) {
|
||||
foreignKeyDescriptor.visitTargetSelectables(
|
||||
(selectionIndex, selectionMapping) -> appendSql( selectionMapping.getSelectionExpression() )
|
||||
);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new NotYetImplementedFor6Exception( getClass() );
|
||||
}
|
||||
throw new UnsupportedOperationException( "This should never be invoked as org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitTableGroup should handle this!" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTableGroupJoin(TableGroupJoin tableGroupJoin) {
|
||||
// TableGroup and TableGroupJoin handling should be performed as part of `#visitFromClause`...
|
||||
|
||||
// todo (6.0) : what is the correct behavior here?
|
||||
appendSql( tableGroupJoin.getJoinedGroup().getPrimaryTableReference().getIdentificationVariable() );
|
||||
appendSql( '.' );
|
||||
//TODO: pretty sure the typecast to Loadable is quite wrong here
|
||||
appendSql( ( (Loadable) tableGroupJoin.getJoinedGroup().getModelPart() ).getIdentifierColumnNames()[0] );
|
||||
throw new UnsupportedOperationException( "This should never be invoked as org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter.visitTableGroup should handle this!" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue