Skip to content

Commit 25a23fd

Browse files
committed
HHH-16441 - Improve support for @batchsize
HHH-16466 - ARRAY parameter support for multi-key loads HHH-16509 - Split parameter limit and IN element limit
1 parent e94d030 commit 25a23fd

File tree

92 files changed

+3908
-1006
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

92 files changed

+3908
-1006
lines changed

README.adoc

+16
Original file line numberDiff line numberDiff line change
@@ -204,3 +204,19 @@ The following table illustrates a list of commands for various databases that ca
204204
|`./docker_db.sh cockroachdb`
205205
|`./gradlew test -Pdb=cockroachdb`
206206
|===
207+
208+
To stop a container started by `docker`, use the command
209+
210+
[source]
211+
----
212+
docker stop $container_name
213+
----
214+
215+
NOTE:: Substitute `podman` command for `docker` if using `podman`
216+
217+
E.g., to stop the mariadb container
218+
219+
[source]
220+
----
221+
docker stop mariadb
222+
----

hibernate-core/src/main/java/org/hibernate/dialect/DerbyDialect.java

+8
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,14 @@ public boolean supportsUnboundedLobLocatorMaterialization() {
628628
return false;
629629
}
630630

631+
@Override
632+
public int getInExpressionCountLimit() {
633+
// Derby does not have a limit on the number of expressions/parameters per-se (it may, I just
634+
// don't know). It does, however, have a limit on the size of the SQL text it will accept as a
635+
// PreparedStatement; so let's limit this to a sensible value to avoid that.
636+
return 512;
637+
}
638+
631639
@Override
632640
public SQLExceptionConversionDelegate buildSQLExceptionConversionDelegate() {
633641
return (sqlException, message, sql) -> {

hibernate-core/src/main/java/org/hibernate/dialect/Dialect.java

+48-33
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@
108108
import org.hibernate.internal.util.StringHelper;
109109
import org.hibernate.internal.util.collections.ArrayHelper;
110110
import org.hibernate.internal.util.io.StreamCopier;
111-
import org.hibernate.loader.BatchLoadSizingStrategy;
111+
import org.hibernate.loader.ast.spi.MultiKeyLoadSizingStrategy;
112112
import org.hibernate.mapping.Column;
113113
import org.hibernate.mapping.Constraint;
114114
import org.hibernate.mapping.ForeignKey;
@@ -177,16 +177,16 @@
177177
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
178178
import org.hibernate.type.descriptor.jdbc.BlobJdbcType;
179179
import org.hibernate.type.descriptor.jdbc.ClobJdbcType;
180-
import org.hibernate.type.descriptor.jdbc.TimeUtcAsOffsetTimeJdbcType;
181-
import org.hibernate.type.descriptor.jdbc.TimestampUtcAsJdbcTimestampJdbcType;
182-
import org.hibernate.type.descriptor.jdbc.TimestampUtcAsOffsetDateTimeJdbcType;
183180
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
184181
import org.hibernate.type.descriptor.jdbc.JdbcType;
185182
import org.hibernate.type.descriptor.jdbc.LongNVarcharJdbcType;
186183
import org.hibernate.type.descriptor.jdbc.NCharJdbcType;
187184
import org.hibernate.type.descriptor.jdbc.NClobJdbcType;
188185
import org.hibernate.type.descriptor.jdbc.NVarcharJdbcType;
189186
import org.hibernate.type.descriptor.jdbc.TimeUtcAsJdbcTimeJdbcType;
187+
import org.hibernate.type.descriptor.jdbc.TimeUtcAsOffsetTimeJdbcType;
188+
import org.hibernate.type.descriptor.jdbc.TimestampUtcAsJdbcTimestampJdbcType;
189+
import org.hibernate.type.descriptor.jdbc.TimestampUtcAsOffsetDateTimeJdbcType;
190190
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
191191
import org.hibernate.type.descriptor.sql.internal.CapacityDependentDdlType;
192192
import org.hibernate.type.descriptor.sql.internal.DdlTypeImpl;
@@ -3774,6 +3774,18 @@ public int getInExpressionCountLimit() {
37743774
return 0;
37753775
}
37763776

3777+
/**
3778+
* Return the limit that the underlying database places on the number of parameters
3779+
* that can be defined for a PreparedStatement. If the database defines no such
3780+
* limits, simply return zero or a number smaller than zero. By default, Dialect
3781+
* returns the same value as {@link #getInExpressionCountLimit()}.
3782+
*
3783+
* @return The limit, or a non-positive integer to indicate no limit.
3784+
*/
3785+
public int getParameterCountLimit() {
3786+
return getInExpressionCountLimit();
3787+
}
3788+
37773789
/**
37783790
* Must LOB values occur last in inserts and updates?
37793791
*
@@ -4008,40 +4020,43 @@ public NameQualifierSupport getNameQualifierSupport() {
40084020
return null;
40094021
}
40104022

4011-
protected final BatchLoadSizingStrategy STANDARD_DEFAULT_BATCH_LOAD_SIZING_STRATEGY =
4012-
(numberOfKeyColumns, numberOfKeys, inClauseParameterPaddingEnabled) -> {
4013-
final int paddedSize;
4023+
/**
4024+
* The strategy used to determine the appropriate number of keys
4025+
* to load in a single SQL query with multi-key loading.
4026+
* @see org.hibernate.Session#byMultipleIds
4027+
* @see org.hibernate.Session#byMultipleNaturalId
4028+
*/
4029+
public MultiKeyLoadSizingStrategy getMultiKeyLoadSizingStrategy() {
4030+
return STANDARD_MULTI_KEY_LOAD_SIZING_STRATEGY;
4031+
}
40144032

4015-
if ( inClauseParameterPaddingEnabled ) {
4016-
paddedSize = MathHelper.ceilingPowerOfTwo( numberOfKeys );
4017-
}
4018-
else {
4019-
paddedSize = numberOfKeys;
4020-
}
4033+
/**
4034+
* The strategy used to determine the appropriate number of keys
4035+
* to load in a single SQL query with batch-fetch loading.
4036+
*
4037+
* @implNote By default, the same as {@linkplain #getMultiKeyLoadSizingStrategy}
4038+
*
4039+
* @see org.hibernate.annotations.BatchSize
4040+
*/
4041+
public MultiKeyLoadSizingStrategy getBatchLoadSizingStrategy() {
4042+
return getMultiKeyLoadSizingStrategy();
4043+
}
40214044

4022-
// For tuples, there is no limit, so we can just use the power of two padding approach
4023-
if ( numberOfKeyColumns > 1 ) {
4024-
return paddedSize;
4025-
}
4026-
final int inExpressionCountLimit = getInExpressionCountLimit();
4027-
if ( inExpressionCountLimit > 0 ) {
4028-
if ( paddedSize < inExpressionCountLimit ) {
4029-
return paddedSize;
4030-
}
4031-
else if ( numberOfKeys < inExpressionCountLimit ) {
4032-
return numberOfKeys;
4045+
protected final MultiKeyLoadSizingStrategy STANDARD_MULTI_KEY_LOAD_SIZING_STRATEGY = (numberOfColumns, numberOfKeys, pad) -> {
4046+
numberOfKeys = pad ? MathHelper.ceilingPowerOfTwo( numberOfKeys ) : numberOfKeys;
4047+
4048+
final long parameterCount = (long) numberOfColumns * numberOfKeys;
4049+
final int limit = getParameterCountLimit();
4050+
4051+
if ( limit > 0 ) {
4052+
// the Dialect reported a limit - see if the parameter count exceeds the limit
4053+
if ( parameterCount >= limit ) {
4054+
return limit / numberOfColumns;
40334055
}
4034-
return getInExpressionCountLimit();
40354056
}
4036-
return paddedSize;
4037-
};
40384057

4039-
/**
4040-
* The strategy to use for determining batch sizes in batch loading.
4041-
*/
4042-
public BatchLoadSizingStrategy getDefaultBatchLoadSizingStrategy() {
4043-
return STANDARD_DEFAULT_BATCH_LOAD_SIZING_STRATEGY;
4044-
}
4058+
return numberOfKeys;
4059+
};
40454060

40464061
/**
40474062
* Is JDBC statement warning logging enabled by default?

hibernate-core/src/main/java/org/hibernate/dialect/DialectDelegateWrapper.java

+13-4
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747
import org.hibernate.engine.spi.SessionFactoryImplementor;
4848
import org.hibernate.exception.spi.SQLExceptionConversionDelegate;
4949
import org.hibernate.exception.spi.ViolatedConstraintNameExtractor;
50-
import org.hibernate.loader.BatchLoadSizingStrategy;
50+
import org.hibernate.loader.ast.spi.MultiKeyLoadSizingStrategy;
5151
import org.hibernate.mapping.Column;
5252
import org.hibernate.mapping.Constraint;
5353
import org.hibernate.mapping.ForeignKey;
@@ -90,7 +90,6 @@
9090
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
9191
import org.hibernate.type.spi.TypeConfiguration;
9292

93-
import jakarta.persistence.GenerationType;
9493
import jakarta.persistence.TemporalType;
9594

9695
/**
@@ -1155,6 +1154,11 @@ public int getInExpressionCountLimit() {
11551154
return wrapped.getInExpressionCountLimit();
11561155
}
11571156

1157+
@Override
1158+
public int getParameterCountLimit() {
1159+
return wrapped.getParameterCountLimit();
1160+
}
1161+
11581162
@Override
11591163
public boolean forceLobAsLastValue() {
11601164
return wrapped.forceLobAsLastValue();
@@ -1241,8 +1245,13 @@ public NameQualifierSupport getNameQualifierSupport() {
12411245
}
12421246

12431247
@Override
1244-
public BatchLoadSizingStrategy getDefaultBatchLoadSizingStrategy() {
1245-
return wrapped.getDefaultBatchLoadSizingStrategy();
1248+
public MultiKeyLoadSizingStrategy getBatchLoadSizingStrategy() {
1249+
return wrapped.getBatchLoadSizingStrategy();
1250+
}
1251+
1252+
@Override
1253+
public MultiKeyLoadSizingStrategy getMultiKeyLoadSizingStrategy() {
1254+
return wrapped.getMultiKeyLoadSizingStrategy();
12461255
}
12471256

12481257
@Override

hibernate-core/src/main/java/org/hibernate/dialect/HSQLSqlAstTranslator.java

+10
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.hibernate.sql.ast.tree.expression.SqlTuple;
2626
import org.hibernate.sql.ast.tree.expression.Summarization;
2727
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
28+
import org.hibernate.sql.ast.tree.predicate.InArrayPredicate;
2829
import org.hibernate.sql.ast.tree.select.QueryPart;
2930
import org.hibernate.sql.exec.spi.JdbcOperation;
3031
import org.hibernate.type.descriptor.jdbc.ArrayJdbcType;
@@ -57,6 +58,15 @@ public void visitBooleanExpressionPredicate(BooleanExpressionPredicate booleanEx
5758
}
5859
}
5960

61+
@Override
62+
public void visitInArrayPredicate(InArrayPredicate inArrayPredicate) {
63+
// column in ( unnest(?) )
64+
inArrayPredicate.getTestExpression().accept( this );
65+
appendSql( " in (unnest(" );
66+
inArrayPredicate.getArrayParameter().accept( this );
67+
appendSql( "))" );
68+
}
69+
6070
@Override
6171
protected boolean supportsArrayConstructor() {
6272
return true;

hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLSqlAstTranslator.java

+14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.hibernate.sql.ast.tree.expression.Literal;
1919
import org.hibernate.sql.ast.tree.expression.Summarization;
2020
import org.hibernate.sql.ast.tree.predicate.BooleanExpressionPredicate;
21+
import org.hibernate.sql.ast.tree.predicate.InArrayPredicate;
2122
import org.hibernate.sql.ast.tree.predicate.LikePredicate;
2223
import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
2324
import org.hibernate.sql.ast.tree.select.QueryGroup;
@@ -38,6 +39,19 @@ public PostgreSQLSqlAstTranslator(SessionFactoryImplementor sessionFactory, Stat
3839
super( sessionFactory, statement );
3940
}
4041

42+
@Override
43+
public void visitInArrayPredicate(InArrayPredicate inArrayPredicate) {
44+
inArrayPredicate.getTestExpression().accept( this );
45+
appendSql( " = any (" );
46+
inArrayPredicate.getArrayParameter().accept( this );
47+
appendSql( ")" );
48+
}
49+
50+
@Override
51+
protected String getArrayContainsFunction() {
52+
return super.getArrayContainsFunction();
53+
}
54+
4155
@Override
4256
protected void renderInsertIntoNoColumns(TableInsertStandard tableInsert) {
4357
renderIntoIntoAndTable( tableInsert );

hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java

+7-1
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,13 @@
118118
*/
119119
public class SQLServerDialect extends AbstractTransactSQLDialect {
120120
private final static DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 10, 0 );
121-
private static final int PARAM_LIST_SIZE_LIMIT = 2100;
121+
122+
/**
123+
* NOTE : 2100 is the documented limit supposedly - but in my testing, sending
124+
* 2100 parameters fails saying it must be less than 2100.
125+
*/
126+
private static final int PARAM_LIST_SIZE_LIMIT = 2048;
127+
122128
// See microsoft.sql.Types.GEOMETRY
123129
private static final int GEOMETRY_TYPE_CODE = -157;
124130
// See microsoft.sql.Types.GEOGRAPHY

hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java

+10-2
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,10 @@ public class SybaseDialect extends AbstractTransactSQLDialect {
7474
private static final DatabaseVersion MINIMUM_VERSION = DatabaseVersion.make( 16, 0 );
7575

7676
//All Sybase dialects share an IN list size limit.
77-
private static final int PARAM_LIST_SIZE_LIMIT = 250000;
77+
private static final int IN_LIST_SIZE_LIMIT = 250000;
78+
79+
private static final int PARAM_COUNT_LIMIT = 2000;
80+
7881
private final UniqueDelegate uniqueDelegate = new SkipNullableUniqueDelegate(this);
7982

8083
public SybaseDialect() {
@@ -163,7 +166,12 @@ public boolean supportsNullPrecedence() {
163166

164167
@Override
165168
public int getInExpressionCountLimit() {
166-
return PARAM_LIST_SIZE_LIMIT;
169+
return IN_LIST_SIZE_LIMIT;
170+
}
171+
172+
@Override
173+
public int getParameterCountLimit() {
174+
return PARAM_COUNT_LIMIT;
167175
}
168176

169177
@Override

hibernate-core/src/main/java/org/hibernate/engine/internal/BatchFetchQueueHelper.java

+11
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,17 @@ public static void removeBatchLoadableEntityKey(
8080
batchFetchQueue.removeBatchLoadableEntityKey( entityKey );
8181
}
8282

83+
/**
84+
* Remove the entity key with the specified {@code id} and {@code persister} from
85+
* the batch loadable entities {@link BatchFetchQueue}.
86+
*/
87+
public static void removeBatchLoadableEntityKey(
88+
EntityKey entityKey,
89+
SharedSessionContractImplementor session) {
90+
final BatchFetchQueue batchFetchQueue = session.getPersistenceContextInternal().getBatchFetchQueue();
91+
batchFetchQueue.removeBatchLoadableEntityKey( entityKey );
92+
}
93+
8394
public static void removeBatchLoadableEntityKey(
8495
Object id,
8596
EntityMappingType entityMappingType,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
6+
*/
7+
package org.hibernate.engine.profile.internal;
8+
9+
import org.hibernate.engine.profile.Fetch;
10+
11+
/**
12+
* Commonality between entities and collections as something that can be affected by fetch profiles.
13+
*
14+
* @author Steve Ebersole
15+
*/
16+
public interface FetchProfileAffectee {
17+
/**
18+
* Register the profile name with the entity/collection
19+
*/
20+
void registerAffectingFetchProfile(String fetchProfileName, Fetch.Style fetchStyle);
21+
}

0 commit comments

Comments
 (0)