mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-03-02 15:59:18 +00:00
HHH-9576 - Use JDBC bind variables for handling JPA Criteria query numeric literals
This commit is contained in:
parent
81f4ab8f06
commit
56947f28dc
@ -44,7 +44,6 @@
|
||||
import org.hibernate.dialect.function.SQLFunction;
|
||||
import org.hibernate.engine.config.internal.ConfigurationServiceImpl;
|
||||
import org.hibernate.engine.config.spi.ConfigurationService;
|
||||
import org.hibernate.engine.config.spi.StandardConverters;
|
||||
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
@ -53,6 +52,7 @@
|
||||
import org.hibernate.internal.util.config.ConfigurationHelper;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder;
|
||||
@ -564,6 +564,7 @@ public static class SessionFactoryOptionsStateStandardImpl implements SessionFac
|
||||
private boolean wrapResultSetsEnabled;
|
||||
private TimeZone jdbcTimeZone;
|
||||
private boolean queryParametersValidationEnabled;
|
||||
private LiteralHandlingMode criteriaLiteralHandlingMode;
|
||||
|
||||
private Map<String, SQLFunction> sqlFunctions;
|
||||
|
||||
@ -776,6 +777,13 @@ else if ( jdbcTimeZoneValue != null ) {
|
||||
configurationSettings,
|
||||
true
|
||||
);
|
||||
|
||||
this.criteriaLiteralHandlingMode = strategySelector.resolveStrategy(
|
||||
LiteralHandlingMode.class,
|
||||
configurationSettings.get( CRITERIA_LITERAL_HANDLING_MODE ),
|
||||
LiteralHandlingMode.AUTO,
|
||||
(clazz) -> LiteralHandlingMode.AUTO
|
||||
);
|
||||
}
|
||||
|
||||
private static Interceptor determineInterceptor(Map configurationSettings, StrategySelector strategySelector) {
|
||||
@ -1216,6 +1224,11 @@ public TimeZone getJdbcTimeZone() {
|
||||
public boolean isQueryParametersValidationEnabled() {
|
||||
return this.queryParametersValidationEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return this.criteriaLiteralHandlingMode;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -1544,4 +1557,9 @@ public TimeZone getJdbcTimeZone() {
|
||||
public boolean isQueryParametersValidationEnabled() {
|
||||
return options.isQueryParametersValidationEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return options.getCriteriaLiteralHandlingMode();
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
||||
@ -127,6 +128,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
||||
|
||||
private final Map<String, SQLFunction> sqlFunctions;
|
||||
private boolean queryParametersValidationEnabled;
|
||||
private LiteralHandlingMode criteriaLiteralHandlingMode;
|
||||
|
||||
public SessionFactoryOptionsImpl(SessionFactoryOptionsState state) {
|
||||
this.serviceRegistry = state.getServiceRegistry();
|
||||
@ -207,6 +209,7 @@ public SessionFactoryOptionsImpl(SessionFactoryOptionsState state) {
|
||||
this.jdbcTimeZone = state.getJdbcTimeZone();
|
||||
|
||||
this.queryParametersValidationEnabled = state.isQueryParametersValidationEnabled();
|
||||
this.criteriaLiteralHandlingMode = state.getCriteriaLiteralHandlingMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -542,4 +545,9 @@ public TimeZone getJdbcTimeZone() {
|
||||
public boolean isQueryParametersValidationEnabled() {
|
||||
return queryParametersValidationEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return criteriaLiteralHandlingMode;
|
||||
}
|
||||
}
|
||||
|
@ -28,6 +28,7 @@
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
||||
@ -178,4 +179,8 @@ public interface SessionFactoryOptionsState {
|
||||
TimeZone getJdbcTimeZone();
|
||||
|
||||
boolean isQueryParametersValidationEnabled();
|
||||
|
||||
default LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return LiteralHandlingMode.AUTO;
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
||||
@ -383,4 +384,9 @@ public TimeZone getJdbcTimeZone() {
|
||||
public boolean isQueryParametersValidationEnabled() {
|
||||
return delegate.isQueryParametersValidationEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return delegate.getCriteriaLiteralHandlingMode();
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
import org.hibernate.hql.spi.id.MultiTableBulkIdStrategy;
|
||||
import org.hibernate.loader.BatchFetchStyle;
|
||||
import org.hibernate.proxy.EntityNotFoundDelegate;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode;
|
||||
import org.hibernate.resource.jdbc.spi.StatementInspector;
|
||||
import org.hibernate.tuple.entity.EntityTuplizerFactory;
|
||||
@ -223,4 +224,8 @@ default boolean doesConnectionProviderDisableAutoCommit() {
|
||||
default boolean isQueryParametersValidationEnabled(){
|
||||
return isJpaBootstrap();
|
||||
}
|
||||
|
||||
default LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return LiteralHandlingMode.AUTO;
|
||||
}
|
||||
}
|
||||
|
@ -1690,4 +1690,24 @@ public interface AvailableSettings {
|
||||
*
|
||||
*/
|
||||
String VALIDATE_QUERY_PARAMETERS = "hibernate.query.validate_parameters";
|
||||
|
||||
/**
|
||||
* By default, Criteria queries uses bind parameters for any literal that is not a numeric value.
|
||||
*
|
||||
* However, to increase the likelihood of JDBC statement caching,
|
||||
* you might want to use bind parameters for numeric values too.
|
||||
* The {@link org.hibernate.query.criteria.LiteralHandlingMode#BIND} mode will use bind variables for any literal value.
|
||||
*
|
||||
* The {@link org.hibernate.query.criteria.LiteralHandlingMode#INLINE} mode will inline literal values as-is.
|
||||
* To prevent SQL injection, never use {@link org.hibernate.query.criteria.LiteralHandlingMode#INLINE} with String variables.
|
||||
* Always use constants with the {@link org.hibernate.query.criteria.LiteralHandlingMode#INLINE} mode.
|
||||
* </p>
|
||||
* Valid options are defined by the {@link org.hibernate.query.criteria.LiteralHandlingMode} enum.
|
||||
* </p>
|
||||
* The default value is {@link org.hibernate.query.criteria.LiteralHandlingMode#AUTO}
|
||||
*
|
||||
* @since 5.2.12
|
||||
* @see org.hibernate.query.criteria.LiteralHandlingMode
|
||||
*/
|
||||
String CRITERIA_LITERAL_HANDLING_MODE = "hibernate.criteria.literal_handling_mode";
|
||||
}
|
||||
|
@ -2921,6 +2921,24 @@ public boolean isLegacyLimitHandlerBehaviorEnabled() {
|
||||
return legacyLimitHandlerBehavior;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inline String literal.
|
||||
*
|
||||
* @return escaped String
|
||||
*/
|
||||
public String inlineLiteral(String literal) {
|
||||
return String.format( "\'%s\'", escapeLiteral( literal ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Escape String literal.
|
||||
*
|
||||
* @return escaped String
|
||||
*/
|
||||
protected String escapeLiteral(String literal) {
|
||||
return literal.replace("'", "''");
|
||||
}
|
||||
|
||||
private void resolveLegacyLimitHandlerBehavior(ServiceRegistry serviceRegistry) {
|
||||
// HHH-11194
|
||||
// Temporary solution to set whether legacy limit handler behavior should be used.
|
||||
|
@ -583,4 +583,9 @@ public boolean dropConstraints() {
|
||||
protected MySQLStorageEngine getDefaultMySQLStorageEngine() {
|
||||
return MyISAMStorageEngine.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String escapeLiteral(String literal) {
|
||||
return super.escapeLiteral( literal ).replace("\\", "\\\\");
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.query.criteria;
|
||||
|
||||
/**
|
||||
* This enum defines how literals are handled by JPA Criteria.
|
||||
*
|
||||
* By default ({@code AUTO}), Criteria queries uses bind parameters for any literal that is not a numeric value.
|
||||
*
|
||||
* However, to increase the likelihood of JDBC statement caching,
|
||||
* you might want to use bind parameters for numeric values too.
|
||||
* The {@code BIND} mode will use bind variables for any literal value.
|
||||
*
|
||||
* The {@code INLINE} mode will inline literal values as-is.
|
||||
* To prevent SQL injection, never use {@code INLINE} with String variables.
|
||||
* Always use constants with the {@code INLINE} mode.
|
||||
*
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public enum LiteralHandlingMode {
|
||||
|
||||
AUTO,
|
||||
BIND,
|
||||
INLINE
|
||||
}
|
@ -14,9 +14,13 @@
|
||||
import javax.persistence.TypedQuery;
|
||||
import javax.persistence.criteria.ParameterExpression;
|
||||
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.engine.jdbc.spi.JdbcServices;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.engine.spi.SessionImplementor;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.query.spi.QueryImplementor;
|
||||
import org.hibernate.type.Type;
|
||||
|
||||
@ -47,6 +51,14 @@ public QueryImplementor compile(CompilableCriteria criteria) {
|
||||
final Map<ParameterExpression<?>, ExplicitParameterInfo<?>> explicitParameterInfoMap = new HashMap<>();
|
||||
final List<ImplicitParameterBinding> implicitParameterBindings = new ArrayList<>();
|
||||
|
||||
final SessionFactoryImplementor sessionFactory = entityManager.getSessionFactory();
|
||||
|
||||
final LiteralHandlingMode criteriaLiteralHandlingMode = sessionFactory
|
||||
.getSessionFactoryOptions()
|
||||
.getCriteriaLiteralHandlingMode();
|
||||
|
||||
final Dialect dialect = sessionFactory.getServiceRegistry().getService( JdbcServices.class ).getDialect();
|
||||
|
||||
RenderingContext renderingContext = new RenderingContext() {
|
||||
private int aliasCount;
|
||||
private int explicitParameterCount;
|
||||
@ -122,6 +134,16 @@ public String getCastType(Class javaType) {
|
||||
}
|
||||
return hibernateType.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Dialect getDialect() {
|
||||
return dialect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return criteriaLiteralHandlingMode;
|
||||
}
|
||||
};
|
||||
|
||||
return criteria.interpret( renderingContext ).buildCompiledQuery(
|
||||
|
@ -8,6 +8,9 @@
|
||||
|
||||
import javax.persistence.criteria.ParameterExpression;
|
||||
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
||||
/**
|
||||
* Used to provide a context and services to the rendering.
|
||||
*
|
||||
@ -19,7 +22,7 @@ public interface RenderingContext {
|
||||
*
|
||||
* @return The generated correlation name
|
||||
*/
|
||||
public String generateAlias();
|
||||
String generateAlias();
|
||||
|
||||
/**
|
||||
* Register parameters explicitly encountered in the criteria query.
|
||||
@ -28,7 +31,7 @@ public interface RenderingContext {
|
||||
*
|
||||
* @return The JPA-QL parameter name
|
||||
*/
|
||||
public ExplicitParameterInfo registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter);
|
||||
ExplicitParameterInfo registerExplicitParameter(ParameterExpression<?> criteriaQueryParameter);
|
||||
|
||||
/**
|
||||
* Register a parameter that was not part of the criteria query (at least not as a parameter).
|
||||
@ -38,7 +41,7 @@ public interface RenderingContext {
|
||||
*
|
||||
* @return The JPA-QL parameter name
|
||||
*/
|
||||
public String registerLiteralParameterBinding(Object literal, Class javaType);
|
||||
String registerLiteralParameterBinding(Object literal, Class javaType);
|
||||
|
||||
/**
|
||||
* Given a java type, determine the proper cast type name.
|
||||
@ -47,5 +50,21 @@ public interface RenderingContext {
|
||||
*
|
||||
* @return The cast type name.
|
||||
*/
|
||||
public String getCastType(Class javaType);
|
||||
String getCastType(Class javaType);
|
||||
|
||||
/**
|
||||
* Current Dialect.
|
||||
*
|
||||
* @return Dialect
|
||||
*/
|
||||
Dialect getDialect();
|
||||
|
||||
/**
|
||||
* How literals are going to be handled.
|
||||
*
|
||||
* @return literal handling strategy
|
||||
*/
|
||||
default LiteralHandlingMode getCriteriaLiteralHandlingMode() {
|
||||
return LiteralHandlingMode.AUTO;
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
import org.hibernate.query.criteria.internal.CriteriaBuilderImpl;
|
||||
import org.hibernate.query.criteria.internal.ParameterRegistry;
|
||||
import org.hibernate.query.criteria.internal.ValueHandlerFactory;
|
||||
@ -46,11 +47,31 @@ public void registerParameters(ParameterRegistry registry) {
|
||||
|
||||
@SuppressWarnings({ "unchecked" })
|
||||
public String render(RenderingContext renderingContext) {
|
||||
if ( ValueHandlerFactory.isNumeric( literal ) ) {
|
||||
return ValueHandlerFactory.determineAppropriateHandler( (Class) literal.getClass() ).render( literal );
|
||||
}
|
||||
|
||||
// else...
|
||||
LiteralHandlingMode literalHandlingMode = renderingContext.getCriteriaLiteralHandlingMode();
|
||||
|
||||
switch ( literalHandlingMode ) {
|
||||
case AUTO:
|
||||
if ( ValueHandlerFactory.isNumeric( literal ) ) {
|
||||
return ValueHandlerFactory.determineAppropriateHandler( (Class) literal.getClass() ).render( literal );
|
||||
}
|
||||
else {
|
||||
return bindLiteral( renderingContext );
|
||||
}
|
||||
case BIND:
|
||||
return bindLiteral( renderingContext );
|
||||
case INLINE:
|
||||
Object literalValue = literal;
|
||||
if ( String.class.equals( literal.getClass() ) ) {
|
||||
literalValue = renderingContext.getDialect().inlineLiteral( (String) literal );
|
||||
}
|
||||
return ValueHandlerFactory.determineAppropriateHandler( (Class) literal.getClass() ).render( literalValue );
|
||||
default:
|
||||
throw new IllegalArgumentException( "Unexpected LiteralHandlingMode: " + literalHandlingMode );
|
||||
}
|
||||
}
|
||||
|
||||
private String bindLiteral(RenderingContext renderingContext) {
|
||||
final String parameterName = renderingContext.registerLiteralParameterBinding( getLiteral(), getJavaType() );
|
||||
return ':' + parameterName;
|
||||
}
|
||||
|
@ -0,0 +1,127 @@
|
||||
/*
|
||||
* 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.jpa.test.criteria.literal;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Tuple;
|
||||
import javax.persistence.criteria.CriteriaBuilder;
|
||||
import javax.persistence.criteria.CriteriaQuery;
|
||||
import javax.persistence.criteria.Root;
|
||||
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public abstract class AbstractCriteriaLiteralHandlingModeTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider;
|
||||
|
||||
@Override
|
||||
protected Map getConfig() {
|
||||
Map config = super.getConfig();
|
||||
config.put(
|
||||
org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
return config;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void buildEntityManagerFactory() throws Exception {
|
||||
connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
super.buildEntityManagerFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Book.class
|
||||
};
|
||||
}
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
Book book = new Book();
|
||||
book.id = 1;
|
||||
book.name = bookName();
|
||||
|
||||
entityManager.persist( book );
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLiteralHandlingMode() throws Exception {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
|
||||
final CriteriaQuery<Tuple> query = cb.createQuery( Tuple.class );
|
||||
|
||||
final Root<Book> entity = query.from( Book.class );
|
||||
query.where(
|
||||
cb.and(
|
||||
cb.equal(
|
||||
entity.get( "id" ),
|
||||
cb.literal( 1 )
|
||||
),
|
||||
cb.equal(
|
||||
entity.get( "name" ),
|
||||
cb.literal( bookName() )
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
query.multiselect(
|
||||
cb.literal( "abc" ),
|
||||
entity.get( "name" )
|
||||
);
|
||||
|
||||
connectionProvider.clear();
|
||||
List<Tuple> tuples = entityManager.createQuery( query )
|
||||
.getResultList();
|
||||
assertEquals( 1, tuples.size() );
|
||||
|
||||
assertNotNull( connectionProvider.getPreparedStatement( expectedSQL() ) );
|
||||
} );
|
||||
}
|
||||
|
||||
protected abstract String expectedSQL();
|
||||
|
||||
@Entity(name = "Book")
|
||||
public static class Book {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
}
|
||||
|
||||
protected String bookName() {
|
||||
return "Vlad's High-Performance Java Persistence";
|
||||
}
|
||||
}
|
@ -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.jpa.test.criteria.literal;
|
||||
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
public class CriteriaLiteralHandlingModeAutoTest extends AbstractCriteriaLiteralHandlingModeTest {
|
||||
|
||||
protected String expectedSQL() {
|
||||
return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=1 and abstractcr0_.name=?";
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.jpa.test.criteria.literal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
public class CriteriaLiteralHandlingModeBindTest extends AbstractCriteriaLiteralHandlingModeTest {
|
||||
|
||||
@Override
|
||||
protected Map getConfig() {
|
||||
Map config = super.getConfig();
|
||||
config.put(
|
||||
AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE,
|
||||
LiteralHandlingMode.BIND
|
||||
);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected String expectedSQL() {
|
||||
return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=? and abstractcr0_.name=?";
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* 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.jpa.test.criteria.literal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
public class CriteriaLiteralHandlingModeInlineTest extends AbstractCriteriaLiteralHandlingModeTest {
|
||||
|
||||
@Override
|
||||
protected Map getConfig() {
|
||||
Map config = super.getConfig();
|
||||
config.put(
|
||||
AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE,
|
||||
LiteralHandlingMode.INLINE
|
||||
);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected String expectedSQL() {
|
||||
return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=1 and abstractcr0_.name='Vlad''s High-Performance Java Persistence'";
|
||||
}
|
||||
}
|
@ -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.jpa.test.criteria.literal;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.dialect.MySQLDialect;
|
||||
import org.hibernate.query.criteria.LiteralHandlingMode;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@RequiresDialect(MySQLDialect.class)
|
||||
public class MySQLCriteriaLiteralHandlingModeInlineTest extends AbstractCriteriaLiteralHandlingModeTest {
|
||||
|
||||
@Override
|
||||
protected Map getConfig() {
|
||||
Map config = super.getConfig();
|
||||
config.put(
|
||||
AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE,
|
||||
LiteralHandlingMode.INLINE
|
||||
);
|
||||
return config;
|
||||
}
|
||||
|
||||
protected String expectedSQL() {
|
||||
return "select 'abc' as col_0_0_, abstractcr0_.name as col_1_0_ from Book abstractcr0_ where abstractcr0_.id=1 and abstractcr0_.name='Vlad\\\\''s High-Performance Java Persistence'";
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String bookName() {
|
||||
return "Vlad\\'s High-Performance Java Persistence";
|
||||
}
|
||||
}
|
@ -11,6 +11,7 @@
|
||||
import java.util.Map;
|
||||
import javax.persistence.CascadeType;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.ManyToOne;
|
||||
@ -141,6 +142,50 @@ public void testLiteralsInWhereClause() throws Exception {
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumericLiteralsInWhereClause() throws Exception {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
testNumericLiterals(
|
||||
entityManager,
|
||||
"select 'abc' as col_0_0_, criteriali0_.name as col_1_0_ from Book criteriali0_ where criteriali0_.id=1"
|
||||
);
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testNumericLiteralsInWhereClauseUsingBindParameters() throws Exception {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
testNumericLiterals(
|
||||
entityManager,
|
||||
"select 'abc' as col_0_0_, criteriali0_.name as col_1_0_ from Book criteriali0_ where criteriali0_.id=1"
|
||||
);
|
||||
} );
|
||||
}
|
||||
|
||||
private void testNumericLiterals(EntityManager entityManager, String expectedSQL) {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
|
||||
final CriteriaQuery<Tuple> query = cb.createQuery( Tuple.class );
|
||||
|
||||
final Root<Book> entity = query.from( Book.class );
|
||||
query.where( cb.equal(
|
||||
entity.get( "id" ),
|
||||
cb.literal( 1 )
|
||||
) );
|
||||
|
||||
query.multiselect(
|
||||
cb.literal( "abc" ),
|
||||
entity.get( "name" )
|
||||
);
|
||||
|
||||
connectionProvider.clear();
|
||||
List<Tuple> tuples = entityManager.createQuery( query )
|
||||
.getResultList();
|
||||
assertEquals( 1, tuples.size() );
|
||||
|
||||
assertNotNull( connectionProvider.getPreparedStatement(expectedSQL) );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testCriteriaParameters() throws Exception {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
|
Loading…
x
Reference in New Issue
Block a user