HHH-16733 Use existing SQM copy logic in QuerySplitter

This commit is contained in:
Marco Belladelli 2023-06-05 13:05:05 +02:00
parent bf422bed95
commit fc852f466b
21 changed files with 161 additions and 1342 deletions

View File

@ -0,0 +1,33 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.internal;
import java.util.IdentityHashMap;
import org.hibernate.query.sqm.tree.SqmCopyContext;
/**
* @author Marco Belladelli
*/
public class SimpleSqmCopyContext implements SqmCopyContext {
private final IdentityHashMap<Object, Object> map = new IdentityHashMap<>();
@Override
@SuppressWarnings( "unchecked" )
public <T> T getCopy(T original) {
return (T) map.get( original );
}
@Override
public <T> T registerCopy(T original, T copy) {
final Object old = map.put( original, copy );
if ( old != null ) {
throw new IllegalArgumentException( "Already registered a copy: " + old );
}
return copy;
}
}

View File

@ -6,9 +6,7 @@
*/ */
package org.hibernate.query.sqm.tree; package org.hibernate.query.sqm.tree;
import java.util.IdentityHashMap; import org.hibernate.query.sqm.internal.SimpleSqmCopyContext;
import org.hibernate.query.sqm.tree.domain.SqmPath;
/** /**
* *
@ -20,54 +18,6 @@ public interface SqmCopyContext {
<T> T registerCopy(T original, T copy); <T> T registerCopy(T original, T copy);
static SqmCopyContext simpleContext() { static SqmCopyContext simpleContext() {
final IdentityHashMap<Object, Object> map = new IdentityHashMap<>(); return new SimpleSqmCopyContext();
return new SqmCopyContext() {
@Override
@SuppressWarnings("unchecked")
public <T> T getCopy(T original) {
if (original instanceof SqmPath) {
return (T) getPathCopy( (SqmPath<?>) original );
}
else {
return (T) map.get( original );
}
}
@Override
public <T> T registerCopy(T original, T copy) {
final Object old = map.put( original, copy );
if ( old != null ) {
throw new IllegalArgumentException( "Already registered a copy: " + old );
}
return copy;
}
@SuppressWarnings("unchecked")
private <T extends SqmPath<?>> T getPathCopy(T original) {
T existing = (T) map.get( original );
if ( existing != null ) {
return existing;
}
SqmPath<?> root = getRoot( original );
if ( root != original ) {
root.copy( this );
// root path might have already copied original
return (T) map.get( original );
}
else {
return null;
}
}
private SqmPath<?> getRoot(SqmPath<?> path) {
if ( path.getLhs() != null ) {
return getRoot( path.getLhs() );
}
else {
return path;
}
}
};
} }
} }

View File

@ -13,6 +13,8 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.function.Consumer; import java.util.function.Consumer;
import org.hibernate.internal.util.NullnessUtil;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
@ -56,6 +58,8 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
} }
protected void copyTo(AbstractSqmPath<T> target, SqmCopyContext context) { protected void copyTo(AbstractSqmPath<T> target, SqmCopyContext context) {
assert lhs == null || lhs.getNavigablePath() == target.getLhs().getNavigablePath()
|| getRoot( lhs ).getNodeType() instanceof SqmPolymorphicRootDescriptor;
super.copyTo( target, context ); super.copyTo( target, context );
if ( reusablePaths != null ) { if ( reusablePaths != null ) {
target.reusablePaths = new HashMap<>( reusablePaths.size() ); target.reusablePaths = new HashMap<>( reusablePaths.size() );
@ -65,6 +69,10 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
} }
} }
private SqmPath<?> getRoot(SqmPath<?> lhs) {
return lhs.getLhs() == null ? lhs : getRoot( lhs.getLhs() );
}
@Override @Override
public SqmPathSource<T> getNodeType() { public SqmPathSource<T> getNodeType() {
return (SqmPathSource<T>) super.getNodeType(); return (SqmPathSource<T>) super.getNodeType();
@ -212,6 +220,28 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
return path; return path;
} }
/**
* Utility that checks if this path's parent navigable path is compatible with the specified SQM parent,
* and if not creates a copy of the navigable path with the correct parent.
*/
protected NavigablePath getNavigablePathCopy(SqmPath<?> parent) {
final NavigablePath parentNavigablePath = NullnessUtil.castNonNull( navigablePath.getRealParent() );
if ( parent.getNavigablePath() == parentNavigablePath ) {
return navigablePath;
}
else if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getLocalName() ) != null ) {
if ( parent.getNavigablePath() == parentNavigablePath.getRealParent() ) {
return navigablePath;
}
else {
return parent.getNavigablePath()
.append( parentNavigablePath.getLocalName() )
.append( navigablePath.getLocalName(), navigablePath.getAlias() );
}
}
return parent.getNavigablePath().append( navigablePath.getLocalName(), navigablePath.getAlias() );
}
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <Y> SqmPath<Y> get(SingularAttribute<? super T, Y> jpaAttribute) { public <Y> SqmPath<Y> get(SingularAttribute<? super T, Y> jpaAttribute) {

View File

@ -39,12 +39,13 @@ public class NonAggregatedCompositeSimplePath<T> extends SqmEntityValuedSimplePa
return existing; return existing;
} }
final SqmPath<?> lhsCopy = getLhs().copy( context );
final NonAggregatedCompositeSimplePath<T> path = context.registerCopy( final NonAggregatedCompositeSimplePath<T> path = context.registerCopy(
this, this,
new NonAggregatedCompositeSimplePath<>( new NonAggregatedCompositeSimplePath<>(
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getReferencedPathSource(), getReferencedPathSource(),
getLhs().copy( context ), lhsCopy,
nodeBuilder() nodeBuilder()
) )
); );

