Copy DomainParameterXref on demand instead of recreating to avoid instance mismatch with ParameterMetadata

This commit is contained in:
Christian Beikov 2022-01-31 11:39:26 +01:00
parent 1e823386f6
commit de0dd8cda3
4 changed files with 44 additions and 30 deletions

View File

@ -39,7 +39,7 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
*/ */
private final BoundedConcurrentHashMap<Key, QueryPlan> queryPlanCache; private final BoundedConcurrentHashMap<Key, QueryPlan> queryPlanCache;
private final BoundedConcurrentHashMap<String, ImmutableHqlInterpretation> hqlInterpretationCache; private final BoundedConcurrentHashMap<String, HqlInterpretation> hqlInterpretationCache;
private final BoundedConcurrentHashMap<String, ParameterInterpretation> nativeQueryParamCache; private final BoundedConcurrentHashMap<String, ParameterInterpretation> nativeQueryParamCache;
private final Supplier<StatisticsImplementor> statisticsSupplier; private final Supplier<StatisticsImplementor> statisticsSupplier;
@ -108,8 +108,8 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
final long startTime = ( stats ) ? System.nanoTime() : 0L; final long startTime = ( stats ) ? System.nanoTime() : 0L;
final DomainParameterXref domainParameterXref; final DomainParameterXref domainParameterXref;
ImmutableHqlInterpretation immutableHqlInterpretation = hqlInterpretationCache.get( queryString ); HqlInterpretation hqlInterpretation = hqlInterpretationCache.get( queryString );
if ( immutableHqlInterpretation == null ) { if ( hqlInterpretation == null ) {
log.debugf( "Creating and caching HqlInterpretation - %s", queryString ); log.debugf( "Creating and caching HqlInterpretation - %s", queryString );
final SqmStatement<?> sqmStatement = creator.apply( queryString ); final SqmStatement<?> sqmStatement = creator.apply( queryString );
final ParameterMetadataImplementor parameterMetadata; final ParameterMetadataImplementor parameterMetadata;
@ -123,8 +123,8 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() ); parameterMetadata = new ParameterMetadataImpl( domainParameterXref.getQueryParameters() );
} }
immutableHqlInterpretation = new ImmutableHqlInterpretation( sqmStatement, parameterMetadata); hqlInterpretation = new SimpleHqlInterpretationImpl( sqmStatement, parameterMetadata, domainParameterXref );
hqlInterpretationCache.put( queryString, immutableHqlInterpretation ); hqlInterpretationCache.put( queryString, hqlInterpretation );
if ( stats ) { if ( stats ) {
final long endTime = System.nanoTime(); final long endTime = System.nanoTime();
@ -136,19 +136,9 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
if ( stats ) { if ( stats ) {
statistics.queryPlanCacheHit( queryString ); statistics.queryPlanCacheHit( queryString );
} }
if ( immutableHqlInterpretation.sqmStatement.getSqmParameters().isEmpty() ) {
domainParameterXref = DomainParameterXref.empty();
}
else {
domainParameterXref = DomainParameterXref.from( immutableHqlInterpretation.sqmStatement );
}
} }
return new SimpleHqlInterpretationImpl( return hqlInterpretation;
immutableHqlInterpretation.sqmStatement,
immutableHqlInterpretation.parameterMetadata,
domainParameterXref);
} }
@Override @Override
@ -179,16 +169,4 @@ public class QueryInterpretationCacheStandardImpl implements QueryInterpretation
queryPlanCache.clear(); queryPlanCache.clear();
} }
private static class ImmutableHqlInterpretation {
private final SqmStatement<?> sqmStatement;
private final ParameterMetadataImplementor parameterMetadata;
public ImmutableHqlInterpretation(
SqmStatement<?> sqmStatement,
ParameterMetadataImplementor parameterMetadata) {
this.sqmStatement = sqmStatement;
this.parameterMetadata = parameterMetadata;
}
}
} }

View File

@ -38,6 +38,6 @@ public class SimpleHqlInterpretationImpl implements HqlInterpretation {
@Override @Override
public DomainParameterXref getDomainParameterXref() { public DomainParameterXref getDomainParameterXref() {
return domainParameterXref; return domainParameterXref.copy();
} }
} }

View File

@ -163,6 +163,14 @@ public class DomainParameterXref {
this.parameterResolutions = parameterResolutions; this.parameterResolutions = parameterResolutions;
} }
public DomainParameterXref copy() {
return new DomainParameterXref(
sqmParamsByQueryParam,
new IdentityHashMap<>( queryParamBySqmParam ),
parameterResolutions
);
}
/** /**
* Does this xref contain any parameters? * Does this xref contain any parameters?
*/ */
@ -256,5 +264,4 @@ public class DomainParameterXref {
expansions.clear(); expansions.clear();
} }
} }

View File

@ -6,10 +6,16 @@
*/ */
package org.hibernate.orm.test.query.sqm.exec; package org.hibernate.orm.test.query.sqm.exec;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.query.spi.QueryParameterImplementor;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.internal.QuerySqmImpl;
import org.hibernate.testing.orm.domain.StandardDomainModel; import org.hibernate.testing.orm.domain.StandardDomainModel;
import org.hibernate.testing.orm.junit.DomainModel; import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory; import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope; import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
/** /**
@ -39,4 +45,27 @@ public class ParameterTest {
} }
); );
} }
@Test
public void testParametersWithQueryInterpretationCache(SessionFactoryScope scope) {
String query = "from SalesAssociate p where p.name.familiarName in :names";
scope.inTransaction(
session -> {
QueryImplementor q = session.createQuery( query );
DomainParameterXref xref = q.unwrap( QuerySqmImpl.class ).getDomainParameterXref();
for ( QueryParameterImplementor<?> p : xref.getQueryParameters().keySet() ) {
Assertions.assertTrue( q.getParameterMetadata().containsReference( p ) );
}
}
);
scope.inTransaction(
session -> {
QueryImplementor q = session.createQuery( query );
DomainParameterXref xref = q.unwrap( QuerySqmImpl.class ).getDomainParameterXref();
for ( QueryParameterImplementor<?> p : xref.getQueryParameters().keySet() ) {
Assertions.assertTrue( q.getParameterMetadata().containsReference( p ) );
}
}
);
}
} }