HHH-17208 Implement support for @Any discriminator and key selection

This commit is contained in:
Marco Belladelli 2023-09-15 16:09:46 +02:00
parent bd5b9b13c4
commit 8629e012f8
11 changed files with 107 additions and 29 deletions

View File

@ -41,6 +41,7 @@ import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.ClassJavaType;
import org.hibernate.type.descriptor.java.JavaType;
@ -334,20 +335,19 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
return FetchTiming.IMMEDIATE;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// NOTE : the following are "unsupported" because handling for any-mapping
// discriminators into SQL AST is handled by outside code. Consolidate
// with `EntityDiscriminatorMapping` to use these contracts for any-mapping
// discriminators as well.
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
throw new UnsupportedOperationException();
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, creationState );
return new BasicResult<>(
sqlSelection.getValuesArrayPosition(),
resultVariable,
jdbcMapping(),
navigablePath
);
}
@Override
@ -356,7 +356,11 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
JdbcMapping jdbcMappingToUse,
TableGroup tableGroup,
SqlAstCreationState creationState) {
throw new UnsupportedOperationException();
return creationState.getSqlExpressionResolver().resolveSqlExpression( tableGroup.resolveTableReference(
navigablePath,
this,
getContainingTableExpression()
), this );
}
@Override
@ -364,7 +368,7 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
throw new UnsupportedOperationException();
resolveSqlSelection( navigablePath, tableGroup, creationState );
}
@Override
@ -373,6 +377,19 @@ public class AnyDiscriminatorPart implements DiscriminatorMapping, FetchOptions
TableGroup tableGroup,
DomainResultCreationState creationState,
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
throw new UnsupportedOperationException();
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, creationState ), getJdbcMapping() );
}
private SqlSelection resolveSqlSelection(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
return sqlAstCreationState.getSqlExpressionResolver().resolveSqlSelection(
resolveSqlExpression( navigablePath, null, tableGroup, sqlAstCreationState ),
jdbcMapping().getJdbcJavaType(),
null,
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory().getTypeConfiguration()
);
}
}

View File

@ -33,6 +33,7 @@ import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchOptions;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.descriptor.java.JavaType;
/**
@ -322,8 +323,13 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
// todo (6.2) : how is this correct?
return anyPart.createDomainResult( navigablePath, tableGroup, resultVariable, creationState );
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, creationState );
return new BasicResult<>(
sqlSelection.getValuesArrayPosition(),
resultVariable,
jdbcMapping,
navigablePath
);
}
@Override
@ -331,8 +337,7 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
// todo (6.2) : how is this correct?
anyPart.applySqlSelections( navigablePath, tableGroup, creationState );
resolveSqlSelection( navigablePath, tableGroup, creationState );
}
@Override
@ -341,7 +346,27 @@ public class AnyKeyPart implements BasicValuedModelPart, FetchOptions {
TableGroup tableGroup,
DomainResultCreationState creationState,
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
// todo (6.2) : how is this correct?
anyPart.applySqlSelections( navigablePath, tableGroup, creationState, selectionConsumer );
selectionConsumer.accept( resolveSqlSelection( navigablePath, tableGroup, creationState ), getJdbcMapping() );
}
private SqlSelection resolveSqlSelection(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
final TableReference tableReference = tableGroup.resolveTableReference(
navigablePath,
this,
getContainingTableExpression()
);
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
return expressionResolver.resolveSqlSelection(
expressionResolver.resolveSqlExpression(
tableReference,
this
),
jdbcMapping.getJdbcJavaType(),
null,
creationState.getSqlAstCreationState().getCreationContext().getSessionFactory().getTypeConfiguration()
);
}
}

View File

@ -336,7 +336,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
}
private static TableGroup getUnderlyingTableGroup(TableGroup tableGroup) {
if ( tableGroup instanceof VirtualTableGroup ) {
if ( tableGroup.isVirtual() ) {
tableGroup = getUnderlyingTableGroup( ( (VirtualTableGroup) tableGroup ).getUnderlyingTableGroup() );
}
return tableGroup;

View File

@ -315,7 +315,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
}
private static TableGroup getUnderlyingTableGroup(TableGroup tableGroup) {
if ( tableGroup instanceof VirtualTableGroup ) {
if ( tableGroup.isVirtual() ) {
tableGroup = getUnderlyingTableGroup( ( (VirtualTableGroup) tableGroup ).getUnderlyingTableGroup() );
}
return tableGroup;

View File

@ -870,7 +870,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private static void verifyManipulationImplicitJoin(TableGroup tableGroup) {
//noinspection StatementWithEmptyBody
if ( !tableGroup.isInitialized() || tableGroup instanceof VirtualTableGroup ) {
if ( !tableGroup.isInitialized() || tableGroup.isVirtual() ) {
// this is fine
}
else {
@ -1244,6 +1244,9 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
if ( !joinedGroup.isInitialized() ) {
continue;
}
else if ( joinedGroup.isVirtual() ) {
return hasJoins( joinedGroup );
}
return true;
}
return false;

View File

@ -17,6 +17,8 @@ import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
public class AnyDiscriminatorPathInterpretation<T> extends AbstractSqmPathInterpretation<T> {
private final Expression expression;
@ -45,7 +47,7 @@ public class AnyDiscriminatorPathInterpretation<T> extends AbstractSqmPathInterp
return new AnyDiscriminatorPathInterpretation<>(
sqmPath.getNavigablePath(),
mapping,
mapping.getDiscriminatorMapping(),
tableGroup,
expression
);

View File

@ -8,6 +8,7 @@ package org.hibernate.query.sqm.sql.internal;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
import org.hibernate.metamodel.mapping.ModelPart;
@ -22,11 +23,12 @@ import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.update.Assignable;
/**
* SqmPathInterpretation for discriminated association (ANY) mappings
*/
public class DiscriminatedAssociationPathInterpretation<T> extends AbstractSqmPathInterpretation<T> implements SqlTupleContainer {
public class DiscriminatedAssociationPathInterpretation<T> extends AbstractSqmPathInterpretation<T> implements SqlTupleContainer, Assignable {
public static <T> DiscriminatedAssociationPathInterpretation<T> from(
SqmAnyValuedSimplePath<T> sqmPath,
@ -86,4 +88,21 @@ public class DiscriminatedAssociationPathInterpretation<T> extends AbstractSqmPa
public SqlTuple getSqlTuple() {
return sqlTuple;
}
@Override
public List<ColumnReference> getColumnReferences() {
final List<ColumnReference> results = new ArrayList<>();
visitColumnReferences( results::add );
return results;
}
@Override
public void visitColumnReferences(Consumer<ColumnReference> columnReferenceConsumer) {
for ( Expression expression : sqlTuple.getExpressions() ) {
if ( !( expression instanceof ColumnReference ) ) {
throw new IllegalArgumentException( "Expecting ColumnReference, found : " + expression );
}
columnReferenceConsumer.accept( (ColumnReference) expression );
}
}
}

View File

@ -1515,7 +1515,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
tableGroupJoin -> {
final TableGroup group = tableGroupJoin.getJoinedGroup();
if ( forUpdateClause.hasAlias( group.getSourceAlias() ) ) {
if ( tableGroupJoin.isInitialized() && tableGroupJoin.getJoinType() != SqlAstJoinType.INNER && !( group instanceof VirtualTableGroup ) ) {
if ( tableGroupJoin.isInitialized() && tableGroupJoin.getJoinType() != SqlAstJoinType.INNER && !group.isVirtual() ) {
if ( Boolean.FALSE.equals( followOnLocking ) ) {
throw new IllegalQueryOperationException(
"Locking with OUTER joins is not supported" );
@ -5233,7 +5233,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
}
private String renderFromClauseRoot(TableGroup root, String separator) {
if ( root instanceof VirtualTableGroup ) {
if ( root.isVirtual() ) {
for ( TableGroupJoin tableGroupJoin : root.getTableGroupJoins() ) {
separator = renderFromClauseRoot( tableGroupJoin.getJoinedGroup(), separator );
}
@ -5382,7 +5382,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
if ( !joinedGroup.isInitialized() ) {
continue;
}
if ( joinedGroup instanceof VirtualTableGroup ) {
if ( joinedGroup.isVirtual() ) {
if ( hasNestedTableGroupsToRender( joinedGroup.getNestedTableGroupJoins() ) ) {
return true;
}
@ -5652,7 +5652,7 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
protected void processTableGroupJoin(TableGroupJoin tableGroupJoin, List<TableGroupJoin> tableGroupJoinCollector) {
final TableGroup joinedGroup = tableGroupJoin.getJoinedGroup();
if ( joinedGroup instanceof VirtualTableGroup ) {
if ( joinedGroup.isVirtual() ) {
processNestedTableGroupJoins( joinedGroup, tableGroupJoinCollector );
if ( tableGroupJoinCollector != null ) {
tableGroupJoinCollector.addAll( joinedGroup.getTableGroupJoins() );

View File

@ -264,7 +264,7 @@ public class FromClause implements SqlAstNode {
private boolean hasJoins(List<TableGroupJoin> tableGroupJoins) {
for ( TableGroupJoin tableGroupJoin : tableGroupJoins ) {
final TableGroup joinedGroup = tableGroupJoin.getJoinedGroup();
if ( joinedGroup instanceof VirtualTableGroup ) {
if ( joinedGroup.isVirtual() ) {
if ( hasJoins( joinedGroup.getTableGroupJoins() ) ) {
return true;
}

View File

@ -202,16 +202,23 @@ public interface TableGroup extends SqlAstNode, ColumnReferenceQualifier, SqmPat
default boolean hasRealJoins() {
for ( TableGroupJoin join : getTableGroupJoins() ) {
final TableGroup joinedGroup = join.getJoinedGroup();
if ( !( joinedGroup instanceof VirtualTableGroup ) || joinedGroup.hasRealJoins() ) {
if ( !joinedGroup.isVirtual() || joinedGroup.hasRealJoins() ) {
return true;
}
}
for ( TableGroupJoin join : getNestedTableGroupJoins() ) {
final TableGroup joinedGroup = join.getJoinedGroup();
if ( !( joinedGroup instanceof VirtualTableGroup ) || joinedGroup.hasRealJoins() ) {
if ( !joinedGroup.isVirtual() || joinedGroup.hasRealJoins() ) {
return true;
}
}
return false;
}
/**
* Utility method that indicates weather this table group is {@linkplain VirtualTableGroup virtual} or not
*/
default boolean isVirtual() {
return false;
}
}

View File

@ -14,4 +14,9 @@ package org.hibernate.sql.ast.tree.from;
*/
public interface VirtualTableGroup extends TableGroup {
TableGroup getUnderlyingTableGroup();
@Override
default boolean isVirtual() {
return true;
}
}