View File

@ -49,12 +49,13 @@ public class SqmAnyValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
return existing; return existing;
} }
final SqmPath<?> lhsCopy = getLhs().copy( context );
final SqmAnyValuedSimplePath<T> path = context.registerCopy( final SqmAnyValuedSimplePath<T> path = context.registerCopy(
this, this,
new SqmAnyValuedSimplePath<>( new SqmAnyValuedSimplePath<>(
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getReferencedPathSource(), getReferencedPathSource(),
getLhs().copy( context ), lhsCopy,
getExplicitAlias(), getExplicitAlias(),
nodeBuilder() nodeBuilder()
) )

View File

@ -56,11 +56,12 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmFrom<?, O> lhsCopy = getLhs().copy( context );
final SqmBagJoin<O, E> path = context.registerCopy( final SqmBagJoin<O, E> path = context.registerCopy(
this, this,
new SqmBagJoin<>( new SqmBagJoin<>(
getLhs().copy( context ), lhsCopy,
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getAttribute(), getAttribute(),
getExplicitAlias(), getExplicitAlias(),
getSqmJoinType(), getSqmJoinType(),

View File

@ -49,12 +49,13 @@ public class SqmBasicValuedSimplePath<T>
return existing; return existing;
} }
final SqmPath<?> lhsCopy = getLhs().copy( context );
final SqmBasicValuedSimplePath<T> path = context.registerCopy( final SqmBasicValuedSimplePath<T> path = context.registerCopy(
this, this,
new SqmBasicValuedSimplePath<>( new SqmBasicValuedSimplePath<>(
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getReferencedPathSource(), getReferencedPathSource(),
getLhs().copy( context ), lhsCopy,
getExplicitAlias(), getExplicitAlias(),
nodeBuilder() nodeBuilder()
) )

View File

@ -53,12 +53,13 @@ public class SqmEmbeddedValuedSimplePath<T>
return existing; return existing;
} }
final SqmPath<?> lhsCopy = getLhs().copy( context );
final SqmEmbeddedValuedSimplePath<T> path = context.registerCopy( final SqmEmbeddedValuedSimplePath<T> path = context.registerCopy(
this, this,
new SqmEmbeddedValuedSimplePath<>( new SqmEmbeddedValuedSimplePath<>(
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getReferencedPathSource(), getReferencedPathSource(),
getLhs().copy( context ), lhsCopy,
getExplicitAlias(), getExplicitAlias(),
nodeBuilder() nodeBuilder()
) )

View File

@ -34,12 +34,13 @@ public class SqmEntityValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
return existing; return existing;
} }
final SqmPath<?> lhsCopy = getLhs().copy( context );
final SqmEntityValuedSimplePath<T> path = context.registerCopy( final SqmEntityValuedSimplePath<T> path = context.registerCopy(
this, this,
new SqmEntityValuedSimplePath<>( new SqmEntityValuedSimplePath<>(
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getReferencedPathSource(), getReferencedPathSource(),
getLhs().copy( context ), lhsCopy,
nodeBuilder() nodeBuilder()
) )
); );

View File

@ -42,11 +42,12 @@ public class SqmIndexedCollectionAccessPath<T> extends AbstractSqmPath<T> implem
return existing; return existing;
} }
final SqmPath<?> lhsCopy = getLhs().copy( context );
final SqmIndexedCollectionAccessPath<T> path = context.registerCopy( final SqmIndexedCollectionAccessPath<T> path = context.registerCopy(
this, this,
new SqmIndexedCollectionAccessPath<T>( new SqmIndexedCollectionAccessPath<T>(
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getLhs().copy( context ), lhsCopy,
selectorExpression.copy( context ) selectorExpression.copy( context )
) )
); );

View File

@ -59,11 +59,12 @@ public class SqmListJoin<O,E>
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmFrom<?, O> lhsCopy = getLhs().copy( context );
final SqmListJoin<O, E> path = context.registerCopy( final SqmListJoin<O, E> path = context.registerCopy(
this, this,
new SqmListJoin<>( new SqmListJoin<>(
getLhs().copy( context ), lhsCopy,
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getAttribute(), getAttribute(),
getExplicitAlias(), getExplicitAlias(),
getSqmJoinType(), getSqmJoinType(),

View File

@ -58,11 +58,12 @@ public class SqmMapJoin<O, K, V>
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmFrom<?, O> lhsCopy = getLhs().copy( context );
final SqmMapJoin<O, K, V> path = context.registerCopy( final SqmMapJoin<O, K, V> path = context.registerCopy(
this, this,
new SqmMapJoin<>( new SqmMapJoin<>(
getLhs().copy( context ), lhsCopy,
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getAttribute(), getAttribute(),
getExplicitAlias(), getExplicitAlias(),
getSqmJoinType(), getSqmJoinType(),

View File

@ -64,11 +64,12 @@ public class SqmPluralPartJoin<O,T> extends AbstractSqmJoin<O,T> implements SqmQ
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmFrom<?, O> lhsCopy = (SqmFrom<?, O>) getLhs().copy( context );
final SqmPluralPartJoin<O, T> path = context.registerCopy( final SqmPluralPartJoin<O, T> path = context.registerCopy(
this, this,
new SqmPluralPartJoin<>( new SqmPluralPartJoin<>(
(SqmFrom<?, O>) getLhs().copy( context ), lhsCopy,
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getReferencedPathSource(), getReferencedPathSource(),
getExplicitAlias(), getExplicitAlias(),
getSqmJoinType(), getSqmJoinType(),

View File

@ -56,12 +56,13 @@ public class SqmPluralValuedSimplePath<E> extends AbstractSqmSimplePath<E> {
return existing; return existing;
} }
final SqmPath<?> lhsCopy = getLhs().copy( context );
final SqmPluralValuedSimplePath<E> path = context.registerCopy( final SqmPluralValuedSimplePath<E> path = context.registerCopy(
this, this,
new SqmPluralValuedSimplePath<>( new SqmPluralValuedSimplePath<>(
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getReferencedPathSource(), getReferencedPathSource(),
getLhs().copy( context ), lhsCopy,
getExplicitAlias(), getExplicitAlias(),
nodeBuilder() nodeBuilder()
) )

View File

@ -58,11 +58,12 @@ public class SqmSetJoin<O, E>
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmFrom<?, O> lhsCopy = getLhs().copy( context );
final SqmSetJoin<O, E> path = context.registerCopy( final SqmSetJoin<O, E> path = context.registerCopy(
this, this,
new SqmSetJoin<>( new SqmSetJoin<>(
getLhs().copy( context ), lhsCopy,
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getModel(), getModel(),
getExplicitAlias(), getExplicitAlias(),
getSqmJoinType(), getSqmJoinType(),

View File

@ -67,11 +67,12 @@ public class SqmSingularJoin<O,T> extends AbstractSqmAttributeJoin<O,T> {
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmFrom<?, O> lhsCopy = getLhs().copy( context );
final SqmSingularJoin<O, T> path = context.registerCopy( final SqmSingularJoin<O, T> path = context.registerCopy(
this, this,
new SqmSingularJoin<>( new SqmSingularJoin<>(
getLhs().copy( context ), lhsCopy,
getNavigablePath(), getNavigablePathCopy( lhsCopy ),
getAttribute(), getAttribute(),
getExplicitAlias(), getExplicitAlias(),
getSqmJoinType(), getSqmJoinType(),

View File

@ -61,13 +61,14 @@ public class SqmCrossJoin<T> extends AbstractSqmFrom<T, T> implements JpaCrossJo
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmRoot<?> rootCopy = getRoot().copy( context );
final SqmCrossJoin<T> path = context.registerCopy( final SqmCrossJoin<T> path = context.registerCopy(
this, this,
new SqmCrossJoin<>( new SqmCrossJoin<>(
getNavigablePath(), getNavigablePathCopy( rootCopy ),
getReferencedPathSource(), getReferencedPathSource(),
getExplicitAlias(), getExplicitAlias(),
sqmRoot.copy( context ) rootCopy
) )
); );
copyTo( path, context ); copyTo( path, context );

View File

@ -91,16 +91,17 @@ public class SqmDerivedJoin<T> extends AbstractSqmQualifiedJoin<T, T> implements
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmRoot<?> rootCopy = findRoot().copy( context );
final SqmDerivedJoin<T> path = context.registerCopy( final SqmDerivedJoin<T> path = context.registerCopy(
this, this,
new SqmDerivedJoin<>( new SqmDerivedJoin<>(
getNavigablePath(), getNavigablePathCopy( rootCopy ),
subQuery, subQuery,
lateral, lateral,
getReferencedPathSource(), getReferencedPathSource(),
getExplicitAlias(), getExplicitAlias(),
getSqmJoinType(), getSqmJoinType(),
findRoot().copy( context ) rootCopy
) )
); );
copyTo( path, context ); copyTo( path, context );

View File

@ -65,14 +65,15 @@ public class SqmEntityJoin<T> extends AbstractSqmQualifiedJoin<T, T> implements
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmRoot<?> rootCopy = getRoot().copy( context );
final SqmEntityJoin<T> path = context.registerCopy( final SqmEntityJoin<T> path = context.registerCopy(
this, this,
new SqmEntityJoin<>( new SqmEntityJoin<>(
getNavigablePath(), getNavigablePathCopy( rootCopy ),
getReferencedPathSource(), getReferencedPathSource(),
getExplicitAlias(), getExplicitAlias(),
getSqmJoinType(), getSqmJoinType(),
getRoot().copy( context ) rootCopy
) )
); );
copyTo( path, context ); copyTo( path, context );

View File

@ -9,6 +9,7 @@ package org.hibernate.query.sqm.tree.from;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import org.hibernate.Internal;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.PathException; import org.hibernate.query.PathException;
@ -87,7 +88,8 @@ public class SqmRoot<E> extends AbstractSqmFrom<E,E> implements JpaRoot<E> {
return path; return path;
} }
protected void copyTo(SqmRoot<E> target, SqmCopyContext context) { @Internal
public void copyTo(SqmRoot<E> target, SqmCopyContext context) {
super.copyTo( target, context ); super.copyTo( target, context );
if ( orderedJoins != null ) { if ( orderedJoins != null ) {
target.orderedJoins = new ArrayList<>( orderedJoins.size() ); target.orderedJoins = new ArrayList<>( orderedJoins.size() );