Skip to content

Commit 0a5b624

Browse files
committed
Fix treat join issue with one-to-many and make sure table pruning always works. Also fix some issues with union subclass pruning
1 parent 65e2827 commit 0a5b624

File tree

12 files changed

+268
-94
lines changed

12 files changed

+268
-94
lines changed

hibernate-core/src/main/java/org/hibernate/dialect/H2SqlAstTranslator.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@
88

99
import java.util.List;
1010

11+
import org.hibernate.LockMode;
1112
import org.hibernate.engine.spi.SessionFactoryImplementor;
13+
import org.hibernate.internal.util.collections.CollectionHelper;
1214
import org.hibernate.query.sqm.ComparisonOperator;
1315
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
1416
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
@@ -21,6 +23,11 @@
2123
import org.hibernate.sql.ast.tree.expression.SqlTuple;
2224
import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
2325
import org.hibernate.sql.ast.tree.expression.Summarization;
26+
import org.hibernate.sql.ast.tree.from.DerivedTableReference;
27+
import org.hibernate.sql.ast.tree.from.NamedTableReference;
28+
import org.hibernate.sql.ast.tree.from.QueryPartTableReference;
29+
import org.hibernate.sql.ast.tree.from.TableGroup;
30+
import org.hibernate.sql.ast.tree.from.TableReference;
2431
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
2532
import org.hibernate.sql.ast.tree.predicate.InSubQueryPredicate;
2633
import org.hibernate.sql.ast.tree.select.QueryPart;
@@ -156,6 +163,23 @@ public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeti
156163
appendSql( CLOSE_PARENTHESIS );
157164
}
158165

166+
@Override
167+
protected boolean renderPrimaryTableReference(TableGroup tableGroup, LockMode lockMode) {
168+
final TableReference tableRef = tableGroup.getPrimaryTableReference();
169+
// The H2 parser can't handle a sub-query as first element in a nested join
170+
// i.e. `join ( (select ...) alias join ... )`, so we have to introduce a dummy table reference
171+
if ( tableRef instanceof QueryPartTableReference || tableRef.getTableId().startsWith( "(select" ) ) {
172+
final boolean realTableGroup = tableGroup.isRealTableGroup()
173+
&& ( CollectionHelper.isNotEmpty( tableGroup.getTableReferenceJoins() )
174+
|| hasNestedTableGroupsToRender( tableGroup.getNestedTableGroupJoins() ) );
175+
if ( realTableGroup ) {
176+
appendSql( "dual cross join " );
177+
}
178+
}
179+
return super.renderPrimaryTableReference( tableGroup, lockMode );
180+
181+
}
182+
159183
@Override
160184
protected boolean supportsRowValueConstructorSyntax() {
161185
// Just a guess

hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6497,11 +6497,6 @@ public void visitSubTypeAttributeMappings(Consumer<? super AttributeMapping> act
64976497
}
64986498
}
64996499

6500-
protected EntityMappingType getSubclassMappingType(String subclassName) {
6501-
return subclassMappingTypes != null ? subclassMappingTypes.get( subclassName ) : null;
6502-
}
6503-
6504-
65056500
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
65066501
// EntityDefinition impl (walking model - deprecated)
65076502

hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
import org.hibernate.metamodel.mapping.internal.CaseStatementDiscriminatorMappingImpl;
4949
import org.hibernate.metamodel.mapping.internal.MappingModelCreationHelper;
5050
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
51+
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
5152
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
5253
import org.hibernate.persister.spi.PersisterCreationContext;
5354
import org.hibernate.query.spi.NavigablePath;
@@ -1214,16 +1215,13 @@ public <T> DomainResult<T> createDomainResult(
12141215

12151216
@Override
12161217
public void pruneForSubclasses(TableGroup tableGroup, Set<String> treatedEntityNames) {
1217-
// If the base type is part of the treatedEntityNames this means we can't optimize this,
1218-
// as the table group is e.g. returned through a select
1219-
if ( treatedEntityNames.contains( getEntityName() ) ) {
1220-
return;
1221-
}
12221218
final Set<TableReference> retainedTableReferences = new HashSet<>( treatedEntityNames.size() );
12231219
final Set<String> sharedSuperclassTables = new HashSet<>();
1220+
final MappingMetamodelImplementor metamodel = getFactory().getRuntimeMetamodels().getMappingMetamodel();
12241221

12251222
for ( String treatedEntityName : treatedEntityNames ) {
1226-
final JoinedSubclassEntityPersister subPersister = (JoinedSubclassEntityPersister) getSubclassMappingType( treatedEntityName );
1223+
final JoinedSubclassEntityPersister subPersister =
1224+
(JoinedSubclassEntityPersister) metamodel.findEntityDescriptor( treatedEntityName );
12271225
final String[] subclassTableNames = subPersister.getSubclassTableNames();
12281226
// For every treated entity name, we collect table names that are needed by all treated entity names
12291227
// In mathematical terms, sharedSuperclassTables will be the "intersection" of the table names of all treated entities

hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -880,11 +880,6 @@ else if ( discriminatorValue == DiscriminatorHelper.NOT_NULL_DISCRIMINATOR ) {
880880

881881
@Override
882882
public void pruneForSubclasses(TableGroup tableGroup, Set<String> treatedEntityNames) {
883-
// If the base type is part of the treatedEntityNames this means we can't optimize this,
884-
// as the table group is e.g. returned through a select
885-
if ( treatedEntityNames.contains( getEntityName() ) ) {
886-
return;
887-
}
888883
// The optimization is to simply add the discriminator filter fragment for all treated entity names
889884
final NamedTableReference tableReference = (NamedTableReference) tableGroup.getPrimaryTableReference();
890885
tableReference.setPrunedTableExpression(

hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,10 @@
4040
import org.hibernate.mapping.Subclass;
4141
import org.hibernate.mapping.Table;
4242
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
43+
import org.hibernate.metamodel.mapping.SelectableConsumer;
4344
import org.hibernate.metamodel.mapping.SelectableMapping;
4445
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
46+
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
4547
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
4648
import org.hibernate.persister.spi.PersisterCreationContext;
4749
import org.hibernate.query.spi.NavigablePath;
@@ -382,11 +384,6 @@ protected boolean hasMultipleTables() {
382384

383385
@Override
384386
public void pruneForSubclasses(TableGroup tableGroup, Set<String> treatedEntityNames) {
385-
// If the base type is part of the treatedEntityNames this means we can't optimize this,
386-
// as the table group is e.g. returned through a select
387-
if ( treatedEntityNames.contains( getEntityName() ) ) {
388-
return;
389-
}
390387
final NamedTableReference tableReference = (NamedTableReference) tableGroup.resolveTableReference( getRootTableName() );
391388
// Replace the default union sub-query with a specially created one that only selects the tables for the treated entity names
392389
tableReference.setPrunedTableExpression( generateSubquery( treatedEntityNames ) );
@@ -496,33 +493,40 @@ protected String generateSubquery(Set<String> treated) {
496493
}
497494

498495
final Dialect dialect = getFactory().getJdbcServices().getDialect();
496+
final MappingMetamodelImplementor metamodel = getFactory().getRuntimeMetamodels().getMappingMetamodel();
499497

500498
// Collect all selectables of every entity subtype and group by selection expression as well as table name
501499
final LinkedHashMap<String, Map<String, SelectableMapping>> selectables = new LinkedHashMap<>();
502-
visitSubTypeAttributeMappings(
503-
attributeMapping -> attributeMapping.forEachSelectable(
504-
(i, selectable) -> selectables.computeIfAbsent( selectable.getSelectionExpression(), k -> new HashMap<>() )
505-
.put( selectable.getContainingTableExpression(), selectable )
506-
)
507-
);
500+
final SelectableConsumer selectableConsumer = (i, selectable) -> {
501+
selectables.computeIfAbsent( selectable.getSelectionExpression(), k -> new HashMap<>() )
502+
.put( selectable.getContainingTableExpression(), selectable );
503+
};
508504
// Collect the concrete subclass table names for the treated entity names
509505
final Set<String> treatedTableNames = new HashSet<>( treated.size() );
510506
for ( String subclassName : treated ) {
511507
final UnionSubclassEntityPersister subPersister =
512-
(UnionSubclassEntityPersister) getSubclassMappingType( subclassName );
508+
(UnionSubclassEntityPersister) metamodel.getEntityDescriptor( subclassName );
513509
for ( String subclassTableName : subPersister.getSubclassTableNames() ) {
514510
if ( ArrayHelper.indexOf( subclassSpaces, subclassTableName ) != -1 ) {
515511
treatedTableNames.add( subclassTableName );
516512
}
517513
}
514+
subPersister.getIdentifierMapping().forEachSelectable( selectableConsumer );
515+
if ( subPersister.getVersionMapping() != null ) {
516+
subPersister.getVersionMapping().forEachSelectable( selectableConsumer );
517+
}
518+
subPersister.visitSubTypeAttributeMappings(
519+
attributeMapping -> attributeMapping.forEachSelectable( selectableConsumer )
520+
);
518521
}
519522

520523
// Create a union sub-query for the table names, like generateSubquery(PersistentClass model, Mapping mapping)
521524
final StringBuilder buf = new StringBuilder( subquery.length() )
522525
.append( "( " );
523526

524-
for ( int i = 0; i < subclassTableNames.length; i++ ) {
525-
final String subclassTableName = subclassTableNames[i];
527+
for ( String name : getEntityMetamodel().getSubclassEntityNames() ) {
528+
final AbstractEntityPersister persister = (AbstractEntityPersister) metamodel.findEntityDescriptor( name );
529+
final String subclassTableName = persister.getTableName();
526530
if ( treatedTableNames.contains( subclassTableName ) ) {
527531
buf.append( "select " );
528532
for ( Map<String, SelectableMapping> selectableMappings : selectables.values() ) {
@@ -540,7 +544,7 @@ protected String generateSubquery(Set<String> treated) {
540544
);
541545
buf.append( ", " );
542546
}
543-
buf.append( i ).append( " as clazz_" );
547+
buf.append( persister.getDiscriminatorSQLValue() ).append( " as clazz_" );
544548
buf.append( " from " ).append( subclassTableName );
545549
buf.append( " union " );
546550
if ( dialect.supportsUnionAll() ) {

hibernate-core/src/main/java/org/hibernate/query/sqm/function/SelfRenderingSqmAggregateFunction.java

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@
2121
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
2222
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
2323
import org.hibernate.sql.ast.tree.SqlAstNode;
24-
import org.hibernate.sql.ast.tree.predicate.Predicate;
2524

2625
/**
2726
* @author Christian Beikov
@@ -88,7 +87,7 @@ public SelfRenderingFunctionSqlAstExpression convertToSqlAst(SqmToSqlAstConverte
8887
getFunctionName(),
8988
getRenderingSupport(),
9089
resolveSqlAstArguments( getArguments(), walker ),
91-
filter == null ? null : (Predicate) filter.accept( walker ),
90+
filter == null ? null : walker.visitNestedTopLevelPredicate( filter ),
9291
resultType,
9392
getMappingModelExpressible( walker, resultType )
9493
);

0 commit comments

Comments
 (0)