99import org .hibernate .LockMode ;
1010import org .hibernate .LockOptions ;
1111import org .hibernate .Locking ;
12+ import org .hibernate .Timeouts ;
1213import org .hibernate .dialect .Dialect ;
1314import org .hibernate .dialect .H2Dialect ;
1415import org .hibernate .dialect .HSQLDialect ;
3435import static org .assertj .core .api .Assertions .assertThat ;
3536import static org .hibernate .LockMode .PESSIMISTIC_WRITE ;
3637import static org .hibernate .orm .test .locking .options .Helper .Table .BOOKS ;
37- import static org .hibernate .orm .test .locking .options .Helper .Table .BOOK_AUTHORS ;
3838import static org .hibernate .orm .test .locking .options .Helper .Table .BOOK_GENRES ;
3939import static org .hibernate .orm .test .locking .options .Helper .Table .JOINED_REPORTER ;
4040import static org .hibernate .orm .test .locking .options .Helper .Table .PERSONS ;
@@ -62,6 +62,8 @@ void dropTestData(SessionFactoryScope factoryScope) {
6262 factoryScope .dropData ();
6363 }
6464
65+ // todo : generally, we do not lock collection tables - HHH-19513 plus maybe general problem with many-to-many tables
66+
6567 @ Test
6668 void testFind (SessionFactoryScope factoryScope ) {
6769 final SQLStatementInspector sqlCollector = factoryScope .getCollectingStatementInspector ();
@@ -72,28 +74,25 @@ void testFind(SessionFactoryScope factoryScope) {
7274 assertThat ( Hibernate .isInitialized ( theTalisman ) ).isTrue ();
7375 assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
7476 Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), BOOKS );
75- TransactionUtil .deleteFromTable ( factoryScope , BOOKS .getTableName (), true );
76- TransactionUtil .deleteFromTable ( factoryScope , BOOK_GENRES .getTableName (), false );
77- TransactionUtil .deleteFromTable ( factoryScope , BOOK_AUTHORS .getTableName (), false );
77+ TransactionUtil .updateTable ( factoryScope , BOOKS .getTableName (), "title" , true );
78+ TransactionUtil .updateTable ( factoryScope , BOOK_GENRES .getTableName (), "genre" , false );
7879 } );
7980 }
8081
8182 @ Test
8283 void testFindWithExtended (SessionFactoryScope factoryScope ) {
8384 final SQLStatementInspector sqlCollector = factoryScope .getCollectingStatementInspector ();
8485
85- // note that this is not strictly spec compliant as it says EXTENDED should extend
86- // the locks to the `book_genres` table...
86+ // note that this is not strictly spec compliant as it says EXTENDED should extend the locks to the `book_genres` table...
8787 factoryScope .inTransaction ( (session ) -> {
8888 sqlCollector .clear ();
8989 final Book theTalisman = session .find ( Book .class , 3 , PESSIMISTIC_WRITE , EXTENDED );
9090 assertThat ( Hibernate .isInitialized ( theTalisman ) ).isTrue ();
9191 assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
9292 Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), BOOKS );
93- TransactionUtil .deleteFromTable ( factoryScope , BOOKS .getTableName (), true );
93+ TransactionUtil .updateTable ( factoryScope , BOOKS .getTableName (), "title" , true );
9494 // For strict compliance, EXTENDED here should lock `book_genres` but we do not
95- TransactionUtil .deleteFromTable ( factoryScope , BOOK_GENRES .getTableName (), false );
96- TransactionUtil .deleteFromTable ( factoryScope , BOOK_AUTHORS .getTableName (), false );
95+ TransactionUtil .updateTable ( factoryScope , BOOK_GENRES .getTableName (), "genre" , false );
9796 } );
9897 }
9998
@@ -109,9 +108,8 @@ void testFindWithExtendedJpaExpectation(SessionFactoryScope factoryScope) {
109108 // these 2 assertions would depend a bit on the approach and/or dialect
110109// assertThat( sqlCollector.getSqlQueries() ).hasSize( 1 );
111110// Helper.checkSql( sqlCollector.getSqlQueries().get( 0 ), session.getDialect(), Helper.Table.BOOK_GENRES );
112- TransactionUtil .deleteFromTable ( factoryScope , BOOKS .getTableName (), true );
113- TransactionUtil .deleteFromTable ( factoryScope , BOOK_GENRES .getTableName (), true );
114- TransactionUtil .deleteFromTable ( factoryScope , BOOK_AUTHORS .getTableName (), false );
111+ TransactionUtil .updateTable ( factoryScope , BOOKS .getTableName (), "title" , true );
112+ TransactionUtil .updateTable ( factoryScope , BOOK_GENRES .getTableName (), "genre" , true );
115113 } );
116114 }
117115
@@ -133,11 +131,23 @@ void testFindWithExtendedAndFetch(SessionFactoryScope factoryScope) {
133131 new EnabledFetchProfile ("book-genres" )
134132 );
135133 assertThat ( Hibernate .isInitialized ( theTalisman ) ).isTrue ();
136- assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
137- Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), BOOKS , BOOK_GENRES );
138- TransactionUtil .deleteFromTable ( factoryScope , BOOKS .getTableName (), true );
139- TransactionUtil .deleteFromTable ( factoryScope , BOOK_GENRES .getTableName (), true );
140- TransactionUtil .deleteFromTable ( factoryScope , BOOK_AUTHORS .getTableName (), false );
134+
135+ if ( session .getDialect ().supportsOuterJoinForUpdate () ) {
136+ assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
137+ Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), BOOKS , BOOK_GENRES );
138+ TransactionUtil .deleteFromTable ( factoryScope , BOOKS .getTableName (), true );
139+ TransactionUtil .deleteFromTable ( factoryScope , BOOK_GENRES .getTableName (), true );
140+ }
141+ else {
142+ // should be 3, but follow-on locking is not locking collection tables...
143+ // todo : track this down - HHH-19513
144+ assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 2 );
145+ Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 1 ), session .getDialect (), BOOKS );
146+
147+ // todo : track this down - HHH-19513
148+ //Helper.checkSql( sqlCollector.getSqlQueries().get( 2 ), session.getDialect(), BOOK_GENRES );
149+ //TransactionUtil.updateTable( factoryScope, BOOK_GENRES.getTableName(), "genre", true );
150+ }
141151 } );
142152 }
143153
@@ -158,18 +168,17 @@ void testLock(SessionFactoryScope factoryScope) {
158168 //Helper.checkSql( sqlCollector.getSqlQueries().get( 0 ), session.getDialect(), BOOKS );
159169 final String sql = sqlCollector .getSqlQueries ().get ( 0 );
160170 if ( session .getDialect ().getPessimisticLockStyle () == PessimisticLockStyle .CLAUSE ) {
161- assertThat ( sql ).endsWith ( " for update" );
171+ final String expectedClause = session .getDialect ().getWriteLockString ( Timeouts .WAIT_FOREVER );
172+ assertThat ( sql ).endsWith ( expectedClause );
162173 }
163174 else {
164175 final LockOptions lockOptions = new LockOptions ( LockMode .PESSIMISTIC_WRITE );
165176 final String booksTableReference = session .getDialect ().appendLockHint ( lockOptions , BOOKS .getTableName () );
166177 assertThat ( sql ).contains ( booksTableReference );
167178 }
168179 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
169-
170- TransactionUtil .deleteFromTable ( factoryScope , BOOKS .getTableName (), true );
171- TransactionUtil .deleteFromTable ( factoryScope , BOOK_GENRES .getTableName (), false );
172- TransactionUtil .deleteFromTable ( factoryScope , BOOK_AUTHORS .getTableName (), false );
180+ TransactionUtil .updateTable ( factoryScope , BOOKS .getTableName (), "title" , true );
181+ TransactionUtil .updateTable ( factoryScope , BOOK_GENRES .getTableName (), "genre" , false );
173182 } );
174183 }
175184
@@ -185,9 +194,9 @@ void testLockWithExtended(SessionFactoryScope factoryScope) {
185194 session .lock ( theTalisman , PESSIMISTIC_WRITE , EXTENDED );
186195 assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
187196 Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), BOOKS );
197+ TransactionUtil .updateTable ( factoryScope , BOOKS .getTableName (), "title" , true );
188198 // Again, for strict compliance, EXTENDED here should lock `book_genres` but we do not
189- TransactionUtil .deleteFromTable ( factoryScope , BOOK_GENRES .getTableName (), false );
190- TransactionUtil .deleteFromTable ( factoryScope , BOOK_AUTHORS .getTableName (), false );
199+ TransactionUtil .updateTable ( factoryScope , BOOK_GENRES .getTableName (), "genre" , false );
191200 } );
192201 }
193202
@@ -203,9 +212,8 @@ void testRefresh(SessionFactoryScope factoryScope) {
203212 session .refresh ( theTalisman , PESSIMISTIC_WRITE );
204213 assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
205214 Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), BOOKS );
206- TransactionUtil .deleteFromTable ( factoryScope , PERSONS .getTableName (), false );
207- TransactionUtil .deleteFromTable ( factoryScope , BOOK_GENRES .getTableName (), false );
208- TransactionUtil .deleteFromTable ( factoryScope , BOOK_AUTHORS .getTableName (), false );
215+ TransactionUtil .updateTable ( factoryScope , BOOKS .getTableName (), "title" , true );
216+ TransactionUtil .updateTable ( factoryScope , BOOK_GENRES .getTableName (), "genre" , false );
209217 } );
210218 }
211219
@@ -221,13 +229,14 @@ void testRefreshWithExtended(SessionFactoryScope factoryScope) {
221229 session .lock ( theTalisman , PESSIMISTIC_WRITE , EXTENDED );
222230 assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
223231 Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), BOOKS );
224- TransactionUtil .deleteFromTable ( factoryScope , BOOKS .getTableName (), true );
225- TransactionUtil . deleteFromTable ( factoryScope , BOOK_GENRES . getTableName (), false );
226- TransactionUtil .deleteFromTable ( factoryScope , BOOK_AUTHORS .getTableName (), false );
232+ TransactionUtil .updateTable ( factoryScope , BOOKS .getTableName (), "title" , true );
233+ // Again, for strict compliance, EXTENDED here should lock `book_genres` but we do not
234+ TransactionUtil .updateTable ( factoryScope , BOOK_GENRES .getTableName (), "genre" , false );
227235 } );
228236 }
229237
230238 @ Test
239+ @ SkipForDialect (dialectClass = HSQLDialect .class , reason = "See https://sourceforge.net/p/hsqldb/bugs/1734/" )
231240 void testEagerFind (SessionFactoryScope factoryScope ) {
232241 final SQLStatementInspector sqlCollector = factoryScope .getCollectingStatementInspector ();
233242
@@ -276,12 +285,29 @@ void testEagerFindWithExtended(SessionFactoryScope factoryScope) {
276285
277286 factoryScope .inTransaction ( (session ) -> {
278287 sqlCollector .clear ();
279- final Report report = session .find ( Report .class , 2 , PESSIMISTIC_WRITE , EXTENDED );
280- assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
281- Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), REPORTS , REPORT_LABELS );
282- TransactionUtil .deleteFromTable ( factoryScope , REPORTS .getTableName (), true );
283- TransactionUtil .deleteFromTable ( factoryScope , PERSONS .getTableName (), false );
284- TransactionUtil .deleteFromTable ( factoryScope , REPORT_LABELS .getTableName (), true );
288+ session .find ( Report .class , 2 , PESSIMISTIC_WRITE , EXTENDED );
289+ if ( session .getDialect ().supportsOuterJoinForUpdate () ) {
290+ assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
291+ Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), REPORTS , REPORT_LABELS );
292+ TransactionUtil .updateTable ( factoryScope , REPORTS .getTableName (), "title" , true );
293+ TransactionUtil .updateTable ( factoryScope , PERSONS .getTableName (), "name" , false );
294+ TransactionUtil .updateTable ( factoryScope , REPORT_LABELS .getTableName (), "txt" , true );
295+ }
296+ else {
297+ assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 3 );
298+ Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 1 ), session .getDialect (), REPORTS );
299+ Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 2 ), session .getDialect (), PERSONS );
300+ TransactionUtil .updateTable ( factoryScope , REPORTS .getTableName (), "title" , true );
301+
302+ // these should happen but currently do not - follow-on locking is not locking element-collection tables...
303+ // todo : track this down - HHH-19513
304+ //Helper.checkSql( sqlCollector.getSqlQueries().get( 2 ), session.getDialect(), REPORT_LABELS );
305+ //TransactionUtil.updateTable( factoryScope, REPORT_LABELS.getTableName(), "txt", true );
306+
307+ // this one should not happen at all. follow-on locking is not understanding scope probably..
308+ // todo : track this down - HHH-19514
309+ TransactionUtil .updateTable ( factoryScope , PERSONS .getTableName (), "name" , true );
310+ }
285311 } );
286312 }
287313
@@ -293,12 +319,30 @@ void testEagerFindWithFetchScope(SessionFactoryScope factoryScope) {
293319
294320 factoryScope .inTransaction ( (session ) -> {
295321 sqlCollector .clear ();
296- final Report report = session .find ( Report .class , 2 , PESSIMISTIC_WRITE , Locking .Scope .INCLUDE_FETCHES );
297- assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
298- Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), REPORTS , REPORT_LABELS , JOINED_REPORTER );
299- TransactionUtil .deleteFromTable ( factoryScope , REPORTS .getTableName (), true );
300- TransactionUtil .deleteFromTable ( factoryScope , PERSONS .getTableName (), true );
301- TransactionUtil .deleteFromTable ( factoryScope , REPORT_LABELS .getTableName (), true );
322+ session .find ( Report .class , 2 , PESSIMISTIC_WRITE , Locking .Scope .INCLUDE_FETCHES );
323+
324+ if ( session .getDialect ().supportsOuterJoinForUpdate () ) {
325+ assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 1 );
326+ Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 0 ), session .getDialect (), REPORTS , REPORT_LABELS , JOINED_REPORTER );
327+ TransactionUtil .updateTable ( factoryScope , REPORTS .getTableName (), "title" , true );
328+ TransactionUtil .updateTable ( factoryScope , PERSONS .getTableName (), "name" , true );
329+ TransactionUtil .updateTable ( factoryScope , REPORT_LABELS .getTableName (), "txt" , true );
330+ }
331+ else {
332+ assertThat ( sqlCollector .getSqlQueries () ).hasSize ( 3 );
333+ Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 1 ), session .getDialect (), REPORTS );
334+ Helper .checkSql ( sqlCollector .getSqlQueries ().get ( 2 ), session .getDialect (), PERSONS );
335+ TransactionUtil .updateTable ( factoryScope , REPORTS .getTableName (), "title" , true );
336+
337+ // these should happen but currently do not - follow-on locking is not locking element-collection tables...
338+ // todo : track this down - HHH-19513
339+ //Helper.checkSql( sqlCollector.getSqlQueries().get( 2 ), session.getDialect(), REPORT_LABELS );
340+ //TransactionUtil.updateTable( factoryScope, REPORT_LABELS.getTableName(), "txt", true );
341+
342+ // this one should not happen at all. follow-on locking is not understanding scope probably..
343+ // todo : track this down - HHH-19514
344+ TransactionUtil .updateTable ( factoryScope , PERSONS .getTableName (), "name" , true );
345+ }
302346 } );
303347 }
304348}
0 commit comments