query.setLockMode("alias", LockMode.LockMode.PESSIMISTIC_WRITE); does not Lock in PostgreSqlDialect

Description

When you call

query.setLockMode("alias", LockMode.PESSIMISTIC_WRITE);

you get a Query with a LockOptions object that has lockMode = LockMode.NONE and a aliasSpecificLockModes-map with an entry "alias" -> LockMode.PESSIMISTIC_WRITE

When calling query.list() you get to the QueryLoader which calls dialect.applyLocksToSql(...)
The LockOptions-Object has still lockMode=LockMode.NONE and a aliasSpecificLockModes-map with the translated alias and -> LockMode.PESSIMISTIC_WRITE

As we use PostgreSQL dialect is an instance of PostgreSQLDialect.

So you get a ForUpdateFragement-object with the same LockOptions-object. The aliases-String contains the translated "alias".

In toFragmentString() getForUpdateString(String aliases, LockOptions lockOptions) is called because we have a LockOptions-object. The aliases are ignored in this case, as you can see in the comment:'by default we simply return the getForUpdateString() result since the default is to say no support for "FOR UPDATE OF ..."'

But the getForUpdateString(LockOptions lockOptions) is only looking at the the lockMode-Attribute of the LockOptions-object what has still the value "LockMode.NONE". It results in an empty String as the return value. But it should be " for update" because there's a LockMode.PESSIMISTIC_WRITE in the aliasSpecificLockModes which is ignored in getForUpdateString(LockOptions lockOptions)

Environment

Hibernate 3.5.5-Final
PostgreSQL 8.4

Activity

Show:
Steve Ebersole
March 11, 2015, 2:47 AM

Applied your pull request Bradley. Thanks!

Patrick Marschik
August 26, 2015, 9:22 AM

Requesting to re-open this issue since the fix breaks use without aliases.
Tested with Hibernate 5.0.0.Final, PostgreSQL 9.4.4 and dialect PostgreSQL94Dialect, queries created through JPA and then unwrapped.

Sample query:

When calling query.setLockMode("this",LockMode.PESSIMISTIC_WRITE) the alias on the LockOptions is correctly set.
When QueryLoader.applyLocks is called the LockOptions get copied but the sqlAliasByEntityAlias is empty so no aliases are set on the copied LockOptions.
Later on ForUpdateFragement gets created with the copied LockOptions that have no aliases, therefore ForUpdateFragment.aliases is empty and when dialect.getForUpdateString( aliases.toString(), lockOptions ) gets called in #toFragmentString() the empty String is passed to #getForUpdateString(String,LockOptions).

I think the error could be in one of two places.

  1. when the LockOptions gets copied

  2. in ForUpdateFragment

If the correct way to patch this is in ForUpdateFragment:
The patched PostgreSQL81Dialect doesn't distinguish between empty and non-empty aliases.
Therefore ForUpdateFragment#toFragmentString() needs to be changed to account for empty aliases even though lockOptions != null.

Patrick Marschik
August 26, 2015, 9:28 AM

Adding to the previous comment:
The generated query looks like this and thus fails to run on PostgreSQL:

Henning Blohm
September 9, 2015, 12:01 PM

Noticed that the equivalent problem exists when running

Steve Ebersole
September 9, 2015, 3:03 PM

If y'all see issues here still:

  1. First make sure the problem still exists in 5.0

  2. If so, create a new Jira with a test case (http://sscce.org/) illustrating the problem

Fixed

Assignee

Steve Ebersole

Reporter

Peter Buning

Fix versions

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Affects versions

Priority

Major
Configure