HHH-10885 - Fix JPA Native Queries with ordinal parameter is zero based

This commit is contained in:
Andrea Boriero 2016-06-23 14:50:52 +02:00
parent e99270c332
commit 92f5032cc0
5 changed files with 73 additions and 30 deletions

View File

@ -824,23 +824,9 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public NativeQueryImplementor createNativeQuery(String sqlString) {
checkOpen();
checkTransactionSynchStatus();
delayedAfterCompletion();
try {
NativeQueryImpl query = new NativeQueryImpl(
sqlString,
false,
this,
getFactory().getQueryPlanCache().getSQLParameterMetadata( sqlString )
);
query.setComment( "dynamic native SQL query" );
return query;
}
catch ( RuntimeException he ) {
throw exceptionConverter.convert( he );
}
final NativeQueryImpl query = (NativeQueryImpl) createSQLQuery( sqlString );
query.setZeroBasedParametersIndex( false );
return query;
}
@Override
@ -891,12 +877,31 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override
public NativeQueryImplementor createSQLQuery(String queryString) {
return createNativeQuery( queryString );
checkOpen();
checkTransactionSynchStatus();
delayedAfterCompletion();
try {
NativeQueryImpl query = new NativeQueryImpl(
queryString,
false,
this,
getFactory().getQueryPlanCache().getSQLParameterMetadata( queryString )
);
query.setComment( "dynamic native SQL query" );
return query;
}
catch ( RuntimeException he ) {
throw exceptionConverter.convert( he );
}
}
@Override
public NativeQueryImplementor getNamedSQLQuery(String name) {
return getNamedNativeQuery( name );
final NativeQueryImpl nativeQuery = (NativeQueryImpl) getNamedNativeQuery( name );
nativeQuery.setZeroBasedParametersIndex( true );
return nativeQuery;
}
@Override

View File

@ -15,6 +15,7 @@ import javax.persistence.Parameter;
* @author Steve Ebersole
*/
public interface ParameterMetadata {
/**
* Does this parameter set contain any named parameters?
*
@ -52,4 +53,11 @@ public interface ParameterMetadata {
<T> QueryParameter<T> getQueryParameter(Integer position);
<T> QueryParameter<T> resolve(Parameter<T> param);
default boolean isOrdinalParametersZeroBased() {
return true;
}
default void setOrdinalParametersZeroBased(boolean isZeroBased) {
}
}

View File

@ -121,6 +121,10 @@ public class NativeQueryImpl<T> extends AbstractProducedQuery<T> implements Nati
return this;
}
public void setZeroBasedParametersIndex(boolean zeroBasedParametersIndex) {
getParameterMetadata().setOrdinalParametersZeroBased( zeroBasedParametersIndex );
}
@Override
public String getQueryString() {
return sqlString;

View File

@ -31,6 +31,7 @@ public class ParameterMetadataImpl implements ParameterMetadata {
private final OrdinalParameterDescriptor[] ordinalDescriptors;
private final Map<String,NamedParameterDescriptor> namedDescriptorMap;
private boolean isOrdinalParametersZeroBased = true;
/**
* Instantiates a ParameterMetadata container.
@ -116,6 +117,9 @@ public class ParameterMetadataImpl implements ParameterMetadata {
* @throws QueryParameterException If the position is out of range
*/
public OrdinalParameterDescriptor getOrdinalParameterDescriptor(int position) {
if ( !isOrdinalParametersZeroBased ) {
position--;
}
if ( position < 0 || position >= ordinalDescriptors.length ) {
throw new QueryParameterException(
"Position beyond number of declared ordinal parameters. " +
@ -239,4 +243,13 @@ public class ParameterMetadataImpl implements ParameterMetadata {
return getNamedParameterDescriptor( name ).getSourceLocations();
}
@Override
public boolean isOrdinalParametersZeroBased() {
return isOrdinalParametersZeroBased;
}
@Override
public void setOrdinalParametersZeroBased(boolean isZeroBased) {
this.isOrdinalParametersZeroBased = isZeroBased;
}
}

View File

@ -197,31 +197,35 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
}
public QueryParameterBinding getBinding(int position) {
int positionAdjustment = 0;
if ( !parameterMetadata.isOrdinalParametersZeroBased() ) {
positionAdjustment = -1;
}
QueryParameterBinding binding = null;
if ( parameterMetadata != null ) {
if ( ! parameterMetadata.hasPositionalParameters() ) {
if ( !parameterMetadata.hasPositionalParameters() ) {
// no positional parameters, assume jpa named.
binding = locateBinding( Integer.toString( position ) );
}
else {
try {
if ( position < positionalParameterBindings.size() ) {
binding = positionalParameterBindings.get( position );
if ( position + positionAdjustment < positionalParameterBindings.size() ) {
binding = positionalParameterBindings.get( position + positionAdjustment );
if ( binding == null ) {
binding = makeBinding( parameterMetadata.getQueryParameter( position ) );
positionalParameterBindings.set( position, binding );
binding = makeBinding( parameterMetadata.getQueryParameter( position ) );
positionalParameterBindings.set( position + positionAdjustment, binding );
}
}
else {
for ( int i = 0; i < position - positionalParameterBindings.size(); i++ ) {
for ( int i = 0; i < position + positionAdjustment - positionalParameterBindings.size(); i++ ) {
positionalParameterBindings.add( null );
}
QueryParameter queryParameter = parameterMetadata.getQueryParameter( position );
QueryParameter queryParameter = parameterMetadata.getQueryParameter( position );
binding = makeBinding( queryParameter );
positionalParameterBindings.add( binding );
}
}
catch ( QueryParameterException e ) {
catch (QueryParameterException e) {
// treat this as null binding
}
}
@ -247,8 +251,18 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
}
}
// verify position parameters bound
for ( int i = 0; i < positionalParameterBindings.size(); i++ ) {
final QueryParameterBinding binding = positionalParameterBindings.get( i );
int startIndex = 0;
if ( !parameterMetadata.isOrdinalParametersZeroBased() ) {
startIndex = 1;
}
for ( int i = startIndex; i < positionalParameterBindings.size(); i++ ) {
QueryParameterBinding binding = null;
if ( parameterMetadata.isOrdinalParametersZeroBased() ) {
binding = positionalParameterBindings.get( i );
}
else {
binding = positionalParameterBindings.get( i - 1 );
}
if ( binding == null || !binding.isBound() ) {
throw new QueryException( "Positional parameter [" + i + "] not set" );
}
@ -282,7 +296,6 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
if ( bindType == null ) {
bindType = SerializableType.INSTANCE;
}
Object object = binding.getBindValue();
positionalValueSpan += bindType.getColumnSpan( sessionFactory );
}
}