Issue Details (XML | Word | Printable)

Key: HHH-1889
Type: Bug Bug
Status: Resolved Resolved
Resolution: Fixed
Priority: Major Major
Assignee: Steve Ebersole
Reporter: Matthias Germann
Votes: 5
Watchers: 7
Operations

If you were logged in you would be able to see more operations.
Hibernate Core

LockMode.UPGRADE not applied in all cases for SQL Server / Sybase

Created: 08/Jul/06 07:20 AM   Updated: 23/Jan/07 10:33 AM
Component/s: core
Affects Version/s: 3.2.0.cr2, 3.2.0.cr3
Fix Version/s: 3.2.2

Time Tracking:
Not Specified

File Attachments: 1. Text File AbstractEntityJoinWalker.java.patch (3 kB)
2. Text File SQLServerDialect.applyLocks.patch (14 kB)

Environment: Windows XP, Hibernate 3.2.cr3


 Description  « Hide
Passing a LockMode parameter to the get(), load() or refresh() method of the Session class has no effect on MS SQL Server.

The statement
session.load(ProcessInstance.class, 33l, LockMode.UPGRADE)

produces this SQL Statement with the SQLServerDialect:

select
        processins0_.ID_ as ID1_20_0_,
        processins0_.VERSION_ as VERSION2_20_0_,
        processins0_.START_ as START3_20_0_,
        processins0_.END_ as END4_20_0_,
        processins0_.ISSUSPENDED_ as ISSUSPEN5_20_0_,
        processins0_.PROCESSDEFINITION_ as PROCESSD6_20_0_,
        processins0_.ROOTTOKEN_ as ROOTTOKEN7_20_0_,
        processins0_.SUPERPROCESSTOKEN_ as SUPERPRO8_20_0_
    from
        JBPM_PROCESSINSTANCE processins0_
    where
        processins0_.ID_=?

This Statement does not contain the requested locking hint. The FROM claus should look like this:
from JBPM_PROCESSINSTANCE processins0_ with (updlock, rowlock)

The OracleDialect produces a correct statement with a FOR UPDATE clause
    select
        processins0_.ID_ as ID1_20_0_,
        processins0_.VERSION_ as VERSION2_20_0_,
        processins0_.START_ as START3_20_0_,
        processins0_.END_ as END4_20_0_,
        processins0_.ISSUSPENDED_ as ISSUSPEN5_20_0_,
        processins0_.PROCESSDEFINITION_ as PROCESSD6_20_0_,
        processins0_.ROOTTOKEN_ as ROOTTOKEN7_20_0_,
        processins0_.SUPERPROCESSTOKEN_ as SUPERPRO8_20_0_
    from
        JBPM_PROCESSINSTANCE processins0_
    where
        processins0_.ID_=? for update


The lock() method works correctly.

IMHO, the problem is that only the SimpleSelect class uses the appendLockHint() method of the Dialect class. The Select class does not seam to use the appendLockHint() method.

 All   Comments   Work Log   Change History   FishEye      Sort Order: Ascending order - Click to sort in descending order
Matthias Germann added a comment - 08/Jul/06 07:44 AM
The LockMode.UPGRADE does also not work for SQL Server with the Query by Criteria API:

session.createCriteria(ProcessInstance.class)
    .add(Restrictions.idEq(33l))
    .setFetchMode("rootToken", FetchMode.JOIN)
    .createAlias("rootToken", "rootToken")
    .setLockMode("rootToken", LockMode.UPGRADE)
    .list();

proces the following SQL Statement with the SQLServer dialect:

    select
        this_.ID_ as ID1_20_1_,
        this_.VERSION_ as VERSION2_20_1_,
        this_.START_ as START3_20_1_,
        this_.END_ as END4_20_1_,
        this_.ISSUSPENDED_ as ISSUSPEN5_20_1_,
        this_.PROCESSDEFINITION_ as PROCESSD6_20_1_,
        this_.ROOTTOKEN_ as ROOTTOKEN7_20_1_,
        this_.SUPERPROCESSTOKEN_ as SUPERPRO8_20_1_,
        roottoken1_.ID_ as ID1_21_0_,
        roottoken1_.VERSION_ as VERSION2_21_0_,
        roottoken1_.NAME_ as NAME3_21_0_,
        roottoken1_.START_ as START4_21_0_,
        roottoken1_.END_ as END5_21_0_,
        roottoken1_.NODEENTER_ as NODEENTER6_21_0_,
        roottoken1_.NEXTLOGINDEX_ as NEXTLOGI7_21_0_,
        roottoken1_.ISABLETOREACTIVATEPARENT_ as ISABLETO8_21_0_,
        roottoken1_.ISTERMINATIONIMPLICIT_ as ISTERMIN9_21_0_,
        roottoken1_.ISSUSPENDED_ as ISSUSPE10_21_0_,
        roottoken1_.NODE_ as NODE11_21_0_,
        roottoken1_.PROCESSINSTANCE_ as PROCESS12_21_0_,
        roottoken1_.PARENT_ as PARENT13_21_0_,
        roottoken1_.SUBPROCESSINSTANCE_ as SUBPROC14_21_0_
    from
        JBPM_PROCESSINSTANCE this_
    inner join
        JBPM_TOKEN roottoken1_
            on this_.ROOTTOKEN_=roottoken1_.ID_
    where
        this_.ID_ = ?

Again, the lock hint is missing.

The OracleDialect produces a correct Statement with the lock clause:
    select
        this_.ID_ as ID1_20_1_,
        this_.VERSION_ as VERSION2_20_1_,
        this_.START_ as START3_20_1_,
        this_.END_ as END4_20_1_,
        this_.ISSUSPENDED_ as ISSUSPEN5_20_1_,
        this_.PROCESSDEFINITION_ as PROCESSD6_20_1_,
        this_.ROOTTOKEN_ as ROOTTOKEN7_20_1_,
        this_.SUPERPROCESSTOKEN_ as SUPERPRO8_20_1_,
        roottoken1_.ID_ as ID1_21_0_,
        roottoken1_.VERSION_ as VERSION2_21_0_,
        roottoken1_.NAME_ as NAME3_21_0_,
        roottoken1_.START_ as START4_21_0_,
        roottoken1_.END_ as END5_21_0_,
        roottoken1_.NODEENTER_ as NODEENTER6_21_0_,
        roottoken1_.NEXTLOGINDEX_ as NEXTLOGI7_21_0_,
        roottoken1_.ISABLETOREACTIVATEPARENT_ as ISABLETO8_21_0_,
        roottoken1_.ISTERMINATIONIMPLICIT_ as ISTERMIN9_21_0_,
        roottoken1_.ISSUSPENDED_ as ISSUSPE10_21_0_,
        roottoken1_.NODE_ as NODE11_21_0_,
        roottoken1_.PROCESSINSTANCE_ as PROCESS12_21_0_,
        roottoken1_.PARENT_ as PARENT13_21_0_,
        roottoken1_.SUBPROCESSINSTANCE_ as SUBPROC14_21_0_
    from
        JBPM_PROCESSINSTANCE this_,
        JBPM_TOKEN roottoken1_
    where
        this_.ROOTTOKEN_=roottoken1_.ID_
        and this_.ID_ = ? for update
            of roottoken1_.ID_



Matthias Germann added a comment - 08/Jul/06 07:49 AM
Setting the from clause by calling the dialect's appendLockHint() method in AbstractEntityJoinWalker.initStatementString() seams to solve the problem with the Session class but not with the QBC API:

.setFromClause(
  /*persister.fromTableFragment(alias) +*/
  getDialect().appendLockHint(lockMode, persister.fromTableFragment(alias)) +
  persister.fromJoinFragment(alias, true, true)
)

Steve Finch added a comment - 17/Nov/06 01:46 PM
I've tested the AbstractEntityJoinWalker suggestion and it does in fact fix the SQL Server issue.

I suggest that the fix go in and that the HQL bug report be broken out into a separate issue so that this one can be closed in the build.

Steve Finch added a comment - 20/Nov/06 08:50 AM
I've attached a patch file for AbstractEntityJoinWalker.java, which should suffice in finishing of the Session portion of this problem.

Steve Finch added a comment - 20/Nov/06 02:23 PM
I'm attaching a second patch that fixes the use of inline lock hints for HQL and Criteria queries. I thought it would be harder than it was, but I've tested it and it works as expected.

My methodology:
1) Locate all the places where ForUpdateFragment is appended to the existing SQL (QueryTranslatorImpl, QueryLoader, and CriteriaLoader);
2) Refactor the code to move this behavior to the Dialect class;
3) Override the new method in the SQLServerDialect class;
4) Create a new class InlineUpdateLockModification which replaces the aliases in the FROM clause with the appropriate update lock hint, if necessary.

I'm not exactly happy with the solution, as it causes the query to be reprocessed each time lock hints occur. However, it seemed a lesser risk than playing with the HQLQueryPlanKey class and adding some metadata about what locks would be needed. My fix could be sped up if there were bookmarks telling where each alias existed in the existing query; with that information a search would not be necessary and the resulting code would be safer.

Steve Ebersole added a comment - 23/Jan/07 07:02 AM
In the future it would be great if the patches were not based on absolute paths, but rather paths relative to the project structure....

Steve Finch added a comment - 23/Jan/07 08:22 AM
Sorry 'bout that. I agree with you that relative paths would be correct. It would be great if the SVN plugin for Eclipse did that automatically.

I wonder how I got it to do that?

Steve Ebersole added a comment - 23/Jan/07 08:55 AM
No worries. I do not use eclipse and so I have no idea.

Just so I understand the correct syntax here... Say I have a query like 'select abc from xyz x' and want to apply a lock hint. The correct syntax for that is 'select abc from xyz x with (updlock, rowlock)'. Correct? Specifically the hint comes after the alias?

Steve Ebersole added a comment - 23/Jan/07 09:02 AM
I ended up needing to make a few changes to your patch, nothing to major:
1) StringBuffer#indexOf is JDK 1.4 specific, so I ended up writing another way to perform this replacement which will work with 1.3
2) I actually ended up overriding Dialect#applyLocksToSql in the SybaseDialect instead since both use the same approach of lock-hints and because SQLServerDialect extends SybaseDialect

Steve Finch added a comment - 23/Jan/07 09:17 AM
You are correct. The Syntax is "from table_name [ [AS] table_alias ] [ WITH ( <table_hint> [,...n]) ]".

Steve Ebersole added a comment - 23/Jan/07 10:33 AM
trunk / 3.2