HHH-16589 In clause padding can no longer cause in clauses to exceed Dialect.getInExpressionCountLimit

This commit is contained in:
Adrodoc 2023-05-11 19:24:06 +02:00 committed by Christian Beikov
parent fd661534d7
commit d4481989b1
1 changed files with 122 additions and 80 deletions

View File

@ -6,6 +6,7 @@
*/ */
package org.hibernate.orm.test.query; package org.hibernate.orm.test.query;
import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.IntStream; import java.util.stream.IntStream;
@ -25,6 +26,8 @@ import org.junit.jupiter.api.Test;
import jakarta.persistence.Entity; import jakarta.persistence.Entity;
import jakarta.persistence.Id; import jakarta.persistence.Id;
import static java.util.stream.Collectors.toList;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
/** /**
@ -39,7 +42,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
@Setting(name = AvailableSettings.IN_CLAUSE_PARAMETER_PADDING, value = "true"), @Setting(name = AvailableSettings.IN_CLAUSE_PARAMETER_PADDING, value = "true"),
@Setting(name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false"), @Setting(name = AvailableSettings.DIALECT_NATIVE_PARAM_MARKERS, value = "false"),
}, },
settingProviders ={ settingProviders = {
@SettingProvider( @SettingProvider(
settingName = AvailableSettings.DIALECT, settingName = AvailableSettings.DIALECT,
provider = MaxInExpressionParameterPaddingTest.DialectProvider.class provider = MaxInExpressionParameterPaddingTest.DialectProvider.class
@ -76,20 +79,33 @@ public class MaxInExpressionParameterPaddingTest {
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
statementInspector.clear(); statementInspector.clear();
scope.inTransaction( entityManager -> scope.inTransaction( entityManager -> entityManager
entityManager.createQuery( "select p from Person p where p.id in :ids" ) .createQuery( "select p from Person p where p.id in :ids" )
.setParameter( "ids", IntStream.range( 0, MAX_COUNT ).boxed().collect( Collectors.toList() ) ) .setParameter( "ids", integerRangeList( 0, 5 ) )
.getResultList() .getResultList() );
);
StringBuilder expectedInClause = new StringBuilder(); StringBuilder expectedInClause = new StringBuilder();
expectedInClause.append( "in (?" ); expectedInClause.append( "where p1_0.id in " );
for ( int i = 1; i < MAX_COUNT; i++ ) { appendInClause( expectedInClause, 8 );
expectedInClause.append( ",?" );
}
expectedInClause.append( ")" );
assertTrue( statementInspector.getSqlQueries().get( 0 ).endsWith( expectedInClause.toString() ) ); assertThat( statementInspector.getSqlQueries().get( 0 ) ).endsWith( expectedInClause.toString() );
}
@Test
public void testInClauseParameterNoPaddingAtLimit(EntityManagerFactoryScope scope) {
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
statementInspector.clear();
scope.inTransaction( entityManager -> entityManager
.createQuery( "select p from Person p where p.id in :ids" )
.setParameter( "ids", integerRangeList( 0, MAX_COUNT ) )
.getResultList() );
StringBuilder expectedInClause = new StringBuilder();
expectedInClause.append( "where p1_0.id in " );
appendInClause( expectedInClause, MAX_COUNT );
assertThat( statementInspector.getSqlQueries().get( 0 ) ).endsWith( expectedInClause.toString() );
} }
@TestForIssue(jiraKey = "HHH-14109") @TestForIssue(jiraKey = "HHH-14109")
@ -98,24 +114,16 @@ public class MaxInExpressionParameterPaddingTest {
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
statementInspector.clear(); statementInspector.clear();
scope.inTransaction( scope.inTransaction( entityManager -> entityManager
entityManager -> .createQuery( "select p from Person p where p.id in :ids" )
entityManager.createQuery( .setParameter( "ids", integerRangeList( 0, 10 ) )
"select p from Person p where p.id in :ids" ) .getResultList() );
.setParameter( "ids", IntStream.range( 0, 10 )
.boxed()
.collect( Collectors.toList() ) )
.getResultList()
);
StringBuilder expectedInClause = new StringBuilder(); StringBuilder expectedInClause = new StringBuilder();
expectedInClause.append( "in (?" ); expectedInClause.append( "where p1_0.id in " );
for ( int i = 1; i < MAX_COUNT; i++ ) { appendInClause( expectedInClause, MAX_COUNT );
expectedInClause.append( ",?" );
}
expectedInClause.append( ")" );
assertTrue( statementInspector.getSqlQueries().get( 0 ).endsWith( expectedInClause.toString() ) ); assertThat( statementInspector.getSqlQueries().get( 0 ) ).endsWith( expectedInClause.toString() );
} }
@Test @Test
@ -123,25 +131,38 @@ public class MaxInExpressionParameterPaddingTest {
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
statementInspector.clear(); statementInspector.clear();
scope.inTransaction( scope.inTransaction( entityManager -> entityManager
entityManager -> .createQuery( "select p from Person p where p.id in :ids" )
entityManager.createQuery( .setParameter( "ids", integerRangeList( 0, 16 ) )
"select p from Person p where p.id in :ids" ) .getResultList() );
.setParameter( "ids", IntStream.range( 0, 16 )
.boxed()
.collect( Collectors.toList() ) )
.getResultList()
);
StringBuilder expectedInClause = new StringBuilder(); StringBuilder expectedInClause = new StringBuilder();
expectedInClause.append( "in (?" ); expectedInClause.append( "where (p1_0.id in " );
for ( int i = 1; i < MAX_COUNT; i++ ) { appendInClause( expectedInClause, MAX_COUNT );
expectedInClause.append( ",?" ); expectedInClause.append( " or p1_0.id in " );
} appendInClause( expectedInClause, 1 );
expectedInClause.append( ")" ); expectedInClause.append( ')' );
expectedInClause.append( " or p1_0.id in (?)" );
assertTrue( statementInspector.getSqlQueries().get( 0 ).endsWith( expectedInClause.toString() ) ); assertThat( statementInspector.getSqlQueries().get( 0 ) ).endsWith( expectedInClause.toString() );
}
@Test
public void testInClauseParameterSplittingAfterLimitNotIn(EntityManagerFactoryScope scope) {
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
statementInspector.clear();
scope.inTransaction( entityManager -> entityManager
.createQuery( "select p from Person p where p.id not in :ids" )
.setParameter( "ids", integerRangeList( 0, 16 ) )
.getResultList() );
StringBuilder expectedInClause = new StringBuilder();
expectedInClause.append( "where p1_0.id not in " );
appendInClause( expectedInClause, MAX_COUNT );
expectedInClause.append( " and p1_0.id not in " );
appendInClause( expectedInClause, 1 );
assertThat( statementInspector.getSqlQueries().get( 0 ) ).endsWith( expectedInClause.toString() );
} }
@Test @Test
@ -149,25 +170,19 @@ public class MaxInExpressionParameterPaddingTest {
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
statementInspector.clear(); statementInspector.clear();
scope.inTransaction( scope.inTransaction( entityManager -> entityManager
entityManager -> .createQuery( "select p from Person p where p.id in :ids" )
entityManager.createQuery( .setParameter( "ids", integerRangeList( 0, 18 ) )
"select p from Person p where p.id in :ids" ) .getResultList() );
.setParameter( "ids", IntStream.range( 0, 18 )
.boxed()
.collect( Collectors.toList() ) )
.getResultList()
);
StringBuilder expectedInClause = new StringBuilder(); StringBuilder expectedInClause = new StringBuilder();
expectedInClause.append( "in (?" ); expectedInClause.append( "where (p1_0.id in " );
for ( int i = 1; i < MAX_COUNT; i++ ) { appendInClause( expectedInClause, MAX_COUNT );
expectedInClause.append( ",?" ); expectedInClause.append( " or p1_0.id in " );
} appendInClause( expectedInClause, 4 );
expectedInClause.append( ")" ); expectedInClause.append( ')' );
expectedInClause.append( " or p1_0.id in (?,?,?,?)" );
assertTrue( statementInspector.getSqlQueries().get( 0 ).endsWith( expectedInClause.toString() ) ); assertThat( statementInspector.getSqlQueries().get( 0 ) ).endsWith( expectedInClause.toString() );
} }
@Test @Test
@ -175,31 +190,58 @@ public class MaxInExpressionParameterPaddingTest {
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector(); final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
statementInspector.clear(); statementInspector.clear();
scope.inTransaction( scope.inTransaction( entityManager -> entityManager
entityManager -> .createQuery( "select p from Person p where p.id in :ids" )
entityManager.createQuery( .setParameter( "ids", integerRangeList( 0, 33 ) )
"select p from Person p where p.id in :ids" ) .getResultList() );
.setParameter( "ids", IntStream.range( 0, 33 )
.boxed()
.collect( Collectors.toList() ) )
.getResultList()
);
StringBuilder expectedInClause = new StringBuilder(); StringBuilder expectedInClause = new StringBuilder();
expectedInClause.append( "in (?" ); expectedInClause.append( "where (p1_0.id in " );
for ( int i = 1; i < MAX_COUNT; i++ ) { appendInClause( expectedInClause, MAX_COUNT );
expectedInClause.append( ",?" ); expectedInClause.append( " or p1_0.id in " );
} appendInClause( expectedInClause, MAX_COUNT );
expectedInClause.append( ")" ); expectedInClause.append( " or p1_0.id in " );
expectedInClause.append( " or p1_0.id in (?"); appendInClause( expectedInClause, 4 );
for ( int i = 1; i < MAX_COUNT; i++ ) { expectedInClause.append( ')' );
expectedInClause.append( ",?" );
}
expectedInClause.append( ")" );
expectedInClause.append( " or p1_0.id in (?,?,?,?)" );
assertThat( statementInspector.getSqlQueries().get( 0 ) ).endsWith( expectedInClause.toString() );
}
assertTrue( statementInspector.getSqlQueries().get( 0 ).endsWith( expectedInClause.toString() ) ); @TestForIssue(jiraKey = "HHH-16589")
@Test
public void testInClauseParameterSplittingAfterLimit4(EntityManagerFactoryScope scope) {
final SQLStatementInspector statementInspector = scope.getCollectingStatementInspector();
statementInspector.clear();
scope.inTransaction( entityManager -> entityManager
.createQuery( "select p from Person p where p.id in :ids" )
.setParameter( "ids", integerRangeList( 0, 39 ) )
.getResultList() );
StringBuilder expectedInClause = new StringBuilder();
expectedInClause.append( "where (p1_0.id in " );
appendInClause( expectedInClause, MAX_COUNT );
expectedInClause.append( " or p1_0.id in " );
appendInClause( expectedInClause, MAX_COUNT );
expectedInClause.append( " or p1_0.id in " );
appendInClause( expectedInClause, MAX_COUNT );
expectedInClause.append( ')' );
assertThat( statementInspector.getSqlQueries().get( 0 ) ).endsWith( expectedInClause.toString() );
}
private static List<Integer> integerRangeList(int start, int end) {
return IntStream.range( start, end )
.boxed()
.collect( Collectors.toList() );
}
private void appendInClause(StringBuilder sql, int inClauseSize) {
sql.append( "(?" );
for ( int i = 1; i < inClauseSize; i++ ) {
sql.append( ",?" );
}
sql.append( ')' );
} }
@Entity(name = "Person") @Entity(name = "Person")