HHH-11121 - Wrong NativeQueryImpl.setZeroBasedParametersIndex when Session#createSQLQuery is executed after EM#createNativeQuery

This commit is contained in:
Andrea Boriero 2016-09-22 19:51:54 +01:00
parent 47e925ead4
commit 306c151fff
2 changed files with 62 additions and 13 deletions

View File

@ -64,7 +64,7 @@ public class QueryPlanCache implements Serializable {
* Used solely for caching param metadata for native-sql queries, see {@link #getSQLParameterMetadata} for a
* discussion as to why...
*/
private final BoundedConcurrentHashMap<String,ParameterMetadataImpl> parameterMetadataCache;
private final BoundedConcurrentHashMap<ParameterMetadataKey,ParameterMetadataImpl> parameterMetadataCache;
private NativeQueryInterpreter nativeQueryInterpreterService;
@ -102,7 +102,7 @@ public class QueryPlanCache implements Serializable {
}
queryPlanCache = new BoundedConcurrentHashMap( maxQueryPlanCount, 20, BoundedConcurrentHashMap.Eviction.LIRS );
parameterMetadataCache = new BoundedConcurrentHashMap<String, ParameterMetadataImpl>(
parameterMetadataCache = new BoundedConcurrentHashMap<>(
maxParameterMetadataCount,
20,
BoundedConcurrentHashMap.Eviction.LIRS
@ -121,11 +121,12 @@ public class QueryPlanCache implements Serializable {
* @param query The query
* @return The parameter metadata
*/
public ParameterMetadata getSQLParameterMetadata(final String query) {
ParameterMetadataImpl value = parameterMetadataCache.get( query );
public ParameterMetadata getSQLParameterMetadata(final String query, boolean isOrdinalParameterZeroBased) {
final ParameterMetadataKey key = new ParameterMetadataKey( query, isOrdinalParameterZeroBased );
ParameterMetadataImpl value = parameterMetadataCache.get( key );
if ( value == null ) {
value = nativeQueryInterpreterService.getParameterMetadata( query );
parameterMetadataCache.putIfAbsent( query, value );
parameterMetadataCache.putIfAbsent( key, value );
}
return value;
}
@ -227,6 +228,41 @@ public class QueryPlanCache implements Serializable {
parameterMetadataCache.clear();
}
private static class ParameterMetadataKey implements Serializable {
private final String query;
private final boolean isOrdinalParameterZeroBased;
private final int hashCode;
public ParameterMetadataKey(String query, boolean isOrdinalParameterZeroBased) {
this.query = query;
this.isOrdinalParameterZeroBased = isOrdinalParameterZeroBased;
int hash = query.hashCode();
hash = 29 * hash + ( isOrdinalParameterZeroBased ? 1 : 0 );
this.hashCode = hash;
}
@Override
public boolean equals(Object o) {
if ( this == o ) {
return true;
}
if ( o == null || getClass() != o.getClass() ) {
return false;
}
final ParameterMetadataKey that = (ParameterMetadataKey) o;
return isOrdinalParameterZeroBased == that.isOrdinalParameterZeroBased
&& query.equals( that.query );
}
@Override
public int hashCode() {
return hashCode;
}
}
private static class HQLQueryPlanKey implements Serializable {
private final String query;
private final boolean shallow;

View File

@ -554,7 +554,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
// then as a native query
final NamedSQLQueryDefinition nativeQueryDefinition = factory.getNamedQueryRepository().getNamedSQLQueryDefinition( name );
if ( nativeQueryDefinition != null ) {
return createNativeQuery( nativeQueryDefinition );
return createNativeQuery( nativeQueryDefinition, true );
}
throw exceptionConverter.convert( new IllegalArgumentException( "No query defined for that name [" + name + "]" ) );
@ -579,10 +579,17 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
return query;
}
private NativeQueryImplementor createNativeQuery(NamedSQLQueryDefinition queryDefinition) {
private NativeQueryImplementor createNativeQuery(NamedSQLQueryDefinition queryDefinition, boolean isOrdinalParameterZeroBased) {
final ParameterMetadata parameterMetadata = factory.getQueryPlanCache().getSQLParameterMetadata(
queryDefinition.getQueryString()
queryDefinition.getQueryString(),
isOrdinalParameterZeroBased
);
return getNativeQueryImplementor( queryDefinition, parameterMetadata );
}
private NativeQueryImplementor getNativeQueryImplementor(
NamedSQLQueryDefinition queryDefinition,
ParameterMetadata parameterMetadata) {
final NativeQueryImpl query = new NativeQueryImpl(
queryDefinition,
this,
@ -761,7 +768,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
final NativeQueryImpl query = new NativeQueryImpl(
queryDefinition,
this,
factory.getQueryPlanCache().getSQLParameterMetadata( queryDefinition.getQueryString() )
factory.getQueryPlanCache().getSQLParameterMetadata( queryDefinition.getQueryString(), false )
);
query.setHibernateFlushMode( queryDefinition.getFlushMode() );
query.setComment( queryDefinition.getComment() != null ? queryDefinition.getComment() : queryDefinition.getName() );
@ -836,7 +843,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public NativeQueryImplementor createNativeQuery(String sqlString) {
final NativeQueryImpl query = (NativeQueryImpl) createSQLQuery( sqlString );
final NativeQueryImpl query = (NativeQueryImpl) getNativeQueryImplementor( sqlString, false );
query.setZeroBasedParametersIndex( false );
return query;
}
@ -881,7 +888,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
final NamedSQLQueryDefinition nativeQueryDefinition = factory.getNamedQueryRepository().getNamedSQLQueryDefinition( name );
if ( nativeQueryDefinition != null ) {
return createNativeQuery( nativeQueryDefinition );
return createNativeQuery( nativeQueryDefinition, true );
}
throw exceptionConverter.convert( new IllegalArgumentException( "No query defined for that name [" + name + "]" ) );
@ -889,6 +896,12 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public NativeQueryImplementor createSQLQuery(String queryString) {
return getNativeQueryImplementor( queryString, true );
}
protected NativeQueryImplementor getNativeQueryImplementor(
String queryString,
boolean isOrdinalParameterZeroBased) {
checkOpen();
checkTransactionSynchStatus();
delayedAfterCompletion();
@ -898,7 +911,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
queryString,
false,
this,
getFactory().getQueryPlanCache().getSQLParameterMetadata( queryString )
getFactory().getQueryPlanCache().getSQLParameterMetadata( queryString, isOrdinalParameterZeroBased )
);
query.setComment( "dynamic native SQL query" );
return query;
@ -906,9 +919,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
catch ( RuntimeException he ) {
throw exceptionConverter.convert( he );
}
}
@Override
public NativeQueryImplementor getNamedSQLQuery(String name) {
final NativeQueryImpl nativeQuery = (NativeQueryImpl) getNamedNativeQuery( name );