Skip to content

Commit 0c261d7

Browse files
committed
HHH-19336 - Proper implementation for JPA extended locking scope
HHH-19459 - LockScope, FollowOnLocking
1 parent a65e301 commit 0c261d7

File tree

152 files changed

+2682
-1920
lines changed

Some content is hidden

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

152 files changed

+2682
-1920
lines changed

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheDialect.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.sql.Types;
1111

1212
import org.hibernate.LockMode;
13+
import org.hibernate.LockOptions;
1314
import org.hibernate.boot.model.FunctionContributions;
1415
import org.hibernate.cfg.Environment;
1516
import org.hibernate.community.dialect.identity.CacheIdentityColumnSupport;
@@ -43,9 +44,12 @@
4344
import org.hibernate.query.common.TemporalUnit;
4445
import org.hibernate.sql.ast.SqlAstTranslator;
4546
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
47+
import org.hibernate.sql.ast.internal.NoOpForUpdateClauseStrategy;
48+
import org.hibernate.sql.ast.spi.ForUpdateClauseStrategy;
4649
import org.hibernate.sql.ast.spi.SqlAppender;
4750
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
4851
import org.hibernate.sql.ast.tree.Statement;
52+
import org.hibernate.sql.ast.tree.select.QuerySpec;
4953
import org.hibernate.sql.exec.spi.JdbcOperation;
5054
import org.hibernate.type.StandardBasicTypes;
5155
import org.hibernate.type.descriptor.jdbc.JdbcType;
@@ -309,6 +313,11 @@ public String getQuerySequencesString() {
309313

310314
// lock acquisition support ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
311315

316+
@Override
317+
public ForUpdateClauseStrategy getForUpdateClauseStrategy(QuerySpec querySpec, LockOptions lockOptions) {
318+
return NoOpForUpdateClauseStrategy.NO_OP_STRATEGY;
319+
}
320+
312321
@Override
313322
public boolean supportsOuterJoinForUpdate() {
314323
return false;

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CacheSqlAstTranslator.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import java.util.List;
88

9+
import org.hibernate.Locking;
910
import org.hibernate.engine.spi.SessionFactoryImplementor;
1011
import org.hibernate.query.sqm.ComparisonOperator;
1112
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
@@ -34,16 +35,10 @@ public CacheSqlAstTranslator(SessionFactoryImplementor sessionFactory, Statement
3435
@Override
3536
protected LockStrategy determineLockingStrategy(
3637
QuerySpec querySpec,
37-
ForUpdateClause forUpdateClause,
38-
Boolean followOnLocking) {
38+
Locking.FollowOn followOnLocking) {
3939
return LockStrategy.NONE;
4040
}
4141

42-
@Override
43-
protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) {
44-
// Cache does not support the FOR UPDATE clause
45-
}
46-
4742
@Override
4843
protected boolean needsRowsToSkip() {
4944
return true;

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java

Lines changed: 3 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@
9292
import java.time.temporal.TemporalAccessor;
9393
import java.util.Calendar;
9494
import java.util.Date;
95-
import java.util.Map;
9695
import java.util.TimeZone;
9796
import java.util.regex.Matcher;
9897
import java.util.regex.Pattern;
@@ -994,25 +993,10 @@ public String getForUpdateString(String aliases, LockOptions lockOptions) {
994993
if ( getVersion().isBefore( 20, 1 ) ) {
995994
return "";
996995
}
997-
/*
998-
* Parent's implementation for (aliases, lockOptions) ignores aliases.
999-
*/
1000-
if ( aliases.isEmpty() ) {
1001-
LockMode lockMode = lockOptions.getLockMode();
1002-
for ( Map.Entry<String, LockMode> entry : lockOptions.getAliasSpecificLocks() ) {
1003-
// seek the highest lock mode
1004-
if ( entry.getValue().greaterThan(lockMode) ) {
1005-
aliases = entry.getKey();
1006-
}
1007-
}
1008-
}
1009-
LockMode lockMode = lockOptions.getAliasSpecificLockMode( aliases );
1010-
if (lockMode == null ) {
1011-
lockMode = lockOptions.getLockMode();
1012-
}
996+
final LockMode lockMode = lockOptions.getLockMode();
1013997
return switch ( lockMode ) {
1014-
case PESSIMISTIC_READ -> getReadLockString( aliases, lockOptions.getTimeOut() );
1015-
case PESSIMISTIC_WRITE -> getWriteLockString( aliases, lockOptions.getTimeOut() );
998+
case PESSIMISTIC_READ -> getReadLockString( aliases, lockOptions.getTimeout() );
999+
case PESSIMISTIC_WRITE -> getWriteLockString( aliases, lockOptions.getTimeout() );
10161000
case UPGRADE_NOWAIT, PESSIMISTIC_FORCE_INCREMENT -> getForUpdateNowaitString( aliases );
10171001
case UPGRADE_SKIPLOCKED -> getForUpdateSkipLockedString( aliases );
10181002
default -> "";

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacySqlAstTranslator.java

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
*/
55
package org.hibernate.community.dialect;
66

7+
import org.hibernate.Locking;
78
import org.hibernate.engine.spi.SessionFactoryImplementor;
89
import org.hibernate.sql.ast.Clause;
910
import org.hibernate.sql.ast.spi.AbstractSqlAstTranslator;
@@ -129,35 +130,15 @@ protected void renderMaterializationHint(CteMaterialization materialization) {
129130
}
130131
}
131132

132-
@Override
133-
protected String getForShare(int timeoutMillis) {
134-
return " for share";
135-
}
136-
137-
@Override
138-
protected String getForUpdate() {
139-
return getDialect().getVersion().isBefore( 20, 1 ) ? "" : " for update";
140-
}
141-
142133
@Override
143134
protected LockStrategy determineLockingStrategy(
144135
QuerySpec querySpec,
145-
ForUpdateClause forUpdateClause,
146-
Boolean followOnLocking) {
136+
Locking.FollowOn followOnLocking) {
147137
// Support was added in 20.1: https://www.cockroachlabs.com/docs/v20.1/select-for-update.html
148138
if ( getDialect().getVersion().isBefore( 20, 1 ) ) {
149139
return LockStrategy.NONE;
150140
}
151-
return super.determineLockingStrategy( querySpec, forUpdateClause, followOnLocking );
152-
}
153-
154-
@Override
155-
protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) {
156-
// Support was added in 20.1: https://www.cockroachlabs.com/docs/v20.1/select-for-update.html
157-
if ( getDialect().getVersion().isBefore( 20, 1 ) ) {
158-
return;
159-
}
160-
super.renderForUpdateClause( querySpec, forUpdateClause );
141+
return super.determineLockingStrategy( querySpec, followOnLocking );
161142
}
162143

163144
protected boolean shouldEmulateFetchClause(QueryPart queryPart) {

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DB2LegacySqlAstTranslator.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -212,21 +212,6 @@ protected void visitAnsiCaseSimpleExpression(
212212
}
213213
}
214214

215-
@Override
216-
protected String getForUpdate() {
217-
return " for read only with rs use and keep update locks";
218-
}
219-
220-
@Override
221-
protected String getForShare(int timeoutMillis) {
222-
return " for read only with rs use and keep share locks";
223-
}
224-
225-
@Override
226-
protected String getSkipLocked() {
227-
return " skip locked data";
228-
}
229-
230215
protected boolean shouldEmulateFetchClause(QueryPart queryPart) {
231216
// Check if current query part is already row numbering to avoid infinite recursion
232217
if ( getQueryPartForRowNumbering() == queryPart ) {

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyDialect.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import java.util.Locale;
1111

1212
import jakarta.persistence.Timeout;
13+
import org.hibernate.LockOptions;
1314
import org.hibernate.boot.model.FunctionContributions;
1415
import org.hibernate.boot.model.TypeContributions;
1516
import org.hibernate.dialect.DB2Dialect;
@@ -62,9 +63,11 @@
6263
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
6364
import org.hibernate.sql.ast.SqlAstTranslator;
6465
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
66+
import org.hibernate.sql.ast.spi.ForUpdateClauseStrategy;
6567
import org.hibernate.sql.ast.spi.SqlAppender;
6668
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
6769
import org.hibernate.sql.ast.tree.Statement;
70+
import org.hibernate.sql.ast.tree.select.QuerySpec;
6871
import org.hibernate.sql.exec.spi.JdbcOperation;
6972
import org.hibernate.community.dialect.sequence.SequenceInformationExtractorDerbyDatabaseImpl;
7073
import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor;
@@ -568,6 +571,11 @@ public boolean supportsCommentOn() {
568571
return false;
569572
}
570573

574+
@Override
575+
public ForUpdateClauseStrategy getForUpdateClauseStrategy(QuerySpec querySpec, LockOptions lockOptions) {
576+
return DerbyForUpdateStrategy.strategy( this, querySpec, lockOptions );
577+
}
578+
571579
@Override
572580
public RowLockStrategy getReadRowLockStrategy() {
573581
return RowLockStrategy.NONE;
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.community.dialect;
6+
7+
import org.hibernate.LockMode;
8+
import org.hibernate.LockOptions;
9+
import org.hibernate.Locking;
10+
import org.hibernate.dialect.Dialect;
11+
import org.hibernate.dialect.RowLockStrategy;
12+
import org.hibernate.sql.ast.internal.PessimisticLockKind;
13+
import org.hibernate.sql.ast.internal.StandardForUpdateClauseStrategy;
14+
import org.hibernate.sql.ast.spi.SqlAppender;
15+
import org.hibernate.sql.ast.tree.select.QuerySpec;
16+
17+
/**
18+
* @author Steve Ebersole
19+
*/
20+
public class DerbyForUpdateStrategy extends StandardForUpdateClauseStrategy {
21+
public DerbyForUpdateStrategy(
22+
Dialect dialect,
23+
RowLockStrategy rowLockStrategy,
24+
LockMode lockMode,
25+
PessimisticLockKind lockKind,
26+
Locking.Scope lockingScope,
27+
int timeout) {
28+
super( dialect, rowLockStrategy, lockMode, lockKind, lockingScope, timeout );
29+
}
30+
31+
@Override
32+
protected void renderResultSetOptions(Dialect dialect, SqlAppender sqlAppender) {
33+
sqlAppender.append( " with rs" );
34+
}
35+
36+
public static DerbyForUpdateStrategy strategy(
37+
Dialect dialect,
38+
QuerySpec querySpec,
39+
LockOptions lockOptions) {
40+
return (DerbyForUpdateStrategy) StandardForUpdateClauseStrategy.strategy(
41+
dialect,
42+
querySpec,
43+
lockOptions,
44+
(dialect1, rowLockStrategy, lockMode, lockKind, lockScope, timeout) -> new StandardForUpdateClauseStrategy(
45+
dialect,
46+
rowLockStrategy,
47+
lockMode,
48+
lockKind,
49+
lockScope,
50+
timeout
51+
)
52+
);
53+
}
54+
}

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacyDialect.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
import java.sql.Types;
1010

1111
import jakarta.persistence.Timeout;
12+
import org.hibernate.LockOptions;
1213
import org.hibernate.boot.model.FunctionContributions;
1314
import org.hibernate.boot.model.TypeContributions;
1415
import org.hibernate.dialect.DB2Dialect;
@@ -60,9 +61,11 @@
6061
import org.hibernate.sql.ast.SqlAstNodeRenderingMode;
6162
import org.hibernate.sql.ast.SqlAstTranslator;
6263
import org.hibernate.sql.ast.SqlAstTranslatorFactory;
64+
import org.hibernate.sql.ast.spi.ForUpdateClauseStrategy;
6365
import org.hibernate.sql.ast.spi.SqlAppender;
6466
import org.hibernate.sql.ast.spi.StandardSqlAstTranslatorFactory;
6567
import org.hibernate.sql.ast.tree.Statement;
68+
import org.hibernate.sql.ast.tree.select.QuerySpec;
6669
import org.hibernate.sql.exec.spi.JdbcOperation;
6770
import org.hibernate.community.dialect.sequence.SequenceInformationExtractorDerbyDatabaseImpl;
6871
import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorNoOpImpl;
@@ -579,6 +582,11 @@ public boolean supportsCommentOn() {
579582
return false;
580583
}
581584

585+
@Override
586+
public ForUpdateClauseStrategy getForUpdateClauseStrategy(QuerySpec querySpec, LockOptions lockOptions) {
587+
return DerbyForUpdateStrategy.strategy( this, querySpec, lockOptions );
588+
}
589+
582590
@Override
583591
public RowLockStrategy getWriteRowLockStrategy() {
584592
return RowLockStrategy.NONE;

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbyLegacySqlAstTranslator.java

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -174,21 +174,6 @@ protected void visitAnsiCaseSimpleExpression(
174174
}
175175
}
176176

177-
@Override
178-
protected String getForUpdate() {
179-
return " for update";
180-
}
181-
182-
@Override
183-
protected String getForShare(int timeoutMillis) {
184-
return " for read only";
185-
}
186-
187-
@Override
188-
protected String getForUpdateWithClause() {
189-
return " with rs";
190-
}
191-
192177
@Override
193178
public void visitOffsetFetchClause(QueryPart queryPart) {
194179
// Derby only supports the OFFSET and FETCH clause with ROWS

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/DerbySqlAstTranslator.java

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -174,16 +174,6 @@ protected void visitAnsiCaseSimpleExpression(
174174
}
175175
}
176176

177-
@Override
178-
protected String getForShare(int timeoutMillis) {
179-
return " for read only";
180-
}
181-
182-
@Override
183-
protected String getForUpdateWithClause() {
184-
return " with rs";
185-
}
186-
187177
@Override
188178
public void visitOffsetFetchClause(QueryPart queryPart) {
189179
// Derby only supports the OFFSET and FETCH clause with ROWS

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/FirebirdSqlAstTranslator.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,6 @@ protected void visitAnsiCaseSimpleExpression(
118118
}
119119
}
120120

121-
@Override
122-
protected String getForUpdate() {
123-
return " with lock";
124-
}
125-
126121
protected boolean shouldEmulateFetchClause(QueryPart queryPart) {
127122
// Percent fetches or ties fetches aren't supported in Firebird
128123
// Before 3.0 there was also no support for window functions

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacyDialect.java

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -674,18 +674,15 @@ public String getForUpdateString(final String aliases) {
674674

675675
@Override
676676
public String getForUpdateString(final String aliases, final LockOptions lockOptions) {
677-
LockMode lockMode = lockOptions.findGreatestLockMode();
678-
lockOptions.setLockMode( lockMode );
679-
680677
// not sure why this is sometimes empty
681678
if ( aliases == null || aliases.isEmpty() ) {
682679
return getForUpdateString( lockOptions );
683680
}
684681

685-
return getForUpdateString( aliases, lockMode, lockOptions.getTimeOut() );
682+
return getForUpdateString( aliases, lockOptions.getLockMode(), lockOptions.getTimeout() );
686683
}
687684

688-
private String getForUpdateString(String aliases, LockMode lockMode, int timeout) {
685+
private String getForUpdateString(String aliases, LockMode lockMode, Timeout timeout) {
689686
return switch ( lockMode ) {
690687
case PESSIMISTIC_READ -> getReadLockString( aliases, timeout );
691688
case PESSIMISTIC_WRITE -> getWriteLockString( aliases, timeout );

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HANALegacySqlAstTranslator.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,9 +326,4 @@ protected void visitValuesList(List<Values> valuesList) {
326326
public void visitValuesTableReference(ValuesTableReference tableReference) {
327327
emulateValuesTableReferenceColumnAliasing( tableReference );
328328
}
329-
330-
@Override
331-
protected String getSkipLocked() {
332-
return " ignore locked";
333-
}
334329
}

hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/HSQLLegacySqlAstTranslator.java

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.List;
88
import java.util.function.Consumer;
99

10+
import org.hibernate.Locking;
1011
import org.hibernate.engine.spi.SessionFactoryImplementor;
1112
import org.hibernate.metamodel.mapping.JdbcMappingContainer;
1213
import org.hibernate.query.IllegalQueryOperationException;
@@ -237,20 +238,11 @@ private boolean isStringLiteral( Expression expression ) {
237238
@Override
238239
protected LockStrategy determineLockingStrategy(
239240
QuerySpec querySpec,
240-
ForUpdateClause forUpdateClause,
241-
Boolean followOnLocking) {
241+
Locking.FollowOn followOnLocking) {
242242
if ( getDialect().getVersion().isBefore( 2 ) ) {
243243
return LockStrategy.NONE;
244244
}
245-
return super.determineLockingStrategy( querySpec, forUpdateClause, followOnLocking );
246-
}
247-
248-
@Override
249-
protected void renderForUpdateClause(QuerySpec querySpec, ForUpdateClause forUpdateClause) {
250-
if ( getDialect().getVersion().isBefore( 2 ) ) {
251-
return;
252-
}
253-
super.renderForUpdateClause( querySpec, forUpdateClause );
245+
return super.determineLockingStrategy( querySpec, followOnLocking );
254246
}
255247

256248
@Override

0 commit comments

Comments
 (0)