[JIRA] (HHH-16589) In-Clause Parameter Padding mistreats Dilect.getInExpressionCountLimit which can cause ORA-01795: maximum number of expressions in a list is 1000
by Adrodoc (JIRA)
Adrodoc ( https://hibernate.atlassian.net/secure/ViewProfile.jspa?accountId=5b2a4a0... ) *commented* on HHH-16589 ( https://hibernate.atlassian.net/browse/HHH-16589?atlOrigin=eyJpIjoiYmQ1Yj... )
Re: In-Clause Parameter Padding mistreats Dilect.getInExpressionCountLimit which can cause ORA-01795: maximum number of expressions in a list is 1000 ( https://hibernate.atlassian.net/browse/HHH-16589?atlOrigin=eyJpIjoiYmQ1Yj... )
I analyzed the code further. It took me a while to figure out exactly what it was trying to do. From my understanding bindValueMaxCount is supposed to be the number of bind variables that should be used in the last IN-Clause. Here is a small program that fixes the calculation of bindValueMaxCount and compares it to the current hibernate implementation. The fix not only makes it so that inExprList is properly respected, but also fixes the calculation for values greater that 1073741824 (probably not that important, but the current implementation fails horribly for such large numbers) and personally I find it much easier to understand:
package de.sanacorp.security.persistence.base.inclause;
import java.util.function.IntBinaryOperator;
import org.hibernate.internal.util.MathHelper;
public class HHH_16589 {
public static void main( String [] args) {
System.out.println( "| bindValueCount | inExprLimit | originalResult | proposalResult |" );
System.out.println( "|----------------|-------------|----------------|----------------|" );
IntBinaryOperator original = HHH_16589::hibernate_6_2_2_Final;
IntBinaryOperator proposal = HHH_16589::calculateLastInClauseSize;
compare(1, 0, original, proposal);
compare(2, 0, original, proposal);
compare(3, 0, original, proposal);
compare(4, 0, original, proposal);
compare(5, 0, original, proposal);
compare(1000, 0, original, proposal);
compare((1 << 30) - 1, 0, original, proposal);
compare(1 << 30, 0, original, proposal);
compare((1 << 30) + 1, 0, original, proposal);
compare( Integer.MAX_VALUE - 1, 0, original, proposal);
compare( Integer.MAX_VALUE, 0, original, proposal);
compare(1, 1000, original, proposal);
compare(7, 1000, original, proposal);
compare(8, 1000, original, proposal);
compare(511, 1000, original, proposal);
compare(512, 1000, original, proposal);
compare(513, 1000, original, proposal);
compare(999, 1000, original, proposal);
compare(1000, 1000, original, proposal);
compare(1001, 1000, original, proposal);
compare(1008, 1000, original, proposal);
compare(1023, 1000, original, proposal);
compare(1024, 1000, original, proposal);
compare(1025, 1000, original, proposal);
compare(1511, 1000, original, proposal);
compare(1512, 1000, original, proposal);
compare(1513, 1000, original, proposal);
compare(1999, 1000, original, proposal);
compare(2000, 1000, original, proposal);
compare(2001, 1000, original, proposal);
compare(2511, 1000, original, proposal);
compare(2512, 1000, original, proposal);
compare(2513, 1000, original, proposal);
compare(2999, 1000, original, proposal);
compare(3000, 1000, original, proposal);
compare(3001, 1000, original, proposal);
compare( Integer.MAX_VALUE - 1, 1000, original, proposal);
compare( Integer.MAX_VALUE, 1000, original, proposal);
}
public static void compare( int bindValueCount, int inExprLimit, IntBinaryOperator original,
IntBinaryOperator proposal) {
int originalResult = original.applyAsInt(bindValueCount, inExprLimit);
int proposalResult = proposal.applyAsInt(bindValueCount, inExprLimit);
System.out
.println( "| " + bindValueCount + " | " + inExprLimit + " | " + originalResult + " | " + proposalResult + " |" );
}
private static int hibernate_6_2_2_Final( int bindValueCount, int inExprLimit) {
int bindValueMaxCount = bindValueCount;
// bindValueCount: 1005
// bindValuePaddingCount: 1024
int bindValuePaddingCount = MathHelper.ceilingPowerOfTwo(bindValueCount);
// inExprLimit: 1000
if (inExprLimit > 0) {
if (bindValuePaddingCount > inExprLimit) {
// bindValueCount % inExprLimit: 5
// bindValuePaddingCount: 8
if (bindValueCount < inExprLimit) {
bindValueMaxCount = inExprLimit;
} else {
bindValueMaxCount = MathHelper.ceilingPowerOfTwo(bindValueCount % inExprLimit);
}
} else if (bindValueCount < bindValuePaddingCount) {
bindValueMaxCount = bindValuePaddingCount;
}
} else if (bindValueCount < bindValuePaddingCount) {
bindValueMaxCount = bindValuePaddingCount;
}
return bindValueMaxCount;
}
private static int calculateLastInClauseSize( int bindValueCount, int inExprLimit) {
if (inExprLimit > 0) {
int lastInClauseSize = bindValueCount % inExprLimit;
int lastInClauseSizeWithPadding = ceilingPowerOfTwoFixed(lastInClauseSize);
return Math.min(inExprLimit, lastInClauseSizeWithPadding);
} else {
return ceilingPowerOfTwoFixed(bindValueCount);
}
}
// This should probably be done in MathHelper already.
// If values above 1073741824 (2^30) are not of a concern we could just use MathHelper directly.
private static int ceilingPowerOfTwoFixed( int value) {
int result = MathHelper.ceilingPowerOfTwo(value);
if (result < value) { // Overflow
return Integer.MAX_VALUE;
}
return result;
}
}
When executed the Program prints this Table (as Markdown):
bindValueCount inExprLimit originalResult proposalResult 1 0 1 1 2 0 2 2 3 0 4 4 4 0 4 4 5 0 8 8 1000 0 1024 1024 1073741823 0 1073741824 1073741824 1073741824 0 1073741824 1073741824 1073741825 0 1073741825 2147483647 2147483646 0 2147483646 2147483647 2147483647 0 2147483647 2147483647 1 1000 1 1 7 1000 8 8 8 1000 8 8 511 1000 512 512 512 1000 512 512 513 1000 1000 1000 999 1000 1000 1000 1000 1000 1 1 1001 1000 1 1 1008 1000 8 8 1023 1000 32 32 1024 1000 32 32 1025 1000 32 32 1511 1000 512 512 1512 1000 512 512 1513 1000 1024 1000 1999 1000 1024 1000 2000 1000 1 1 2001 1000 1 1 2511 1000 512 512 2512 1000 512 512 2513 1000 1024 1000 2999 1000 1024 1000 3000 1000 1 1 3001 1000 1 1 2147483646 1000 2147483646 1000 2147483647 1000 2147483647 1000
( https://hibernate.atlassian.net/browse/HHH-16589#add-comment?atlOrigin=ey... ) Add Comment ( https://hibernate.atlassian.net/browse/HHH-16589#add-comment?atlOrigin=ey... )
Get Jira notifications on your phone! Download the Jira Cloud app for Android ( https://play.google.com/store/apps/details?id=com.atlassian.android.jira.... ) or iOS ( https://itunes.apple.com/app/apple-store/id1006972087?pt=696495&ct=EmailN... ) This message was sent by Atlassian Jira (v1001.0.0-SNAPSHOT#100225- sha1:84d3b45 )
2 years, 11 months