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 @Override
public NativeQueryImplementor createNativeQuery(String sqlString) { public NativeQueryImplementor createNativeQuery(String sqlString) {
checkOpen(); final NativeQueryImpl query = (NativeQueryImpl) createSQLQuery( sqlString );
checkTransactionSynchStatus(); query.setZeroBasedParametersIndex( false );
delayedAfterCompletion(); return query;
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 );
}
} }
@Override @Override
@ -891,12 +877,31 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
@Override @Override
public NativeQueryImplementor createSQLQuery(String queryString) { 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 @Override
public NativeQueryImplementor getNamedSQLQuery(String name) { public NativeQueryImplementor getNamedSQLQuery(String name) {
return getNamedNativeQuery( name ); final NativeQueryImpl nativeQuery = (NativeQueryImpl) getNamedNativeQuery( name );
nativeQuery.setZeroBasedParametersIndex( true );
return nativeQuery;
} }
@Override @Override

View File

@ -15,6 +15,7 @@ import javax.persistence.Parameter;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface ParameterMetadata { public interface ParameterMetadata {
/** /**
* Does this parameter set contain any named parameters? * Does this parameter set contain any named parameters?
* *
@ -52,4 +53,11 @@ public interface ParameterMetadata {
<T> QueryParameter<T> getQueryParameter(Integer position); <T> QueryParameter<T> getQueryParameter(Integer position);
<T> QueryParameter<T> resolve(Parameter<T> param); <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; return this;
} }
public void setZeroBasedParametersIndex(boolean zeroBasedParametersIndex) {
getParameterMetadata().setOrdinalParametersZeroBased( zeroBasedParametersIndex );
}
@Override @Override
public String getQueryString() { public String getQueryString() {
return sqlString; return sqlString;

View File

@ -31,6 +31,7 @@ public class ParameterMetadataImpl implements ParameterMetadata {
private final OrdinalParameterDescriptor[] ordinalDescriptors; private final OrdinalParameterDescriptor[] ordinalDescriptors;
private final Map<String,NamedParameterDescriptor> namedDescriptorMap; private final Map<String,NamedParameterDescriptor> namedDescriptorMap;
private boolean isOrdinalParametersZeroBased = true;
/** /**
* Instantiates a ParameterMetadata container. * Instantiates a ParameterMetadata container.
@ -116,6 +117,9 @@ public class ParameterMetadataImpl implements ParameterMetadata {
* @throws QueryParameterException If the position is out of range * @throws QueryParameterException If the position is out of range
*/ */
public OrdinalParameterDescriptor getOrdinalParameterDescriptor(int position) { public OrdinalParameterDescriptor getOrdinalParameterDescriptor(int position) {
if ( !isOrdinalParametersZeroBased ) {
position--;
}
if ( position < 0 || position >= ordinalDescriptors.length ) { if ( position < 0 || position >= ordinalDescriptors.length ) {
throw new QueryParameterException( throw new QueryParameterException(
"Position beyond number of declared ordinal parameters. " + "Position beyond number of declared ordinal parameters. " +
@ -239,4 +243,13 @@ public class ParameterMetadataImpl implements ParameterMetadata {
return getNamedParameterDescriptor( name ).getSourceLocations(); 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) { public QueryParameterBinding getBinding(int position) {
int positionAdjustment = 0;
if ( !parameterMetadata.isOrdinalParametersZeroBased() ) {
positionAdjustment = -1;
}
QueryParameterBinding binding = null; QueryParameterBinding binding = null;
if ( parameterMetadata != null ) { if ( parameterMetadata != null ) {
if ( ! parameterMetadata.hasPositionalParameters() ) { if ( !parameterMetadata.hasPositionalParameters() ) {
// no positional parameters, assume jpa named. // no positional parameters, assume jpa named.
binding = locateBinding( Integer.toString( position ) ); binding = locateBinding( Integer.toString( position ) );
} }
else { else {
try { try {
if ( position < positionalParameterBindings.size() ) { if ( position + positionAdjustment < positionalParameterBindings.size() ) {
binding = positionalParameterBindings.get( position ); binding = positionalParameterBindings.get( position + positionAdjustment );
if ( binding == null ) { if ( binding == null ) {
binding = makeBinding( parameterMetadata.getQueryParameter( position ) ); binding = makeBinding( parameterMetadata.getQueryParameter( position ) );
positionalParameterBindings.set( position, binding ); positionalParameterBindings.set( position + positionAdjustment, binding );
} }
} }
else { else {
for ( int i = 0; i < position - positionalParameterBindings.size(); i++ ) { for ( int i = 0; i < position + positionAdjustment - positionalParameterBindings.size(); i++ ) {
positionalParameterBindings.add( null ); positionalParameterBindings.add( null );
} }
QueryParameter queryParameter = parameterMetadata.getQueryParameter( position ); QueryParameter queryParameter = parameterMetadata.getQueryParameter( position );
binding = makeBinding( queryParameter ); binding = makeBinding( queryParameter );
positionalParameterBindings.add( binding ); positionalParameterBindings.add( binding );
} }
} }
catch ( QueryParameterException e ) { catch (QueryParameterException e) {
// treat this as null binding // treat this as null binding
} }
} }
@ -247,8 +251,18 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
} }
} }
// verify position parameters bound // verify position parameters bound
for ( int i = 0; i < positionalParameterBindings.size(); i++ ) { int startIndex = 0;
final QueryParameterBinding binding = positionalParameterBindings.get( i ); 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() ) { if ( binding == null || !binding.isBound() ) {
throw new QueryException( "Positional parameter [" + i + "] not set" ); throw new QueryException( "Positional parameter [" + i + "] not set" );
} }
@ -282,7 +296,6 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
if ( bindType == null ) { if ( bindType == null ) {
bindType = SerializableType.INSTANCE; bindType = SerializableType.INSTANCE;
} }
Object object = binding.getBindValue();
positionalValueSpan += bindType.getColumnSpan( sessionFactory ); positionalValueSpan += bindType.getColumnSpan( sessionFactory );
} }
} }