HHH-12116 - Positional parameters report position as name
HHH-12101 - Remove support for legacy HQL-style positional parameters
This commit is contained in:
parent
8308e4252c
commit
5e0274adbb
|
@ -779,12 +779,12 @@ public class HQLTest extends BaseEntityManagerFunctionalTestCase {
|
|||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Date timestamp = new Date( );
|
||||
Session session = entityManager.unwrap( Session.class );
|
||||
//tag::hql-api-positional-parameter-example[]
|
||||
//tag::hql-api-positional-parameter-example[]56:37
|
||||
org.hibernate.query.Query query = session.createQuery(
|
||||
"select p " +
|
||||
"from Person p " +
|
||||
"where p.name like ? " )
|
||||
.setParameter( 0, "J%" );
|
||||
"where p.name like ?1" )
|
||||
.setParameter( 1, "J%" );
|
||||
//end::hql-api-positional-parameter-example[]
|
||||
});
|
||||
}
|
||||
|
|
|
@ -225,8 +225,8 @@ tokens
|
|||
return #( [NAMED_PARAM, nameNode.getText()] );
|
||||
}
|
||||
|
||||
protected AST generatePositionalParameter(AST inputNode) throws SemanticException {
|
||||
return #( [PARAM, "?"] );
|
||||
protected AST generatePositionalParameter(AST delimiterNode, AST numberNode) throws SemanticException {
|
||||
return #( [PARAM, numberNode.getText()] );
|
||||
}
|
||||
|
||||
protected void lookupAlias(AST ident) throws SemanticException { }
|
||||
|
@ -805,24 +805,13 @@ mapPropertyExpression
|
|||
|
||||
parameter!
|
||||
: #(c:COLON a:identifier) {
|
||||
// Create a NAMED_PARAM node instead of (COLON IDENT).
|
||||
#parameter = generateNamedParameter( c, a );
|
||||
// #parameter = #([NAMED_PARAM,a.getText()]);
|
||||
// namedParameter(#parameter);
|
||||
}
|
||||
| #(p:PARAM (n:NUM_INT)?) {
|
||||
if ( n != null ) {
|
||||
// An ejb3-style "positional parameter", which we handle internally as a named-param
|
||||
#parameter = generateNamedParameter( p, n );
|
||||
// #parameter = #([NAMED_PARAM,n.getText()]);
|
||||
// namedParameter(#parameter);
|
||||
}
|
||||
else {
|
||||
#parameter = generatePositionalParameter( p );
|
||||
// #parameter = #([PARAM,"?"]);
|
||||
// positionalParameter(#parameter);
|
||||
}
|
||||
}
|
||||
// Create a NAMED_PARAM node instead of (COLON IDENT) - semantics ftw!
|
||||
#parameter = generateNamedParameter( c, a );
|
||||
}
|
||||
| #(p:PARAM (n:NUM_INT)? ) {
|
||||
// Create a (POSITIONAL_)PARAM node instead of (PARAM NUM_INT) - semantics ftw!
|
||||
#parameter = generatePositionalParameter( p, n );
|
||||
}
|
||||
;
|
||||
|
||||
numericInteger
|
||||
|
|
|
@ -603,6 +603,7 @@ public interface Query<R> extends TypedQuery<R>, CommonQueryContract {
|
|||
* @return {@code this}, for method chaining
|
||||
*/
|
||||
Query<R> setParameterList(String name, Collection values);
|
||||
Query<R> setParameterList(int position, Collection values);
|
||||
|
||||
/**
|
||||
* Bind multiple values to a named query parameter. This is useful for binding
|
||||
|
@ -615,6 +616,7 @@ public interface Query<R> extends TypedQuery<R>, CommonQueryContract {
|
|||
* @return {@code this}, for method chaining
|
||||
*/
|
||||
Query<R> setParameterList(String name, Collection values, Type type);
|
||||
Query<R> setParameterList(int position, Collection values, Type type);
|
||||
|
||||
/**
|
||||
* Bind multiple values to a named query parameter. This is useful for binding
|
||||
|
@ -627,6 +629,7 @@ public interface Query<R> extends TypedQuery<R>, CommonQueryContract {
|
|||
* @return {@code this}, for method chaining
|
||||
*/
|
||||
Query<R> setParameterList(String name, Object[] values, Type type);
|
||||
Query<R> setParameterList(int position, Object[] values, Type type);
|
||||
|
||||
/**
|
||||
* Bind multiple values to a named query parameter. The Hibernate type of the parameter is
|
||||
|
@ -640,6 +643,7 @@ public interface Query<R> extends TypedQuery<R>, CommonQueryContract {
|
|||
* @return {@code this}, for method chaining
|
||||
*/
|
||||
Query<R> setParameterList(String name, Object[] values);
|
||||
Query<R> setParameterList(int position, Object[] values);
|
||||
|
||||
/**
|
||||
* Bind the property values of the given bean to named parameters of the query,
|
||||
|
|
|
@ -64,7 +64,61 @@ import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
|||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.cfg.AvailableSettings.*;
|
||||
import static org.hibernate.cfg.AvailableSettings.ACQUIRE_CONNECTIONS;
|
||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_JTA_TRANSACTION_ACCESS;
|
||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY;
|
||||
import static org.hibernate.cfg.AvailableSettings.ALLOW_UPDATE_OUTSIDE_TRANSACTION;
|
||||
import static org.hibernate.cfg.AvailableSettings.AUTO_CLOSE_SESSION;
|
||||
import static org.hibernate.cfg.AvailableSettings.AUTO_EVICT_COLLECTION_CACHE;
|
||||
import static org.hibernate.cfg.AvailableSettings.AUTO_SESSION_EVENTS_LISTENER;
|
||||
import static org.hibernate.cfg.AvailableSettings.BATCH_FETCH_STYLE;
|
||||
import static org.hibernate.cfg.AvailableSettings.BATCH_VERSIONED_DATA;
|
||||
import static org.hibernate.cfg.AvailableSettings.CACHE_REGION_PREFIX;
|
||||
import static org.hibernate.cfg.AvailableSettings.CHECK_NULLABILITY;
|
||||
import static org.hibernate.cfg.AvailableSettings.COLLECTION_JOIN_SUBQUERY;
|
||||
import static org.hibernate.cfg.AvailableSettings.CONNECTION_HANDLING;
|
||||
import static org.hibernate.cfg.AvailableSettings.CONVENTIONAL_JAVA_CONSTANTS;
|
||||
import static org.hibernate.cfg.AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE;
|
||||
import static org.hibernate.cfg.AvailableSettings.CUSTOM_ENTITY_DIRTINESS_STRATEGY;
|
||||
import static org.hibernate.cfg.AvailableSettings.DEFAULT_BATCH_FETCH_SIZE;
|
||||
import static org.hibernate.cfg.AvailableSettings.DEFAULT_ENTITY_MODE;
|
||||
import static org.hibernate.cfg.AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS;
|
||||
import static org.hibernate.cfg.AvailableSettings.FLUSH_BEFORE_COMPLETION;
|
||||
import static org.hibernate.cfg.AvailableSettings.GENERATE_STATISTICS;
|
||||
import static org.hibernate.cfg.AvailableSettings.HQL_BULK_ID_STRATEGY;
|
||||
import static org.hibernate.cfg.AvailableSettings.INTERCEPTOR;
|
||||
import static org.hibernate.cfg.AvailableSettings.JDBC_TIME_ZONE;
|
||||
import static org.hibernate.cfg.AvailableSettings.JDBC_TYLE_PARAMS_ZERO_BASE;
|
||||
import static org.hibernate.cfg.AvailableSettings.JPAQL_STRICT_COMPLIANCE;
|
||||
import static org.hibernate.cfg.AvailableSettings.JTA_TRACK_BY_THREAD;
|
||||
import static org.hibernate.cfg.AvailableSettings.LOG_SESSION_METRICS;
|
||||
import static org.hibernate.cfg.AvailableSettings.MAX_FETCH_DEPTH;
|
||||
import static org.hibernate.cfg.AvailableSettings.MULTI_TENANT_IDENTIFIER_RESOLVER;
|
||||
import static org.hibernate.cfg.AvailableSettings.ORDER_INSERTS;
|
||||
import static org.hibernate.cfg.AvailableSettings.ORDER_UPDATES;
|
||||
import static org.hibernate.cfg.AvailableSettings.PREFER_USER_TRANSACTION;
|
||||
import static org.hibernate.cfg.AvailableSettings.PROCEDURE_NULL_PARAM_PASSING;
|
||||
import static org.hibernate.cfg.AvailableSettings.QUERY_CACHE_FACTORY;
|
||||
import static org.hibernate.cfg.AvailableSettings.QUERY_STARTUP_CHECKING;
|
||||
import static org.hibernate.cfg.AvailableSettings.QUERY_SUBSTITUTIONS;
|
||||
import static org.hibernate.cfg.AvailableSettings.RELEASE_CONNECTIONS;
|
||||
import static org.hibernate.cfg.AvailableSettings.SESSION_FACTORY_NAME;
|
||||
import static org.hibernate.cfg.AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI;
|
||||
import static org.hibernate.cfg.AvailableSettings.SESSION_SCOPED_INTERCEPTOR;
|
||||
import static org.hibernate.cfg.AvailableSettings.STATEMENT_BATCH_SIZE;
|
||||
import static org.hibernate.cfg.AvailableSettings.STATEMENT_FETCH_SIZE;
|
||||
import static org.hibernate.cfg.AvailableSettings.STATEMENT_INSPECTOR;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_DIRECT_REFERENCE_CACHE_ENTRIES;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_GET_GENERATED_KEYS;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_IDENTIFIER_ROLLBACK;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_MINIMAL_PUTS;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_QUERY_CACHE;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_SCROLLABLE_RESULTSET;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_SECOND_LEVEL_CACHE;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_SQL_COMMENTS;
|
||||
import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE;
|
||||
import static org.hibernate.cfg.AvailableSettings.VALIDATE_QUERY_PARAMETERS;
|
||||
import static org.hibernate.cfg.AvailableSettings.WRAP_RESULT_SETS;
|
||||
import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN;
|
||||
import static org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE;
|
||||
|
||||
|
@ -475,6 +529,10 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
this.options.jtaTransactionAccessEnabled = false;
|
||||
}
|
||||
|
||||
public void enableJdbcStyleParamsZeroBased() {
|
||||
this.options.jdbcStyleParamsZeroBased = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryOptions buildSessionFactoryOptions() {
|
||||
return new SessionFactoryOptionsImpl( this );
|
||||
|
@ -547,6 +605,7 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
private boolean conventionalJavaConstants;
|
||||
private final boolean procedureParameterNullPassingEnabled;
|
||||
private final boolean collectionJoinSubqueryRewriteEnabled;
|
||||
private boolean jdbcStyleParamsZeroBased;
|
||||
|
||||
// Caching
|
||||
private boolean secondLevelCacheEnabled;
|
||||
|
@ -790,6 +849,12 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
this.criteriaLiteralHandlingMode = LiteralHandlingMode.interpret(
|
||||
configurationSettings.get( CRITERIA_LITERAL_HANDLING_MODE )
|
||||
);
|
||||
|
||||
this.jdbcStyleParamsZeroBased = ConfigurationHelper.getBoolean(
|
||||
JDBC_TYLE_PARAMS_ZERO_BASE,
|
||||
configurationSettings,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
private static Interceptor determineInterceptor(Map configurationSettings, StrategySelector strategySelector) {
|
||||
|
@ -1243,6 +1308,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
public LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return this.criteriaLiteralHandlingMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean jdbcStyleParamsZeroBased() {
|
||||
return this.jdbcStyleParamsZeroBased;
|
||||
}
|
||||
}
|
||||
|
||||
private static Supplier<? extends Interceptor> interceptorSupplier(Class<? extends Interceptor> clazz) {
|
||||
|
@ -1592,4 +1662,9 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
public LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return options.getCriteriaLiteralHandlingMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean jdbcStyleParamsZeroBased() {
|
||||
return options.jdbcStyleParamsZeroBased();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import org.hibernate.cfg.BaselineSessionEventsListenerBuilder;
|
|||
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
@ -131,6 +132,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
private final Map<String, SQLFunction> sqlFunctions;
|
||||
private boolean queryParametersValidationEnabled;
|
||||
private LiteralHandlingMode criteriaLiteralHandlingMode;
|
||||
private boolean jdbcStyleParamsZeroBased;
|
||||
|
||||
public SessionFactoryOptionsImpl(SessionFactoryOptionsState state) {
|
||||
this.serviceRegistry = state.getServiceRegistry();
|
||||
|
@ -186,6 +188,12 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
this.conventionalJavaConstants = state.isConventionalJavaConstants();
|
||||
this.procedureParameterNullPassingEnabled = state.isProcedureParameterNullPassingEnabled();
|
||||
this.collectionJoinSubqueryRewriteEnabled = state.isCollectionJoinSubqueryRewriteEnabled();
|
||||
this.queryParametersValidationEnabled = state.isQueryParametersValidationEnabled();
|
||||
this.criteriaLiteralHandlingMode = state.getCriteriaLiteralHandlingMode();
|
||||
this.jdbcStyleParamsZeroBased = state.jdbcStyleParamsZeroBased();
|
||||
if ( jdbcStyleParamsZeroBased ) {
|
||||
DeprecationLogger.DEPRECATION_LOGGER.logUseOfDeprecatedZeroBasedJdbcStyleParams();
|
||||
}
|
||||
|
||||
this.secondLevelCacheEnabled = state.isSecondLevelCacheEnabled();
|
||||
this.queryCacheEnabled = state.isQueryCacheEnabled();
|
||||
|
@ -210,9 +218,6 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
this.sqlFunctions = state.getCustomSqlFunctionMap();
|
||||
|
||||
this.jdbcTimeZone = state.getJdbcTimeZone();
|
||||
|
||||
this.queryParametersValidationEnabled = state.isQueryParametersValidationEnabled();
|
||||
this.criteriaLiteralHandlingMode = state.getCriteriaLiteralHandlingMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -558,4 +563,9 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
public LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return criteriaLiteralHandlingMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean jdbcStyleParamsZeroBased() {
|
||||
return jdbcStyleParamsZeroBased;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -203,4 +203,6 @@ public interface SessionFactoryOptionsState {
|
|||
default LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return LiteralHandlingMode.AUTO;
|
||||
}
|
||||
|
||||
boolean jdbcStyleParamsZeroBased();
|
||||
}
|
||||
|
|
|
@ -36,6 +36,11 @@ public abstract class AbstractDelegatingSessionFactoryBuilderImplementor<T exten
|
|||
delegate().disableJtaTransactionAccess();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enableJdbcStyleParamsZeroBased() {
|
||||
delegate().enableJdbcStyleParamsZeroBased();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryOptions buildSessionFactoryOptions() {
|
||||
return delegate().buildSessionFactoryOptions();
|
||||
|
|
|
@ -395,4 +395,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
public LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return delegate.getCriteriaLiteralHandlingMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean jdbcStyleParamsZeroBased() {
|
||||
return delegate.jdbcStyleParamsZeroBased();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,6 +33,11 @@ public interface SessionFactoryBuilderImplementor extends SessionFactoryBuilder
|
|||
default void disableRefreshDetachedEntity() {
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.hibernate.cfg.AvailableSettings#JDBC_TYLE_PARAMS_ZERO_BASE
|
||||
*/
|
||||
void enableJdbcStyleParamsZeroBased();
|
||||
|
||||
/**
|
||||
* Build the SessionFactoryOptions that will ultimately be passed to SessionFactoryImpl constructor.
|
||||
*
|
||||
|
|
|
@ -248,4 +248,6 @@ public interface SessionFactoryOptions {
|
|||
default LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return LiteralHandlingMode.AUTO;
|
||||
}
|
||||
|
||||
boolean jdbcStyleParamsZeroBased();
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.util.function.Supplier;
|
|||
|
||||
import org.hibernate.boot.MetadataBuilder;
|
||||
import org.hibernate.boot.registry.classloading.internal.TcclLookupPrecedence;
|
||||
import org.hibernate.internal.log.DeprecationLogger;
|
||||
import org.hibernate.query.internal.ParameterMetadataImpl;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
|
||||
|
@ -477,6 +478,20 @@ public interface AvailableSettings {
|
|||
*/
|
||||
String JTA_CACHE_UT = "hibernate.jta.cacheUserTransaction";
|
||||
|
||||
/**
|
||||
* `true` / `false - should zero be used as the base for JDBC-style parameters
|
||||
* found in native-queries?
|
||||
*
|
||||
* @since 5.3
|
||||
*
|
||||
* @see DeprecationLogger#logUseOfDeprecatedZeroBasedJdbcStyleParams
|
||||
*
|
||||
* @deprecated This is a temporary backwards-compatibility setting to help applications
|
||||
* using versions prior to 5.3 in upgrading. Deprecation warnings are issued when this
|
||||
* is set to `true`.
|
||||
*/
|
||||
@Deprecated
|
||||
String JDBC_TYLE_PARAMS_ZERO_BASE = "hibernate.query.sql.jdbc_style_params_base";
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.criterion;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.Criteria;
|
||||
|
|
|
@ -0,0 +1,17 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.criterion;
|
||||
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ParameterInfoCollector {
|
||||
void addNamedParameter(String name, Type type);
|
||||
void addPositionalParameter(int label, Type type);
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.engine.query;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.engine.query.spi.ParamLocationRecognizer;
|
||||
|
||||
/**
|
||||
* Indicates a problem during parameter recognition via
|
||||
* {@link ParamLocationRecognizer}
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ParameterRecognitionException extends HibernateException {
|
||||
public ParameterRecognitionException(String message) {
|
||||
super( message );
|
||||
}
|
||||
|
||||
public ParameterRecognitionException(String message, Throwable cause) {
|
||||
super( message, cause );
|
||||
}
|
||||
}
|
|
@ -6,13 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.engine.query.internal;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.query.spi.NamedParameterDescriptor;
|
||||
import org.hibernate.engine.query.spi.NativeQueryInterpreter;
|
||||
import org.hibernate.engine.query.spi.NativeSQLQueryPlan;
|
||||
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
||||
import org.hibernate.engine.query.spi.ParamLocationRecognizer;
|
||||
import org.hibernate.engine.query.spi.sql.NativeSQLQuerySpecification;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -24,46 +19,25 @@ import org.hibernate.query.internal.ParameterMetadataImpl;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NativeQueryInterpreterStandardImpl implements NativeQueryInterpreter {
|
||||
/**
|
||||
* Singleton access
|
||||
*/
|
||||
public static final NativeQueryInterpreterStandardImpl INSTANCE = new NativeQueryInterpreterStandardImpl();
|
||||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
public NativeQueryInterpreterStandardImpl(SessionFactoryImplementor sessionFactory) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ParameterMetadataImpl getParameterMetadata(String nativeQuery) {
|
||||
final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( nativeQuery );
|
||||
|
||||
final int size = recognizer.getOrdinalParameterLocationList().size();
|
||||
final OrdinalParameterDescriptor[] ordinalDescriptors = new OrdinalParameterDescriptor[ size ];
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final Integer position = recognizer.getOrdinalParameterLocationList().get( i );
|
||||
ordinalDescriptors[i] = new OrdinalParameterDescriptor( i, null, position );
|
||||
}
|
||||
|
||||
final Map<String, NamedParameterDescriptor> namedParamDescriptorMap = new HashMap<String, NamedParameterDescriptor>();
|
||||
final Map<String, ParamLocationRecognizer.NamedParameterDescription> map = recognizer.getNamedParameterDescriptionMap();
|
||||
|
||||
for ( final String name : map.keySet() ) {
|
||||
final ParamLocationRecognizer.NamedParameterDescription description = map.get( name );
|
||||
namedParamDescriptorMap.put(
|
||||
name,
|
||||
new NamedParameterDescriptor(
|
||||
name,
|
||||
null,
|
||||
description.buildPositionsArray(),
|
||||
description.isJpaStyle()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new ParameterMetadataImpl( ordinalDescriptors, namedParamDescriptorMap );
|
||||
final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( nativeQuery, sessionFactory );
|
||||
return new ParameterMetadataImpl(
|
||||
recognizer.getOrdinalParameterDescriptionMap(),
|
||||
recognizer.getNamedParameterDescriptionMap()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NativeSQLQueryPlan createQueryPlan(
|
||||
NativeSQLQuerySpecification specification,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
|
||||
CustomQuery customQuery = new SQLCustomQuery(
|
||||
specification.getQueryString(),
|
||||
specification.getQueryReturns(),
|
||||
|
|
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.engine.query.spi;
|
||||
|
||||
import org.hibernate.query.QueryParameter;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractParameterDescriptor implements QueryParameter {
|
||||
private final int[] sourceLocations;
|
||||
|
||||
private Type expectedType;
|
||||
|
||||
public AbstractParameterDescriptor(int[] sourceLocations, Type expectedType) {
|
||||
this.sourceLocations = sourceLocations;
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPosition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getParameterType() {
|
||||
return expectedType == null ? null : expectedType.getReturnedClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return getExpectedType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSourceLocations() {
|
||||
return sourceLocations;
|
||||
}
|
||||
|
||||
public Type getExpectedType() {
|
||||
return expectedType;
|
||||
}
|
||||
|
||||
public void resetExpectedType(Type expectedType) {
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
}
|
|
@ -8,6 +8,7 @@ package org.hibernate.engine.query.spi;
|
|||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
|
@ -25,7 +26,9 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
|||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.hql.internal.QuerySplitter;
|
||||
import org.hibernate.hql.spi.FilterTranslator;
|
||||
import org.hibernate.hql.spi.NamedParameterInformation;
|
||||
import org.hibernate.hql.spi.ParameterTranslations;
|
||||
import org.hibernate.hql.spi.PositionalParameterInformation;
|
||||
import org.hibernate.hql.spi.QueryTranslator;
|
||||
import org.hibernate.hql.spi.QueryTranslatorFactory;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
|
@ -58,6 +61,7 @@ public class HQLQueryPlan implements Serializable {
|
|||
|
||||
private final Set<String> enabledFilterNames;
|
||||
private final boolean shallow;
|
||||
private final SessionFactoryImplementor factory;
|
||||
|
||||
/**
|
||||
* We'll check the trace level only once per instance
|
||||
|
@ -92,8 +96,9 @@ public class HQLQueryPlan implements Serializable {
|
|||
EntityGraphQueryHint entityGraphQueryHint) {
|
||||
this.sourceQuery = hql;
|
||||
this.shallow = shallow;
|
||||
this.factory = factory;
|
||||
|
||||
final Set<String> copy = new HashSet<String>();
|
||||
final Set<String> copy = new HashSet<>();
|
||||
copy.addAll( enabledFilters.keySet() );
|
||||
this.enabledFilterNames = java.util.Collections.unmodifiableSet( copy );
|
||||
|
||||
|
@ -101,8 +106,8 @@ public class HQLQueryPlan implements Serializable {
|
|||
final int length = concreteQueryStrings.length;
|
||||
this.translators = new QueryTranslator[length];
|
||||
|
||||
final List<String> sqlStringList = new ArrayList<String>();
|
||||
final Set<Serializable> combinedQuerySpaces = new HashSet<Serializable>();
|
||||
final List<String> sqlStringList = new ArrayList<>();
|
||||
final Set<Serializable> combinedQuerySpaces = new HashSet<>();
|
||||
|
||||
final Map querySubstitutions = factory.getSessionFactoryOptions().getQuerySubstitutions();
|
||||
final QueryTranslatorFactory queryTranslatorFactory = factory.getServiceRegistry().getService( QueryTranslatorFactory.class );
|
||||
|
@ -151,7 +156,7 @@ public class HQLQueryPlan implements Serializable {
|
|||
}
|
||||
|
||||
public ParameterMetadataImpl getParameterMetadata() {
|
||||
return parameterMetadata.getOrdinalParametersZeroBasedCopy();
|
||||
return parameterMetadata;
|
||||
}
|
||||
|
||||
public ReturnMetadata getReturnMetadata() {
|
||||
|
@ -377,46 +382,53 @@ public class HQLQueryPlan implements Serializable {
|
|||
}
|
||||
|
||||
private ParameterMetadataImpl buildParameterMetadata(ParameterTranslations parameterTranslations, String hql) {
|
||||
final long start = traceEnabled ? System.nanoTime() : 0;
|
||||
final ParamLocationRecognizer recognizer = ParamLocationRecognizer.parseLocations( hql );
|
||||
|
||||
if ( traceEnabled ) {
|
||||
final long end = System.nanoTime();
|
||||
LOG.tracev( "HQL param location recognition took {0} nanoseconds ({1})", ( end - start ), hql );
|
||||
final Map<Integer,OrdinalParameterDescriptor> ordinalParamDescriptors;
|
||||
if ( parameterTranslations.getPositionalParameterInformationMap().isEmpty() ) {
|
||||
ordinalParamDescriptors = Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
final Map<Integer,OrdinalParameterDescriptor> temp = new HashMap<>();
|
||||
for ( Map.Entry<Integer, PositionalParameterInformation> entry :
|
||||
parameterTranslations.getPositionalParameterInformationMap().entrySet() ) {
|
||||
final int position = entry.getKey();
|
||||
temp.put(
|
||||
position,
|
||||
new OrdinalParameterDescriptor(
|
||||
position,
|
||||
position - 1,
|
||||
entry.getValue().getExpectedType(),
|
||||
entry.getValue().getSourceLocations()
|
||||
)
|
||||
);
|
||||
}
|
||||
ordinalParamDescriptors = Collections.unmodifiableMap( temp );
|
||||
}
|
||||
|
||||
int ordinalParamCount = parameterTranslations.getOrdinalParameterCount();
|
||||
final int[] locations = ArrayHelper.toIntArray( recognizer.getOrdinalParameterLocationList() );
|
||||
if ( parameterTranslations.supportsOrdinalParameterMetadata() && locations.length != ordinalParamCount ) {
|
||||
throw new HibernateException( "ordinal parameter mismatch" );
|
||||
}
|
||||
ordinalParamCount = locations.length;
|
||||
|
||||
final OrdinalParameterDescriptor[] ordinalParamDescriptors = new OrdinalParameterDescriptor[ordinalParamCount];
|
||||
for ( int i = 0; i < ordinalParamCount; i++ ) {
|
||||
ordinalParamDescriptors[ i ] = new OrdinalParameterDescriptor(
|
||||
i,
|
||||
parameterTranslations.supportsOrdinalParameterMetadata()
|
||||
? parameterTranslations.getOrdinalParameterExpectedType( i )
|
||||
: null,
|
||||
locations[ i ]
|
||||
);
|
||||
final Map<String, NamedParameterDescriptor> namedParamDescriptorMap;
|
||||
|
||||
if ( parameterTranslations.getNamedParameterInformationMap().isEmpty() ) {
|
||||
namedParamDescriptorMap = Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
final Map<String, NamedParameterDescriptor> tmp = new HashMap<>();
|
||||
for ( Map.Entry<String, NamedParameterInformation> namedEntry :
|
||||
parameterTranslations.getNamedParameterInformationMap().entrySet() ) {
|
||||
final String name = namedEntry.getKey();
|
||||
tmp.put(
|
||||
name,
|
||||
new NamedParameterDescriptor(
|
||||
name,
|
||||
parameterTranslations.getNamedParameterInformation( name ).getExpectedType(),
|
||||
namedEntry.getValue().getSourceLocations()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
namedParamDescriptorMap = Collections.unmodifiableMap( tmp );
|
||||
}
|
||||
|
||||
final Map<String, NamedParameterDescriptor> namedParamDescriptorMap = new HashMap<String, NamedParameterDescriptor>();
|
||||
final Map<String, ParamLocationRecognizer.NamedParameterDescription> map = recognizer.getNamedParameterDescriptionMap();
|
||||
for ( final String name : map.keySet() ) {
|
||||
final ParamLocationRecognizer.NamedParameterDescription description = map.get( name );
|
||||
namedParamDescriptorMap.put(
|
||||
name,
|
||||
new NamedParameterDescriptor(
|
||||
name,
|
||||
parameterTranslations.getNamedParameterExpectedType( name ),
|
||||
description.buildPositionsArray(),
|
||||
description.isJpaStyle()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return new ParameterMetadataImpl( ordinalParamDescriptors, namedParamDescriptorMap );
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.engine.query.spi;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.query.QueryParameter;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
|
@ -16,11 +15,8 @@ import org.hibernate.type.Type;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public class NamedParameterDescriptor implements QueryParameter {
|
||||
public class NamedParameterDescriptor extends AbstractParameterDescriptor {
|
||||
private final String name;
|
||||
private Type expectedType;
|
||||
private final int[] sourceLocations;
|
||||
private final boolean jpaStyle;
|
||||
|
||||
/**
|
||||
* Constructs a NamedParameterDescriptor
|
||||
|
@ -28,60 +24,16 @@ public class NamedParameterDescriptor implements QueryParameter {
|
|||
* @param name The name of the parameter
|
||||
* @param expectedType The expected type of the parameter, according to the translator
|
||||
* @param sourceLocations The locations of the named parameters (aye aye aye)
|
||||
* @param jpaStyle Was the parameter a JPA style "named parameter"?
|
||||
*/
|
||||
public NamedParameterDescriptor(String name, Type expectedType, int[] sourceLocations, boolean jpaStyle) {
|
||||
public NamedParameterDescriptor(String name, Type expectedType, int[] sourceLocations) {
|
||||
super( sourceLocations, expectedType );
|
||||
this.name = name;
|
||||
this.expectedType = expectedType;
|
||||
this.sourceLocations = sourceLocations;
|
||||
this.jpaStyle = jpaStyle;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPosition() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getParameterType() {
|
||||
return expectedType == null ? null : expectedType.getReturnedClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaPositionalParameter() {
|
||||
return isJpaStyle();
|
||||
}
|
||||
|
||||
public Type getExpectedType() {
|
||||
return expectedType;
|
||||
}
|
||||
|
||||
public int[] getSourceLocations() {
|
||||
return sourceLocations;
|
||||
}
|
||||
|
||||
public boolean isJpaStyle() {
|
||||
return jpaStyle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the parameters expected type
|
||||
*
|
||||
* @param type The new expected type
|
||||
*/
|
||||
public void resetExpectedType(Type type) {
|
||||
this.expectedType = type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return expectedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
|
|
|
@ -26,7 +26,7 @@ public class NativeQueryInterpreterInitiator implements SessionFactoryServiceIni
|
|||
SessionFactoryImplementor sessionFactory,
|
||||
SessionFactoryOptions sessionFactoryOptions,
|
||||
ServiceRegistryImplementor registry) {
|
||||
return NativeQueryInterpreterStandardImpl.INSTANCE;
|
||||
return new NativeQueryInterpreterStandardImpl( sessionFactory );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,22 +9,16 @@ package org.hibernate.engine.query.spi;
|
|||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.action.internal.BulkOperationCleanupAction;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.TypedValue;
|
||||
import org.hibernate.event.spi.EventSource;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.loader.custom.CustomQuery;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
|
||||
/**
|
||||
* Defines a query execution plan for a native-SQL query.
|
||||
|
@ -56,98 +50,6 @@ public class NativeSQLQueryPlan implements Serializable {
|
|||
return customQuery;
|
||||
}
|
||||
|
||||
private int[] getNamedParameterLocs(String name) throws QueryException {
|
||||
final Object loc = customQuery.getNamedParameterBindPoints().get( name );
|
||||
if ( loc == null ) {
|
||||
throw new QueryException(
|
||||
"Named parameter does not appear in Query: " + name,
|
||||
customQuery.getSQL() );
|
||||
}
|
||||
if ( loc instanceof Integer ) {
|
||||
return new int[] { (Integer) loc };
|
||||
}
|
||||
else {
|
||||
return ArrayHelper.toIntArray( (List) loc );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform binding of all the JDBC bind parameter values based on the user-defined
|
||||
* positional query parameters (these are the '?'-style hibernate query
|
||||
* params) into the JDBC {@link PreparedStatement}.
|
||||
*
|
||||
* @param st The prepared statement to which to bind the parameter values.
|
||||
* @param queryParameters The query parameters specified by the application.
|
||||
* @param start JDBC paramer binds are positional, so this is the position
|
||||
* from which to start binding.
|
||||
* @param session The session from which the query originated.
|
||||
*
|
||||
* @return The number of JDBC bind positions accounted for during execution.
|
||||
*
|
||||
* @throws SQLException Some form of JDBC error binding the values.
|
||||
* @throws HibernateException Generally indicates a mapping problem or type mismatch.
|
||||
*/
|
||||
private int bindPositionalParameters(
|
||||
final PreparedStatement st,
|
||||
final QueryParameters queryParameters,
|
||||
final int start,
|
||||
final SharedSessionContractImplementor session) throws SQLException {
|
||||
final Object[] values = queryParameters.getFilteredPositionalParameterValues();
|
||||
final Type[] types = queryParameters.getFilteredPositionalParameterTypes();
|
||||
int span = 0;
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
types[i].nullSafeSet( st, values[i], start + span, session );
|
||||
span += types[i].getColumnSpan( session.getFactory() );
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform binding of all the JDBC bind parameter values based on the user-defined
|
||||
* named query parameters into the JDBC {@link PreparedStatement}.
|
||||
*
|
||||
* @param ps The prepared statement to which to bind the parameter values.
|
||||
* @param namedParams The named query parameters specified by the application.
|
||||
* @param start JDBC paramer binds are positional, so this is the position
|
||||
* from which to start binding.
|
||||
* @param session The session from which the query originated.
|
||||
*
|
||||
* @return The number of JDBC bind positions accounted for during execution.
|
||||
*
|
||||
* @throws SQLException Some form of JDBC error binding the values.
|
||||
* @throws HibernateException Generally indicates a mapping problem or type mismatch.
|
||||
*/
|
||||
private int bindNamedParameters(
|
||||
final PreparedStatement ps,
|
||||
final Map namedParams,
|
||||
final int start,
|
||||
final SharedSessionContractImplementor session) throws SQLException {
|
||||
if ( namedParams != null ) {
|
||||
// assumes that types are all of span 1
|
||||
final Iterator iter = namedParams.entrySet().iterator();
|
||||
int result = 0;
|
||||
while ( iter.hasNext() ) {
|
||||
final Map.Entry e = (Map.Entry) iter.next();
|
||||
final String name = (String) e.getKey();
|
||||
final TypedValue typedval = (TypedValue) e.getValue();
|
||||
final int[] locs = getNamedParameterLocs( name );
|
||||
for ( int loc : locs ) {
|
||||
LOG.debugf( "bindNamedParameters() %s -> %s [%s]", typedval.getValue(), name, loc + start );
|
||||
typedval.getType().nullSafeSet(
|
||||
ps,
|
||||
typedval.getValue(),
|
||||
loc + start,
|
||||
session
|
||||
);
|
||||
}
|
||||
result += locs.length;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected void coordinateSharedCacheCleanup(SharedSessionContractImplementor session) {
|
||||
final BulkOperationCleanupAction action = new BulkOperationCleanupAction( session, getCustomQuery().getQuerySpaces() );
|
||||
|
||||
|
@ -194,8 +96,9 @@ public class NativeSQLQueryPlan implements Serializable {
|
|||
|
||||
try {
|
||||
int col = 1;
|
||||
col += bindPositionalParameters( ps, queryParameters, col, session );
|
||||
col += bindNamedParameters( ps, queryParameters.getNamedParameters(), col, session );
|
||||
for ( ParameterBinder binder : this.customQuery.getParameterValueBinders() ) {
|
||||
col += binder.bind( ps, queryParameters, session, col );
|
||||
}
|
||||
result = session.getJdbcCoordinator().getResultSetReturn().executeUpdate( ps );
|
||||
}
|
||||
finally {
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.engine.query.spi;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.query.QueryParameter;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
|
@ -16,58 +15,29 @@ import org.hibernate.type.Type;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
@Incubating
|
||||
public class OrdinalParameterDescriptor implements QueryParameter {
|
||||
private final int ordinalPosition;
|
||||
private final Type expectedType;
|
||||
private final int sourceLocation;
|
||||
public class OrdinalParameterDescriptor extends AbstractParameterDescriptor {
|
||||
private final int label;
|
||||
private final int valuePosition;
|
||||
|
||||
/**
|
||||
* Constructs an ordinal parameter descriptor.
|
||||
*
|
||||
* @param ordinalPosition The ordinal position
|
||||
* @param expectedType The expected type of the parameter
|
||||
* @param sourceLocation The location of the parameter
|
||||
*/
|
||||
public OrdinalParameterDescriptor(int ordinalPosition, Type expectedType, int sourceLocation) {
|
||||
this.ordinalPosition = ordinalPosition;
|
||||
this.expectedType = expectedType;
|
||||
this.sourceLocation = sourceLocation;
|
||||
}
|
||||
|
||||
public int getOrdinalPosition() {
|
||||
return ordinalPosition;
|
||||
}
|
||||
|
||||
public Type getExpectedType() {
|
||||
return expectedType;
|
||||
}
|
||||
|
||||
public int getSourceLocation() {
|
||||
return sourceLocation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getType() {
|
||||
return expectedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return null;
|
||||
public OrdinalParameterDescriptor(
|
||||
int label,
|
||||
int valuePosition,
|
||||
Type expectedType,
|
||||
int[] sourceLocations) {
|
||||
super( sourceLocations, expectedType );
|
||||
this.label = label;
|
||||
this.valuePosition = valuePosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getPosition() {
|
||||
return ordinalPosition;
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class getParameterType() {
|
||||
return expectedType == null ? null : expectedType.getReturnedClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaPositionalParameter() {
|
||||
return false;
|
||||
public int getValuePosition() {
|
||||
return valuePosition;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,13 @@
|
|||
package org.hibernate.engine.query.spi;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.engine.query.ParameterRecognitionException;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
|
||||
/**
|
||||
|
@ -20,97 +23,234 @@ import org.hibernate.internal.util.collections.ArrayHelper;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ParamLocationRecognizer implements ParameterParser.Recognizer {
|
||||
/**
|
||||
* Internal representation of a recognized named parameter
|
||||
*/
|
||||
public static class NamedParameterDescription {
|
||||
private final boolean jpaStyle;
|
||||
private final List<Integer> positions = new ArrayList<Integer>();
|
||||
|
||||
NamedParameterDescription(boolean jpaStyle) {
|
||||
this.jpaStyle = jpaStyle;
|
||||
}
|
||||
private Map<String, NamedParameterDescriptor> namedParameterDescriptors;
|
||||
private Map<Integer, OrdinalParameterDescriptor> ordinalParameterDescriptors;
|
||||
|
||||
public boolean isJpaStyle() {
|
||||
return jpaStyle;
|
||||
}
|
||||
private Map<String, InFlightNamedParameterState> inFlightNamedStateMap;
|
||||
private Map<Integer, InFlightOrdinalParameterState> inFlightOrdinalStateMap;
|
||||
private Map<Integer, InFlightJpaOrdinalParameterState> inFlightJpaOrdinalStateMap;
|
||||
|
||||
private void add(int position) {
|
||||
positions.add( position );
|
||||
}
|
||||
private final int jdbcStyleOrdinalCountBase;
|
||||
private int jdbcStyleOrdinalCount;
|
||||
|
||||
public int[] buildPositionsArray() {
|
||||
return ArrayHelper.toIntArray( positions );
|
||||
}
|
||||
public ParamLocationRecognizer(int jdbcStyleOrdinalCountBase) {
|
||||
this.jdbcStyleOrdinalCountBase = jdbcStyleOrdinalCountBase;
|
||||
this.jdbcStyleOrdinalCount = jdbcStyleOrdinalCountBase;
|
||||
}
|
||||
|
||||
private Map<String, NamedParameterDescription> namedParameterDescriptions = new HashMap<String, NamedParameterDescription>();
|
||||
private List<Integer> ordinalParameterLocationList = new ArrayList<Integer>();
|
||||
|
||||
/**
|
||||
* Convenience method for creating a param location recognizer and
|
||||
* initiating the parse.
|
||||
*
|
||||
* @param query The query to be parsed for parameter locations.
|
||||
* @param sessionFactory
|
||||
* @return The generated recognizer, with journaled location info.
|
||||
*/
|
||||
public static ParamLocationRecognizer parseLocations(String query) {
|
||||
final ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
|
||||
public static ParamLocationRecognizer parseLocations(
|
||||
String query,
|
||||
SessionFactoryImplementor sessionFactory) {
|
||||
final ParamLocationRecognizer recognizer = new ParamLocationRecognizer(
|
||||
sessionFactory.getSessionFactoryOptions().jdbcStyleParamsZeroBased() ? 0 : 1
|
||||
);
|
||||
ParameterParser.parse( query, recognizer );
|
||||
return recognizer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the map of named parameter locations. The map is keyed by
|
||||
* parameter name; the corresponding value is a (@link NamedParameterDescription}.
|
||||
*
|
||||
* @return The map of named parameter locations.
|
||||
*/
|
||||
public Map<String, NamedParameterDescription> getNamedParameterDescriptionMap() {
|
||||
return namedParameterDescriptions;
|
||||
@Override
|
||||
public void complete() {
|
||||
if ( inFlightNamedStateMap != null && ( inFlightOrdinalStateMap != null || inFlightJpaOrdinalStateMap != null ) ) {
|
||||
throw mixedParamStrategy();
|
||||
}
|
||||
|
||||
// we know `inFlightNamedStateMap` is null, so no need to check it again
|
||||
|
||||
if ( inFlightOrdinalStateMap != null && inFlightJpaOrdinalStateMap != null ) {
|
||||
throw mixedParamStrategy();
|
||||
}
|
||||
|
||||
if ( inFlightNamedStateMap != null ) {
|
||||
final Map<String, NamedParameterDescriptor> tmp = new HashMap<>();
|
||||
for ( InFlightNamedParameterState inFlightState : inFlightNamedStateMap.values() ) {
|
||||
tmp.put( inFlightState.name, inFlightState.complete() );
|
||||
}
|
||||
namedParameterDescriptors = Collections.unmodifiableMap( tmp );
|
||||
}
|
||||
else {
|
||||
namedParameterDescriptors = Collections.emptyMap();
|
||||
}
|
||||
|
||||
if ( inFlightOrdinalStateMap == null && inFlightJpaOrdinalStateMap == null ) {
|
||||
ordinalParameterDescriptors = Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
final Map<Integer, OrdinalParameterDescriptor> tmp = new HashMap<>();
|
||||
if ( inFlightOrdinalStateMap != null ) {
|
||||
for ( InFlightOrdinalParameterState state : inFlightOrdinalStateMap.values() ) {
|
||||
tmp.put( state.identifier, state.complete() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
for ( InFlightJpaOrdinalParameterState state : inFlightJpaOrdinalStateMap.values() ) {
|
||||
tmp.put( state.identifier, state.complete() );
|
||||
}
|
||||
}
|
||||
ordinalParameterDescriptors = Collections.unmodifiableMap( tmp );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the list of ordinal parameter locations. The list elements
|
||||
* are Integers, representing the location for that given ordinal. Thus calling
|
||||
* {@code getOrdinalParameterLocationList().elementAt(n)} represents the
|
||||
* location for the nth parameter.
|
||||
*
|
||||
* @return The list of ordinal parameter locations.
|
||||
*/
|
||||
public List<Integer> getOrdinalParameterLocationList() {
|
||||
return ordinalParameterLocationList;
|
||||
private ParameterRecognitionException mixedParamStrategy() {
|
||||
throw new ParameterRecognitionException( "Mixed parameter strategies - use just one of named, positional or JPA-ordinal strategy" );
|
||||
}
|
||||
|
||||
public Map<String, NamedParameterDescriptor> getNamedParameterDescriptionMap() {
|
||||
return namedParameterDescriptors;
|
||||
}
|
||||
|
||||
public Map<Integer, OrdinalParameterDescriptor> getOrdinalParameterDescriptionMap() {
|
||||
return ordinalParameterDescriptors;
|
||||
}
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// Recognition code ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
||||
// NOTE : we keep track of `inFlightOrdinalStateMap` versus `inFlightJpaOrdinalStateMap`
|
||||
// in order to perform better validations of mixed parameter strategies
|
||||
|
||||
@Override
|
||||
public void ordinalParameter(int position) {
|
||||
ordinalParameterLocationList.add( position );
|
||||
}
|
||||
@Override
|
||||
public void namedParameter(String name, int position) {
|
||||
getOrBuildNamedParameterDescription( name, false ).add( position );
|
||||
}
|
||||
@Override
|
||||
public void jpaPositionalParameter(String name, int position) {
|
||||
getOrBuildNamedParameterDescription( name, true ).add( position );
|
||||
if ( inFlightOrdinalStateMap == null ) {
|
||||
inFlightOrdinalStateMap = new HashMap<>();
|
||||
}
|
||||
|
||||
final int label = jdbcStyleOrdinalCount++;
|
||||
inFlightOrdinalStateMap.put(
|
||||
label,
|
||||
new InFlightOrdinalParameterState( label, label - jdbcStyleOrdinalCountBase, position )
|
||||
);
|
||||
}
|
||||
|
||||
private NamedParameterDescription getOrBuildNamedParameterDescription(String name, boolean jpa) {
|
||||
NamedParameterDescription desc = namedParameterDescriptions.get( name );
|
||||
if ( desc == null ) {
|
||||
desc = new NamedParameterDescription( jpa );
|
||||
namedParameterDescriptions.put( name, desc );
|
||||
}
|
||||
return desc;
|
||||
@Override
|
||||
public void namedParameter(String name, int position) {
|
||||
getOrBuildNamedParameterDescription( name ).add( position );
|
||||
}
|
||||
|
||||
private InFlightNamedParameterState getOrBuildNamedParameterDescription(String name) {
|
||||
if ( inFlightNamedStateMap == null ) {
|
||||
inFlightNamedStateMap = new HashMap<>();
|
||||
}
|
||||
|
||||
InFlightNamedParameterState descriptor = inFlightNamedStateMap.get( name );
|
||||
if ( descriptor == null ) {
|
||||
descriptor = new InFlightNamedParameterState( name );
|
||||
inFlightNamedStateMap.put( name, descriptor );
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jpaPositionalParameter(int name, int position) {
|
||||
getOrBuildJpaOrdinalParameterDescription( name ).add( position );
|
||||
}
|
||||
|
||||
private InFlightJpaOrdinalParameterState getOrBuildJpaOrdinalParameterDescription(int name) {
|
||||
if ( inFlightJpaOrdinalStateMap == null ) {
|
||||
inFlightJpaOrdinalStateMap = new HashMap<>();
|
||||
}
|
||||
|
||||
InFlightJpaOrdinalParameterState descriptor = inFlightJpaOrdinalStateMap.get( name );
|
||||
if ( descriptor == null ) {
|
||||
descriptor = new InFlightJpaOrdinalParameterState( name );
|
||||
inFlightJpaOrdinalStateMap.put( name, descriptor );
|
||||
}
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void other(char character) {
|
||||
// don't care...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outParameter(int position) {
|
||||
// don't care...
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal in-flight representation of a recognized named parameter
|
||||
*/
|
||||
public static class InFlightNamedParameterState {
|
||||
private final String name;
|
||||
private final List<Integer> sourcePositions = new ArrayList<>();
|
||||
|
||||
InFlightNamedParameterState(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
private void add(int position) {
|
||||
sourcePositions.add( position );
|
||||
}
|
||||
|
||||
private NamedParameterDescriptor complete() {
|
||||
return new NamedParameterDescriptor(
|
||||
name,
|
||||
null,
|
||||
ArrayHelper.toIntArray( sourcePositions )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal in-flight representation of a recognized named parameter
|
||||
*/
|
||||
public static class InFlightOrdinalParameterState {
|
||||
private final int identifier;
|
||||
private final int valuePosition;
|
||||
private final int sourcePosition;
|
||||
|
||||
InFlightOrdinalParameterState(int label, int valuePosition, int sourcePosition) {
|
||||
this.identifier = label;
|
||||
this.valuePosition = valuePosition;
|
||||
this.sourcePosition = sourcePosition;
|
||||
}
|
||||
|
||||
private OrdinalParameterDescriptor complete() {
|
||||
return new OrdinalParameterDescriptor(
|
||||
identifier,
|
||||
valuePosition,
|
||||
null,
|
||||
new int[] { sourcePosition }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Internal in-flight representation of a recognized named parameter
|
||||
*/
|
||||
public static class InFlightJpaOrdinalParameterState {
|
||||
private final int identifier;
|
||||
private final List<Integer> sourcePositions = new ArrayList<>();
|
||||
|
||||
InFlightJpaOrdinalParameterState(int identifier) {
|
||||
this.identifier = identifier;
|
||||
}
|
||||
|
||||
private void add(int position) {
|
||||
sourcePositions.add( position );
|
||||
}
|
||||
|
||||
private OrdinalParameterDescriptor complete() {
|
||||
return new OrdinalParameterDescriptor(
|
||||
identifier,
|
||||
identifier - 1,
|
||||
null,
|
||||
ArrayHelper.toIntArray( sourcePositions )
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,20 +22,20 @@ public class ParameterParser {
|
|||
/**
|
||||
* Maybe better named a Journaler. Essentially provides a callback contract for things that recognize parameters
|
||||
*/
|
||||
public static interface Recognizer {
|
||||
public interface Recognizer {
|
||||
/**
|
||||
* Called when an output parameter is recognized
|
||||
*
|
||||
* @param position The position within the query
|
||||
*/
|
||||
public void outParameter(int position);
|
||||
void outParameter(int position);
|
||||
|
||||
/**
|
||||
* Called when an ordinal parameter is recognized
|
||||
*
|
||||
* @param position The position within the query
|
||||
*/
|
||||
public void ordinalParameter(int position);
|
||||
void ordinalParameter(int position);
|
||||
|
||||
/**
|
||||
* Called when a named parameter is recognized
|
||||
|
@ -43,22 +43,24 @@ public class ParameterParser {
|
|||
* @param name The recognized parameter name
|
||||
* @param position The position within the query
|
||||
*/
|
||||
public void namedParameter(String name, int position);
|
||||
void namedParameter(String name, int position);
|
||||
|
||||
/**
|
||||
* Called when a JPA-style named parameter is recognized
|
||||
*
|
||||
* @param name The name of the JPA-style parameter
|
||||
* @param identifier The identifier (name) of the JPA-style parameter
|
||||
* @param position The position within the query
|
||||
*/
|
||||
public void jpaPositionalParameter(String name, int position);
|
||||
void jpaPositionalParameter(int identifier, int position);
|
||||
|
||||
/**
|
||||
* Called when a character that is not a parameter (or part of a parameter dfinition) is recognized.
|
||||
*
|
||||
* @param character The recognized character
|
||||
*/
|
||||
public void other(char character);
|
||||
void other(char character);
|
||||
|
||||
void complete();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,20 +181,19 @@ public class ParameterParser {
|
|||
}
|
||||
else if ( c == '?' ) {
|
||||
// could be either an ordinal or JPA-positional parameter
|
||||
if ( indx < stringLength - 1 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {
|
||||
if ( indx < stringLength - 2 && Character.isDigit( sqlString.charAt( indx + 1 ) ) ) {
|
||||
// a peek ahead showed this as an JPA-positional parameter
|
||||
final int right = StringHelper.firstIndexOfChar( sqlString, ParserHelper.HQL_SEPARATORS, indx + 1 );
|
||||
final int chopLocation = right < 0 ? sqlString.length() : right;
|
||||
final String param = sqlString.substring( indx + 1, chopLocation );
|
||||
// make sure this "name" is an integral
|
||||
try {
|
||||
Integer.valueOf( param );
|
||||
recognizer.jpaPositionalParameter( Integer.valueOf( param ), indx );
|
||||
indx = chopLocation - 1;
|
||||
}
|
||||
catch( NumberFormatException e ) {
|
||||
throw new QueryException( "JPA-style positional param was not an integral ordinal" );
|
||||
}
|
||||
recognizer.jpaPositionalParameter( param, indx );
|
||||
indx = chopLocation - 1;
|
||||
}
|
||||
else {
|
||||
if ( hasMainOutputParameter && !foundMainOutputParam ) {
|
||||
|
@ -209,6 +210,8 @@ public class ParameterParser {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
recognizer.complete();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -45,6 +45,7 @@ public final class QueryParameters {
|
|||
private Type[] positionalParameterTypes;
|
||||
private Object[] positionalParameterValues;
|
||||
private Map<String,TypedValue> namedParameters;
|
||||
|
||||
private LockOptions lockOptions;
|
||||
private RowSelection rowSelection;
|
||||
private boolean cacheable;
|
||||
|
|
|
@ -20,23 +20,24 @@ import antlr.RecognitionException;
|
|||
/**
|
||||
* An error handler that counts parsing errors and warnings.
|
||||
*/
|
||||
public class ErrorCounter implements ParseErrorHandler {
|
||||
public class ErrorTracker implements ParseErrorHandler {
|
||||
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
|
||||
CoreMessageLogger.class,
|
||||
ErrorCounter.class.getName()
|
||||
ErrorTracker.class.getName()
|
||||
);
|
||||
|
||||
private final String hql;
|
||||
|
||||
private List<String> errorList = new ArrayList<String>();
|
||||
private List<RecognitionException> recognitionExceptions = new ArrayList<RecognitionException>();
|
||||
private List<String> errorList = new ArrayList<>();
|
||||
private List<RecognitionException> recognitionExceptions = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Constructs an ErrorCounter without knowledge of the HQL, meaning that generated QueryException
|
||||
* instances *will not* contain the HQL (and will need to be wrapped at a higher level in another
|
||||
* QueryException).
|
||||
*/
|
||||
public ErrorCounter() {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public ErrorTracker() {
|
||||
this( null );
|
||||
}
|
||||
|
||||
|
@ -44,7 +45,8 @@ public class ErrorCounter implements ParseErrorHandler {
|
|||
* Constructs an ErrorCounter with knowledge of the HQL, meaning that generated QueryException
|
||||
* instances *will* contain the HQL.
|
||||
*/
|
||||
public ErrorCounter(String hql) {
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
public ErrorTracker(String hql) {
|
||||
this.hql = hql;
|
||||
}
|
||||
|
|
@ -61,7 +61,7 @@ public final class HqlParser extends HqlBaseParser {
|
|||
private HqlParser(String hql) {
|
||||
// The fix for HHH-558...
|
||||
super( new HqlLexer( new StringReader( hql ) ) );
|
||||
parseErrorHandler = new ErrorCounter( hql );
|
||||
parseErrorHandler = new ErrorTracker( hql );
|
||||
// Create nodes that track line and column number.
|
||||
setASTFactory( new HqlASTFactory() );
|
||||
}
|
||||
|
|
|
@ -15,6 +15,7 @@ import java.util.HashMap;
|
|||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
|
@ -94,6 +95,8 @@ import antlr.RecognitionException;
|
|||
import antlr.SemanticException;
|
||||
import antlr.collections.AST;
|
||||
|
||||
import static org.hibernate.hql.spi.QueryTranslator.ERROR_LEGACY_ORDINAL_PARAMS_NO_LONGER_SUPPORTED;
|
||||
|
||||
/**
|
||||
* Implements methods used by the HQL->SQL tree transform grammar (a.k.a. the second phase).
|
||||
* <ul>
|
||||
|
@ -125,15 +128,16 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
|||
* Maps each top-level result variable to its SelectExpression;
|
||||
* (excludes result variables defined in subqueries)
|
||||
*/
|
||||
private Map<String, SelectExpression> selectExpressionsByResultVariable = new HashMap<String, SelectExpression>();
|
||||
private Map<String, SelectExpression> selectExpressionsByResultVariable = new HashMap<>();
|
||||
|
||||
private Set<Serializable> querySpaces = new HashSet<Serializable>();
|
||||
private Set<Serializable> querySpaces = new HashSet<>();
|
||||
|
||||
private int parameterCount;
|
||||
private Map namedParameters = new HashMap();
|
||||
private ArrayList<ParameterSpecification> parameters = new ArrayList<ParameterSpecification>();
|
||||
private Map namedParameters;
|
||||
private Map positionalParameters;
|
||||
|
||||
private ArrayList<ParameterSpecification> parameterSpecs = new ArrayList<>();
|
||||
private int numberOfParametersInSetClause;
|
||||
private int positionalParameterCount;
|
||||
|
||||
private ArrayList assignmentSpecifications = new ArrayList();
|
||||
|
||||
|
@ -160,7 +164,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
|||
String collectionRole) {
|
||||
setASTFactory( new SqlASTFactory( this ) );
|
||||
// Initialize the error handling delegate.
|
||||
this.parseErrorHandler = new ErrorCounter( qti.getQueryString() );
|
||||
this.parseErrorHandler = new ErrorTracker( qti.getQueryString() );
|
||||
this.queryTranslatorImpl = qti;
|
||||
this.sessionFactoryHelper = new SessionFactoryHelper( sfi );
|
||||
this.literalProcessor = new LiteralProcessor( this );
|
||||
|
@ -227,7 +231,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
|||
// positionalParameterCount++
|
||||
// );
|
||||
// collectionFilterKeyParameter.setHqlParameterSpecification( paramSpec );
|
||||
// parameters.add( paramSpec );
|
||||
// parameterSpecs.add( paramSpec );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
@ -252,14 +256,16 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
|||
queryTranslatorImpl.showHqlAst( hqlParser.getAST() );
|
||||
|
||||
// Create a parameter specification for the collection filter...
|
||||
Type collectionFilterKeyType = sessionFactoryHelper.requireQueryableCollection( collectionFilterRole )
|
||||
final Type collectionFilterKeyType = sessionFactoryHelper.requireQueryableCollection( collectionFilterRole )
|
||||
.getKeyType();
|
||||
ParameterNode collectionFilterKeyParameter = (ParameterNode) astFactory.create( PARAM, "?" );
|
||||
CollectionFilterKeyParameterSpecification collectionFilterKeyParameterSpec = new CollectionFilterKeyParameterSpecification(
|
||||
collectionFilterRole, collectionFilterKeyType, positionalParameterCount++
|
||||
final ParameterNode collectionFilterKeyParameter = (ParameterNode) astFactory.create( PARAM, "?" );
|
||||
final CollectionFilterKeyParameterSpecification collectionFilterKeyParameterSpec = new CollectionFilterKeyParameterSpecification(
|
||||
collectionFilterRole,
|
||||
collectionFilterKeyType
|
||||
);
|
||||
parameterCount++;
|
||||
collectionFilterKeyParameter.setHqlParameterSpecification( collectionFilterKeyParameterSpec );
|
||||
parameters.add( collectionFilterKeyParameterSpec );
|
||||
parameterSpecs.add( collectionFilterKeyParameterSpec );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -936,7 +942,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
|||
versionValueNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" );
|
||||
ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType );
|
||||
( (ParameterNode) versionValueNode ).setHqlParameterSpecification( paramSpec );
|
||||
parameters.add( 0, paramSpec );
|
||||
parameterSpecs.add( 0, paramSpec );
|
||||
|
||||
if ( sessionFactoryHelper.getFactory().getDialect().requiresCastingOfParametersInSelectClause() ) {
|
||||
// we need to wrtap the param in a cast()
|
||||
|
@ -977,7 +983,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
|||
versionValueNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, functionName );
|
||||
}
|
||||
else {
|
||||
throw new QueryException( "cannot handle version type [" + versionType + "] on bulk inserts with dialects not supporting parameters in insert-select statements" );
|
||||
throw new QueryException( "cannot handle version type [" + versionType + "] on bulk inserts with dialects not supporting parameterSpecs in insert-select statements" );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1081,64 +1087,109 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
|||
}
|
||||
|
||||
@Override
|
||||
protected AST generatePositionalParameter(AST inputNode) throws SemanticException {
|
||||
if ( namedParameters.size() > 0 ) {
|
||||
protected AST generatePositionalParameter(AST delimiterNode, AST numberNode) throws SemanticException {
|
||||
// todo : we check this multiple times
|
||||
if ( namedParameters != null ) {
|
||||
throw new SemanticException(
|
||||
"cannot define positional parameter after any named parameters have been defined"
|
||||
"Cannot define positional and named parameterSpecs : " + queryTranslatorImpl.getQueryString()
|
||||
);
|
||||
}
|
||||
LOG.warnf(
|
||||
"[DEPRECATION] Encountered positional parameter near line %s, column %s in HQL: [%s]. Positional parameter " +
|
||||
"are considered deprecated; use named parameters or JPA-style positional parameters instead.",
|
||||
inputNode.getLine(),
|
||||
inputNode.getColumn(),
|
||||
queryTranslatorImpl.getQueryString()
|
||||
);
|
||||
ParameterNode parameter = (ParameterNode) astFactory.create( PARAM, "?" );
|
||||
PositionalParameterSpecification paramSpec = new PositionalParameterSpecification(
|
||||
inputNode.getLine(),
|
||||
inputNode.getColumn(),
|
||||
positionalParameterCount++
|
||||
|
||||
if ( numberNode == null ) {
|
||||
throw new QueryException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
ERROR_LEGACY_ORDINAL_PARAMS_NO_LONGER_SUPPORTED,
|
||||
queryTranslatorImpl.getQueryString()
|
||||
)
|
||||
);
|
||||
}
|
||||
final String positionString = numberNode.getText();
|
||||
final int label = Integer.parseInt( positionString );
|
||||
trackPositionalParameterPositions( label );
|
||||
|
||||
final ParameterNode parameter = (ParameterNode) astFactory.create( PARAM, positionString );
|
||||
parameter.setText( "?" );
|
||||
|
||||
final int queryParamtersPosition = isFilter()
|
||||
? label
|
||||
: label - 1;
|
||||
final PositionalParameterSpecification paramSpec = new PositionalParameterSpecification(
|
||||
delimiterNode.getLine(),
|
||||
delimiterNode.getColumn(),
|
||||
label,
|
||||
queryParamtersPosition
|
||||
);
|
||||
parameter.setHqlParameterSpecification( paramSpec );
|
||||
parameters.add( paramSpec );
|
||||
parameterSpecs.add( paramSpec );
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void trackPositionalParameterPositions(int label) {
|
||||
if ( positionalParameters == null ) {
|
||||
positionalParameters = new HashMap();
|
||||
}
|
||||
|
||||
final Integer loc = parameterCount++;
|
||||
|
||||
final Object existingValue = positionalParameters.get( label );
|
||||
if ( existingValue == null ) {
|
||||
positionalParameters.put( label, loc );
|
||||
}
|
||||
else if ( existingValue instanceof Integer ) {
|
||||
final ArrayList list = new ArrayList();
|
||||
positionalParameters.put( label, list );
|
||||
list.add( existingValue );
|
||||
list.add( loc );
|
||||
}
|
||||
else {
|
||||
( (List) existingValue ).add( loc );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected AST generateNamedParameter(AST delimiterNode, AST nameNode) throws SemanticException {
|
||||
String name = nameNode.getText();
|
||||
final String name = nameNode.getText();
|
||||
trackNamedParameterPositions( name );
|
||||
|
||||
// create the node initially with the param name so that it shows
|
||||
// appropriately in the "original text" attribute
|
||||
ParameterNode parameter = (ParameterNode) astFactory.create( NAMED_PARAM, name );
|
||||
final ParameterNode parameter = (ParameterNode) astFactory.create( NAMED_PARAM, name );
|
||||
parameter.setText( "?" );
|
||||
|
||||
NamedParameterSpecification paramSpec = new NamedParameterSpecification(
|
||||
final NamedParameterSpecification paramSpec = new NamedParameterSpecification(
|
||||
delimiterNode.getLine(),
|
||||
delimiterNode.getColumn(),
|
||||
name
|
||||
);
|
||||
parameter.setHqlParameterSpecification( paramSpec );
|
||||
parameters.add( paramSpec );
|
||||
parameterSpecs.add( paramSpec );
|
||||
|
||||
return parameter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void trackNamedParameterPositions(String name) {
|
||||
Integer loc = parameterCount++;
|
||||
Object o = namedParameters.get( name );
|
||||
if ( o == null ) {
|
||||
if ( namedParameters == null ) {
|
||||
namedParameters = new HashMap();
|
||||
}
|
||||
|
||||
final Integer loc = parameterCount++;
|
||||
|
||||
final Object existingValue = namedParameters.get( name );
|
||||
if ( existingValue == null ) {
|
||||
namedParameters.put( name, loc );
|
||||
}
|
||||
else if ( o instanceof Integer ) {
|
||||
ArrayList list = new ArrayList( 4 );
|
||||
list.add( o );
|
||||
else if ( existingValue instanceof Integer ) {
|
||||
ArrayList<Integer> list = new ArrayList<>( 4 );
|
||||
list.add( (Integer) existingValue );
|
||||
list.add( loc );
|
||||
namedParameters.put( name, list );
|
||||
}
|
||||
else {
|
||||
( (ArrayList) o ).add( loc );
|
||||
( (List) existingValue ).add( loc );
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1284,8 +1335,8 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
|||
return printer;
|
||||
}
|
||||
|
||||
public ArrayList<ParameterSpecification> getParameters() {
|
||||
return parameters;
|
||||
public ArrayList<ParameterSpecification> getParameterSpecs() {
|
||||
return parameterSpecs;
|
||||
}
|
||||
|
||||
public int getNumberOfParametersInSetClause() {
|
||||
|
@ -1356,7 +1407,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
|
|||
versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" );
|
||||
ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType );
|
||||
( (ParameterNode) versionIncrementNode ).setHqlParameterSpecification( paramSpec );
|
||||
parameters.add( 0, paramSpec );
|
||||
parameterSpecs.add( 0, paramSpec );
|
||||
}
|
||||
else {
|
||||
// Not possible to simply re-use the versionPropertyNode here as it causes
|
||||
|
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.hql.internal.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.hql.spi.NamedParameterInformation;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NamedParameterInformationImpl implements NamedParameterInformation {
|
||||
private final String name;
|
||||
|
||||
private final List<Integer> sqlPositions = new ArrayList<>();
|
||||
|
||||
private Type expectedType;
|
||||
|
||||
NamedParameterInformationImpl(String name, Type initialType) {
|
||||
this.name = name;
|
||||
this.expectedType = initialType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSourceLocations() {
|
||||
return ArrayHelper.toIntArray( sqlPositions );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getExpectedType() {
|
||||
return expectedType;
|
||||
}
|
||||
|
||||
public void addSourceLocation(int position) {
|
||||
sqlPositions.add( position );
|
||||
}
|
||||
|
||||
public void setExpectedType(Type expectedType) {
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
}
|
|
@ -6,19 +6,17 @@
|
|||
*/
|
||||
package org.hibernate.hql.internal.ast;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.hql.spi.NamedParameterInformation;
|
||||
import org.hibernate.hql.spi.ParameterTranslations;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.hql.spi.PositionalParameterInformation;
|
||||
import org.hibernate.param.NamedParameterSpecification;
|
||||
import org.hibernate.param.ParameterSpecification;
|
||||
import org.hibernate.param.PositionalParameterSpecification;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* Defines the information available for parameters encountered during
|
||||
|
@ -27,52 +25,8 @@ import org.hibernate.type.Type;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ParameterTranslationsImpl implements ParameterTranslations {
|
||||
private final Map<String,ParameterInfo> namedParameters;
|
||||
private final ParameterInfo[] ordinalParameters;
|
||||
|
||||
@Override
|
||||
public boolean supportsOrdinalParameterMetadata() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrdinalParameterCount() {
|
||||
return ordinalParameters.length;
|
||||
}
|
||||
|
||||
public ParameterInfo getOrdinalParameterInfo(int ordinalPosition) {
|
||||
return ordinalParameters[ordinalPosition];
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrdinalParameterSqlLocation(int ordinalPosition) {
|
||||
return getOrdinalParameterInfo( ordinalPosition ).getSqlLocations()[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getOrdinalParameterExpectedType(int ordinalPosition) {
|
||||
return getOrdinalParameterInfo( ordinalPosition ).getExpectedType();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set getNamedParameterNames() {
|
||||
return namedParameters.keySet();
|
||||
}
|
||||
|
||||
public ParameterInfo getNamedParameterInfo(String name) {
|
||||
return namedParameters.get( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getNamedParameterSqlLocations(String name) {
|
||||
return getNamedParameterInfo( name ).getSqlLocations();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getNamedParameterExpectedType(String name) {
|
||||
return getNamedParameterInfo( name ).getExpectedType();
|
||||
}
|
||||
|
||||
private final Map<String,NamedParameterInformationImpl> namedParameters;
|
||||
private final Map<Integer,PositionalParameterInformationImpl > ordinalParameters;
|
||||
/**
|
||||
* Constructs a parameter metadata object given a list of parameter
|
||||
* specifications.
|
||||
|
@ -82,78 +36,72 @@ public class ParameterTranslationsImpl implements ParameterTranslations {
|
|||
*
|
||||
* @param parameterSpecifications The parameter specifications
|
||||
*/
|
||||
public ParameterTranslationsImpl(List<ParameterSpecification> parameterSpecifications) {
|
||||
class NamedParamTempHolder {
|
||||
private String name;
|
||||
private Type type;
|
||||
private List<Integer> positions = new ArrayList<>();
|
||||
ParameterTranslationsImpl(List<ParameterSpecification> parameterSpecifications) {
|
||||
Map<String, NamedParameterInformationImpl> namedParameters = null;
|
||||
Map<Integer, PositionalParameterInformationImpl> ordinalParameters = null;
|
||||
|
||||
int i = 0;
|
||||
for ( ParameterSpecification specification : parameterSpecifications ) {
|
||||
if ( PositionalParameterSpecification.class.isInstance( specification ) ) {
|
||||
if ( ordinalParameters == null ) {
|
||||
ordinalParameters = new HashMap<>();
|
||||
}
|
||||
|
||||
final PositionalParameterSpecification ordinalSpecification = (PositionalParameterSpecification) specification;
|
||||
final PositionalParameterInformationImpl info = ordinalParameters.computeIfAbsent(
|
||||
ordinalSpecification.getLabel(),
|
||||
k -> new PositionalParameterInformationImpl( k, ordinalSpecification.getExpectedType() )
|
||||
);
|
||||
info.addSourceLocation( i++ );
|
||||
}
|
||||
else if ( NamedParameterSpecification.class.isInstance( specification ) ) {
|
||||
if ( namedParameters == null ) {
|
||||
namedParameters = new HashMap<>();
|
||||
}
|
||||
|
||||
final NamedParameterSpecification namedSpecification = (NamedParameterSpecification) specification;
|
||||
final NamedParameterInformationImpl info = namedParameters.computeIfAbsent(
|
||||
namedSpecification.getName(),
|
||||
k -> new NamedParameterInformationImpl( k, namedSpecification.getExpectedType() )
|
||||
);
|
||||
info.addSourceLocation( i++ );
|
||||
}
|
||||
}
|
||||
|
||||
final int size = parameterSpecifications.size();
|
||||
final List<ParameterInfo> ordinalParameterList = new ArrayList<>();
|
||||
final Map<String,NamedParamTempHolder> namedParameterMap = new HashMap<>();
|
||||
for ( int i = 0; i < size; i++ ) {
|
||||
final ParameterSpecification spec = parameterSpecifications.get( i );
|
||||
if ( PositionalParameterSpecification.class.isInstance( spec ) ) {
|
||||
final PositionalParameterSpecification ordinalSpec = (PositionalParameterSpecification) spec;
|
||||
ordinalParameterList.add( new ParameterInfo( i, ordinalSpec.getExpectedType() ) );
|
||||
}
|
||||
else if ( NamedParameterSpecification.class.isInstance( spec ) ) {
|
||||
final NamedParameterSpecification namedSpec = (NamedParameterSpecification) spec;
|
||||
NamedParamTempHolder paramHolder = namedParameterMap.get( namedSpec.getName() );
|
||||
if ( paramHolder == null ) {
|
||||
paramHolder = new NamedParamTempHolder();
|
||||
paramHolder.name = namedSpec.getName();
|
||||
paramHolder.type = namedSpec.getExpectedType();
|
||||
namedParameterMap.put( namedSpec.getName(), paramHolder );
|
||||
}
|
||||
else if ( paramHolder.type == null && namedSpec.getExpectedType() != null ) {
|
||||
// previous reference to the named parameter did not have type determined;
|
||||
// this time, it can be determined by namedSpec.getExpectedType().
|
||||
paramHolder.type = namedSpec.getExpectedType();
|
||||
}
|
||||
paramHolder.positions.add( i );
|
||||
}
|
||||
// don't care about other param types here, just those explicitly user-defined...
|
||||
}
|
||||
|
||||
ordinalParameters = ordinalParameterList.toArray( new ParameterInfo[ordinalParameterList.size()] );
|
||||
|
||||
if ( namedParameterMap.isEmpty() ) {
|
||||
namedParameters = java.util.Collections.emptyMap();
|
||||
if ( namedParameters == null ) {
|
||||
this.namedParameters = Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
final Map<String,ParameterInfo> namedParametersBacking = new HashMap<>( namedParameterMap.size() );
|
||||
for ( NamedParamTempHolder holder : namedParameterMap.values() ) {
|
||||
namedParametersBacking.put(
|
||||
holder.name,
|
||||
new ParameterInfo( ArrayHelper.toIntArray( holder.positions ), holder.type )
|
||||
);
|
||||
}
|
||||
namedParameters = java.util.Collections.unmodifiableMap( namedParametersBacking );
|
||||
this.namedParameters = Collections.unmodifiableMap( namedParameters );
|
||||
}
|
||||
|
||||
if ( ordinalParameters == null ) {
|
||||
this.ordinalParameters = Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
this.ordinalParameters = Collections.unmodifiableMap( ordinalParameters );
|
||||
}
|
||||
}
|
||||
|
||||
public static class ParameterInfo implements Serializable {
|
||||
private final int[] sqlLocations;
|
||||
private final Type expectedType;
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map getNamedParameterInformationMap() {
|
||||
return namedParameters;
|
||||
}
|
||||
|
||||
public ParameterInfo(int[] sqlPositions, Type expectedType) {
|
||||
this.sqlLocations = sqlPositions;
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public Map getPositionalParameterInformationMap() {
|
||||
return ordinalParameters;
|
||||
}
|
||||
|
||||
public ParameterInfo(int sqlPosition, Type expectedType) {
|
||||
this.sqlLocations = new int[] { sqlPosition };
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
@Override
|
||||
public PositionalParameterInformation getPositionalParameterInformation(int position) {
|
||||
return ordinalParameters.get( position );
|
||||
}
|
||||
|
||||
public int[] getSqlLocations() {
|
||||
return sqlLocations;
|
||||
}
|
||||
|
||||
public Type getExpectedType() {
|
||||
return expectedType;
|
||||
}
|
||||
@Override
|
||||
public NamedParameterInformation getNamedParameterInformation(String name) {
|
||||
return namedParameters.get( name );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.hql.internal.ast;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.hql.spi.PositionalParameterInformation;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PositionalParameterInformationImpl implements PositionalParameterInformation {
|
||||
private final int label;
|
||||
|
||||
private final List<Integer> sourceLocations = new ArrayList<>();
|
||||
|
||||
private Type expectedType;
|
||||
|
||||
public PositionalParameterInformationImpl(int label, Type initialType) {
|
||||
this.label = label;
|
||||
this.expectedType = initialType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getSourceLocations() {
|
||||
return ArrayHelper.toIntArray( sourceLocations );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getExpectedType() {
|
||||
return expectedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpectedType(Type expectedType) {
|
||||
this.expectedType = expectedType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSourceLocation(int location) {
|
||||
sourceLocations.add( location );
|
||||
}
|
||||
}
|
|
@ -48,6 +48,7 @@ import org.hibernate.internal.util.ReflectHelper;
|
|||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.IdentitySet;
|
||||
import org.hibernate.loader.hql.QueryLoader;
|
||||
import org.hibernate.param.CollectionFilterKeyParameterSpecification;
|
||||
import org.hibernate.param.ParameterSpecification;
|
||||
import org.hibernate.persister.entity.Queryable;
|
||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||
|
@ -252,7 +253,12 @@ public class QueryTranslatorImpl implements FilterTranslator {
|
|||
LOG.debugf( "SQL: %s", sql );
|
||||
}
|
||||
gen.getParseErrorHandler().throwQueryException();
|
||||
collectedParameterSpecifications = gen.getCollectedParameters();
|
||||
if ( collectedParameterSpecifications == null ) {
|
||||
collectedParameterSpecifications = gen.getCollectedParameters();
|
||||
}
|
||||
else {
|
||||
collectedParameterSpecifications.addAll( gen.getCollectedParameters() );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -583,7 +589,7 @@ public class QueryTranslatorImpl implements FilterTranslator {
|
|||
@Override
|
||||
public ParameterTranslations getParameterTranslations() {
|
||||
if ( paramTranslations == null ) {
|
||||
paramTranslations = new ParameterTranslationsImpl( getWalker().getParameters() );
|
||||
paramTranslations = new ParameterTranslationsImpl( getWalker().getParameterSpecs() );
|
||||
}
|
||||
return paramTranslations;
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter {
|
|||
|
||||
public SqlGenerator(SessionFactoryImplementor sfi) {
|
||||
super();
|
||||
parseErrorHandler = new ErrorCounter();
|
||||
parseErrorHandler = new ErrorTracker();
|
||||
sessionFactory = sfi;
|
||||
}
|
||||
|
||||
|
|
|
@ -88,8 +88,7 @@ public class SyntheticAndFactory implements HqlSqlTokenTypes {
|
|||
.getKeyType();
|
||||
CollectionFilterKeyParameterSpecification paramSpec = new CollectionFilterKeyParameterSpecification(
|
||||
hqlSqlWalker.getCollectionFilterRole(),
|
||||
collectionFilterKeyType,
|
||||
0
|
||||
collectionFilterKeyType
|
||||
);
|
||||
fragment.addEmbeddedParameter( paramSpec );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.hql.internal.classic;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.hql.spi.ParameterInformation;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public abstract class AbstractParameterInformation implements ParameterInformation, ParameterBinder {
|
||||
private List<Integer> sqlPositions = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public int[] getSourceLocations() {
|
||||
return ArrayHelper.toIntArray( sqlPositions );
|
||||
}
|
||||
|
||||
public void addSourceLocation(int position) {
|
||||
sqlPositions.add( position );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getExpectedType() {
|
||||
// the classic translator does not know this information
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setExpectedType(Type expectedType) {
|
||||
// nothing to do - classic translator does not know this information
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.hql.internal.classic;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.TypedValue;
|
||||
import org.hibernate.hql.spi.NamedParameterInformation;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NamedParameterInformationImpl extends AbstractParameterInformation implements NamedParameterInformation {
|
||||
private final String name;
|
||||
|
||||
NamedParameterInformationImpl(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSourceName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bind(
|
||||
PreparedStatement statement,
|
||||
QueryParameters qp,
|
||||
SharedSessionContractImplementor session,
|
||||
int position) throws SQLException {
|
||||
final TypedValue typedValue = qp.getNamedParameters().get( name );
|
||||
typedValue.getType().nullSafeSet( statement, typedValue.getValue(), position, session );
|
||||
return typedValue.getType().getColumnSpan( session.getFactory() );
|
||||
}
|
||||
}
|
|
@ -5,9 +5,13 @@
|
|||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.hql.internal.classic;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
|
||||
import static org.hibernate.hql.spi.QueryTranslator.ERROR_LEGACY_ORDINAL_PARAMS_NO_LONGER_SUPPORTED;
|
||||
|
||||
/**
|
||||
* Parses the ORDER BY clause of a query
|
||||
*/
|
||||
|
@ -40,6 +44,29 @@ public class OrderByParser implements Parser {
|
|||
q.addNamedParameter( token.substring( 1 ) );
|
||||
q.appendOrderByToken( "?" );
|
||||
}
|
||||
else if ( token.startsWith( "?" ) ) {
|
||||
// ordinal query parameter
|
||||
if ( token.length() == 1 ) {
|
||||
throw new QueryException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
ERROR_LEGACY_ORDINAL_PARAMS_NO_LONGER_SUPPORTED,
|
||||
q.getQueryString()
|
||||
)
|
||||
);
|
||||
}
|
||||
else {
|
||||
final String labelString = token.substring( 1 );
|
||||
try {
|
||||
final int label = Integer.parseInt( labelString );
|
||||
q.addOrdinalParameter( label );
|
||||
q.appendOrderByToken( "?" );
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new QueryException( "Ordinal parameter label must be numeric : " + labelString, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
q.appendOrderByToken( token );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.hql.internal.classic;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.TypedValue;
|
||||
import org.hibernate.hql.spi.PositionalParameterInformation;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PositionalParameterInformationImpl
|
||||
extends AbstractParameterInformation
|
||||
implements PositionalParameterInformation {
|
||||
private final int label;
|
||||
|
||||
public PositionalParameterInformationImpl(int label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getLabel() {
|
||||
return label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bind(
|
||||
PreparedStatement statement,
|
||||
QueryParameters qp,
|
||||
SharedSessionContractImplementor session,
|
||||
int position) throws SQLException {
|
||||
final TypedValue typedValue = qp.getNamedParameters().get( Integer.toString( label ) );
|
||||
typedValue.getType().nullSafeSet( statement, typedValue.getValue(), position, session );
|
||||
return typedValue.getType().getColumnSpan( session.getFactory() );
|
||||
}
|
||||
}
|
|
@ -38,7 +38,9 @@ import org.hibernate.event.spi.EventSource;
|
|||
import org.hibernate.hql.internal.HolderInstantiator;
|
||||
import org.hibernate.hql.internal.NameGenerator;
|
||||
import org.hibernate.hql.spi.FilterTranslator;
|
||||
import org.hibernate.hql.spi.NamedParameterInformation;
|
||||
import org.hibernate.hql.spi.ParameterTranslations;
|
||||
import org.hibernate.hql.spi.PositionalParameterInformation;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.IteratorImpl;
|
||||
|
@ -47,6 +49,8 @@ import org.hibernate.internal.util.StringHelper;
|
|||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.loader.BasicLoader;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.param.CollectionFilterKeyParameterSpecification;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
|
@ -78,12 +82,15 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
|
|||
private List returnedTypes = new ArrayList();
|
||||
private final List fromTypes = new ArrayList();
|
||||
private final List scalarTypes = new ArrayList();
|
||||
private final Map namedParameters = new HashMap();
|
||||
private final Map aliasNames = new HashMap();
|
||||
private final Map oneToOneOwnerNames = new HashMap();
|
||||
private final Map uniqueKeyOwnerReferences = new HashMap();
|
||||
private final Map decoratedPropertyMappings = new HashMap();
|
||||
|
||||
private final Map<String,NamedParameterInformationImpl> namedParameters = new HashMap<>();
|
||||
private final Map<Integer, PositionalParameterInformationImpl> ordinalParameters = new HashMap<>();
|
||||
private final List<ParameterBinder> paramValueBinders = new ArrayList<>();
|
||||
|
||||
private final List scalarSelectTokens = new ArrayList();
|
||||
private final List whereTokens = new ArrayList();
|
||||
private final List havingTokens = new ArrayList();
|
||||
|
@ -205,6 +212,12 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
|
|||
|
||||
if ( !isCompiled() ) {
|
||||
addFromAssociation( "this", collectionRole );
|
||||
paramValueBinders.add(
|
||||
new CollectionFilterKeyParameterSpecification(
|
||||
collectionRole,
|
||||
getFactory().getMetamodel().collectionPersister( collectionRole ).getKeyType()
|
||||
)
|
||||
);
|
||||
compile( replacements, scalar );
|
||||
}
|
||||
}
|
||||
|
@ -530,20 +543,81 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
|
|||
if ( superQuery != null ) {
|
||||
superQuery.addNamedParameter( name );
|
||||
}
|
||||
Integer loc = parameterCount++;
|
||||
Object o = namedParameters.get( name );
|
||||
if ( o == null ) {
|
||||
namedParameters.put( name, loc );
|
||||
|
||||
final Integer loc = parameterCount++;
|
||||
|
||||
final NamedParameterInformationImpl info = namedParameters.computeIfAbsent(
|
||||
name,
|
||||
k -> new NamedParameterInformationImpl( name )
|
||||
);
|
||||
paramValueBinders.add( info );
|
||||
info.addSourceLocation( loc );
|
||||
}
|
||||
|
||||
private enum OrdinalParameterStyle { LABELED, LEGACY }
|
||||
|
||||
private OrdinalParameterStyle ordinalParameterStyle;
|
||||
|
||||
private int legacyPositionalParameterCount = 0;
|
||||
|
||||
void addLegacyPositionalParameter() {
|
||||
if ( superQuery != null ) {
|
||||
superQuery.addLegacyPositionalParameter();
|
||||
}
|
||||
else if ( o instanceof Integer ) {
|
||||
ArrayList list = new ArrayList( 4 );
|
||||
list.add( o );
|
||||
list.add( loc );
|
||||
namedParameters.put( name, list );
|
||||
|
||||
if ( ordinalParameterStyle == null ) {
|
||||
ordinalParameterStyle = OrdinalParameterStyle.LEGACY;
|
||||
}
|
||||
else {
|
||||
( (ArrayList) o ).add( loc );
|
||||
else if ( ordinalParameterStyle != OrdinalParameterStyle.LEGACY ) {
|
||||
throw new QueryException( "Cannot mix legacy and labeled positional parameters" );
|
||||
}
|
||||
|
||||
final Integer label = legacyPositionalParameterCount++;
|
||||
final PositionalParameterInformationImpl paramInfo = new PositionalParameterInformationImpl( label );
|
||||
ordinalParameters.put( label, paramInfo );
|
||||
paramValueBinders.add( paramInfo );
|
||||
|
||||
final Integer loc = parameterCount++;
|
||||
paramInfo.addSourceLocation( loc );
|
||||
|
||||
}
|
||||
|
||||
void addOrdinalParameter(int label) {
|
||||
if ( superQuery != null ) {
|
||||
superQuery.addOrdinalParameter( label );
|
||||
}
|
||||
|
||||
if ( ordinalParameterStyle == null ) {
|
||||
ordinalParameterStyle = OrdinalParameterStyle.LABELED;
|
||||
}
|
||||
else if ( ordinalParameterStyle != OrdinalParameterStyle.LABELED ) {
|
||||
throw new QueryException( "Cannot mix legacy and labeled positional parameters" );
|
||||
}
|
||||
|
||||
final Integer loc = parameterCount++;
|
||||
|
||||
final PositionalParameterInformationImpl info = ordinalParameters.computeIfAbsent(
|
||||
label,
|
||||
k -> new PositionalParameterInformationImpl( label )
|
||||
);
|
||||
|
||||
paramValueBinders.add( info );
|
||||
|
||||
info.addSourceLocation( loc );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected int bindParameterValues(
|
||||
PreparedStatement statement,
|
||||
QueryParameters queryParameters,
|
||||
int startIndex,
|
||||
SharedSessionContractImplementor session) throws SQLException {
|
||||
|
||||
int span = 0;
|
||||
for ( ParameterBinder binder : paramValueBinders ) {
|
||||
span += binder.bind( statement, queryParameters, session, startIndex + span );
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -561,7 +635,6 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
|
|||
}
|
||||
|
||||
private void renderSQL() throws QueryException, MappingException {
|
||||
|
||||
final int rtsize;
|
||||
if ( returnedTypes.size() == 0 && scalarTypes.size() == 0 ) {
|
||||
//ie no select clause in HQL
|
||||
|
@ -973,7 +1046,7 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
|
|||
}
|
||||
|
||||
try {
|
||||
final List<AfterLoadAction> afterLoadActions = new ArrayList<AfterLoadAction>();
|
||||
final List<AfterLoadAction> afterLoadActions = new ArrayList<>();
|
||||
final SqlStatementWrapper wrapper = executeQueryStatement(
|
||||
queryParameters,
|
||||
false,
|
||||
|
@ -1267,40 +1340,25 @@ public class QueryTranslatorImpl extends BasicLoader implements FilterTranslator
|
|||
public ParameterTranslations getParameterTranslations() {
|
||||
return new ParameterTranslations() {
|
||||
@Override
|
||||
public boolean supportsOrdinalParameterMetadata() {
|
||||
// classic translator does not support collection of ordinal
|
||||
// param metadata
|
||||
return false;
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map getNamedParameterInformationMap() {
|
||||
return namedParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrdinalParameterCount() {
|
||||
return 0; // not known!
|
||||
@SuppressWarnings("unchecked")
|
||||
public Map getPositionalParameterInformationMap() {
|
||||
return ordinalParameters;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrdinalParameterSqlLocation(int ordinalPosition) {
|
||||
return 0; // not known!
|
||||
public PositionalParameterInformation getPositionalParameterInformation(int position) {
|
||||
return ordinalParameters.get( position );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getOrdinalParameterExpectedType(int ordinalPosition) {
|
||||
return null; // not known!
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set getNamedParameterNames() {
|
||||
return namedParameters.keySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int[] getNamedParameterSqlLocations(String name) {
|
||||
return getNamedParameterLocs( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type getNamedParameterExpectedType(String name) {
|
||||
return null; // not known!
|
||||
public NamedParameterInformation getNamedParameterInformation(String name) {
|
||||
return namedParameters.get( name );
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -27,6 +27,8 @@ import org.hibernate.type.EntityType;
|
|||
import org.hibernate.type.LiteralType;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import static org.hibernate.hql.spi.QueryTranslator.ERROR_LEGACY_ORDINAL_PARAMS_NO_LONGER_SUPPORTED;
|
||||
|
||||
/**
|
||||
* Parses the where clause of a hibernate query and translates it to an
|
||||
* SQL where clause.
|
||||
|
@ -396,13 +398,33 @@ public class WhereParser implements Parser {
|
|||
}
|
||||
|
||||
private void doToken(String token, QueryTranslatorImpl q) throws QueryException {
|
||||
if ( q.isName( StringHelper.root( token ) ) ) { //path expression
|
||||
if ( q.isName( StringHelper.root( token ) ) ) {
|
||||
//path expression
|
||||
doPathExpression( q.unalias( token ), q );
|
||||
}
|
||||
else if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) { //named query parameter
|
||||
else if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) {
|
||||
//named query parameter
|
||||
q.addNamedParameter( token.substring( 1 ) );
|
||||
appendToken( q, "?" );
|
||||
}
|
||||
else if ( token.startsWith( "?" ) ) {
|
||||
// ordinal query parameter
|
||||
if ( token.length() == 1 ) {
|
||||
q.addLegacyPositionalParameter();
|
||||
appendToken( q, "?" );
|
||||
}
|
||||
else {
|
||||
final String labelString = token.substring( 1 );
|
||||
try {
|
||||
final int label = Integer.parseInt( labelString );
|
||||
q.addOrdinalParameter( label );
|
||||
appendToken( q, "?" );
|
||||
}
|
||||
catch (NumberFormatException e) {
|
||||
throw new QueryException( "Ordinal parameter label must be numeric : " + labelString, e );
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
Queryable persister = q.getEntityPersisterUsingImports( token );
|
||||
if ( persister != null ) { // the name of a class
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.hql.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface NamedParameterInformation extends ParameterInformation {
|
||||
String getSourceName();
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.hql.spi;
|
||||
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ParameterInformation {
|
||||
/**
|
||||
* The positions (relative to all parameters) that this parameter
|
||||
* was discovered in the source query (HQL, etc). E.g., given a query
|
||||
* like `.. where a.name = :name or a.nickName = :name` this would
|
||||
* return `[0,1]`
|
||||
*/
|
||||
int[] getSourceLocations();
|
||||
|
||||
Type getExpectedType();
|
||||
|
||||
void setExpectedType(Type expectedType);
|
||||
|
||||
void addSourceLocation(int position);
|
||||
}
|
|
@ -5,9 +5,8 @@
|
|||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.hql.spi;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.type.Type;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Defines available information about the parameters encountered during
|
||||
|
@ -16,18 +15,10 @@ import org.hibernate.type.Type;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ParameterTranslations {
|
||||
Map<String,NamedParameterInformation> getNamedParameterInformationMap();
|
||||
Map<Integer,PositionalParameterInformation> getPositionalParameterInformationMap();
|
||||
|
||||
public boolean supportsOrdinalParameterMetadata();
|
||||
PositionalParameterInformation getPositionalParameterInformation(int position);
|
||||
|
||||
public int getOrdinalParameterCount();
|
||||
|
||||
public int getOrdinalParameterSqlLocation(int ordinalPosition);
|
||||
|
||||
public Type getOrdinalParameterExpectedType(int ordinalPosition);
|
||||
|
||||
public Set getNamedParameterNames();
|
||||
|
||||
public int[] getNamedParameterSqlLocations(String name);
|
||||
|
||||
public Type getNamedParameterExpectedType(String name);
|
||||
NamedParameterInformation getNamedParameterInformation(String name);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.hql.spi;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface PositionalParameterInformation extends ParameterInformation {
|
||||
int getLabel();
|
||||
}
|
|
@ -29,6 +29,8 @@ import org.hibernate.type.Type;
|
|||
public interface QueryTranslator {
|
||||
String ERROR_CANNOT_FETCH_WITH_ITERATE = "fetch may not be used with scroll() or iterate()";
|
||||
String ERROR_NAMED_PARAMETER_DOES_NOT_APPEAR = "Named parameter does not appear in Query: ";
|
||||
String ERROR_ORDINAL_PARAMETER_DOES_NOT_APPEAR = "Ordinal parameter [%s] does not appear in Query [%s] ";
|
||||
String ERROR_LEGACY_ORDINAL_PARAMS_NO_LONGER_SUPPORTED = "Legacy-style query parameters (`?`) are no longer supported; use JPA-style ordinal parameters (e.g., `?1`) instead : %s";
|
||||
String ERROR_CANNOT_DETERMINE_TYPE = "Could not determine type of: ";
|
||||
String ERROR_CANNOT_FORMAT_LITERAL = "Could not format constant value to SQL literal: ";
|
||||
|
||||
|
|
|
@ -746,9 +746,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
|
||||
@Override
|
||||
public QueryImplementor createNamedQuery(String name) {
|
||||
final QueryImplementor<Object> query = buildQueryFromName( name, null );
|
||||
query.getParameterMetadata().setOrdinalParametersZeroBased( false );
|
||||
return query;
|
||||
return buildQueryFromName( name, null );
|
||||
}
|
||||
|
||||
protected <T> QueryImplementor<T> buildQueryFromName(String name, Class<T> resultType) {
|
||||
|
@ -872,9 +870,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
|
||||
@Override
|
||||
public NativeQueryImplementor createNativeQuery(String sqlString) {
|
||||
final NativeQueryImpl query = (NativeQueryImpl) getNativeQueryImplementor( sqlString, false );
|
||||
query.setZeroBasedParametersIndex( false );
|
||||
return query;
|
||||
return getNativeQueryImplementor( sqlString, false );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -962,9 +958,7 @@ public abstract class AbstractSharedSessionContract implements SharedSessionCont
|
|||
|
||||
@Override
|
||||
public NativeQueryImplementor getNamedSQLQuery(String name) {
|
||||
final NativeQueryImpl nativeQuery = (NativeQueryImpl) getNamedNativeQuery( name );
|
||||
nativeQuery.setZeroBasedParametersIndex( true );
|
||||
return nativeQuery;
|
||||
return getNamedNativeQuery( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -96,6 +96,7 @@ import org.hibernate.engine.spi.SessionImplementor;
|
|||
import org.hibernate.engine.spi.SessionOwner;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.Status;
|
||||
import org.hibernate.engine.spi.TypedValue;
|
||||
import org.hibernate.engine.transaction.spi.TransactionImplementor;
|
||||
import org.hibernate.engine.transaction.spi.TransactionObserver;
|
||||
import org.hibernate.event.service.spi.EventListenerGroup;
|
||||
|
@ -153,6 +154,7 @@ import org.hibernate.loader.criteria.CriteriaLoader;
|
|||
import org.hibernate.loader.custom.CustomLoader;
|
||||
import org.hibernate.loader.custom.CustomQuery;
|
||||
import org.hibernate.metamodel.spi.MetamodelImplementor;
|
||||
import org.hibernate.param.CollectionFilterKeyParameterSpecification;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.MultiLoadOptions;
|
||||
|
@ -179,6 +181,7 @@ import org.hibernate.resource.transaction.spi.TransactionCoordinator;
|
|||
import org.hibernate.resource.transaction.spi.TransactionStatus;
|
||||
import org.hibernate.stat.SessionStatistics;
|
||||
import org.hibernate.stat.internal.SessionStatisticsImpl;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE;
|
||||
import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT;
|
||||
|
@ -1755,8 +1758,13 @@ public final class SessionImpl
|
|||
}
|
||||
|
||||
if ( parameters != null ) {
|
||||
parameters.getPositionalParameterValues()[0] = entry.getLoadedKey();
|
||||
parameters.getPositionalParameterTypes()[0] = entry.getLoadedPersister().getKeyType();
|
||||
parameters.getNamedParameters().put(
|
||||
CollectionFilterKeyParameterSpecification.PARAM_KEY,
|
||||
new TypedValue(
|
||||
entry.getLoadedPersister().getKeyType(),
|
||||
entry.getLoadedKey()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return plan;
|
||||
|
|
|
@ -238,4 +238,13 @@ public interface DeprecationLogger extends BasicLogger {
|
|||
"or [hibernate.connection.release_mode]; use [hibernate.connection.handling_mode] instead"
|
||||
)
|
||||
void logUseOfDeprecatedConnectionHandlingSettings();
|
||||
|
||||
@LogMessage(level = WARN)
|
||||
@Message(
|
||||
id = 90000024,
|
||||
value = "Application requested zero be used as the base for JDBC-style parameters found in native-queries; " +
|
||||
"this is a *temporary* backwards-compatibility setting to help applications using versions prior to " +
|
||||
"5.3 in upgrading. It will be removed in a later version."
|
||||
)
|
||||
void logUseOfDeprecatedZeroBasedJdbcStyleParams();
|
||||
}
|
||||
|
|
|
@ -29,7 +29,6 @@ import org.hibernate.LockOptions;
|
|||
import org.hibernate.QueryException;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.StaleObjectStateException;
|
||||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.cache.spi.FilterKey;
|
||||
|
@ -68,6 +67,7 @@ import org.hibernate.internal.ScrollableResultsImpl;
|
|||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
|
|
|
@ -29,7 +29,9 @@ import org.hibernate.QueryException;
|
|||
import org.hibernate.criterion.CriteriaQuery;
|
||||
import org.hibernate.criterion.Criterion;
|
||||
import org.hibernate.criterion.EnhancedProjection;
|
||||
import org.hibernate.criterion.ParameterInfoCollector;
|
||||
import org.hibernate.criterion.Projection;
|
||||
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.RowSelection;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
|
@ -311,6 +313,7 @@ public class CriteriaQueryTranslator implements CriteriaQuery {
|
|||
|
||||
final List<Object> values = new ArrayList<Object>();
|
||||
final List<Type> types = new ArrayList<Type>();
|
||||
|
||||
final Iterator<CriteriaImpl.Subcriteria> subcriteriaIterator = rootCriteria.iterateSubcriteria();
|
||||
while ( subcriteriaIterator.hasNext() ) {
|
||||
final CriteriaImpl.Subcriteria subcriteria = subcriteriaIterator.next();
|
||||
|
|
|
@ -7,12 +7,12 @@
|
|||
package org.hibernate.loader.custom;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -33,6 +33,7 @@ import org.hibernate.loader.CollectionAliases;
|
|||
import org.hibernate.loader.EntityAliases;
|
||||
import org.hibernate.loader.Loader;
|
||||
import org.hibernate.loader.spi.AfterLoadAction;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
import org.hibernate.persister.collection.CollectionPersister;
|
||||
import org.hibernate.persister.collection.QueryableCollection;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
|
@ -55,7 +56,8 @@ public class CustomLoader extends Loader {
|
|||
|
||||
private final String sql;
|
||||
private final Set<Serializable> querySpaces = new HashSet<>();
|
||||
private final Map namedParameterBindPoints;
|
||||
|
||||
private final List<ParameterBinder> paramValueBinders;
|
||||
|
||||
private final Queryable[] entityPersisters;
|
||||
private final int[] entiytOwners;
|
||||
|
@ -85,7 +87,8 @@ public class CustomLoader extends Loader {
|
|||
|
||||
this.sql = customQuery.getSQL();
|
||||
this.querySpaces.addAll( customQuery.getQuerySpaces() );
|
||||
this.namedParameterBindPoints = customQuery.getNamedParameterBindPoints();
|
||||
|
||||
this.paramValueBinders = customQuery.getParameterValueBinders();
|
||||
|
||||
List<Queryable> entityPersisters = new ArrayList<>();
|
||||
List<Integer> entityOwners = new ArrayList<>();
|
||||
|
@ -453,23 +456,32 @@ public class CustomLoader extends Loader {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int[] getNamedParameterLocs(String name) throws QueryException {
|
||||
Object loc = namedParameterBindPoints.get( name );
|
||||
if ( loc == null ) {
|
||||
throw new QueryException(
|
||||
"Named parameter does not appear in Query: " + name,
|
||||
sql
|
||||
protected int bindParameterValues(
|
||||
PreparedStatement statement,
|
||||
QueryParameters queryParameters,
|
||||
int startIndex,
|
||||
SharedSessionContractImplementor session) throws SQLException {
|
||||
final Serializable optionalId = queryParameters.getOptionalId();
|
||||
if ( optionalId != null ) {
|
||||
paramValueBinders.get( 0 ).bind( statement, queryParameters, session, startIndex );
|
||||
return session.getFactory().getMetamodel()
|
||||
.entityPersister( queryParameters.getOptionalEntityName() )
|
||||
.getIdentifierType()
|
||||
.getColumnSpan( session.getFactory() );
|
||||
}
|
||||
|
||||
int span = 0;
|
||||
for ( ParameterBinder paramValueBinder : paramValueBinders ) {
|
||||
span += paramValueBinder.bind(
|
||||
statement,
|
||||
queryParameters,
|
||||
session,
|
||||
startIndex + span
|
||||
);
|
||||
}
|
||||
if ( loc instanceof Integer ) {
|
||||
return new int[] {(Integer) loc};
|
||||
}
|
||||
else {
|
||||
return ArrayHelper.toIntArray( (List) loc );
|
||||
}
|
||||
return span;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void autoDiscoverTypes(ResultSet rs) {
|
||||
try {
|
||||
|
|
|
@ -5,10 +5,12 @@
|
|||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.loader.custom;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
|
||||
/**
|
||||
* Extension point allowing any SQL query with named and positional parameters
|
||||
* to be executed by Hibernate, returning managed entities, collections and
|
||||
|
@ -23,7 +25,7 @@ public interface CustomQuery {
|
|||
*
|
||||
* @return The SQL statement string.
|
||||
*/
|
||||
public String getSQL();
|
||||
String getSQL();
|
||||
|
||||
/**
|
||||
* Any query spaces to apply to the query execution. Query spaces are
|
||||
|
@ -32,22 +34,9 @@ public interface CustomQuery {
|
|||
*
|
||||
* @return The query spaces
|
||||
*/
|
||||
public Set<String> getQuerySpaces();
|
||||
Set<String> getQuerySpaces();
|
||||
|
||||
/**
|
||||
* A map representing positions within the supplied {@link #getSQL query} to
|
||||
* which we need to bind named parameters.
|
||||
* <p/>
|
||||
* Optional, may return null if no named parameters.
|
||||
* <p/>
|
||||
* The structure of the returned map (if one) as follows:<ol>
|
||||
* <li>The keys into the map are the named parameter names</li>
|
||||
* <li>The corresponding value is either an {@link Integer} if the
|
||||
* parameter occurs only once in the query; or a List of Integers if the
|
||||
* parameter occurs more than once</li>
|
||||
* </ol>
|
||||
*/
|
||||
public Map getNamedParameterBindPoints();
|
||||
List<ParameterBinder> getParameterValueBinders();
|
||||
|
||||
/**
|
||||
* A collection of {@link Return descriptors} describing the
|
||||
|
@ -55,5 +44,6 @@ public interface CustomQuery {
|
|||
*
|
||||
* @return List of return descriptors.
|
||||
*/
|
||||
public List<Return> getCustomQueryReturns();
|
||||
List<Return> getCustomQueryReturns();
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.loader.custom.sql;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.TypedValue;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class NamedParamBinder implements ParameterBinder {
|
||||
private final String name;
|
||||
|
||||
public NamedParamBinder(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bind(
|
||||
PreparedStatement statement,
|
||||
QueryParameters qp,
|
||||
SharedSessionContractImplementor session,
|
||||
int position) throws SQLException {
|
||||
final TypedValue typedValue = qp.getNamedParameters().get( name );
|
||||
typedValue.getType().nullSafeSet( statement, typedValue.getValue(), position, session );
|
||||
return typedValue.getType().getColumnSpan( session.getFactory() );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.loader.custom.sql;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.TypedValue;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PositionalParamBinder implements ParameterBinder {
|
||||
private final int label;
|
||||
|
||||
public PositionalParamBinder(int label) {
|
||||
this.label = label;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int bind(
|
||||
PreparedStatement statement,
|
||||
QueryParameters qp,
|
||||
SharedSessionContractImplementor session,
|
||||
int position) throws SQLException {
|
||||
final TypedValue typedValue = qp.getNamedParameters().get( Integer.toString( label ) );
|
||||
typedValue.getType().nullSafeSet( statement, typedValue.getValue(), position, session );
|
||||
return typedValue.getType().getColumnSpan( session.getFactory() );
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ package org.hibernate.loader.custom.sql;
|
|||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -20,6 +19,7 @@ import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.loader.custom.CustomQuery;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
import org.hibernate.persister.collection.SQLLoadableCollection;
|
||||
import org.hibernate.persister.entity.SQLLoadable;
|
||||
|
||||
|
@ -40,7 +40,9 @@ public class SQLCustomQuery implements CustomQuery, Serializable {
|
|||
|
||||
private final String sql;
|
||||
private final Set querySpaces = new HashSet();
|
||||
private final Map namedParameterBindPoints = new HashMap();
|
||||
|
||||
private final List<ParameterBinder> paramValueBinders;
|
||||
|
||||
private final List customQueryReturns = new ArrayList();
|
||||
|
||||
|
||||
|
@ -52,8 +54,9 @@ public class SQLCustomQuery implements CustomQuery, Serializable {
|
|||
return querySpaces;
|
||||
}
|
||||
|
||||
public Map getNamedParameterBindPoints() {
|
||||
return namedParameterBindPoints;
|
||||
@Override
|
||||
public List<ParameterBinder > getParameterValueBinders() {
|
||||
return paramValueBinders;
|
||||
}
|
||||
|
||||
public List getCustomQueryReturns() {
|
||||
|
@ -115,7 +118,8 @@ public class SQLCustomQuery implements CustomQuery, Serializable {
|
|||
|
||||
SQLQueryParser parser = new SQLQueryParser( sqlQuery, new ParserContext( aliasContext ), factory );
|
||||
this.sql = parser.process();
|
||||
this.namedParameterBindPoints.putAll( parser.getNamedParameters() );
|
||||
|
||||
this.paramValueBinders = parser.getParameterValueBinders();
|
||||
|
||||
// SQLQueryParser parser = new SQLQueryParser(
|
||||
// sqlQuery,
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
package org.hibernate.loader.custom.sql;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.regex.Pattern;
|
||||
|
@ -15,6 +15,7 @@ import java.util.regex.Pattern;
|
|||
import org.hibernate.QueryException;
|
||||
import org.hibernate.engine.query.spi.ParameterParser;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
import org.hibernate.persister.collection.SQLLoadableCollection;
|
||||
import org.hibernate.persister.entity.SQLLoadable;
|
||||
|
||||
|
@ -35,9 +36,10 @@ public class SQLQueryParser {
|
|||
private final String originalQueryString;
|
||||
private final ParserContext context;
|
||||
|
||||
private final Map namedParameters = new HashMap();
|
||||
private long aliasesFound;
|
||||
|
||||
private List<ParameterBinder> paramValueBinders;
|
||||
|
||||
interface ParserContext {
|
||||
boolean isEntityAlias(String aliasName);
|
||||
SQLLoadable getEntityPersisterByAlias(String alias);
|
||||
|
@ -54,8 +56,8 @@ public class SQLQueryParser {
|
|||
this.factory = factory;
|
||||
}
|
||||
|
||||
public Map getNamedParameters() {
|
||||
return namedParameters;
|
||||
public List<ParameterBinder> getParameterValueBinders() {
|
||||
return paramValueBinders == null ? Collections.emptyList() : paramValueBinders;
|
||||
}
|
||||
|
||||
public boolean queryHasAliases() {
|
||||
|
@ -276,19 +278,25 @@ public class SQLQueryParser {
|
|||
* @return The SQL query with parameter substitution complete.
|
||||
*/
|
||||
private String substituteParams(String sqlString) {
|
||||
ParameterSubstitutionRecognizer recognizer = new ParameterSubstitutionRecognizer();
|
||||
final ParameterSubstitutionRecognizer recognizer = new ParameterSubstitutionRecognizer( factory );
|
||||
ParameterParser.parse( sqlString, recognizer );
|
||||
|
||||
namedParameters.clear();
|
||||
namedParameters.putAll( recognizer.namedParameterBindPoints );
|
||||
paramValueBinders = recognizer.getParameterValueBinders();
|
||||
|
||||
return recognizer.result.toString();
|
||||
}
|
||||
|
||||
public static class ParameterSubstitutionRecognizer implements ParameterParser.Recognizer {
|
||||
StringBuilder result = new StringBuilder();
|
||||
Map namedParameterBindPoints = new HashMap();
|
||||
int parameterCount;
|
||||
|
||||
int jdbcPositionalParamCount;
|
||||
private List<ParameterBinder> paramValueBinders;
|
||||
|
||||
public ParameterSubstitutionRecognizer(SessionFactoryImplementor factory) {
|
||||
this.jdbcPositionalParamCount = factory.getSessionFactoryOptions().jdbcStyleParamsZeroBased()
|
||||
? 0
|
||||
: 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void outParameter(int position) {
|
||||
|
@ -298,17 +306,35 @@ public class SQLQueryParser {
|
|||
@Override
|
||||
public void ordinalParameter(int position) {
|
||||
result.append( '?' );
|
||||
registerPositionParamBinder( jdbcPositionalParamCount++ );
|
||||
}
|
||||
|
||||
private void registerPositionParamBinder(int label) {
|
||||
if ( paramValueBinders == null ) {
|
||||
paramValueBinders = new ArrayList<>();
|
||||
}
|
||||
|
||||
paramValueBinders.add( new PositionalParamBinder( label ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jpaPositionalParameter(int name, int position) {
|
||||
result.append( '?' );
|
||||
registerPositionParamBinder( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void namedParameter(String name, int position) {
|
||||
addNamedParameter( name );
|
||||
result.append( '?' );
|
||||
registerNamedParamBinder( name );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jpaPositionalParameter(String name, int position) {
|
||||
namedParameter( name, position );
|
||||
private void registerNamedParamBinder(String name) {
|
||||
if ( paramValueBinders == null ) {
|
||||
paramValueBinders = new ArrayList<>();
|
||||
}
|
||||
|
||||
paramValueBinders.add( new NamedParamBinder( name ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -316,21 +342,12 @@ public class SQLQueryParser {
|
|||
result.append( character );
|
||||
}
|
||||
|
||||
private void addNamedParameter(String name) {
|
||||
Integer loc = parameterCount++;
|
||||
Object o = namedParameterBindPoints.get( name );
|
||||
if ( o == null ) {
|
||||
namedParameterBindPoints.put( name, loc );
|
||||
}
|
||||
else if ( o instanceof Integer ) {
|
||||
ArrayList list = new ArrayList( 4 );
|
||||
list.add( o );
|
||||
list.add( loc );
|
||||
namedParameterBindPoints.put( name, list );
|
||||
}
|
||||
else {
|
||||
( ( List ) o ).add( loc );
|
||||
}
|
||||
public List<ParameterBinder> getParameterValueBinders() {
|
||||
return paramValueBinders;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,14 +9,17 @@ package org.hibernate.loader.entity;
|
|||
import java.io.Serializable;
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.engine.spi.LoadQueryInfluencers;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.loader.OuterJoinLoader;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
import org.hibernate.persister.entity.OuterJoinLoadable;
|
||||
import org.hibernate.transform.ResultTransformer;
|
||||
import org.hibernate.type.Type;
|
||||
|
|
|
@ -32,6 +32,8 @@ import org.hibernate.hql.internal.ast.tree.AggregatedSelectExpression;
|
|||
import org.hibernate.hql.internal.ast.tree.FromElement;
|
||||
import org.hibernate.hql.internal.ast.tree.QueryNode;
|
||||
import org.hibernate.hql.internal.ast.tree.SelectClause;
|
||||
import org.hibernate.hql.spi.NamedParameterInformation;
|
||||
import org.hibernate.hql.spi.ParameterInformation;
|
||||
import org.hibernate.internal.IteratorImpl;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.loader.BasicLoader;
|
||||
|
@ -599,7 +601,22 @@ public class QueryLoader extends BasicLoader {
|
|||
*/
|
||||
@Override
|
||||
public int[] getNamedParameterLocs(String name) throws QueryException {
|
||||
return queryTranslator.getParameterTranslations().getNamedParameterSqlLocations( name );
|
||||
ParameterInformation info = queryTranslator.getParameterTranslations().getNamedParameterInformation( name );
|
||||
if ( info == null ) {
|
||||
try {
|
||||
info = queryTranslator.getParameterTranslations().getPositionalParameterInformation(
|
||||
Integer.parseInt( name )
|
||||
);
|
||||
}
|
||||
catch (Exception ignore) {
|
||||
}
|
||||
}
|
||||
|
||||
if ( info == null ) {
|
||||
throw new QueryException( "Unrecognized parameter label : " + name );
|
||||
}
|
||||
|
||||
return info.getSourceLocations();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -15,8 +15,6 @@ import java.util.List;
|
|||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.engine.spi.EntityKey;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
|
@ -30,10 +28,11 @@ import org.hibernate.loader.plan.spi.EntityFetch;
|
|||
import org.hibernate.loader.plan.spi.EntityReference;
|
||||
import org.hibernate.loader.plan.spi.Fetch;
|
||||
import org.hibernate.loader.plan.spi.LoadPlan;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.persister.entity.Loadable;
|
||||
import org.hibernate.type.EntityType;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
|
|
@ -6,9 +6,11 @@
|
|||
*/
|
||||
package org.hibernate.param;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.Type;
|
||||
|
@ -20,22 +22,20 @@ import org.hibernate.type.Type;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class CollectionFilterKeyParameterSpecification implements ParameterSpecification {
|
||||
public static final String PARAM_KEY = "{collection_key}";
|
||||
|
||||
private final String collectionRole;
|
||||
private final Type keyType;
|
||||
private final int queryParameterPosition;
|
||||
|
||||
/**
|
||||
* Creates a specialized collection-filter collection-key parameter spec.
|
||||
*
|
||||
* @param collectionRole The collection role being filtered.
|
||||
* @param keyType The mapped collection-key type.
|
||||
* @param queryParameterPosition The position within {@link org.hibernate.engine.spi.QueryParameters} where
|
||||
* we can find the appropriate param value to bind.
|
||||
*/
|
||||
public CollectionFilterKeyParameterSpecification(String collectionRole, Type keyType, int queryParameterPosition) {
|
||||
public CollectionFilterKeyParameterSpecification(String collectionRole, Type keyType) {
|
||||
this.collectionRole = collectionRole;
|
||||
this.keyType = keyType;
|
||||
this.queryParameterPosition = queryParameterPosition;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -44,7 +44,7 @@ public class CollectionFilterKeyParameterSpecification implements ParameterSpeci
|
|||
QueryParameters qp,
|
||||
SharedSessionContractImplementor session,
|
||||
int position) throws SQLException {
|
||||
Object value = qp.getPositionalParameterValues()[queryParameterPosition];
|
||||
final Object value = qp.getNamedParameters().get( PARAM_KEY ).getValue();
|
||||
keyType.nullSafeSet( statement, value, position, session );
|
||||
return keyType.getColumnSpan( session.getFactory() );
|
||||
}
|
||||
|
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.param;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ParameterBinder {
|
||||
/**
|
||||
* Bind the appropriate value into the given statement at the specified position.
|
||||
*
|
||||
* @param statement The statement into which the value should be bound.
|
||||
* @param qp The defined values for the current query execution.
|
||||
* @param session The session against which the current execution is occuring.
|
||||
* @param position The position from which to start binding value(s).
|
||||
*
|
||||
* @return The number of sql bind positions "eaten" by this bind operation.
|
||||
* @throws java.sql.SQLException Indicates problems performing the JDBC biind operation.
|
||||
*/
|
||||
int bind(PreparedStatement statement, QueryParameters qp, SharedSessionContractImplementor session, int position) throws SQLException;
|
||||
|
||||
}
|
|
@ -7,10 +7,7 @@
|
|||
package org.hibernate.param;
|
||||
|
||||
import java.sql.PreparedStatement;
|
||||
import java.sql.SQLException;
|
||||
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
/**
|
||||
|
@ -19,20 +16,7 @@ import org.hibernate.type.Type;
|
|||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ParameterSpecification {
|
||||
/**
|
||||
* Bind the appropriate value into the given statement at the specified position.
|
||||
*
|
||||
* @param statement The statement into which the value should be bound.
|
||||
* @param qp The defined values for the current query execution.
|
||||
* @param session The session against which the current execution is occuring.
|
||||
* @param position The position from which to start binding value(s).
|
||||
*
|
||||
* @return The number of sql bind positions "eaten" by this bind operation.
|
||||
* @throws java.sql.SQLException Indicates problems performing the JDBC biind operation.
|
||||
*/
|
||||
int bind(PreparedStatement statement, QueryParameters qp, SharedSessionContractImplementor session, int position) throws SQLException;
|
||||
|
||||
public interface ParameterSpecification extends ParameterBinder {
|
||||
/**
|
||||
* Get the type which we are expeting for a bind into this parameter based
|
||||
* on translated contextual information.
|
||||
|
|
|
@ -11,7 +11,7 @@ import java.sql.SQLException;
|
|||
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.engine.spi.TypedValue;
|
||||
|
||||
/**
|
||||
* Parameter bind specification for an explicit positional (or ordinal) parameter.
|
||||
|
@ -19,18 +19,24 @@ import org.hibernate.type.Type;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class PositionalParameterSpecification extends AbstractExplicitParameterSpecification {
|
||||
private final int hqlPosition;
|
||||
private final int label;
|
||||
private final int bindingPosition;
|
||||
|
||||
/**
|
||||
* Constructs a position/ordinal parameter bind specification.
|
||||
*
|
||||
* @param sourceLine See {@link #getSourceLine()}
|
||||
* @param sourceColumn See {@link #getSourceColumn()}
|
||||
* @param hqlPosition The position in the source query, relative to the other source positional parameters.
|
||||
* @param label The position in the source query, relative to the other source positional parameters.
|
||||
*/
|
||||
public PositionalParameterSpecification(int sourceLine, int sourceColumn, int hqlPosition) {
|
||||
public PositionalParameterSpecification(
|
||||
int sourceLine,
|
||||
int sourceColumn,
|
||||
int label,
|
||||
int bindingPosition) {
|
||||
super( sourceLine, sourceColumn );
|
||||
this.hqlPosition = hqlPosition;
|
||||
this.label = label;
|
||||
this.bindingPosition = bindingPosition;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -45,24 +51,17 @@ public class PositionalParameterSpecification extends AbstractExplicitParameterS
|
|||
*/
|
||||
@Override
|
||||
public int bind(PreparedStatement statement, QueryParameters qp, SharedSessionContractImplementor session, int position) throws SQLException {
|
||||
Type type = qp.getPositionalParameterTypes()[hqlPosition];
|
||||
Object value = qp.getPositionalParameterValues()[hqlPosition];
|
||||
|
||||
type.nullSafeSet( statement, value, position, session );
|
||||
return type.getColumnSpan( session.getFactory() );
|
||||
final TypedValue typedValue = qp.getNamedParameters().get( Integer.toString( label ) );
|
||||
typedValue.getType().nullSafeSet( statement, typedValue.getValue(), position, session );
|
||||
return typedValue.getType().getColumnSpan( session.getFactory() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String renderDisplayInfo() {
|
||||
return "ordinal=" + hqlPosition + ", expectedType=" + getExpectedType();
|
||||
return "label=" + label + ", expectedType=" + getExpectedType();
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for property 'hqlPosition'.
|
||||
*
|
||||
* @return Value for property 'hqlPosition'.
|
||||
*/
|
||||
public int getHqlPosition() {
|
||||
return hqlPosition;
|
||||
public int getLabel() {
|
||||
return label;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,7 +46,7 @@ public final class NamedQueryCollectionInitializer implements CollectionInitiali
|
|||
);
|
||||
}
|
||||
else {
|
||||
nativeQuery.setParameter( 0, key, persister.getKeyType() );
|
||||
nativeQuery.setParameter( 1, key, persister.getKeyType() );
|
||||
}
|
||||
|
||||
nativeQuery.setCollectionKey( key ).setFlushMode( FlushMode.MANUAL ).list();
|
||||
|
|
|
@ -29,6 +29,8 @@ public final class NamedQueryLoader implements UniqueEntityLoader {
|
|||
private final String queryName;
|
||||
private final EntityPersister persister;
|
||||
|
||||
private final int position;
|
||||
|
||||
/**
|
||||
* Constructs the NamedQueryLoader
|
||||
*
|
||||
|
@ -39,6 +41,9 @@ public final class NamedQueryLoader implements UniqueEntityLoader {
|
|||
super();
|
||||
this.queryName = queryName;
|
||||
this.persister = persister;
|
||||
this.position = persister.getFactory().getSessionFactoryOptions().jdbcStyleParamsZeroBased()
|
||||
? 0
|
||||
: 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -61,7 +66,7 @@ public final class NamedQueryLoader implements UniqueEntityLoader {
|
|||
query.setParameter( query.getNamedParameters()[0], id, persister.getIdentifierType() );
|
||||
}
|
||||
else {
|
||||
query.setParameter( 0, id, persister.getIdentifierType() );
|
||||
query.setParameter( position, id, persister.getIdentifierType() );
|
||||
}
|
||||
|
||||
query.setOptionalId( id );
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.query;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Parameter;
|
||||
|
||||
|
@ -54,10 +55,9 @@ public interface ParameterMetadata {
|
|||
|
||||
<T> QueryParameter<T> resolve(Parameter<T> param);
|
||||
|
||||
default boolean isOrdinalParametersZeroBased() {
|
||||
return true;
|
||||
}
|
||||
Collection<QueryParameter> getPositionalParameters();
|
||||
|
||||
default void setOrdinalParametersZeroBased(boolean isZeroBased) {
|
||||
}
|
||||
Collection<QueryParameter> getNamedParameters();
|
||||
|
||||
int getParameterCount();
|
||||
}
|
||||
|
|
|
@ -23,16 +23,9 @@ public interface QueryParameter<T> extends javax.persistence.Parameter<T> {
|
|||
*/
|
||||
Type getType();
|
||||
|
||||
/**
|
||||
* JPA has a different definition of positional parameters than what legacy Hibernate HQL had. In JPA,
|
||||
* the parameter holders are labelled (named :/). At any rate the semantics are different and we often
|
||||
* need to understand which we are dealing with (and applications might too).
|
||||
*
|
||||
* @return {@code true} if this is a JPA-style positional parameter; {@code false} would indicate
|
||||
* we have either a named parameter ({@link #getName()} would return a non-{@code null} value) or a native
|
||||
* Hibernate positional parameter.
|
||||
*/
|
||||
boolean isJpaPositionalParameter();
|
||||
int[] getSourceLocations();
|
||||
|
||||
// todo : add a method indicating whether this parameter is valid for use in "parameter list binding"
|
||||
// actually this already implemented in 6.0 code and I'm not going to mess with
|
||||
// this in earlier versions
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.hibernate.CacheMode;
|
|||
import org.hibernate.FlushMode;
|
||||
import org.hibernate.LockMode;
|
||||
import org.hibernate.LockOptions;
|
||||
import org.hibernate.Query;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.engine.spi.RowSelection;
|
||||
|
@ -558,6 +559,14 @@ public class CriteriaQueryTypeQueryAdapter<X> implements QueryImplementor<X> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<X> setParameterList(int position, Collection values) {
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByPosition( position );
|
||||
parameterInfo.validateDateBind();
|
||||
jpqlQuery.setParameter( position, values );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryImplementor<X> setParameterList(String name, Collection values, Type type) {
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByName( name );
|
||||
|
@ -566,6 +575,14 @@ public class CriteriaQueryTypeQueryAdapter<X> implements QueryImplementor<X> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<X> setParameterList(int position, Collection values, Type type) {
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByPosition( position );
|
||||
parameterInfo.validateDateBind();
|
||||
jpqlQuery.setParameter( position, values, type );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryImplementor<X> setParameterList(String name, Object[] values, Type type) {
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByName( name );
|
||||
|
@ -574,6 +591,14 @@ public class CriteriaQueryTypeQueryAdapter<X> implements QueryImplementor<X> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<X> setParameterList(int position, Object[] values, Type type) {
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByPosition( position );
|
||||
parameterInfo.validateDateBind();
|
||||
jpqlQuery.setParameter( position, values, type );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public QueryImplementor<X> setParameterList(String name, Object[] values) {
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByName( name );
|
||||
|
@ -582,6 +607,14 @@ public class CriteriaQueryTypeQueryAdapter<X> implements QueryImplementor<X> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Query<X> setParameterList(int position, Object[] values) {
|
||||
ExplicitParameterInfo parameterInfo = locateParameterByPosition( position );
|
||||
parameterInfo.validateDateBind();
|
||||
jpqlQuery.setParameter( position, values );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <P> QueryImplementor<X> setParameter(QueryParameter<P> parameter, P value, Type type) {
|
||||
final ExplicitParameterInfo parameterInfo = resolveParameterInfo( parameter );
|
||||
|
|
|
@ -503,7 +503,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
setParameter( position, typedParameterValue.getValue(), typedParameterValue.getType() );
|
||||
}
|
||||
else if ( value instanceof Collection && !isRegisteredAsBasicType( value.getClass() ) ) {
|
||||
setParameterList( Integer.toString( position ), (Collection) value );
|
||||
setParameterList( parameterMetadata.getQueryParameter( position ), (Collection) value );
|
||||
}
|
||||
else {
|
||||
queryParameterBindings.getBinding( position ).setBindValue( value );
|
||||
|
@ -567,6 +567,13 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryImplementor setParameterList(int position, Collection values) {
|
||||
queryParameterBindings.getQueryParameterListBinding( position ).setBindValues( values );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryImplementor setParameterList(String name, Collection values, Type type) {
|
||||
|
@ -574,6 +581,13 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryImplementor setParameterList(int position, Collection values, Type type) {
|
||||
queryParameterBindings.getQueryParameterListBinding( position ).setBindValues( values, type );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryImplementor setParameterList(String name, Object[] values, Type type) {
|
||||
|
@ -581,6 +595,13 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryImplementor setParameterList(int position, Object[] values, Type type) {
|
||||
queryParameterBindings.getQueryParameterListBinding( position ).setBindValues( Arrays.asList( values ), type );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryImplementor setParameterList(String name, Object[] values) {
|
||||
|
@ -588,6 +609,13 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryImplementor setParameterList(int position, Object[] values) {
|
||||
queryParameterBindings.getQueryParameterListBinding( position ).setBindValues( Arrays.asList( values ) );
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryImplementor setParameter(Parameter<Calendar> param, Calendar value, TemporalType temporalType) {
|
||||
|
@ -1271,19 +1299,14 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
// throw new IllegalArgumentException( "Could not unwrap this [" + toString() + "] as requested Java type [" + cls.getName() + "]" );
|
||||
}
|
||||
|
||||
public QueryParameters getQueryParameters() {
|
||||
protected QueryParameters makeQueryParametersForExecution(String hql) {
|
||||
final HQLQueryPlan entityGraphHintedQueryPlan;
|
||||
if ( entityGraphQueryHint == null) {
|
||||
entityGraphHintedQueryPlan = null;
|
||||
}
|
||||
else {
|
||||
queryParameterBindings.verifyParametersBound( false );
|
||||
|
||||
// todo : ideally we'd update the instance state related to queryString but that is final atm
|
||||
|
||||
final String expandedQuery = queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() );
|
||||
entityGraphHintedQueryPlan = new HQLQueryPlan(
|
||||
expandedQuery,
|
||||
hql,
|
||||
false,
|
||||
getProducer().getLoadQueryInfluencers().getEnabledFilters(),
|
||||
getProducer().getFactory(),
|
||||
|
@ -1291,10 +1314,8 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
);
|
||||
}
|
||||
|
||||
QueryParameters queryParameters = new QueryParameters(
|
||||
getPositionalParameterTypes(),
|
||||
getPositionalParameterValues(),
|
||||
getNamedParameterMap(),
|
||||
QueryParameters queryParameters = new QueryParameters(
|
||||
queryParameterBindings,
|
||||
getLockOptions(),
|
||||
queryOptions,
|
||||
true,
|
||||
|
@ -1316,6 +1337,11 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
return queryParameters;
|
||||
}
|
||||
|
||||
public QueryParameters getQueryParameters() {
|
||||
final String expandedQuery = queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() );
|
||||
return makeQueryParametersForExecution( expandedQuery );
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
protected Type[] getPositionalParameterTypes() {
|
||||
return queryParameterBindings.collectPositionalBindTypes();
|
||||
|
@ -1335,7 +1361,9 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
private CacheMode sessionCacheMode;
|
||||
|
||||
protected void beforeQuery() {
|
||||
queryParameterBindings.verifyParametersBound( isCallable() );
|
||||
if ( optionalId == null ) {
|
||||
queryParameterBindings.verifyParametersBound( isCallable() );
|
||||
}
|
||||
|
||||
assert sessionFlushMode == null;
|
||||
assert sessionCacheMode == null;
|
||||
|
@ -1405,7 +1433,7 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
return EmptyScrollableResults.INSTANCE;
|
||||
}
|
||||
final String query = queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() );
|
||||
QueryParameters queryParameters = getQueryParameters();
|
||||
QueryParameters queryParameters = makeQueryParametersForExecution( query );
|
||||
queryParameters.setScrollMode( scrollMode );
|
||||
return getProducer().scroll( query, queryParameters );
|
||||
}
|
||||
|
@ -1467,9 +1495,10 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
}
|
||||
}
|
||||
|
||||
final String expandedQuery = queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() );
|
||||
return getProducer().list(
|
||||
queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() ),
|
||||
getQueryParameters()
|
||||
expandedQuery,
|
||||
makeQueryParametersForExecution( expandedQuery )
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -1548,9 +1577,10 @@ public abstract class AbstractProducedQuery<R> implements QueryImplementor<R> {
|
|||
}
|
||||
|
||||
protected int doExecuteUpdate() {
|
||||
final String expandedQuery = queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() );
|
||||
return getProducer().executeUpdate(
|
||||
queryParameterBindings.expandListValuedParameters( getQueryString(), getProducer() ),
|
||||
getQueryParameters()
|
||||
expandedQuery,
|
||||
makeQueryParametersForExecution( expandedQuery )
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.engine.spi.QueryParameters;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.query.Query;
|
||||
import org.hibernate.query.spi.ScrollableResultsImplementor;
|
||||
|
@ -48,20 +49,24 @@ public class CollectionFilterImpl extends org.hibernate.query.internal.AbstractP
|
|||
@Override
|
||||
public Iterator iterate() throws HibernateException {
|
||||
getQueryParameterBindings().verifyParametersBound( false );
|
||||
|
||||
final String expandedQuery = getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() );
|
||||
return getProducer().iterateFilter(
|
||||
collection,
|
||||
getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() ),
|
||||
getQueryParameters()
|
||||
expandedQuery,
|
||||
makeQueryParametersForExecution( expandedQuery )
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List list() throws HibernateException {
|
||||
getQueryParameterBindings().verifyParametersBound( false );
|
||||
|
||||
final String expandedQuery = getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() );
|
||||
return getProducer().listFilter(
|
||||
collection,
|
||||
getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() ),
|
||||
getQueryParameters()
|
||||
expandedQuery,
|
||||
makeQueryParametersForExecution( expandedQuery )
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -126,10 +126,6 @@ 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;
|
||||
|
|
|
@ -6,17 +6,22 @@
|
|||
*/
|
||||
package org.hibernate.query.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import javax.persistence.Parameter;
|
||||
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.QueryParameterException;
|
||||
import org.hibernate.engine.query.spi.NamedParameterDescriptor;
|
||||
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.compare.ComparableComparator;
|
||||
import org.hibernate.query.ParameterMetadata;
|
||||
import org.hibernate.query.QueryParameter;
|
||||
import org.hibernate.type.Type;
|
||||
|
@ -27,73 +32,62 @@ import org.hibernate.type.Type;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public class ParameterMetadataImpl implements ParameterMetadata {
|
||||
private static final OrdinalParameterDescriptor[] EMPTY_ORDINALS = new OrdinalParameterDescriptor[0];
|
||||
|
||||
private final OrdinalParameterDescriptor[] ordinalDescriptors;
|
||||
private final Map<Integer,OrdinalParameterDescriptor> ordinalDescriptorMap;
|
||||
private final Map<String,NamedParameterDescriptor> namedDescriptorMap;
|
||||
private boolean isOrdinalParametersZeroBased = true;
|
||||
|
||||
private ParameterMetadataImpl(
|
||||
OrdinalParameterDescriptor[] ordinalDescriptors,
|
||||
Map<String, NamedParameterDescriptor> namedDescriptorMap, boolean isOrdinalParametersZeroBased) {
|
||||
this.ordinalDescriptors = ordinalDescriptors;
|
||||
this.namedDescriptorMap = namedDescriptorMap;
|
||||
this.isOrdinalParametersZeroBased = isOrdinalParametersZeroBased;
|
||||
}
|
||||
|
||||
/**
|
||||
* Instantiates a ParameterMetadata container.
|
||||
*
|
||||
* @param ordinalDescriptors Descriptors of the ordinal parameters
|
||||
* @param namedDescriptorMap Descriptors of the named parameters
|
||||
*/
|
||||
public ParameterMetadataImpl(
|
||||
OrdinalParameterDescriptor[] ordinalDescriptors,
|
||||
Map<String,NamedParameterDescriptor> namedDescriptorMap) {
|
||||
if ( ordinalDescriptors == null ) {
|
||||
this.ordinalDescriptors = EMPTY_ORDINALS;
|
||||
}
|
||||
else {
|
||||
final OrdinalParameterDescriptor[] copy = new OrdinalParameterDescriptor[ ordinalDescriptors.length ];
|
||||
System.arraycopy( ordinalDescriptors, 0, copy, 0, ordinalDescriptors.length );
|
||||
this.ordinalDescriptors = copy;
|
||||
}
|
||||
Map<Integer,OrdinalParameterDescriptor> ordinalDescriptorMap,
|
||||
Map<String, NamedParameterDescriptor> namedDescriptorMap) {
|
||||
this.ordinalDescriptorMap = ordinalDescriptorMap == null
|
||||
? Collections.emptyMap()
|
||||
: Collections.unmodifiableMap( ordinalDescriptorMap );
|
||||
this.namedDescriptorMap = namedDescriptorMap == null
|
||||
? Collections.emptyMap()
|
||||
: Collections.unmodifiableMap( namedDescriptorMap );
|
||||
|
||||
if (ordinalDescriptorMap != null && ! ordinalDescriptorMap.isEmpty() ) {
|
||||
final List<Integer> sortedPositions = new ArrayList<>( ordinalDescriptorMap.keySet() );
|
||||
sortedPositions.sort( ComparableComparator.INSTANCE );
|
||||
|
||||
int lastPosition = -1;
|
||||
for ( Integer sortedPosition : sortedPositions ) {
|
||||
if ( lastPosition == -1 ) {
|
||||
lastPosition = sortedPosition;
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( sortedPosition != lastPosition + 1 ) {
|
||||
throw new QueryException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Unexpected gap in ordinal parameter labels [%s -> %s] : [%s]",
|
||||
lastPosition,
|
||||
sortedPosition,
|
||||
StringHelper.join( ",", sortedPositions )
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
lastPosition = sortedPosition;
|
||||
}
|
||||
|
||||
if ( namedDescriptorMap == null ) {
|
||||
this.namedDescriptorMap = java.util.Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
final int size = (int) ( ( namedDescriptorMap.size() / .75 ) + 1 );
|
||||
final Map<String,NamedParameterDescriptor> copy = new HashMap<>( size );
|
||||
copy.putAll( namedDescriptorMap );
|
||||
this.namedDescriptorMap = java.util.Collections.unmodifiableMap( copy );
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<QueryParameter<?>> collectAllParameters() {
|
||||
if ( hasNamedParameters() || hasPositionalParameters() ) {
|
||||
final HashSet allParameters = new HashSet();
|
||||
allParameters.addAll( namedDescriptorMap.values() );
|
||||
allParameters.addAll( ArrayHelper.toList( ordinalDescriptors ) );
|
||||
return allParameters;
|
||||
}
|
||||
|
||||
return Collections.emptySet();
|
||||
public Collection<QueryParameter> getPositionalParameters() {
|
||||
return Collections.unmodifiableCollection( ordinalDescriptorMap.values() );
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<Parameter<?>> collectAllParametersJpa() {
|
||||
if ( hasNamedParameters() || hasPositionalParameters() ) {
|
||||
final HashSet allParameters = new HashSet();
|
||||
allParameters.addAll( namedDescriptorMap.values() );
|
||||
allParameters.addAll( ArrayHelper.toList( ordinalDescriptors ) );
|
||||
return allParameters;
|
||||
}
|
||||
public Collection<QueryParameter> getNamedParameters() {
|
||||
return Collections.unmodifiableCollection( namedDescriptorMap.values() );
|
||||
}
|
||||
|
||||
return Collections.emptySet();
|
||||
|
||||
@Override
|
||||
public int getParameterCount() {
|
||||
return ordinalDescriptorMap.size() + namedDescriptorMap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -112,7 +106,16 @@ public class ParameterMetadataImpl implements ParameterMetadata {
|
|||
}
|
||||
|
||||
public int getOrdinalParameterCount() {
|
||||
return ordinalDescriptors.length;
|
||||
return ordinalDescriptorMap.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<String> getNamedParameterNames() {
|
||||
return namedDescriptorMap.keySet();
|
||||
}
|
||||
|
||||
public Set<Integer> getOrdinalParameterLabels() {
|
||||
return ordinalDescriptorMap.keySet();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -125,16 +128,18 @@ 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. " +
|
||||
"Remember that ordinal parameters are 0-based! Position: " + position
|
||||
final OrdinalParameterDescriptor descriptor = ordinalDescriptorMap.get( position );
|
||||
if ( descriptor == null ) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Could not locate ordinal parameter [%s], expecting one of [%s]",
|
||||
position,
|
||||
StringHelper.join( ", ", ordinalDescriptorMap.keySet() )
|
||||
)
|
||||
);
|
||||
}
|
||||
return ordinalDescriptors[position];
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,25 +164,17 @@ public class ParameterMetadataImpl implements ParameterMetadata {
|
|||
*
|
||||
* @return The source location
|
||||
*
|
||||
* @deprecated Use {@link OrdinalParameterDescriptor#getSourceLocation()} from the
|
||||
* @deprecated Use {@link OrdinalParameterDescriptor#getPosition()} from the
|
||||
* {@link #getOrdinalParameterDescriptor} return instead
|
||||
*/
|
||||
@Deprecated
|
||||
public int getOrdinalParameterSourceLocation(int position) {
|
||||
return getOrdinalParameterDescriptor( position ).getSourceLocation();
|
||||
}
|
||||
|
||||
/**
|
||||
* Access to the names of all named parameters
|
||||
*
|
||||
* @return The named parameter names
|
||||
*/
|
||||
public Set<String> getNamedParameterNames() {
|
||||
return namedDescriptorMap.keySet();
|
||||
return getOrdinalParameterDescriptor( position ).getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> QueryParameter<T> getQueryParameter(String name) {
|
||||
//noinspection unchecked
|
||||
return getNamedParameterDescriptor( name );
|
||||
}
|
||||
|
||||
|
@ -214,11 +211,18 @@ public class ParameterMetadataImpl implements ParameterMetadata {
|
|||
* @throws QueryParameterException If the name could not be resolved to a named parameter
|
||||
*/
|
||||
public NamedParameterDescriptor getNamedParameterDescriptor(String name) {
|
||||
final NamedParameterDescriptor meta = namedDescriptorMap.get( name );
|
||||
if ( meta == null ) {
|
||||
throw new QueryParameterException( "could not locate named parameter [" + name + "]" );
|
||||
final NamedParameterDescriptor descriptor = namedDescriptorMap.get( name );
|
||||
if ( descriptor == null ) {
|
||||
throw new QueryParameterException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Could not locate named parameter [%s], expecting one of [%s]",
|
||||
name,
|
||||
StringHelper.join( ", ", namedDescriptorMap.keySet() )
|
||||
)
|
||||
);
|
||||
}
|
||||
return meta;
|
||||
return descriptor;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -243,7 +247,7 @@ public class ParameterMetadataImpl implements ParameterMetadata {
|
|||
*
|
||||
* @return The type
|
||||
*
|
||||
* @deprecated Use {@link NamedParameterDescriptor#getSourceLocations()} from the
|
||||
* @deprecated Use {@link NamedParameterDescriptor#getPosition()} from the
|
||||
* {@link #getNamedParameterDescriptor} return instead
|
||||
*/
|
||||
@Deprecated
|
||||
|
@ -252,20 +256,28 @@ public class ParameterMetadataImpl implements ParameterMetadata {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isOrdinalParametersZeroBased() {
|
||||
return isOrdinalParametersZeroBased;
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<QueryParameter<?>> collectAllParameters() {
|
||||
if ( hasNamedParameters() || hasPositionalParameters() ) {
|
||||
final HashSet allParameters = new HashSet();
|
||||
allParameters.addAll( namedDescriptorMap.values() );
|
||||
allParameters.addAll( ordinalDescriptorMap.values() );
|
||||
return allParameters;
|
||||
}
|
||||
|
||||
return Collections.emptySet();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOrdinalParametersZeroBased(boolean isZeroBased) {
|
||||
this.isOrdinalParametersZeroBased = isZeroBased;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public Set<Parameter<?>> collectAllParametersJpa() {
|
||||
if ( hasNamedParameters() || hasPositionalParameters() ) {
|
||||
final HashSet allParameters = new HashSet();
|
||||
allParameters.addAll( namedDescriptorMap.values() );
|
||||
allParameters.addAll( ordinalDescriptorMap.values() );
|
||||
return allParameters;
|
||||
}
|
||||
|
||||
public ParameterMetadataImpl getOrdinalParametersZeroBasedCopy() {
|
||||
return new ParameterMetadataImpl(
|
||||
this.ordinalDescriptors,
|
||||
this.namedDescriptorMap,
|
||||
true
|
||||
);
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,14 +7,18 @@
|
|||
package org.hibernate.query.internal;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import javax.persistence.Parameter;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.QueryException;
|
||||
|
@ -22,13 +26,15 @@ import org.hibernate.QueryParameterException;
|
|||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.query.spi.NamedParameterDescriptor;
|
||||
import org.hibernate.engine.query.spi.OrdinalParameterDescriptor;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SharedSessionContractImplementor;
|
||||
import org.hibernate.engine.spi.TypedValue;
|
||||
import org.hibernate.hql.internal.classic.ParserHelper;
|
||||
import org.hibernate.internal.CoreLogging;
|
||||
import org.hibernate.internal.CoreMessageLogger;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.internal.util.collections.ArrayHelper;
|
||||
import org.hibernate.internal.util.collections.CollectionHelper;
|
||||
import org.hibernate.query.ParameterMetadata;
|
||||
import org.hibernate.query.QueryParameter;
|
||||
import org.hibernate.query.spi.QueryParameterBinding;
|
||||
|
@ -51,73 +57,88 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
private final ParameterMetadata parameterMetadata;
|
||||
private final boolean queryParametersValidationEnabled;
|
||||
|
||||
private final int ordinalParamValueOffset;
|
||||
|
||||
private Map<QueryParameter, QueryParameterBinding> parameterBindingMap;
|
||||
private Map<QueryParameter, QueryParameterListBinding> parameterListBindingMap;
|
||||
private Map<Integer, QueryParameterBinding> positionalParameterBindings;
|
||||
private Set<QueryParameter> parametersConvertedToListBindings;
|
||||
|
||||
public static QueryParameterBindingsImpl from(
|
||||
ParameterMetadata parameterMetadata,
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
boolean queryParametersValidationEnabled) {
|
||||
if ( parameterMetadata == null ) {
|
||||
return new QueryParameterBindingsImpl(
|
||||
sessionFactory,
|
||||
parameterMetadata,
|
||||
queryParametersValidationEnabled
|
||||
);
|
||||
}
|
||||
else {
|
||||
return new QueryParameterBindingsImpl(
|
||||
sessionFactory,
|
||||
parameterMetadata.collectAllParameters(),
|
||||
parameterMetadata, queryParametersValidationEnabled
|
||||
);
|
||||
throw new QueryParameterException( "Query parameter metadata cannot be null" );
|
||||
}
|
||||
|
||||
return new QueryParameterBindingsImpl(
|
||||
sessionFactory,
|
||||
parameterMetadata,
|
||||
queryParametersValidationEnabled
|
||||
);
|
||||
}
|
||||
|
||||
private QueryParameterBindingsImpl(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
ParameterMetadata parameterMetadata,
|
||||
boolean queryParametersValidationEnabled) {
|
||||
this( sessionFactory, Collections.emptySet(), parameterMetadata, queryParametersValidationEnabled );
|
||||
}
|
||||
|
||||
private QueryParameterBindingsImpl(
|
||||
SessionFactoryImplementor sessionFactory,
|
||||
Set<QueryParameter<?>> queryParameters,
|
||||
ParameterMetadata parameterMetadata,
|
||||
boolean queryParametersValidationEnabled) {
|
||||
this.sessionFactory = sessionFactory;
|
||||
this.parameterMetadata = parameterMetadata;
|
||||
this.queryParametersValidationEnabled = queryParametersValidationEnabled;
|
||||
this.positionalParameterBindings = new TreeMap<>( );
|
||||
|
||||
if ( queryParameters == null || queryParameters.isEmpty() ) {
|
||||
parameterBindingMap = Collections.emptyMap();
|
||||
}
|
||||
else {
|
||||
parameterBindingMap = new HashMap<>();
|
||||
this.parameterBindingMap = CollectionHelper.concurrentMap( parameterMetadata.getParameterCount() );
|
||||
|
||||
for ( QueryParameter queryParameter : queryParameters ) {
|
||||
if ( parameterMetadata.hasPositionalParameters() ) {
|
||||
int smallestOrdinalParamLabel = Integer.MAX_VALUE;
|
||||
for ( QueryParameter queryParameter : parameterMetadata.getPositionalParameters() ) {
|
||||
if ( queryParameter.getPosition() == null ) {
|
||||
// only cache the non-positional parameters in this map
|
||||
// positional parameters will be bound dynamically with getBinding(int)
|
||||
parameterBindingMap.put( queryParameter, makeBinding( queryParameter ) );
|
||||
throw new HibernateException( "Non-ordinal parameter ended up in ordinal param list" );
|
||||
}
|
||||
|
||||
if ( queryParameter.getPosition() < smallestOrdinalParamLabel ) {
|
||||
smallestOrdinalParamLabel = queryParameter.getPosition();
|
||||
}
|
||||
}
|
||||
ordinalParamValueOffset = smallestOrdinalParamLabel;
|
||||
}
|
||||
else {
|
||||
ordinalParamValueOffset = 0;
|
||||
}
|
||||
|
||||
parameterListBindingMap = new HashMap<>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected QueryParameterBinding makeBinding(QueryParameter queryParameter) {
|
||||
return makeBinding( queryParameter.getType() );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected QueryParameterBinding makeBinding(Type bindType) {
|
||||
return new QueryParameterBindingImpl( bindType, sessionFactory, shouldValidateBindingValue() );
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unchecked", "WeakerAccess"})
|
||||
protected <T> QueryParameterListBinding<T> makeListBinding(QueryParameter<T> param) {
|
||||
if ( parametersConvertedToListBindings == null ) {
|
||||
parametersConvertedToListBindings = new HashSet<>();
|
||||
}
|
||||
|
||||
parametersConvertedToListBindings.add( param );
|
||||
|
||||
if ( parameterListBindingMap == null ) {
|
||||
parameterListBindingMap = new HashMap<>();
|
||||
}
|
||||
|
||||
return parameterListBindingMap.computeIfAbsent(
|
||||
param,
|
||||
p -> new QueryParameterListBindingImpl(
|
||||
param.getType(),
|
||||
shouldValidateBindingValue()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings( "unchecked" )
|
||||
public boolean isBound(QueryParameter parameter) {
|
||||
final QueryParameterBinding binding = locateBinding( parameter );
|
||||
if ( binding != null ) {
|
||||
|
@ -171,16 +192,6 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
return null;
|
||||
}
|
||||
|
||||
protected QueryParameterBinding locateBinding(String name) {
|
||||
for ( Map.Entry<QueryParameter, QueryParameterBinding> entry : parameterBindingMap.entrySet() ) {
|
||||
if ( name.equals( entry.getKey().getName() ) ) {
|
||||
return entry.getValue();
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected QueryParameterBinding locateAndRemoveBinding(String name) {
|
||||
final Iterator<Map.Entry<QueryParameter, QueryParameterBinding>> entryIterator = parameterBindingMap.entrySet().iterator();
|
||||
while ( entryIterator.hasNext() ) {
|
||||
|
@ -194,117 +205,69 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
return null;
|
||||
}
|
||||
|
||||
protected QueryParameterBinding locateBinding(int position) {
|
||||
if ( position < positionalParameterBindings.size() ) {
|
||||
return positionalParameterBindings.get( position );
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public QueryParameterBinding getBinding(String name) {
|
||||
final QueryParameterBinding binding = locateBinding( name );
|
||||
if ( binding == null ) {
|
||||
throw new IllegalArgumentException( "Unknown parameter name : " + name );
|
||||
}
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryParameterBinding getBinding(int position) {
|
||||
int positionAdjustment = 0;
|
||||
if ( !parameterMetadata.isOrdinalParametersZeroBased() ) {
|
||||
positionAdjustment = -1;
|
||||
}
|
||||
QueryParameterBinding binding = null;
|
||||
if ( parameterMetadata != null ) {
|
||||
if ( !parameterMetadata.hasPositionalParameters() ) {
|
||||
// no positional parameters, assume jpa named.
|
||||
binding = locateBinding( Integer.toString( position ) );
|
||||
}
|
||||
else {
|
||||
try {
|
||||
binding = positionalParameterBindings.get( position + positionAdjustment );
|
||||
if ( binding == null ) {
|
||||
binding = makeBinding( parameterMetadata.getQueryParameter( position ) );
|
||||
positionalParameterBindings.put( position + positionAdjustment, binding );
|
||||
}
|
||||
}
|
||||
catch (QueryParameterException e) {
|
||||
// treat this as null binding
|
||||
}
|
||||
}
|
||||
return locateBinding( position );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected QueryParameterBinding locateBinding(int position) {
|
||||
final QueryParameter<Object> param = parameterMetadata.getQueryParameter( position );
|
||||
if ( param == null ) {
|
||||
throw new IllegalArgumentException( "Unknown ordinal parameter : " + position );
|
||||
}
|
||||
|
||||
if ( binding == null ) {
|
||||
throw new IllegalArgumentException( "Unknown parameter position: " + position );
|
||||
return parameterBindingMap.computeIfAbsent(
|
||||
param,
|
||||
this::makeBinding
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public QueryParameterBinding getBinding(String name) {
|
||||
return locateBinding( name );
|
||||
}
|
||||
|
||||
@SuppressWarnings("WeakerAccess")
|
||||
protected QueryParameterBinding locateBinding(String name) {
|
||||
final QueryParameter<Object> param = parameterMetadata.getQueryParameter( name );
|
||||
if ( param == null ) {
|
||||
throw new IllegalArgumentException( "Unknown named parameter : " + name );
|
||||
}
|
||||
|
||||
return binding;
|
||||
return parameterBindingMap.computeIfAbsent(
|
||||
param,
|
||||
this::makeBinding
|
||||
);
|
||||
}
|
||||
|
||||
public void verifyParametersBound(boolean reserveFirstParameter) {
|
||||
// verify named parameters bound
|
||||
for ( Map.Entry<QueryParameter, QueryParameterBinding> bindEntry : parameterBindingMap.entrySet() ) {
|
||||
if ( !bindEntry.getValue().isBound() ) {
|
||||
if ( bindEntry.getKey().getName() != null ) {
|
||||
throw new QueryException( "Named parameter [" + bindEntry.getKey().getName() + "] not set" );
|
||||
}
|
||||
else {
|
||||
throw new QueryException( "Parameter memento [" + bindEntry.getKey() + "] not set" );
|
||||
}
|
||||
for ( QueryParameter<?> parameter : parameterMetadata.collectAllParameters() ) {
|
||||
// check the "normal" bindings
|
||||
if ( parameterBindingMap.containsKey( parameter ) ) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
// verify position parameters bound
|
||||
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 );
|
||||
|
||||
// next check the "list" bindings
|
||||
if ( parameterListBindingMap != null
|
||||
&& parameterListBindingMap.containsKey( parameter ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( parametersConvertedToListBindings != null
|
||||
&& parametersConvertedToListBindings.contains( parameter ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( parameter.getName() != null ) {
|
||||
throw new QueryException( "Named parameter not bound : " + parameter.getName() );
|
||||
}
|
||||
else {
|
||||
binding = positionalParameterBindings.get( i - 1 );
|
||||
}
|
||||
if ( binding == null || !binding.isBound() ) {
|
||||
throw new QueryException( "Positional parameter [" + i + "] not set" );
|
||||
throw new QueryException( "Ordinal parameter not bound : " + parameter.getPosition() );
|
||||
}
|
||||
}
|
||||
// verify position parameter count is correct
|
||||
final int positionalValueSpan = calculatePositionalValueSpan( reserveFirstParameter );
|
||||
final int positionCounts = parameterMetadata.getPositionalParameterCount();
|
||||
if ( positionCounts != positionalValueSpan ) {
|
||||
if ( reserveFirstParameter && positionCounts - 1 != positionalValueSpan ) {
|
||||
throw new QueryException(
|
||||
"Expected positional parameter count: " +
|
||||
( positionCounts - 1 ) +
|
||||
", actually detected " + positionalValueSpan
|
||||
);
|
||||
}
|
||||
else if ( !reserveFirstParameter ) {
|
||||
throw new QueryException(
|
||||
"Expected positional parameter count: " +
|
||||
( positionCounts ) +
|
||||
", actually detected " + positionalValueSpan
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private int calculatePositionalValueSpan(boolean reserveFirstParameter) {
|
||||
int positionalValueSpan = 0;
|
||||
for ( QueryParameterBinding binding : positionalParameterBindings.values() ) {
|
||||
if ( binding.isBound() ) {
|
||||
Type bindType = binding.getBindType();
|
||||
if ( bindType == null ) {
|
||||
bindType = SerializableType.INSTANCE;
|
||||
}
|
||||
positionalValueSpan += bindType.getColumnSpan( sessionFactory );
|
||||
}
|
||||
}
|
||||
return positionalValueSpan;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -334,42 +297,79 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
*/
|
||||
@Deprecated
|
||||
public Type[] collectPositionalBindTypes() {
|
||||
Type[] types = new Type[ positionalParameterBindings.size() ];
|
||||
return ArrayHelper.EMPTY_TYPE_ARRAY;
|
||||
// if ( ! parameterMetadata.hasPositionalParameters() ) {
|
||||
// return ArrayHelper.EMPTY_TYPE_ARRAY;
|
||||
// }
|
||||
//
|
||||
// // callers expect these in ordinal order. In a way that is natural, but at the same
|
||||
// // time long term a way to find types/values by name/position would be better
|
||||
//
|
||||
// final TreeMap<QueryParameter, QueryParameterBinding> sortedPositionalParamBindings = getSortedPositionalParamBindingMap();
|
||||
// final List<Type> types = CollectionHelper.arrayList( sortedPositionalParamBindings.size() );
|
||||
//
|
||||
// for ( Map.Entry<QueryParameter, QueryParameterBinding> entry : sortedPositionalParamBindings.entrySet() ) {
|
||||
// if ( entry.getKey().getPosition() == null ) {
|
||||
// continue;
|
||||
// }
|
||||
//
|
||||
// Type type = entry.getValue().getBindType();
|
||||
// if ( type == null ) {
|
||||
// type = entry.getKey().getType();
|
||||
// }
|
||||
//
|
||||
// if ( type == null ) {
|
||||
// log.debugf(
|
||||
// "Binding for positional-parameter [%s] did not define type, using SerializableType",
|
||||
// entry.getKey().getPosition()
|
||||
// );
|
||||
// type = SerializableType.INSTANCE;
|
||||
// }
|
||||
//
|
||||
// types.add( type );
|
||||
// }
|
||||
//
|
||||
// return types.toArray( new Type[ types.size() ] );
|
||||
}
|
||||
|
||||
// NOTE : bindings should be ordered by position by nature of a TreeMap...
|
||||
// NOTE : we also assume the contiguity of the positions
|
||||
private TreeMap<QueryParameter, QueryParameterBinding> getSortedPositionalParamBindingMap() {
|
||||
final TreeMap<QueryParameter, QueryParameterBinding> map = new TreeMap<>( Comparator.comparing( Parameter::getPosition ) );
|
||||
|
||||
for ( Map.Entry<Integer, QueryParameterBinding> entry : positionalParameterBindings.entrySet() ) {
|
||||
final int position = entry.getKey();
|
||||
|
||||
Type type = entry.getValue().getBindType();
|
||||
if ( type == null ) {
|
||||
log.debugf( "Binding for positional-parameter [%s] did not define type, using SerializableType", position );
|
||||
type = SerializableType.INSTANCE;
|
||||
for ( Map.Entry<QueryParameter, QueryParameterBinding> entry : parameterBindingMap.entrySet() ) {
|
||||
if ( entry.getKey().getPosition() == null ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
types[ position ] = type;
|
||||
map.put( entry.getKey(), entry.getValue() );
|
||||
}
|
||||
|
||||
return types;
|
||||
return map;
|
||||
}
|
||||
|
||||
private static final Object[] EMPTY_VALUES = new Object[0];
|
||||
|
||||
/**
|
||||
* @deprecated (since 5.2) expect a different approach to org.hibernate.engine.spi.QueryParameters in 6.0
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object[] collectPositionalBindValues() {
|
||||
Object[] values = new Object[ positionalParameterBindings.size() ];
|
||||
|
||||
// NOTE : bindings should be ordered by position by nature of a TreeMap...
|
||||
// NOTE : we also assume the contiguity of the positions
|
||||
|
||||
for ( Map.Entry<Integer, QueryParameterBinding> entry : positionalParameterBindings.entrySet() ) {
|
||||
final int position = entry.getKey();
|
||||
values[ position ] = entry.getValue().getBindValue();
|
||||
}
|
||||
|
||||
return values;
|
||||
return EMPTY_VALUES;
|
||||
// if ( ! parameterMetadata.hasPositionalParameters() ) {
|
||||
// return EMPTY_VALUES;
|
||||
// }
|
||||
//
|
||||
// final TreeMap<QueryParameter, QueryParameterBinding> sortedPositionalParamBindings = getSortedPositionalParamBindingMap();
|
||||
// final List values = CollectionHelper.arrayList( sortedPositionalParamBindings.size() );
|
||||
//
|
||||
// for ( Map.Entry<QueryParameter, QueryParameterBinding> entry : sortedPositionalParamBindings.entrySet() ) {
|
||||
// if ( entry.getKey().getPosition() == null ) {
|
||||
// continue;
|
||||
// }
|
||||
// values.add( entry.getValue().getBindValue() );
|
||||
// }
|
||||
//
|
||||
// return values.toArray( new Object[values.size()] );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -377,20 +377,25 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
*/
|
||||
@Deprecated
|
||||
public Map<String, TypedValue> collectNamedParameterBindings() {
|
||||
Map<String, TypedValue> collectedBindings = new HashMap<>();
|
||||
final Map<String, TypedValue> collectedBindings = new HashMap<>();
|
||||
|
||||
for ( Map.Entry<QueryParameter, QueryParameterBinding> entry : parameterBindingMap.entrySet() ) {
|
||||
if ( entry.getKey().getName() == null ) {
|
||||
continue;
|
||||
final String key;
|
||||
if ( entry.getKey().getPosition() != null ) {
|
||||
key = Integer.toString( entry.getKey().getPosition() );
|
||||
}
|
||||
else {
|
||||
key = entry.getKey().getName();
|
||||
}
|
||||
|
||||
Type bindType = entry.getValue().getBindType();
|
||||
if ( bindType == null ) {
|
||||
log.debugf( "Binding for named-parameter [%s] did not define type", entry.getKey().getName() );
|
||||
log.debugf( "Binding for parameter [%s] did not define type", key );
|
||||
bindType = SerializableType.INSTANCE;
|
||||
}
|
||||
|
||||
collectedBindings.put(
|
||||
entry.getKey().getName(),
|
||||
key,
|
||||
new TypedValue( bindType, entry.getValue().getBindValue() )
|
||||
);
|
||||
}
|
||||
|
@ -408,11 +413,14 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> QueryParameterListBinding<T> getQueryParameterListBinding(QueryParameter<T> queryParameter) {
|
||||
QueryParameterListBinding result = parameterListBindingMap.get( queryParameter );
|
||||
if ( result == null ) {
|
||||
result = transformQueryParameterBindingToQueryParameterListBinding( queryParameter );
|
||||
if ( parameterListBindingMap == null ) {
|
||||
parameterListBindingMap = new HashMap<>();
|
||||
}
|
||||
return result;
|
||||
|
||||
return parameterListBindingMap.computeIfAbsent(
|
||||
queryParameter,
|
||||
this::transformQueryParameterBindingToQueryParameterListBinding
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -420,41 +428,45 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
*/
|
||||
@Deprecated
|
||||
private QueryParameterListBinding locateQueryParameterListBinding(QueryParameter queryParameter) {
|
||||
QueryParameterListBinding result = parameterListBindingMap.get( queryParameter );
|
||||
if ( parameterListBindingMap == null ) {
|
||||
parameterListBindingMap = new HashMap<>();
|
||||
}
|
||||
|
||||
if ( result == null && queryParameter.getName() != null ) {
|
||||
for ( Map.Entry<QueryParameter, QueryParameterListBinding> entry : parameterListBindingMap.entrySet() ) {
|
||||
if ( queryParameter.getName().equals( entry.getKey().getName() ) ) {
|
||||
result = entry.getValue();
|
||||
break;
|
||||
}
|
||||
QueryParameterListBinding binding = parameterListBindingMap.get( queryParameter );
|
||||
if ( binding == null ) {
|
||||
QueryParameter resolved = resolveParameter( queryParameter );
|
||||
if ( resolved != queryParameter ) {
|
||||
binding = parameterListBindingMap.get( resolved );
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
if ( binding == null ) {
|
||||
throw new IllegalArgumentException( "Could not locate parameter list binding" );
|
||||
}
|
||||
|
||||
return binding;
|
||||
}
|
||||
|
||||
private QueryParameter resolveParameter(QueryParameter queryParameter) {
|
||||
if ( queryParameter.getName() != null ) {
|
||||
return parameterMetadata.getQueryParameter( queryParameter.getName() );
|
||||
}
|
||||
else {
|
||||
return parameterMetadata.getQueryParameter( queryParameter.getPosition() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> QueryParameterListBinding<T> transformQueryParameterBindingToQueryParameterListBinding(QueryParameter<T> queryParameter) {
|
||||
log.debugf( "Converting QueryParameterBinding to QueryParameterListBinding for given QueryParameter : %s", queryParameter );
|
||||
final QueryParameterBinding binding = getAndRemoveBinding( queryParameter );
|
||||
if ( binding == null ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Could not locate QueryParameterBinding for given QueryParameter : " + queryParameter +
|
||||
"; parameter list must be defined using named parameter"
|
||||
);
|
||||
}
|
||||
|
||||
final QueryParameterListBinding<T> convertedBinding = new QueryParameterListBindingImpl<>(
|
||||
binding.getBindType(),
|
||||
shouldValidateBindingValue()
|
||||
);
|
||||
parameterListBindingMap.put( queryParameter, convertedBinding );
|
||||
getAndRemoveBinding( queryParameter );
|
||||
|
||||
return convertedBinding;
|
||||
return makeListBinding( queryParameter );
|
||||
}
|
||||
|
||||
private boolean shouldValidateBindingValue() {
|
||||
|
@ -467,25 +479,23 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> QueryParameterBinding<T> getAndRemoveBinding(QueryParameter<T> parameter) {
|
||||
// see if this exact instance is known as a key
|
||||
if ( parameterBindingMap.containsKey( parameter ) ) {
|
||||
return parameterBindingMap.remove( parameter );
|
||||
}
|
||||
QueryParameterBinding<T> binding = parameterBindingMap.remove( parameter );
|
||||
|
||||
// if the incoming parameter has a name, try to find it by name
|
||||
if ( StringHelper.isNotEmpty( parameter.getName() ) ) {
|
||||
final QueryParameterBinding binding = locateAndRemoveBinding( parameter.getName() );
|
||||
if ( binding != null ) {
|
||||
return binding;
|
||||
if ( binding == null ) {
|
||||
if ( parameter.getName() != null ) {
|
||||
parameter = parameterMetadata.getQueryParameter( parameter.getName() );
|
||||
}
|
||||
else {
|
||||
parameter = parameterMetadata.getQueryParameter( parameter.getPosition() );
|
||||
}
|
||||
|
||||
if ( parameter == null ) {
|
||||
throw new HibernateException( "Unable to resolve QueryParameter" );
|
||||
}
|
||||
}
|
||||
binding = parameterBindingMap.remove( parameter );
|
||||
|
||||
// NOTE : getAndRemoveBinding is only intended for usage from #transformQueryParameterBindingToQueryParameterListBinding
|
||||
// which only supports named parameters, so there is no need to look into legacy positional parameters
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Could not resolve QueryParameter reference [" + parameter + "] to QueryParameterBinding"
|
||||
);
|
||||
return binding;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -505,21 +515,43 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> QueryParameter<T> resolveQueryParameter(String name) {
|
||||
for ( QueryParameter queryParameter : parameterListBindingMap.keySet() ) {
|
||||
if ( name.equals( queryParameter.getName() ) ) {
|
||||
return queryParameter;
|
||||
}
|
||||
final QueryParameter<Object> param = parameterMetadata.getQueryParameter( name );
|
||||
|
||||
if ( param == null ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to resolve given parameter name [" + name + "] to QueryParameter reference"
|
||||
);
|
||||
}
|
||||
|
||||
for ( QueryParameter queryParameter : parameterBindingMap.keySet() ) {
|
||||
if ( name.equals( queryParameter.getName() ) ) {
|
||||
return queryParameter;
|
||||
}
|
||||
return (QueryParameter<T>) param;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> QueryParameterListBinding<T> getQueryParameterListBinding(int name) {
|
||||
// find the QueryParameter instance for the given name
|
||||
final QueryParameter<T> queryParameter = resolveQueryParameter( name );
|
||||
return getQueryParameterListBinding( queryParameter );
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated (since 5.2) expected changes to "collection-valued parameter binding" in 6.0
|
||||
*/
|
||||
@Deprecated
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> QueryParameter<T> resolveQueryParameter(int name) {
|
||||
final QueryParameter<Object> param = parameterMetadata.getQueryParameter( name );
|
||||
|
||||
if ( param == null ) {
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to resolve given parameter name [" + name + "] to QueryParameter reference"
|
||||
);
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException(
|
||||
"Unable to resolve given parameter name [" + name + "] to QueryParameter reference"
|
||||
);
|
||||
return (QueryParameter<T>) param;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -532,6 +564,10 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
return null;
|
||||
}
|
||||
|
||||
if ( parameterListBindingMap == null || parameterListBindingMap.isEmpty() ) {
|
||||
return queryString;
|
||||
}
|
||||
|
||||
// more-or-less... for each entry in parameterListBindingMap we will create an
|
||||
// entry in parameterBindingMap for each of the values in the bound value list. afterwards
|
||||
// we will clear the parameterListBindingMap.
|
||||
|
@ -545,24 +581,29 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
final int inExprLimit = dialect.getInExpressionCountLimit();
|
||||
|
||||
for ( Map.Entry<QueryParameter, QueryParameterListBinding> entry : parameterListBindingMap.entrySet() ) {
|
||||
final NamedParameterDescriptor sourceParam = (NamedParameterDescriptor) entry.getKey();
|
||||
final QueryParameter sourceParam = entry.getKey();
|
||||
final Collection bindValues = entry.getValue().getBindValues();
|
||||
|
||||
if ( inExprLimit > 0 && bindValues.size() > inExprLimit ) {
|
||||
log.tooManyInExpressions( dialect.getClass().getName(), inExprLimit, sourceParam.getName(), bindValues.size() );
|
||||
}
|
||||
|
||||
final boolean isJpaPositionalParam = sourceParam.isJpaPositionalParameter();
|
||||
final String paramPrefix = isJpaPositionalParam ? "?" : ParserHelper.HQL_VARIABLE_PREFIX;
|
||||
final String placeholder = paramPrefix + sourceParam.getName();
|
||||
final int loc = queryString.indexOf( placeholder );
|
||||
final String sourceToken;
|
||||
if ( sourceParam instanceof NamedParameterDescriptor ) {
|
||||
sourceToken = ":" + NamedParameterDescriptor.class.cast( sourceParam ).getName();
|
||||
}
|
||||
else {
|
||||
sourceToken = "?" + OrdinalParameterDescriptor.class.cast( sourceParam ).getPosition();
|
||||
}
|
||||
|
||||
final int loc = queryString.indexOf( sourceToken );
|
||||
|
||||
if ( loc < 0 ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String beforePlaceholder = queryString.substring( 0, loc );
|
||||
final String afterPlaceholder = queryString.substring( loc + placeholder.length() );
|
||||
final String afterPlaceholder = queryString.substring( loc + sourceToken.length() );
|
||||
|
||||
// check if placeholder is already immediately enclosed in parentheses
|
||||
// (ignoring whitespace)
|
||||
|
@ -583,21 +624,30 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
|
||||
int i = 0;
|
||||
for ( Object bindValue : entry.getValue().getBindValues() ) {
|
||||
if ( i > 0 ) {
|
||||
expansionList.append( ", " );
|
||||
}
|
||||
|
||||
// for each value in the bound list-of-values we:
|
||||
// 1) create a synthetic named parameter
|
||||
// 2) expand the queryString to include each synthetic named param in place of the original
|
||||
// 3) create a new synthetic binding for just that single value under the synthetic name
|
||||
final String syntheticName = ( isJpaPositionalParam ? 'x' : "" ) + sourceParam.getName() + '_' + i;
|
||||
if ( i > 0 ) {
|
||||
expansionList.append( ", " );
|
||||
final String syntheticName;
|
||||
if ( sourceParam instanceof NamedParameterDescriptor ) {
|
||||
syntheticName = NamedParameterDescriptor.class.cast( sourceParam ).getName() + '_' + i;
|
||||
}
|
||||
expansionList.append( ParserHelper.HQL_VARIABLE_PREFIX ).append( syntheticName );
|
||||
final QueryParameter syntheticParam = new QueryParameterNamedImpl<>(
|
||||
else {
|
||||
syntheticName = "x" + OrdinalParameterDescriptor.class.cast( sourceParam ).getPosition() + '_' + i;
|
||||
}
|
||||
|
||||
expansionList.append( ":" ).append( syntheticName );
|
||||
|
||||
final QueryParameter syntheticParam = new NamedParameterDescriptor(
|
||||
syntheticName,
|
||||
sourceParam.getSourceLocations(),
|
||||
sourceParam.isJpaPositionalParameter(),
|
||||
sourceParam.getType()
|
||||
sourceParam.getType(),
|
||||
sourceParam.getSourceLocations()
|
||||
);
|
||||
|
||||
final QueryParameterBinding syntheticBinding = makeBinding( entry.getValue().getBindType() );
|
||||
syntheticBinding.setBindValue( bindValue );
|
||||
parameterBindingMap.put( syntheticParam, syntheticBinding );
|
||||
|
@ -607,13 +657,17 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
queryString = StringHelper.replace(
|
||||
beforePlaceholder,
|
||||
afterPlaceholder,
|
||||
placeholder,
|
||||
sourceToken,
|
||||
expansionList.toString(),
|
||||
true,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
if ( parameterListBindingMap != null ) {
|
||||
parameterListBindingMap.clear();
|
||||
}
|
||||
|
||||
return queryString;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,13 +22,11 @@ import org.hibernate.type.Type;
|
|||
public class QueryParameterNamedImpl<T> extends QueryParameterImpl<T> implements QueryParameter<T> {
|
||||
private final String name;
|
||||
private final int[] sourceLocations;
|
||||
private final boolean jpaStyle;
|
||||
|
||||
public QueryParameterNamedImpl(String name, int[] sourceLocations, boolean jpaStyle, Type expectedType) {
|
||||
public QueryParameterNamedImpl(String name, int[] sourceLocations, Type expectedType) {
|
||||
super( expectedType );
|
||||
this.name = name;
|
||||
this.sourceLocations = sourceLocations;
|
||||
this.jpaStyle = jpaStyle;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -45,11 +43,6 @@ public class QueryParameterNamedImpl<T> extends QueryParameterImpl<T> implements
|
|||
return sourceLocations;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaPositionalParameter() {
|
||||
return jpaStyle;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if ( this == o ) {
|
||||
|
|
|
@ -39,8 +39,8 @@ public class ProcedureParameterImpl<T> extends QueryParameterImpl<T> implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isJpaPositionalParameter() {
|
||||
return false;
|
||||
public int[] getSourceLocations() {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -7,10 +7,12 @@
|
|||
package org.hibernate.query.procedure.internal;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.persistence.Parameter;
|
||||
|
||||
import org.hibernate.QueryParameterException;
|
||||
|
@ -153,4 +155,19 @@ public class ProcedureParameterMetadata implements ParameterMetadata {
|
|||
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<QueryParameter> getPositionalParameters() {
|
||||
return parameters.stream().filter( p -> p.getPosition() != null ).collect( Collectors.toList() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<QueryParameter> getNamedParameters() {
|
||||
return parameters.stream().filter( p -> p.getPosition() == null ).collect( Collectors.toList() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getParameterCount() {
|
||||
return parameters.size();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,6 @@ import java.sql.ResultSet;
|
|||
import java.sql.SQLException;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
@ -22,6 +21,7 @@ import org.hibernate.internal.CoreLogging;
|
|||
import org.hibernate.loader.custom.CustomLoader;
|
||||
import org.hibernate.loader.custom.CustomQuery;
|
||||
import org.hibernate.loader.custom.sql.SQLQueryReturnProcessor;
|
||||
import org.hibernate.param.ParameterBinder;
|
||||
import org.hibernate.result.NoMoreReturnsException;
|
||||
import org.hibernate.result.Output;
|
||||
import org.hibernate.result.Outputs;
|
||||
|
@ -245,9 +245,9 @@ public class OutputsImpl implements Outputs {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Map getNamedParameterBindPoints() {
|
||||
// no named parameters in terms of embedded in the SQL string
|
||||
return null;
|
||||
public List<ParameterBinder> getParameterValueBinders() {
|
||||
// no parameters in terms of embedded in the SQL string
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -33,7 +33,7 @@ public class ParameterParserTest {
|
|||
}
|
||||
@Test
|
||||
public void testQuotedTextInComment() {
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer( 0 );
|
||||
|
||||
ParameterParser.parse("-- 'This' should not fail the test.\n"
|
||||
+ "SELECT column FROM Table WHERE column <> :param", recognizer);
|
||||
|
@ -43,35 +43,35 @@ public class ParameterParserTest {
|
|||
|
||||
@Test
|
||||
public void testContractionInComment() {
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer( 0 );
|
||||
|
||||
ParameterParser.parse("-- This shouldn't fail the test.\n" + "SELECT column FROM Table WHERE column <> :param",
|
||||
recognizer);
|
||||
|
||||
assertTrue(recognizer.getNamedParameterDescriptionMap().containsKey("param"));
|
||||
assertTrue( recognizer.getNamedParameterDescriptionMap().containsKey("param"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDoubleDashInCharLiteral() {
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer( 0 );
|
||||
|
||||
ParameterParser.parse("select coalesce(i.name, '--NONE--') as itname from Item i where i.intVal=? ",recognizer);
|
||||
|
||||
assertEquals( 1, recognizer.getOrdinalParameterLocationList().size() );
|
||||
assertEquals( 1, recognizer.getOrdinalParameterDescriptionMap().size() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSlashStarInCharLiteral() {
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer( 0 );
|
||||
|
||||
ParameterParser.parse("select coalesce(i.name, '/*NONE') as itname from Item i where i.intVal=? ",recognizer);
|
||||
|
||||
assertEquals( 1, recognizer.getOrdinalParameterLocationList().size() );
|
||||
assertEquals( 1, recognizer.getOrdinalParameterDescriptionMap().size() );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testApostropheInOracleAlias() {
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer( 0 );
|
||||
|
||||
ParameterParser.parse("SELECT column as \"Table's column\" FROM Table WHERE column <> :param", recognizer);
|
||||
|
||||
|
@ -87,30 +87,38 @@ public class ParameterParserTest {
|
|||
public void outParameter(int position) {
|
||||
fail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void ordinalParameter(int position) {
|
||||
fail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void namedParameter(String name, int position) {
|
||||
fail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void jpaPositionalParameter(String name, int position) {
|
||||
public void jpaPositionalParameter(int name, int position) {
|
||||
fail();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void other(char character) {
|
||||
captured.append(character);
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void complete() {
|
||||
}
|
||||
};
|
||||
ParameterParser.parse("SELECT @a,(@a::=20) FROM tbl_name", recognizer);
|
||||
assertEquals("SELECT @a,(@a:=20) FROM tbl_name", captured.toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testParseNamedParameter() {
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer();
|
||||
ParamLocationRecognizer recognizer = new ParamLocationRecognizer( 0 );
|
||||
ParameterParser.parse("from Stock s where s.stockCode = :stockCode and s.xyz = :pxyz", recognizer);
|
||||
assertTrue(recognizer.getNamedParameterDescriptionMap().containsKey("stockCode"));
|
||||
assertTrue(recognizer.getNamedParameterDescriptionMap().containsKey("pxyz"));
|
||||
|
|
|
@ -79,8 +79,8 @@ public class NamedQueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
assertEquals( 1, list.size() );
|
||||
|
||||
final Session session = entityManager.unwrap( Session.class );
|
||||
final org.hibernate.query.Query sessionQuery = session.createQuery( "select g from Game g where title = ?" );
|
||||
sessionQuery.setParameter( 0, GAME_TITLES[0] );
|
||||
final org.hibernate.query.Query sessionQuery = session.createQuery( "select g from Game g where title = ?1" );
|
||||
sessionQuery.setParameter( 1, GAME_TITLES[0] );
|
||||
list = sessionQuery.getResultList();
|
||||
|
||||
query.setParameter( 1, GAME_TITLES[0] );
|
||||
|
@ -99,7 +99,7 @@ public class NamedQueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
final Session session = entityManager.unwrap( Session.class );
|
||||
final org.hibernate.query.Query sessionQuery = session.getNamedQuery( "NamedQuery" );
|
||||
sessionQuery.setParameter( 0, GAME_TITLES[0] );
|
||||
sessionQuery.setParameter( 1, GAME_TITLES[0] );
|
||||
list = sessionQuery.getResultList();
|
||||
|
||||
query.setParameter( 1, GAME_TITLES[0] );
|
||||
|
@ -130,7 +130,7 @@ public class NamedQueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
final Session session = entityManager.unwrap( Session.class );
|
||||
final org.hibernate.query.Query sessionQuery = session.createSQLQuery(
|
||||
"select * from Game g where title = ?" );
|
||||
sessionQuery.setParameter( 0, GAME_TITLES[0] );
|
||||
sessionQuery.setParameter( 1, GAME_TITLES[0] );
|
||||
list = sessionQuery.getResultList();
|
||||
|
||||
query.setParameter( 1, GAME_TITLES[0] );
|
||||
|
@ -150,7 +150,7 @@ public class NamedQueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
final Session session = entityManager.unwrap( Session.class );
|
||||
final org.hibernate.query.Query sessionQuery = session.getNamedNativeQuery(
|
||||
"NamedNativeQuery" );
|
||||
sessionQuery.setParameter( 0, GAME_TITLES[0] );
|
||||
sessionQuery.setParameter( 1, GAME_TITLES[0] );
|
||||
list = sessionQuery.getResultList();
|
||||
|
||||
query.setParameter( 1, GAME_TITLES[0] );
|
||||
|
@ -160,7 +160,7 @@ public class NamedQueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Entity(name = "Game")
|
||||
@NamedQueries(@NamedQuery(name = "NamedQuery", query = "select g from Game g where title = ?"))
|
||||
@NamedQueries(@NamedQuery(name = "NamedQuery", query = "select g from Game g where title = ?1"))
|
||||
@NamedNativeQueries(@NamedNativeQuery(name = "NamedNativeQuery", query = "select * from Game g where title = ?"))
|
||||
public static class Game {
|
||||
private Long id;
|
||||
|
|
|
@ -115,7 +115,7 @@ public class NativeQueryOrdinalParametersTest extends BaseEntityManagerFunctiona
|
|||
final String sqlString = "SELECT * FROM GAME g WHERE title = ?";
|
||||
try {
|
||||
NativeQuery sqlQuery = em.unwrap( Session.class ).createSQLQuery( sqlString );
|
||||
sqlQuery.setString( 0, "Super Mario Brothers").setCacheable( true );
|
||||
sqlQuery.setString( 1, "Super Mario Brothers").setCacheable( true );
|
||||
|
||||
List results = sqlQuery.list();
|
||||
assertEquals( 1, results.size() );
|
||||
|
@ -126,7 +126,7 @@ public class NativeQueryOrdinalParametersTest extends BaseEntityManagerFunctiona
|
|||
assertEquals( 1, list.size() );
|
||||
|
||||
sqlQuery = em.unwrap( Session.class ).createSQLQuery( sqlString );
|
||||
sqlQuery.setString( 0, "Super Mario Brothers").setCacheable( true );
|
||||
sqlQuery.setString( 1, "Super Mario Brothers").setCacheable( true );
|
||||
|
||||
results = sqlQuery.list();
|
||||
assertEquals( 1, results.size() );
|
||||
|
|
|
@ -23,6 +23,7 @@ import javax.persistence.TemporalType;
|
|||
import javax.persistence.Tuple;
|
||||
|
||||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.QueryException;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.Oracle8iDialect;
|
||||
import org.hibernate.dialect.PostgreSQL9Dialect;
|
||||
|
@ -139,17 +140,17 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
try {
|
||||
Item item = new Item( "Mouse", "Micro$oft mouse" );
|
||||
em.persist( item );
|
||||
Query q = em.createQuery( "from Item i where i.intVal=?" );
|
||||
q.setParameter( 0, null );
|
||||
Query q = em.createQuery( "from Item i where i.intVal=?1" );
|
||||
q.setParameter( 1, null );
|
||||
List results = q.getResultList();
|
||||
// null != null
|
||||
assertEquals( 0, results.size() );
|
||||
q = em.createQuery( "from Item i where i.intVal is null and ? is null" );
|
||||
q.setParameter( 0, null );
|
||||
q = em.createQuery( "from Item i where i.intVal is null and ?1 is null" );
|
||||
q.setParameter( 1, null );
|
||||
results = q.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
q = em.createQuery( "from Item i where i.intVal is null or i.intVal = ?" );
|
||||
q.setParameter( 0, null );
|
||||
q = em.createQuery( "from Item i where i.intVal is null or i.intVal = ?1" );
|
||||
q.setParameter( 1, null );
|
||||
results = q.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
}
|
||||
|
@ -169,7 +170,7 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
try {
|
||||
Item item = new Item( "Mouse", "Micro$oft mouse" );
|
||||
em.persist( item );
|
||||
Query q = em.createQuery( "from Item i where i.intVal=?" );
|
||||
Query q = em.createQuery( "from Item i where i.intVal=?1" );
|
||||
Parameter p = new Parameter() {
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -178,7 +179,7 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
@Override
|
||||
public Integer getPosition() {
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -191,11 +192,11 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
List results = q.getResultList();
|
||||
// null != null
|
||||
assertEquals( 0, results.size() );
|
||||
q = em.createQuery( "from Item i where i.intVal is null and ? is null" );
|
||||
q = em.createQuery( "from Item i where i.intVal is null and ?1 is null" );
|
||||
q.setParameter( p, null );
|
||||
results = q.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
q = em.createQuery( "from Item i where i.intVal is null or i.intVal = ?" );
|
||||
q = em.createQuery( "from Item i where i.intVal is null or i.intVal = ?1" );
|
||||
q.setParameter( p, null );
|
||||
results = q.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
|
@ -216,7 +217,7 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
try {
|
||||
Item item = new Item( "Mouse", "Micro$oft mouse" );
|
||||
em.persist( item );
|
||||
Query q = em.createQuery( "from Item i where i.intVal=?" );
|
||||
Query q = em.createQuery( "from Item i where i.intVal=?1" );
|
||||
Parameter p = new Parameter() {
|
||||
@Override
|
||||
public String getName() {
|
||||
|
@ -225,7 +226,7 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
|
||||
@Override
|
||||
public Integer getPosition() {
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -238,11 +239,11 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
List results = q.getResultList();
|
||||
// null != null
|
||||
assertEquals( 0, results.size() );
|
||||
q = em.createQuery( "from Item i where i.intVal is null and ? is null" );
|
||||
q = em.createQuery( "from Item i where i.intVal is null and ?1 is null" );
|
||||
q.setParameter( p, null );
|
||||
results = q.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
q = em.createQuery( "from Item i where i.intVal is null or i.intVal = ?" );
|
||||
q = em.createQuery( "from Item i where i.intVal is null or i.intVal = ?1" );
|
||||
q.setParameter( p, null );
|
||||
results = q.getResultList();
|
||||
assertEquals( 1, results.size() );
|
||||
|
@ -688,9 +689,8 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
Query query = em.createQuery( "from Item item where item.name =?1 or item.descr = ?1" );
|
||||
Parameter p1 = query.getParameter( 1 );
|
||||
Assert.assertNotNull( p1 );
|
||||
// in 5.2, '?<position' parameters are named while '?' are position-based.
|
||||
Assert.assertNotNull( p1.getName() );
|
||||
Assert.assertNull( p1.getPosition() );
|
||||
Assert.assertNotNull( p1.getPosition() );
|
||||
Assert.assertNull( p1.getName() );
|
||||
|
||||
em.getTransaction().commit();
|
||||
}
|
||||
|
@ -745,7 +745,7 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
params.add( item.getName() );
|
||||
params.add( item2.getName() );
|
||||
// deprecated usage of positional parameter by String
|
||||
q.setParameter( "1", params );
|
||||
q.setParameter( 1, params );
|
||||
result = q.getResultList();
|
||||
assertNotNull( result );
|
||||
assertEquals( 2, result.size() );
|
||||
|
@ -807,7 +807,7 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
params.add( item.getName() );
|
||||
params.add( item2.getName() );
|
||||
// deprecated usage of positional parameter by String
|
||||
q.setParameter( "1", params );
|
||||
q.setParameter( 1, params );
|
||||
result = q.getResultList();
|
||||
assertNotNull( result );
|
||||
assertEquals( 2, result.size() );
|
||||
|
@ -1011,13 +1011,7 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
// next using jpa-style positional parameter, but as a name (which is how Hibernate core treats these
|
||||
query = em.createQuery( "select w from Wallet w where w.brand = ?1" );
|
||||
// deprecated usage of positional parameter by String
|
||||
query.setParameter( "1", "Lacoste" );
|
||||
w = (Wallet) query.getSingleResult();
|
||||
assertNotNull( w );
|
||||
|
||||
// finally using hql-style positional parameter
|
||||
query = em.createQuery( "select w from Wallet w where w.brand = ?" );
|
||||
query.setParameter( 0, "Lacoste" );
|
||||
query.setParameter( 1, "Lacoste" );
|
||||
w = (Wallet) query.getSingleResult();
|
||||
assertNotNull( w );
|
||||
|
||||
|
@ -1047,8 +1041,19 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
em.persist( w );
|
||||
em.flush();
|
||||
|
||||
// using jpa-style, position index should match syntax '?<position'.
|
||||
Query jpaQuery = em.createQuery( "select w from Wallet w where w.brand = ?1 and w.model = ?3" );
|
||||
// Gaps are not allowed
|
||||
try {
|
||||
Query jpaQuery = em.createQuery( "select w from Wallet w where w.brand = ?1 and w.model = ?3" );
|
||||
fail( "expecting error regarding gap in positional param labels" );
|
||||
}
|
||||
catch ( IllegalArgumentException e ) {
|
||||
assertNotNull( e.getCause() );
|
||||
assertTyping( QueryException.class, e.getCause() );
|
||||
assertTrue( e.getCause().getMessage().contains( "gap" ) );
|
||||
}
|
||||
|
||||
// using jpa-style, position index should match syntax '?<position>'.
|
||||
Query jpaQuery = em.createQuery( "select w from Wallet w where w.brand = ?1" );
|
||||
jpaQuery.setParameter( 1, "Lacoste" );
|
||||
try {
|
||||
jpaQuery.setParameter( 2, "Expensive" );
|
||||
|
@ -1077,17 +1082,6 @@ public class QueryTest extends BaseEntityManagerFunctionalTestCase {
|
|||
catch (Exception e) {
|
||||
assertTyping( IllegalArgumentException.class, e );
|
||||
}
|
||||
|
||||
// using hql-style, should be 0-based
|
||||
Query hqlQuery = em.createQuery( "select w from Wallet w where w.brand = ? and w.model = ?" );
|
||||
try {
|
||||
hqlQuery.setParameter( 1, "Lacoste" );
|
||||
hqlQuery.setParameter( 2, "Expensive" );
|
||||
fail( "Should fail due to a user error in parameters" );
|
||||
}
|
||||
catch (Exception e) {
|
||||
assertTyping( IllegalArgumentException.class, e );
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if ( em.getTransaction() != null && em.getTransaction().isActive() ) {
|
||||
|
|
|
@ -92,7 +92,7 @@ public class Java5FeaturesTest extends BaseCoreFunctionalTestCase {
|
|||
s.clear();
|
||||
communityBid = (CommunityBid) s.createSQLQuery( "select {b.*} from Bid b where b.id = ?" )
|
||||
.addEntity( "b", CommunityBid.class )
|
||||
.setInteger( 0, communityBid.getId() ).uniqueResult();
|
||||
.setInteger( 1, communityBid.getId() ).uniqueResult();
|
||||
assertEquals( Starred.OK, communityBid.getCommunityNote() );
|
||||
s.delete( communityBid );
|
||||
tx.commit();
|
||||
|
|
|
@ -376,8 +376,8 @@ public class EnumeratedTypeTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
assertEquals( resultList.get(1).getTrimmed(), Trimmed.B );
|
||||
|
||||
// ensure querying works
|
||||
final Query query = s.createQuery("select e from EntityEnum e where e.trimmed=?");
|
||||
query.setParameter( 0, Trimmed.A );
|
||||
final Query query = s.createQuery("select e from EntityEnum e where e.trimmed=?1");
|
||||
query.setParameter( 1, Trimmed.A );
|
||||
resultList = query.list();
|
||||
assertEquals( resultList.size(), 1 );
|
||||
assertEquals( resultList.get(0).getTrimmed(), Trimmed.A );
|
||||
|
|
|
@ -57,13 +57,13 @@ public class LoaderWithInvalidQueryTest extends BaseEntityManagerFunctionalTestC
|
|||
name = "invalid_sql",
|
||||
query = "SELECT p " +
|
||||
"FROM Person p " +
|
||||
"WHERE p.id = ? and p.valid = true"
|
||||
"WHERE p.id = ?1 and p.valid = true"
|
||||
)
|
||||
@NamedQuery(
|
||||
name = "another_invalid_sql",
|
||||
query = "SELECT p " +
|
||||
"FROM _Person p " +
|
||||
"WHERE p.id = ?"
|
||||
"WHERE p.id = ?1"
|
||||
)
|
||||
public static class Person {
|
||||
|
||||
|
|
|
@ -57,10 +57,10 @@ public class NamedQueryTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testNamedQueriesOrdinalParametersAreZeroBased() {
|
||||
public void testNamedQueriesOrdinalParametersAreOneBased() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Query query = session.getNamedQuery( "NamedQuery" );
|
||||
query.setParameter( 0, GAME_TITLES[0] );
|
||||
query.setParameter( 1, GAME_TITLES[0] );
|
||||
List list = query.getResultList();
|
||||
assertEquals( 1, list.size() );
|
||||
}
|
||||
|
@ -68,10 +68,10 @@ public class NamedQueryTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testNativeNamedQueriesOrdinalParametersAreZeroBased() {
|
||||
public void testNativeNamedQueriesOrdinalParametersAreOneBased() {
|
||||
doInHibernate( this::sessionFactory, session -> {
|
||||
Query query = session.getNamedNativeQuery( "NamedNativeQuery" );
|
||||
query.setParameter( 0, GAME_TITLES[0] );
|
||||
query.setParameter( 1, GAME_TITLES[0] );
|
||||
List list = query.getResultList();
|
||||
assertEquals( 1, list.size() );
|
||||
}
|
||||
|
@ -79,7 +79,7 @@ public class NamedQueryTest extends BaseCoreFunctionalTestCase {
|
|||
}
|
||||
|
||||
@Entity(name = "Game")
|
||||
@NamedQueries(@NamedQuery(name = "NamedQuery", query = "select g from Game g where title = ?"))
|
||||
@NamedQueries(@NamedQuery(name = "NamedQuery", query = "select g from Game g where title = ?1"))
|
||||
@NamedNativeQueries(@NamedNativeQuery(name = "NamedNativeQuery", query = "select * from Game g where title = ?"))
|
||||
public static class Game {
|
||||
private Long id;
|
||||
|
|
|
@ -351,7 +351,7 @@ public class QueryAndSQLTest extends BaseCoreFunctionalTestCase {
|
|||
s.clear();
|
||||
tx = s.beginTransaction();
|
||||
Query q = s.getNamedQuery( "night.getAll.bySQL" );
|
||||
q.setParameter( 0, 9990 );
|
||||
q.setParameter( 1, 9990 );
|
||||
List result = q.list();
|
||||
assertEquals( 1, result.size() );
|
||||
Night n2 = (Night) result.get( 0 );
|
||||
|
|
|
@ -59,9 +59,9 @@ public class ColumnTransformerTest extends BaseCoreFunctionalTestCase {
|
|||
assertEquals(HEIGHT_INCHES, staff.getSizeInInches(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
staff = (Staff)s.createQuery("from Staff s where s.sizeInInches between ? and ?")
|
||||
.setDouble(0, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(1, HEIGHT_INCHES + 0.01d)
|
||||
staff = (Staff)s.createQuery("from Staff s where s.sizeInInches between ?1 and ?2")
|
||||
.setDouble(1, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(2, HEIGHT_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, staff.getSizeInInches(), 0.01d);
|
||||
|
||||
|
|
|
@ -247,9 +247,9 @@ public class ComponentTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
assertEquals(HEIGHT_INCHES, u.getPerson().getHeightInches(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
u = (User)s.createQuery("from User u where u.person.heightInches between ? and ?")
|
||||
.setDouble(0, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(1, HEIGHT_INCHES + 0.01d)
|
||||
u = (User)s.createQuery("from User u where u.person.heightInches between ?1 and ?2")
|
||||
.setDouble(1, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(2, HEIGHT_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, u.getPerson().getHeightInches(), 0.01d);
|
||||
|
||||
|
|
|
@ -97,9 +97,9 @@ public class CompositeUserTypeTest extends BaseCoreFunctionalTestCase {
|
|||
assertEquals(AMOUNT.doubleValue(), f.getHoldings().getAmount().doubleValue(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
f = (MutualFund)s.createQuery("from MutualFund f where f.holdings.amount between ? and ?")
|
||||
.setBigDecimal(0, AMOUNT.subtract(one))
|
||||
.setBigDecimal(1, AMOUNT.add(one))
|
||||
f = (MutualFund)s.createQuery("from MutualFund f where f.holdings.amount between ?1 and ?2")
|
||||
.setBigDecimal(1, AMOUNT.subtract(one))
|
||||
.setBigDecimal(2, AMOUNT.add(one))
|
||||
.uniqueResult();
|
||||
assertEquals(AMOUNT.doubleValue(), f.getHoldings().getAmount().doubleValue(), 0.01d);
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
assertTrue( "Incorrect collectionfilter count", result.getOrders().size() == 1 );
|
||||
|
||||
log.info( "HQL against Product..." );
|
||||
results = session.createQuery( "from Product as p where p.stockNumber = ?" ).setInteger( 0, 124 ).list();
|
||||
results = session.createQuery( "from Product as p where p.stockNumber = ?1" ).setInteger( 1, 124 ).list();
|
||||
assertTrue( results.size() == 1 );
|
||||
|
||||
session.close();
|
||||
|
@ -392,23 +392,23 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
log.info("query against Department with a subquery on Salesperson in the APAC reqion...");
|
||||
|
||||
List departments = session.createQuery(
|
||||
"select d from Department as d where d.id in (select s.department from Salesperson s where s.name = ?)"
|
||||
).setString( 0, "steve" ).list();
|
||||
"select d from Department as d where d.id in (select s.department from Salesperson s where s.name = ?1)"
|
||||
).setString( 1, "steve" ).list();
|
||||
|
||||
assertEquals("Incorrect department count", 1, departments.size());
|
||||
|
||||
log.info("query against Department with a subquery on Salesperson in the FooBar reqion...");
|
||||
|
||||
session.enableFilter("region").setParameter( "region", "Foobar" );
|
||||
departments = session.createQuery("select d from Department as d where d.id in (select s.department from Salesperson s where s.name = ?)").setString(0, "steve").list();
|
||||
departments = session.createQuery("select d from Department as d where d.id in (select s.department from Salesperson s where s.name = ?1)").setString(1, "steve").list();
|
||||
|
||||
assertEquals( "Incorrect department count", 0, departments.size() );
|
||||
|
||||
log.info("query against Order with a subquery for line items with a subquery line items where the product name is Acme Hair Gel and the quantity is greater than 1 in a given region for a given buyer");
|
||||
session.enableFilter("region").setParameter( "region", "APAC" );
|
||||
|
||||
List orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li, Product as p where p.id = li.product and li.quantity >= ? and p.name = ?) and o.buyer = ?")
|
||||
.setLong(0, 1L).setString(1, "Acme Hair Gel").setString(2, "gavin").list();
|
||||
List orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li, Product as p where p.id = li.product and li.quantity >= ?1 and p.name = ?2) and o.buyer = ?3")
|
||||
.setLong(1, 1L).setString(2, "Acme Hair Gel").setString(3, "gavin").list();
|
||||
|
||||
assertEquals( "Incorrect orders count", 1, orders.size() );
|
||||
|
||||
|
@ -417,8 +417,8 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
session.enableFilter("region").setParameter("region", "APAC");
|
||||
session.enableFilter("effectiveDate").setParameter( "asOfDate", testData.lastMonth.getTime() );
|
||||
|
||||
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ? and li.product in (select p.id from Product p where p.name = ?)) and o.buyer = ?")
|
||||
.setLong(0, 1L).setString(1, "Acme Hair Gel").setString(2, "gavin").list();
|
||||
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ?1 and li.product in (select p.id from Product p where p.name = ?2)) and o.buyer = ?3")
|
||||
.setLong(1, 1L).setString(2, "Acme Hair Gel").setString(3, "gavin").list();
|
||||
|
||||
assertEquals( "Incorrect orders count", 1, orders.size() );
|
||||
|
||||
|
@ -430,8 +430,8 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
session.enableFilter("region").setParameter("region", "APAC");
|
||||
session.enableFilter("effectiveDate").setParameter("asOfDate", testData.fourMonthsAgo.getTime());
|
||||
|
||||
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ? and li.product in (select p.id from Product p where p.name = ?)) and o.buyer = ?")
|
||||
.setLong( 0, 1L ).setString( 1, "Acme Hair Gel" ).setString( 2, "gavin" ).list();
|
||||
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ?1 and li.product in (select p.id from Product p where p.name = ?2)) and o.buyer = ?3")
|
||||
.setLong(1, 1L).setString(2, "Acme Hair Gel").setString(3, "gavin").list();
|
||||
|
||||
assertEquals("Incorrect orders count", 0, orders.size());
|
||||
|
||||
|
@ -440,8 +440,8 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
session.enableFilter("region").setParameter("region", "APAC");
|
||||
session.enableFilter("effectiveDate").setParameter("asOfDate", testData.lastMonth.getTime());
|
||||
|
||||
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= :quantity and li.product in (select p.id from Product p where p.name = :name)) and o.buyer = :buyer")
|
||||
.setLong("quantity", 1L).setString("name", "Acme Hair Gel").setString("buyer", "gavin").list();
|
||||
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ?1 and li.product in (select p.id from Product p where p.name = ?2)) and o.buyer = ?3")
|
||||
.setLong(1, 1L).setString(2, "Acme Hair Gel").setString(3, "gavin").list();
|
||||
|
||||
assertEquals("Incorrect orders count", 1, orders.size());
|
||||
|
||||
|
@ -450,8 +450,8 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
session.enableFilter("region").setParameter("region", "APAC");
|
||||
session.enableFilter("effectiveDate").setParameter("asOfDate", testData.lastMonth.getTime());
|
||||
|
||||
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ? and li.product in (select p.id from Product p where p.name = ?)) and o.buyer = :buyer")
|
||||
.setLong( 0, 1L ).setString( 1, "Acme Hair Gel" ).setString( "buyer", "gavin" ).list();
|
||||
orders = session.createQuery("select o from Order as o where exists (select li.id from LineItem li where li.quantity >= ?1 and li.product in (select p.id from Product p where p.name = ?2)) and o.buyer = ?3")
|
||||
.setLong(1, 1L).setString(2, "Acme Hair Gel").setString(3, "gavin").list();
|
||||
|
||||
assertEquals("Incorrect orders count", 1, orders.size());
|
||||
|
||||
|
@ -476,25 +476,25 @@ public class DynamicFilterTest extends BaseNonConfigCoreFunctionalTestCase {
|
|||
Session session = openSession();
|
||||
session.beginTransaction();
|
||||
|
||||
final String queryString = "from Order o where ? in ( select sp.name from Salesperson sp )";
|
||||
final String queryString = "from Order o where ?1 in ( select sp.name from Salesperson sp )";
|
||||
|
||||
// first a control-group query
|
||||
List result = session.createQuery( queryString ).setParameter( 0, "steve" ).list();
|
||||
List result = session.createQuery( queryString ).setParameter( 1, "steve" ).list();
|
||||
assertEquals( 2, result.size() );
|
||||
|
||||
// now lets enable filters on Order...
|
||||
session.enableFilter( "fulfilledOrders" ).setParameter( "asOfDate", testData.lastMonth.getTime() );
|
||||
result = session.createQuery( queryString ).setParameter( 0, "steve" ).list();
|
||||
result = session.createQuery( queryString ).setParameter( 1, "steve" ).list();
|
||||
assertEquals( 1, result.size() );
|
||||
|
||||
// now, lets additionally enable filter on Salesperson. First a valid one...
|
||||
session.enableFilter( "regionlist" ).setParameterList( "regions", new String[] { "APAC" } );
|
||||
result = session.createQuery( queryString ).setParameter( 0, "steve" ).list();
|
||||
result = session.createQuery( queryString ).setParameter( 1, "steve" ).list();
|
||||
assertEquals( 1, result.size() );
|
||||
|
||||
// ... then a silly one...
|
||||
session.enableFilter( "regionlist" ).setParameterList( "regions", new String[] { "gamma quadrant" } );
|
||||
result = session.createQuery( queryString ).setParameter( 0, "steve" ).list();
|
||||
result = session.createQuery( queryString ).setParameter( 1, "steve" ).list();
|
||||
assertEquals( 0, result.size() );
|
||||
|
||||
session.getTransaction().commit();
|
||||
|
|
|
@ -195,9 +195,9 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
session.clear();
|
||||
|
||||
session.getTransaction().begin();
|
||||
List result = session.createQuery( "FROM Zoo z WHERE z.name IN (?1) and z.address.city IN (?11)" )
|
||||
.setParameterList( "1", namesArray )
|
||||
.setParameterList( "11", citiesArray )
|
||||
List result = session.createQuery( "FROM Zoo z WHERE z.name IN (?1) and z.address.city IN (?2)" )
|
||||
.setParameterList( 1, namesArray )
|
||||
.setParameterList( 2, citiesArray )
|
||||
.list();
|
||||
assertEquals( 1, result.size() );
|
||||
session.getTransaction().commit();
|
||||
|
@ -761,13 +761,13 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
String query =
|
||||
( getDialect() instanceof DB2Dialect || getDialect() instanceof HSQLDialect ) ?
|
||||
"from Human where cast(? as string) is null" :
|
||||
"from Human where ? is null"
|
||||
"from Human where ?1 is null"
|
||||
;
|
||||
if ( getDialect() instanceof DerbyDialect ) {
|
||||
s.createQuery( query ).setParameter( 0, "null" ).list();
|
||||
s.createQuery( query ).setParameter( 1, "null" ).list();
|
||||
}
|
||||
else {
|
||||
s.createQuery( query ).setParameter( 0, null ).list();
|
||||
s.createQuery( query ).setParameter( 1, null ).list();
|
||||
}
|
||||
|
||||
s.getTransaction().commit();
|
||||
|
@ -1429,35 +1429,35 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
params.add( "Doe" );
|
||||
params.add( "Public" );
|
||||
s.createQuery( "from Human where name.last in (?1)" )
|
||||
.setParameterList( "1", params )
|
||||
.setParameterList( 1, params )
|
||||
.list();
|
||||
|
||||
s.createQuery( "from Human where name.last in ?1" )
|
||||
.setParameterList( "1", params )
|
||||
.setParameterList( 1, params )
|
||||
.list();
|
||||
|
||||
s.createQuery( "from Human where nickName = ?1 and ( name.first = ?2 or name.last in (?3) )" )
|
||||
.setParameter( "1", "Yogster" )
|
||||
.setParameter( "2", "Yogi" )
|
||||
.setParameterList( "3", params )
|
||||
.setParameter( 1, "Yogster" )
|
||||
.setParameter( 2, "Yogi" )
|
||||
.setParameterList( 3, params )
|
||||
.list();
|
||||
|
||||
s.createQuery( "from Human where nickName = ?1 and ( name.first = ?2 or name.last in ?3 )" )
|
||||
.setParameter( "1", "Yogster" )
|
||||
.setParameter( "2", "Yogi" )
|
||||
.setParameterList( "3", params )
|
||||
.setParameter( 1, "Yogster" )
|
||||
.setParameter( 2, "Yogi" )
|
||||
.setParameterList( 3, params )
|
||||
.list();
|
||||
|
||||
s.createQuery( "from Human where nickName = ?1 or ( name.first = ?2 and name.last in (?3) )" )
|
||||
.setParameter( "1", "Yogster" )
|
||||
.setParameter( "2", "Yogi" )
|
||||
.setParameterList( "3", params )
|
||||
.setParameter( 1, "Yogster" )
|
||||
.setParameter( 2, "Yogi" )
|
||||
.setParameterList( 3, params )
|
||||
.list();
|
||||
|
||||
s.createQuery( "from Human where nickName = ?1 or ( name.first = ?2 and name.last in ?3 )" )
|
||||
.setParameter( "1", "Yogster" )
|
||||
.setParameter( "2", "Yogi" )
|
||||
.setParameterList( "3", params )
|
||||
.setParameter( 1, "Yogster" )
|
||||
.setParameter( 2, "Yogi" )
|
||||
.setParameterList( 3, params )
|
||||
.list();
|
||||
|
||||
s.getTransaction().commit();
|
||||
|
@ -2489,9 +2489,9 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
public void testParameterMixing() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
s.createQuery( "from Animal a where a.description = ? and a.bodyWeight = ? or a.bodyWeight = :bw" )
|
||||
.setString( 0, "something" )
|
||||
.setFloat( 1, 12345f )
|
||||
s.createQuery( "from Animal a where a.description = ?1 and a.bodyWeight = ?2 or a.bodyWeight = :bw" )
|
||||
.setString( 1, "something" )
|
||||
.setFloat( 2, 12345f )
|
||||
.setFloat( "bw", 123f )
|
||||
.list();
|
||||
t.commit();
|
||||
|
@ -2502,13 +2502,13 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
public void testOrdinalParameters() {
|
||||
Session s = openSession();
|
||||
Transaction t = s.beginTransaction();
|
||||
s.createQuery( "from Animal a where a.description = ? and a.bodyWeight = ?" )
|
||||
.setString( 0, "something" )
|
||||
.setFloat( 1, 123f )
|
||||
s.createQuery( "from Animal a where a.description = ?1 and a.bodyWeight = ?2" )
|
||||
.setString( 1, "something" )
|
||||
.setFloat( 2, 123f )
|
||||
.list();
|
||||
s.createQuery( "from Animal a where a.bodyWeight in (?, ?)" )
|
||||
.setFloat( 0, 999f )
|
||||
.setFloat( 1, 123f )
|
||||
s.createQuery( "from Animal a where a.bodyWeight in (?1, ?2)" )
|
||||
.setFloat( 1, 999f )
|
||||
.setFloat( 2, 123f )
|
||||
.list();
|
||||
t.commit();
|
||||
s.close();
|
||||
|
@ -2801,8 +2801,8 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
session.flush();
|
||||
|
||||
assertEquals( session.createFilter( human.getFriends(), "" ).list().size(), 1 );
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.bodyWeight > ?" ).setFloat( 0, 10f ).list().size(), 1 );
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.bodyWeight < ?" ).setFloat( 0, 10f ).list().size(), 0 );
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.bodyWeight > ?1" ).setFloat( 1, 10f ).list().size(), 1 );
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.bodyWeight < ?1" ).setFloat( 1, 10f ).list().size(), 0 );
|
||||
|
||||
session.delete(human);
|
||||
session.delete(friend);
|
||||
|
@ -2835,17 +2835,22 @@ public class ASTParserLoadingTest extends BaseCoreFunctionalTestCase {
|
|||
session.flush();
|
||||
|
||||
assertEquals( session.createFilter( human.getFriends(), "" ).list().size(), 1 );
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.heightInches < ?" ).setDouble( 0, 51d ).list().size(), 1 );
|
||||
assertEquals(
|
||||
session.createFilter( human.getFriends(), "where this.heightInches > ?" )
|
||||
.setDouble( 0, 51d )
|
||||
.list()
|
||||
.size(), 0
|
||||
session.createFilter( human.getFriends(), "where this.heightInches < ?1" ).setDouble( 1, 51d ).list().size(),
|
||||
1
|
||||
);
|
||||
assertEquals(
|
||||
session.createFilter( human.getFriends(), "where this.heightInches between 49 and 51" ).list().size(), 1
|
||||
session.createFilter( human.getFriends(), "where this.heightInches > ?1" ).setDouble( 1, 51d ).list().size(),
|
||||
0
|
||||
);
|
||||
assertEquals(
|
||||
session.createFilter( human.getFriends(), "where this.heightInches between 49 and 51" ).list().size(),
|
||||
1
|
||||
);
|
||||
assertEquals(
|
||||
session.createFilter( human.getFriends(), "where this.heightInches not between 49 and 51" ).list().size(),
|
||||
0
|
||||
);
|
||||
assertEquals( session.createFilter( human.getFriends(), "where this.heightInches not between 49 and 51" ).list().size(), 0 );
|
||||
|
||||
session.delete( human );
|
||||
session.delete( friend );
|
||||
|
|
|
@ -369,8 +369,8 @@ public class BulkManipulationTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
Car c = (Car) s.createQuery( "from Car where owner = 'Kirsten'" ).uniqueResult();
|
||||
c.setOwner( "NotKirsten" );
|
||||
assertEquals( 0, s.getNamedQuery( "native-delete-car" ).setString( 0, "Kirsten" ).executeUpdate() );
|
||||
assertEquals( 1, s.getNamedQuery( "native-delete-car" ).setString( 0, "NotKirsten" ).executeUpdate() );
|
||||
assertEquals( 0, s.getNamedQuery( "native-delete-car" ).setString( 1, "Kirsten" ).executeUpdate() );
|
||||
assertEquals( 1, s.getNamedQuery( "native-delete-car" ).setString( 1, "NotKirsten" ).executeUpdate() );
|
||||
|
||||
|
||||
assertEquals(
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.hibernate.test.hql;
|
|||
import org.junit.Test;
|
||||
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.hql.internal.classic.ClassicQueryTranslatorFactory;
|
||||
|
@ -26,6 +27,7 @@ public class ClassicTranslatorTest extends QueryTranslatorTestCase {
|
|||
public void configure(Configuration cfg) {
|
||||
super.configure( cfg );
|
||||
cfg.setProperty( Environment.QUERY_TRANSLATOR, ClassicQueryTranslatorFactory.class.getName() );
|
||||
cfg.setProperty( AvailableSettings.JDBC_TYLE_PARAMS_ZERO_BASE, "true" );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -52,10 +54,6 @@ public class ClassicTranslatorTest extends QueryTranslatorTestCase {
|
|||
|
||||
session.createQuery( "from Animal as a where a.description = ?" ).setString( 0, "jj" ).list();
|
||||
session.createQuery( "from Animal as a where a.description = :desc" ).setString( "desc", "jr" ).list();
|
||||
session.createQuery( "from Animal as a where a.description = ? or a.description = :desc" )
|
||||
.setString( 0, "jj" )
|
||||
.setString( "desc", "jr" )
|
||||
.list();
|
||||
|
||||
session.getTransaction().commit();
|
||||
session.close();
|
||||
|
|
|
@ -83,14 +83,14 @@ public class CollectionMapWithComponentValueTest extends BaseCoreFunctionalTestC
|
|||
public void testMapKeyExpressionInWhere() {
|
||||
doInHibernate( this::sessionFactory, s -> {
|
||||
// JPA form
|
||||
Query query = s.createQuery( "select te from TestEntity te join te.values v where ? in (key(v)) " );
|
||||
query.setParameter( 0, keyValue );
|
||||
Query query = s.createQuery( "select te from TestEntity te join te.values v where ?1 in (key(v)) " );
|
||||
query.setParameter( 1, keyValue );
|
||||
|
||||
assertThat( query.list().size(), is( 1 ) );
|
||||
|
||||
// Hibernate additional form
|
||||
query = s.createQuery( "select te from TestEntity te where ? in (key(te.values))" );
|
||||
query.setParameter( 0, keyValue );
|
||||
query = s.createQuery( "select te from TestEntity te where ?1 in (key(te.values))" );
|
||||
query.setParameter( 1, keyValue );
|
||||
|
||||
assertThat( query.list().size(), is( 1 ) );
|
||||
|
||||
|
@ -113,7 +113,7 @@ public class CollectionMapWithComponentValueTest extends BaseCoreFunctionalTestC
|
|||
fail( "HibernateException expected - Could not determine type for EmbeddableValue" );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
assertTyping( HibernateException.class, e );
|
||||
assertTyping( IllegalArgumentException.class, e );
|
||||
}
|
||||
|
||||
// Hibernate additional form
|
||||
|
@ -124,7 +124,7 @@ public class CollectionMapWithComponentValueTest extends BaseCoreFunctionalTestC
|
|||
fail( "HibernateException expected - Could not determine type for EmbeddableValue" );
|
||||
}
|
||||
catch ( Exception e ) {
|
||||
assertTyping( HibernateException.class, e );
|
||||
assertTyping( IllegalArgumentException.class, e );
|
||||
}
|
||||
|
||||
// Test value property dereference
|
||||
|
|
|
@ -70,12 +70,12 @@ public class EJBQLTest extends BaseCoreFunctionalTestCase {
|
|||
QueryTranslatorImpl qt = compile( "from Animal a where a.bodyWeight = ?1" );
|
||||
AST ast = ( AST ) qt.getSqlAST();
|
||||
|
||||
// make certain that the ejb3-positional param got recognized as a named param
|
||||
// make certain that the ejb3-positional param got recognized as a positional param
|
||||
List namedParams = ASTUtil.collectChildren(
|
||||
ast,
|
||||
new ASTUtil.FilterPredicate() {
|
||||
public boolean exclude(AST n) {
|
||||
return n.getType() != HqlSqlTokenTypes.NAMED_PARAM;
|
||||
return n.getType() != HqlSqlTokenTypes.PARAM;
|
||||
}
|
||||
}
|
||||
);
|
||||
|
|
|
@ -170,15 +170,15 @@ public class HQLTest extends QueryTranslatorTestCase {
|
|||
} )
|
||||
|
||||
public void testRowValueConstructorSyntaxInInListBeingTranslated() {
|
||||
QueryTranslatorImpl translator = createNewQueryTranslator("from LineItem l where l.id in (?)");
|
||||
QueryTranslatorImpl translator = createNewQueryTranslator("from LineItem l where l.id in (?1)");
|
||||
assertInExist("'in' should be translated to 'and'", false, translator);
|
||||
translator = createNewQueryTranslator("from LineItem l where l.id in ?");
|
||||
translator = createNewQueryTranslator("from LineItem l where l.id in ?1");
|
||||
assertInExist("'in' should be translated to 'and'", false, translator);
|
||||
translator = createNewQueryTranslator("from LineItem l where l.id in (('a1',1,'b1'),('a2',2,'b2'))");
|
||||
assertInExist("'in' should be translated to 'and'", false, translator);
|
||||
translator = createNewQueryTranslator("from Animal a where a.id in (?)");
|
||||
translator = createNewQueryTranslator("from Animal a where a.id in (?1)");
|
||||
assertInExist("only translated tuple has 'in' syntax", true, translator);
|
||||
translator = createNewQueryTranslator("from Animal a where a.id in ?");
|
||||
translator = createNewQueryTranslator("from Animal a where a.id in ?1");
|
||||
assertInExist("only translated tuple has 'in' syntax", true, translator);
|
||||
translator = createNewQueryTranslator("from LineItem l where l.id in (select a1 from Animal a1 left join a1.offspring o where a1.id = 1)");
|
||||
assertInExist("do not translate sub-queries", true, translator);
|
||||
|
@ -290,13 +290,13 @@ public class HQLTest extends QueryTranslatorTestCase {
|
|||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", CalendarDateType.INSTANCE, translator.getReturnTypes()[0] );
|
||||
|
||||
translator = createNewQueryTranslator( "from Order o where o.orderDate > ?" );
|
||||
assertEquals( "incorrect expected param type", CalendarDateType.INSTANCE, translator.getParameterTranslations().getOrdinalParameterExpectedType( 0 ) );
|
||||
translator = createNewQueryTranslator( "from Order o where o.orderDate > ?1" );
|
||||
assertEquals( "incorrect expected param type", CalendarDateType.INSTANCE, translator.getParameterTranslations().getPositionalParameterInformation( 1 ).getExpectedType() );
|
||||
|
||||
translator = createNewQueryTranslator( "select o.orderDate + ? from Order o" );
|
||||
translator = createNewQueryTranslator( "select o.orderDate + ?1 from Order o" );
|
||||
assertEquals( "incorrect return type count", 1, translator.getReturnTypes().length );
|
||||
assertEquals( "incorrect return type", CalendarDateType.INSTANCE, translator.getReturnTypes()[0] );
|
||||
assertEquals( "incorrect expected param type", DoubleType.INSTANCE, translator.getParameterTranslations().getOrdinalParameterExpectedType( 0 ) );
|
||||
assertEquals( "incorrect expected param type", DoubleType.INSTANCE, translator.getParameterTranslations().getPositionalParameterInformation( 1 ).getExpectedType() );
|
||||
|
||||
}
|
||||
|
||||
|
@ -1010,7 +1010,7 @@ public class HQLTest extends QueryTranslatorTestCase {
|
|||
@Test
|
||||
public void testImplicitJoins() throws Exception {
|
||||
// Two dots...
|
||||
assertTranslation( "from Animal an where an.mother.bodyWeight > ?" );
|
||||
assertTranslation( "from Animal an where an.mother.bodyWeight > ?1" );
|
||||
assertTranslation( "from Animal an where an.mother.bodyWeight > 10" );
|
||||
assertTranslation( "from Dog dog where dog.mother.bodyWeight > 10" );
|
||||
// Three dots...
|
||||
|
@ -1220,7 +1220,7 @@ public class HQLTest extends QueryTranslatorTestCase {
|
|||
|
||||
@Test
|
||||
public void testPositionalParameters() throws Exception {
|
||||
assertTranslation( "from Animal an where an.bodyWeight > ?" );
|
||||
assertTranslation( "from Animal an where an.bodyWeight > ?1" );
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
|
@ -137,8 +137,8 @@ public class WithClauseTest extends BaseCoreFunctionalTestCase {
|
|||
|
||||
s.beginTransaction();
|
||||
|
||||
Query query = s.createQuery( "select a from SimpleEntityWithAssociation as e INNER JOIN e.associatedEntities as a WITH e.name=?" );
|
||||
query.setParameter( 0, "entity1" );
|
||||
Query query = s.createQuery( "select a from SimpleEntityWithAssociation as e INNER JOIN e.associatedEntities as a WITH e.name=?1" );
|
||||
query.setParameter( 1, "entity1" );
|
||||
List list = query.list();
|
||||
assertEquals( list.size(), 1 );
|
||||
|
||||
|
|
|
@ -15,6 +15,8 @@ import java.util.List;
|
|||
import org.hibernate.Hibernate;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.cfg.Configuration;
|
||||
import org.hibernate.criterion.Restrictions;
|
||||
import org.hibernate.jdbc.AbstractWork;
|
||||
|
||||
|
@ -23,6 +25,7 @@ import org.junit.Test;
|
|||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
|
@ -34,6 +37,12 @@ public class JoinTest extends BaseCoreFunctionalTestCase {
|
|||
return new String[] { "join/Person.hbm.xml" };
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configure(Configuration configuration) {
|
||||
super.afterConfigurationBuilt( configuration );
|
||||
configuration.setProperty( AvailableSettings.JDBC_TYLE_PARAMS_ZERO_BASE, "true" );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSequentialSelects() {
|
||||
Session s = openSession();
|
||||
|
@ -197,14 +206,15 @@ public class JoinTest extends BaseCoreFunctionalTestCase {
|
|||
assertEquals(PASSWORD_EXPIRY_DAYS, u.getPasswordExpiryDays(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
p = (Person)s.createQuery("from Person p where p.heightInches between ? and ?")
|
||||
.setDouble(0, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(1, HEIGHT_INCHES + 0.01d)
|
||||
p = (Person)s.createQuery("from Person p where p.heightInches between ?1 and ?2")
|
||||
.setDouble(1, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(2, HEIGHT_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
assertNotNull( p );
|
||||
assertEquals(HEIGHT_INCHES, p.getHeightInches(), 0.01d);
|
||||
u = (User)s.createQuery("from User u where u.passwordExpiryDays between ? and ?")
|
||||
.setDouble(0, PASSWORD_EXPIRY_DAYS - 0.01d)
|
||||
.setDouble(1, PASSWORD_EXPIRY_DAYS + 0.01d)
|
||||
u = (User)s.createQuery("from User u where u.passwordExpiryDays between ?1 and ?2")
|
||||
.setDouble(1, PASSWORD_EXPIRY_DAYS - 0.01d)
|
||||
.setDouble(2, PASSWORD_EXPIRY_DAYS + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(PASSWORD_EXPIRY_DAYS, u.getPasswordExpiryDays(), 0.01d);
|
||||
|
||||
|
|
|
@ -214,7 +214,7 @@ public class JoinedSubclassTest extends BaseCoreFunctionalTestCase {
|
|||
assertEquals(HEIGHT_CENTIMETERS, heightViaSql, 0.01d);
|
||||
Double expiryViaSql =
|
||||
( (Number)s.createSQLQuery("select pwd_expiry_weeks from JEmployee where person_id=?")
|
||||
.setLong(0, e.getId())
|
||||
.setLong(1, e.getId())
|
||||
.uniqueResult()
|
||||
).doubleValue();
|
||||
assertEquals(PASSWORD_EXPIRY_WEEKS, expiryViaSql, 0.01d);
|
||||
|
@ -236,14 +236,14 @@ public class JoinedSubclassTest extends BaseCoreFunctionalTestCase {
|
|||
assertEquals(PASSWORD_EXPIRY_DAYS, e.getPasswordExpiryDays(), 0.01d);
|
||||
|
||||
// Test predicate and entity load via HQL
|
||||
p = (Person)s.createQuery("from Person p where p.heightInches between ? and ?")
|
||||
.setDouble(0, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(1, HEIGHT_INCHES + 0.01d)
|
||||
p = (Person)s.createQuery("from Person p where p.heightInches between ?1 and ?2")
|
||||
.setDouble(1, HEIGHT_INCHES - 0.01d)
|
||||
.setDouble(2, HEIGHT_INCHES + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(HEIGHT_INCHES, p.getHeightInches(), 0.01d);
|
||||
e = (Employee)s.createQuery("from Employee e where e.passwordExpiryDays between ? and ?")
|
||||
.setDouble(0, PASSWORD_EXPIRY_DAYS - 0.01d)
|
||||
.setDouble(1, PASSWORD_EXPIRY_DAYS + 0.01d)
|
||||
e = (Employee)s.createQuery("from Employee e where e.passwordExpiryDays between ?1 and ?2")
|
||||
.setDouble(1, PASSWORD_EXPIRY_DAYS - 0.01d)
|
||||
.setDouble(2, PASSWORD_EXPIRY_DAYS + 0.01d)
|
||||
.uniqueResult();
|
||||
assertEquals(PASSWORD_EXPIRY_DAYS, e.getPasswordExpiryDays(), 0.01d);
|
||||
|
||||
|
@ -257,7 +257,7 @@ public class JoinedSubclassTest extends BaseCoreFunctionalTestCase {
|
|||
assertEquals(2.54d, heightViaSql, 0.01d);
|
||||
expiryViaSql =
|
||||
( (Number)s.createSQLQuery("select pwd_expiry_weeks from JEmployee where person_id=?")
|
||||
.setLong(0, e.getId())
|
||||
.setLong(1, e.getId())
|
||||
.uniqueResult()
|
||||
).doubleValue();
|
||||
assertEquals(1d, expiryViaSql, 0.01d);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
|
||||
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
|
||||
*/
|
||||
package org.hibernate.test.jpa.compliance;
|
||||
|
||||
import javax.persistence.Parameter;
|
||||
|
||||
import org.hibernate.query.Query;
|
||||
|
||||
import org.hibernate.testing.transaction.TransactionUtil2;
|
||||
import org.hibernate.test.jpa.AbstractJPATest;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.either;
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.CoreMatchers.notNullValue;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class JpaPositionalParameterTest extends AbstractJPATest {
|
||||
@Test
|
||||
public void testPositionalParameters() {
|
||||
TransactionUtil2.inTransaction(
|
||||
sessionFactory(),
|
||||
session -> {
|
||||
Query query = session.createQuery( "select i from Item i where name = ?1 or name = ?2" );
|
||||
for ( Parameter<?> parameter : query.getParameters() ) {
|
||||
assertThat( parameter.getPosition(), notNullValue() );
|
||||
assertThat( parameter.getPosition(), either( is(1) ).or( is(2) ) );
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
|
@ -19,7 +19,7 @@ public class NativeQueryTest extends AbstractJPATest {
|
|||
public void testJpaStylePositionalParametersInNativeSql() {
|
||||
Session s = openSession();
|
||||
s.beginTransaction();
|
||||
s.createSQLQuery( "select NAME from EJB3_ITEM where ITEM_ID = ?1" ).setParameter( "1", new Long( 123 ) ).list();
|
||||
s.createSQLQuery( "select NAME from EJB3_ITEM where ITEM_ID = ?1" ).setParameter( 1, 123L ).list();
|
||||
s.getTransaction().commit();
|
||||
s.close();
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue