keywords as parameter names

Description

Query worked fine using Hibernate 4.2.10
Query borked using Hibernate 4.2.12
query in question:
delete from com.mrbear.Transactionrelation trel where trel.timeperiod = :TIMEPERIOD and trel.krlObject = :OBJECT and not exists ( select '' from com.mrbear.Taxationtransaction tatr where tatr.transactionrelation.transactionRelationNr = trel.transactionRelationNr )

The problem disappears when I rename :OBJECT to :KRLOBJECT.

It is possible that OBJECT is a keyword in HQL and not allowed to be used, but why then did it work in the previous version of Hibernate (4.2.10)?

I hope you can reproduce it.

Environment

Hibernate 4.2.12/Java 7/JBoss AS 7.1.3 Final
Oracle Database 11g Enterprise Edition Release 11.2.0.3.0 - 64bit Production

Activity

Show:
Gail Badner
May 13, 2014, 11:06 PM

I've added 2 tests to ASTParserLoadingTest that reproduce this issue: testClassAsParameter() (using a parameter name "class"), and testClassAsParameter() (using a parameter named "OBJECT").

It's been pushed to 4.2, 4.3, and master.

On 4.2, it was introduced by the first commit for HHH-9100: 6cef805a328c7490671f82c8390cc37b79b188ce .

Gail Badner
May 13, 2014, 11:10 PM

15:31:41,973 DEBUG QueryTranslatorImpl:267 - parse() - HQL: from org.hibernate.test.hql.Human h where h.name = :OBJECT
15:31:41,973 ERROR ErrorCounter:54 - line 1:52: unexpected token: :
15:31:41,973 ERROR ErrorCounter:50 - line 1:52: unexpected token: :
line 1:52: unexpected token: :
at org.hibernate.hql.internal.antlr.HqlBaseParser.atom(HqlBaseParser.java:3608)
at org.hibernate.hql.internal.antlr.HqlBaseParser.unaryExpression(HqlBaseParser.java:3267)
at org.hibernate.hql.internal.antlr.HqlBaseParser.multiplyExpression(HqlBaseParser.java:3139)
at org.hibernate.hql.internal.antlr.HqlBaseParser.additiveExpression(HqlBaseParser.java:2844)
at org.hibernate.hql.internal.antlr.HqlBaseParser.concatenation(HqlBaseParser.java:582)
at org.hibernate.hql.internal.antlr.HqlBaseParser.relationalExpression(HqlBaseParser.java:2610)
at org.hibernate.hql.internal.antlr.HqlBaseParser.equalityExpression(HqlBaseParser.java:2566)
at org.hibernate.hql.internal.antlr.HqlBaseParser.negatedExpression(HqlBaseParser.java:2435)
at org.hibernate.hql.internal.antlr.HqlBaseParser.logicalAndExpression(HqlBaseParser.java:2351)
at org.hibernate.hql.internal.antlr.HqlBaseParser.logicalOrExpression(HqlBaseParser.java:2316)
at org.hibernate.hql.internal.antlr.HqlBaseParser.expression(HqlBaseParser.java:2026)
at org.hibernate.hql.internal.antlr.HqlBaseParser.logicalExpression(HqlBaseParser.java:1802)
at org.hibernate.hql.internal.antlr.HqlBaseParser.whereClause(HqlBaseParser.java:466)
at org.hibernate.hql.internal.antlr.HqlBaseParser.queryRule(HqlBaseParser.java:722)
at org.hibernate.hql.internal.antlr.HqlBaseParser.selectStatement(HqlBaseParser.java:308)
at org.hibernate.hql.internal.antlr.HqlBaseParser.statement(HqlBaseParser.java:171)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.parse(QueryTranslatorImpl.java:268)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.doCompile(QueryTranslatorImpl.java:182)
at org.hibernate.hql.internal.ast.QueryTranslatorImpl.compile(QueryTranslatorImpl.java:138)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:104)
at org.hibernate.engine.query.spi.HQLQueryPlan.<init>(HQLQueryPlan.java:79)
at org.hibernate.engine.query.spi.QueryPlanCache.getHQLQueryPlan(QueryPlanCache.java:168)
at org.hibernate.internal.AbstractSessionImpl.getHQLQueryPlan(AbstractSessionImpl.java:222)
at org.hibernate.internal.AbstractSessionImpl.createQuery(AbstractSessionImpl.java:200)
at org.hibernate.internal.SessionImpl.createQuery(SessionImpl.java:1703)
at org.hibernate.test.hql.ASTParserLoadingTest.testObjectAsParameter(ASTParserLoadingTest.java:295)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:45)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:42)
at org.hibernate.testing.junit4.ExtendedFrameworkMethod.invokeExplosively(ExtendedFrameworkMethod.java:63)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.junit.internal.runners.statements.FailOnTimeout$StatementThread.run(FailOnTimeout.java:62)

Steve Ebersole
May 15, 2014, 2:44 PM

For reasons I cannot fully explain, adding the semantic predicates to the atom rule caused the prediction checks in the generated parser to be very different. As far as I can tell our use of k=3 in the grammar also comes into play as the predictions were checking 3 tokens out. The end result being that after COLON the parser was always looking specifically for IDENT (not allowing for keyword-turned-ident). Moving the semantic predicates (and therefore recognition of CAST/FUNCTION) to primaryExpression instead fixed the problem.

This part of the grammar (atom/primaryExpression and related sub-rules) is a mess imo. It tries to generically handle too many cases. However refactoring them to be more readable would require major changes and is best left for the new parser

Steve Ebersole
May 15, 2014, 10:00 PM
Edited

From Gail:

... need to get a list of reserved words, at least those that were affected by this bug.

I tried a couple of random tokens in hql.g and they did not cause a problem without the fix. Do you know what other than "class" and "OBJECT" would be affected? I did notice that things like "claSs" and "object" were also affected by by the bug, so case doesn't matter.

Did this bug only affect named parameters?

It should only affect named parameters, specifically named parameters whose name is recognized as something other than an IDENT in the lexer. This will be any tokens whose text is explicitly named in the grammar (the hql.g file). As an example, look at the difference in how the ALL (or OBJECT or CLASS) token is defined versus say the FIRST token:

This difference has an effect on the lexer. The lexer, based on the above declarations, will recognized the character sequence "all" (any case) as a token with type ALL (not IDENT!!!) and text "all". Whereas it will recognize the character sequence "first" as a token with type IDENT and text "first".

Using "all" or "object" or "class" (or any other "token literals") as a named parameter name will trigger this; meanwhile, using ":first" as a named parameter should be fine. So look through hql.g and find all the defined tokens that assign a text literal... those are the words that will trigger this if used as a named parameter name. There are some others, but this rule covers most cases.

Maarten van Leunen
May 17, 2014, 8:26 PM

Thanks very much for the extensive explanation. I'll keep it in mind, when writing HQL queries.

Assignee

Steve Ebersole

Reporter

Maarten van Leunen

Fix versions

backPortable

None

Suitable for new contributors

None

Requires Release Note

Affirmative

Pull Request

None

backportDecision

None

Components

Affects versions

Priority

Minor
Configure