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

View File

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

View File

@ -6,10 +6,16 @@
*/
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.junit.DomainModel;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.Assertions;
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 ) );
}
}
);
}
}