HHH-12469 - Add support for IN clause parameter padding to better reuse cached statements
This commit is contained in:
parent
6c42a17210
commit
74d0fd0dbe
|
@ -583,6 +583,8 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
private boolean jpaProxyComplianceEnabled;
|
||||
private ImmutableEntityUpdateQueryHandlingMode immutableEntityUpdateQueryHandlingMode;
|
||||
|
||||
private boolean inClauseParameterPaddingEnabled;
|
||||
|
||||
public SessionFactoryOptionsStateStandardImpl(StandardServiceRegistry serviceRegistry) {
|
||||
this.serviceRegistry = serviceRegistry;
|
||||
|
||||
|
@ -829,6 +831,12 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
this.immutableEntityUpdateQueryHandlingMode = ImmutableEntityUpdateQueryHandlingMode.interpret(
|
||||
configurationSettings.get( IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE )
|
||||
);
|
||||
|
||||
this.inClauseParameterPaddingEnabled = ConfigurationHelper.getBoolean(
|
||||
IN_CLAUSE_PARAMETER_PADDING,
|
||||
configurationSettings,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
private static Interceptor determineInterceptor(Map configurationSettings, StrategySelector strategySelector) {
|
||||
|
@ -1297,6 +1305,11 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
|
||||
return immutableEntityUpdateQueryHandlingMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inClauseParameterPaddingEnabled() {
|
||||
return this.inClauseParameterPaddingEnabled;
|
||||
}
|
||||
}
|
||||
|
||||
private static Supplier<? extends Interceptor> interceptorSupplier(Class<? extends Interceptor> clazz) {
|
||||
|
@ -1661,4 +1674,9 @@ public class SessionFactoryBuilderImpl implements SessionFactoryBuilderImplement
|
|||
public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
|
||||
return options.getImmutableEntityUpdateQueryHandlingMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inClauseParameterPaddingEnabled() {
|
||||
return options.inClauseParameterPaddingEnabled();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -137,6 +137,7 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
private final boolean failOnPaginationOverCollectionFetchEnabled;
|
||||
private final boolean jpaProxyComplianceEnabled;
|
||||
private ImmutableEntityUpdateQueryHandlingMode immutableEntityUpdateQueryHandlingMode;
|
||||
private boolean inClauseParameterPaddingEnabled;
|
||||
|
||||
public SessionFactoryOptionsImpl(SessionFactoryOptionsState state) {
|
||||
this.serviceRegistry = state.getServiceRegistry();
|
||||
|
@ -225,6 +226,8 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
this.jpaProxyComplianceEnabled = state.isJpaProxyComplianceEnabled();
|
||||
|
||||
this.immutableEntityUpdateQueryHandlingMode = state.getImmutableEntityUpdateQueryHandlingMode();
|
||||
|
||||
this.inClauseParameterPaddingEnabled = state.inClauseParameterPaddingEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -585,4 +588,9 @@ public class SessionFactoryOptionsImpl implements SessionFactoryOptions {
|
|||
public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
|
||||
return immutableEntityUpdateQueryHandlingMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inClauseParameterPaddingEnabled() {
|
||||
return inClauseParameterPaddingEnabled;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,4 +216,8 @@ public interface SessionFactoryOptionsState {
|
|||
default ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
|
||||
return ImmutableEntityUpdateQueryHandlingMode.WARNING;
|
||||
}
|
||||
|
||||
default boolean inClauseParameterPaddingEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -411,4 +411,9 @@ public class AbstractDelegatingSessionFactoryOptions implements SessionFactoryOp
|
|||
public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
|
||||
return delegate.getImmutableEntityUpdateQueryHandlingMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean inClauseParameterPaddingEnabled() {
|
||||
return delegate.inClauseParameterPaddingEnabled();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -261,4 +261,8 @@ public interface SessionFactoryOptions {
|
|||
default ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandlingMode() {
|
||||
return ImmutableEntityUpdateQueryHandlingMode.WARNING;
|
||||
}
|
||||
|
||||
default boolean inClauseParameterPaddingEnabled() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1779,4 +1779,22 @@ public interface AvailableSettings {
|
|||
* @see org.hibernate.query.ImmutableEntityUpdateQueryHandlingMode
|
||||
*/
|
||||
String IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE = "hibernate.query.immutable_entity_update_query_handling_mode";
|
||||
|
||||
/**
|
||||
* By default, the IN clause expands to include all bind parameter values.
|
||||
* </p>
|
||||
* However, for database systems supporting execution plan caching,
|
||||
* there's a better chance of hitting the cache if the number of possible IN clause parameters lowers.
|
||||
* </p>
|
||||
* For this reason, we can expand the bind parameters to power-of-two: 4, 8, 16, 32, 64.
|
||||
* This way, an IN clause with 5, 6, or 7 bind parameters will use the 8 IN clause,
|
||||
* therefore reusing its execution plan.
|
||||
* </p>
|
||||
* If you want to activate this feature, you need to set this property to {@code true}.
|
||||
* </p>
|
||||
* The default value is {@code false}.
|
||||
*
|
||||
* @since 5.2.17
|
||||
*/
|
||||
String IN_CLAUSE_PARAMETER_PADDING = "hibernate.query.in_clause_parameter_padding";
|
||||
}
|
||||
|
|
|
@ -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.internal.util;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public final class MathHelper {
|
||||
|
||||
private MathHelper() { /* static methods only - hide constructor */
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the smallest power of two number that is greater than or equal to {@code value}.
|
||||
*
|
||||
* @param value reference number
|
||||
* @return smallest power of two number
|
||||
*/
|
||||
public static int ceilingPowerOfTwo(int value) {
|
||||
return 1 << -Integer.numberOfLeadingZeros(value - 1);
|
||||
}
|
||||
}
|
|
@ -28,6 +28,7 @@ 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.MathHelper;
|
||||
import org.hibernate.internal.util.StringHelper;
|
||||
import org.hibernate.query.ParameterMetadata;
|
||||
import org.hibernate.query.QueryParameter;
|
||||
|
@ -548,8 +549,23 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
final NamedParameterDescriptor sourceParam = (NamedParameterDescriptor) entry.getKey();
|
||||
final Collection bindValues = entry.getValue().getBindValues();
|
||||
|
||||
if ( inExprLimit > 0 && bindValues.size() > inExprLimit ) {
|
||||
log.tooManyInExpressions( dialect.getClass().getName(), inExprLimit, sourceParam.getName(), bindValues.size() );
|
||||
int bindValueCount = bindValues.size();
|
||||
int bindValueMaxCount = bindValueCount;
|
||||
|
||||
boolean inClauseParameterPaddingEnabled =
|
||||
session.getFactory().getSessionFactoryOptions().inClauseParameterPaddingEnabled() &&
|
||||
bindValueCount > 2;
|
||||
|
||||
if ( inClauseParameterPaddingEnabled ) {
|
||||
int bindValuePaddingCount = MathHelper.ceilingPowerOfTwo( bindValueCount );
|
||||
|
||||
if ( bindValueCount < bindValuePaddingCount && (inExprLimit == 0 || bindValuePaddingCount < inExprLimit) ) {
|
||||
bindValueMaxCount = bindValuePaddingCount;
|
||||
}
|
||||
}
|
||||
|
||||
if ( inExprLimit > 0 && bindValueCount > inExprLimit ) {
|
||||
log.tooManyInExpressions( dialect.getClass().getName(), inExprLimit, sourceParam.getName(), bindValueCount );
|
||||
}
|
||||
|
||||
final boolean isJpaPositionalParam = sourceParam.isJpaPositionalParameter();
|
||||
|
@ -581,8 +597,15 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
|
||||
StringBuilder expansionList = new StringBuilder();
|
||||
|
||||
int i = 0;
|
||||
for ( Object bindValue : entry.getValue().getBindValues() ) {
|
||||
Iterator bindValueIterator = entry.getValue().getBindValues().iterator();
|
||||
Object bindValue = null;
|
||||
|
||||
for ( int i = 0; i < bindValueMaxCount; i++ ) {
|
||||
|
||||
if ( i < bindValueCount ) {
|
||||
bindValue = bindValueIterator.next();
|
||||
}
|
||||
|
||||
// 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
|
||||
|
@ -601,7 +624,6 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings {
|
|||
final QueryParameterBinding syntheticBinding = makeBinding( entry.getValue().getBindType() );
|
||||
syntheticBinding.setBindValue( bindValue );
|
||||
parameterBindingMap.put( syntheticParam, syntheticBinding );
|
||||
i++;
|
||||
}
|
||||
|
||||
queryString = StringHelper.replace(
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
/*
|
||||
* 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.internal.util;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.junit.Assert.*;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class MathHelperTest {
|
||||
|
||||
@Test
|
||||
public void ceilingPowerOfTwo() {
|
||||
assertEquals( 1, MathHelper.ceilingPowerOfTwo( 1 ) );
|
||||
assertEquals( 2, MathHelper.ceilingPowerOfTwo( 2 ) );
|
||||
assertEquals( 4, MathHelper.ceilingPowerOfTwo( 3 ) );
|
||||
assertEquals( 4, MathHelper.ceilingPowerOfTwo( 4 ) );
|
||||
assertEquals( 8, MathHelper.ceilingPowerOfTwo( 5 ) );
|
||||
assertEquals( 8, MathHelper.ceilingPowerOfTwo( 6 ) );
|
||||
assertEquals( 8, MathHelper.ceilingPowerOfTwo( 7 ) );
|
||||
assertEquals( 8, MathHelper.ceilingPowerOfTwo( 8 ) );
|
||||
assertEquals( 16, MathHelper.ceilingPowerOfTwo( 9 ) );
|
||||
assertEquals( 16, MathHelper.ceilingPowerOfTwo( 10 ) );
|
||||
assertEquals( 16, MathHelper.ceilingPowerOfTwo( 11 ) );
|
||||
assertEquals( 16, MathHelper.ceilingPowerOfTwo( 12 ) );
|
||||
assertEquals( 16, MathHelper.ceilingPowerOfTwo( 13 ) );
|
||||
assertEquals( 16, MathHelper.ceilingPowerOfTwo( 16 ) );
|
||||
assertEquals( 16, MathHelper.ceilingPowerOfTwo( 14 ) );
|
||||
assertEquals( 16, MathHelper.ceilingPowerOfTwo( 15 ) );
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,129 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Map;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-12469" )
|
||||
public class InClauseParameterPaddingTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider;
|
||||
|
||||
@Override
|
||||
public void buildEntityManagerFactory() {
|
||||
connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
super.buildEntityManagerFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
options.put( AvailableSettings.IN_CLAUSE_PARAMETER_PADDING, Boolean.TRUE.toString() );
|
||||
options.put(
|
||||
org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterEntityManagerFactoryBuilt() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
for ( int i = 1; i < 10; i++ ) {
|
||||
Person person = new Person();
|
||||
person.setId( i );
|
||||
person.setName( String.format( "Person nr %d", i ) );
|
||||
|
||||
entityManager.persist( person );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInClauseParameterPadding() {
|
||||
validateInClauseParameterPadding( "in (?)", 1 );
|
||||
validateInClauseParameterPadding( "in (? , ?)", 1, 2 );
|
||||
validateInClauseParameterPadding( "in (? , ? , ? , ?)", 1, 2, 3 );
|
||||
validateInClauseParameterPadding( "in (? , ? , ? , ?)", 1, 2, 3, 4 );
|
||||
validateInClauseParameterPadding( "in (? , ? , ? , ? , ? , ? , ? , ?)", 1, 2, 3, 4, 5 );
|
||||
validateInClauseParameterPadding( "in (? , ? , ? , ? , ? , ? , ? , ?)", 1, 2, 3, 4, 5, 6 );
|
||||
validateInClauseParameterPadding( "in (? , ? , ? , ? , ? , ? , ? , ?)", 1, 2, 3, 4, 5, 6, 7 );
|
||||
validateInClauseParameterPadding( "in (? , ? , ? , ? , ? , ? , ? , ?)", 1, 2, 3, 4, 5, 6, 7, 8 );
|
||||
validateInClauseParameterPadding( "in (? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ?)", 1, 2, 3, 4, 5, 6, 7, 8, 9 );
|
||||
validateInClauseParameterPadding( "in (? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ? , ?)", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 );
|
||||
}
|
||||
|
||||
private void validateInClauseParameterPadding(String expectedInClause, Integer... ids) {
|
||||
connectionProvider.clear();
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
return entityManager.createQuery(
|
||||
"select p " +
|
||||
"from Person p " +
|
||||
"where p.id in :ids" )
|
||||
.setParameter( "ids", Arrays.asList(ids) )
|
||||
.getResultList();
|
||||
} );
|
||||
|
||||
assertTrue(connectionProvider.getPreparedSQLStatements().get( 0 ).endsWith( expectedInClause ));
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,140 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.IntStream;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.cfg.AvailableSettings;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
import org.hibernate.dialect.H2Dialect;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.hibernate.testing.RequiresDialect;
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider;
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.testing.transaction.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
@TestForIssue( jiraKey = "HHH-12469" )
|
||||
@RequiresDialect(H2Dialect.class)
|
||||
public class MaxInExpressionParameterPaddingTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private PreparedStatementSpyConnectionProvider connectionProvider;
|
||||
|
||||
public static final int MAX_COUNT = 15;
|
||||
|
||||
@Override
|
||||
public void buildEntityManagerFactory() {
|
||||
connectionProvider = new PreparedStatementSpyConnectionProvider();
|
||||
super.buildEntityManagerFactory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void releaseResources() {
|
||||
super.releaseResources();
|
||||
connectionProvider.stop();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class[] getAnnotatedClasses() {
|
||||
return new Class[] {
|
||||
Person.class
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addConfigOptions(Map options) {
|
||||
options.put( AvailableSettings.IN_CLAUSE_PARAMETER_PADDING, Boolean.TRUE.toString() );
|
||||
options.put(
|
||||
AvailableSettings.CONNECTION_PROVIDER,
|
||||
connectionProvider
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialect getDialect() {
|
||||
return new MaxCountInExpressionH2Dialect();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void afterEntityManagerFactoryBuilt() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
for ( int i = 0; i < MAX_COUNT; i++ ) {
|
||||
Person person = new Person();
|
||||
person.setId( i );
|
||||
person.setName( String.format( "Person nr %d", i ) );
|
||||
|
||||
entityManager.persist( person );
|
||||
}
|
||||
} );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInClauseParameterPadding() {
|
||||
connectionProvider.clear();
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
return entityManager.createQuery(
|
||||
"select p " +
|
||||
"from Person p " +
|
||||
"where p.id in :ids" )
|
||||
.setParameter( "ids", IntStream.range( 0, MAX_COUNT ).boxed().collect(Collectors.toList()) )
|
||||
.getResultList();
|
||||
} );
|
||||
|
||||
StringBuilder expectedInClause = new StringBuilder();
|
||||
expectedInClause.append( "in (?" );
|
||||
for ( int i = 1; i < MAX_COUNT; i++ ) {
|
||||
expectedInClause.append( " , ?" );
|
||||
}
|
||||
expectedInClause.append( ")" );
|
||||
|
||||
assertTrue(connectionProvider.getPreparedSQLStatements().get( 0 ).endsWith( expectedInClause.toString() ));
|
||||
}
|
||||
|
||||
@Entity(name = "Person")
|
||||
public static class Person {
|
||||
|
||||
@Id
|
||||
private Integer id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MaxCountInExpressionH2Dialect extends H2Dialect {
|
||||
@Override
|
||||
public int getInExpressionCountLimit() {
|
||||
return MAX_COUNT;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue