|
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) ) 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. I've attached a patch file for AbstractEntityJoinWalker.java, which should suffice in finishing of the Session portion of this problem.
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. In the future it would be great if the patches were not based on absolute paths, but rather paths relative to the project structure....
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? 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? 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 You are correct. The Syntax is "from table_name [ [AS] table_alias ] [ WITH ( <table_hint> [,...n]) ]".
|
||||||||||||||||||||||||||||||||||||||||||||||||||
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_