Hi,
I discovered a problem in the QuerySplitter, when executing a hql-query with more than two selected Objects.
e.g.
SELECT Customer, CustomerProperty, CustomerAddress
FROM CustomerProperty AS CustomerProperty, Customer AS Customer, CustomerAddress AS CustomerAddress
WHERE (
Customer.customerId = 5135 AND
Customer.customerId = CustomerProperty.customerId AND
Customer.customerId = CustomerAddress.customerId)
The QuerySplitter makes some strange assumption about when to substitute class names with persistent implementors.
It is explicitly said the following:
"make sure we don't pick up a class in the select clause!"
But the following hql is generated out of this:
SELECT
Customer,
eg.CustomerProperty,
CustomerAddress
FROM
eg.CustomerProperty AS CustomerProperty,
eg.Customer AS Customer,
eg.CustomerAddress AS CustomerAddress
WHERE
(Customer.customerId = 5135 AND
Customer.customerId = CustomerProperty.customerId AND
Customer.customerId = CustomerAddress.customerId)
As you can see, for the selected object in the middle, the name is replaced. This concludes out of some strange assumptions what to to after having parsed a comma.
This leads to the following exception:
java.lang.IllegalStateException: DOT node with no left-hand-side!
at org.hibernate.hql.ast.DotNode.getLhs(DotNode.java:488)
at org.hibernate.hql.ast.DotNode.getDataType(DotNode.java:467)
at org.hibernate.hql.ast.DotNode.resolveSelectExpression(DotNode.java:533)
at org.hibernate.hql.ast.HqlSqlWalker.resolveSelectExpression(HqlSqlWalker.java:471)
...
I created a little patch to QuerySplitter which solves this issue and works for me which is based on the assumption never to replace a class in the select clause. Perhaps someone here can comment on this and might consider it useful.
Code:
--- QuerySplitter.java 2005-03-31 23:44:28.000000000 +0200
+++ QuerySplitter-patched.java 2005-04-13 14:16:12.000000000 +0200
@@ -64,12 +64,21 @@
String last = null;
int nextIndex = 0;
String next = null;
+ boolean in_select_clause = false;
+
templateQuery.append( tokens[0] );
+ if ( "select".equals(tokens[0].toLowerCase()) )
+ in_select_clause = true;
+
for ( int i = 1; i < tokens.length; i++ ) {
//update last non-whitespace token, if necessary
if ( !ParserHelper.isWhitespace( tokens[i - 1] ) ) last = tokens[i - 1].toLowerCase();
+ // select-range is terminated by declaration of "from"
+ if ( "from".equals(tokens[i].toLowerCase()))
+ in_select_clause = false;
+
String token = tokens[i];
if ( !ParserHelper.isWhitespace( token ) || last == null ) {
@@ -82,7 +91,7 @@
}
if (
- Character.isJavaIdentifierStart( token.charAt( 0 ) ) && (
+ Character.isJavaIdentifierStart( token.charAt( 0 ) ) && !in_select_clause &&(
( BEFORE_CLASS_TOKENS.contains( last ) && !NOT_AFTER_CLASS_TOKENS.contains( next ) ) ||
"class".equals( last )
)