HHH-5727 Collection member declaration not handling optional AS in HQL.

This commit is contained in:
Strong Liu 2010-12-14 04:53:15 +08:00
parent 55e27c3825
commit 4c7983151c
5 changed files with 67 additions and 110 deletions

View File

@ -52,6 +52,13 @@ public class FromParser implements Parser {
private int joinType; private int joinType;
private boolean afterFetch; private boolean afterFetch;
//support collection member declarations
//e.g. "from Customer c, in(c.orders) as o"
private boolean memberDeclarations;
private boolean expectingPathExpression;
private boolean afterMemberDeclarations;
private String collectionName;
private static final int NONE = -666; private static final int NONE = -666;
private static final Map JOIN_TYPES = new HashMap(); private static final Map JOIN_TYPES = new HashMap();
@ -113,15 +120,33 @@ public class FromParser implements Parser {
afterClass = true; afterClass = true;
} }
else if ( lcToken.equals( "in" ) ) { else if ( lcToken.equals( "in" ) ) {
if ( !expectingIn ) throw new QueryException( "unexpected token: in" ); if (alias == null ){
memberDeclarations = true;
afterMemberDeclarations = false;
}
else if ( !expectingIn ) {
throw new QueryException( "unexpected token: in" );
} else {
afterIn = true; afterIn = true;
expectingIn = false; expectingIn = false;
} }
}
else if ( lcToken.equals( "as" ) ) { else if ( lcToken.equals( "as" ) ) {
if ( !expectingAs ) throw new QueryException( "unexpected token: as" ); if ( !expectingAs ) throw new QueryException( "unexpected token: as" );
afterAs = true; afterAs = true;
expectingAs = false; expectingAs = false;
} }
else if ( "(".equals( token ) ){
if( !memberDeclarations ) throw new QueryException( "unexpected token: (" );
//TODO alias should be null here
expectingPathExpression = true;
}
else if ( ")".equals( token ) ){
// memberDeclarations = false;
// expectingPathExpression = false;
afterMemberDeclarations = true;
}
else { else {
if ( afterJoinType ) throw new QueryException( "join expected: " + token ); if ( afterJoinType ) throw new QueryException( "join expected: " + token );
@ -141,6 +166,9 @@ public class FromParser implements Parser {
if ( entityName != null ) { if ( entityName != null ) {
q.setAliasName( token, entityName ); q.setAliasName( token, entityName );
} }
else if ( collectionName != null ) {
q.setAliasName( token, collectionName );
}
else { else {
throw new QueryException( "unexpected: as " + token ); throw new QueryException( "unexpected: as " + token );
} }
@ -148,6 +176,10 @@ public class FromParser implements Parser {
expectingJoin = true; expectingJoin = true;
expectingAs = false; expectingAs = false;
entityName = null; entityName = null;
collectionName = null;
memberDeclarations = false;
expectingPathExpression = false;
afterMemberDeclarations = false;
} }
else if ( afterIn ) { else if ( afterIn ) {
@ -180,6 +212,16 @@ public class FromParser implements Parser {
afterClass = false; afterClass = false;
expectingJoin = true; expectingJoin = true;
} }
else if( memberDeclarations && expectingPathExpression ){
expectingAs = true;
peParser.setJoinType( JoinFragment.INNER_JOIN );
peParser.setUseThetaStyleJoin( false );
ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
if ( !peParser.isCollectionValued() ) throw new QueryException( "path expression did not resolve to collection: " + token );
collectionName = peParser.addFromCollection( q );
expectingPathExpression = false;
memberDeclarations = false;
}
else { else {
// handle a path expression or class name that // handle a path expression or class name that
@ -238,6 +280,7 @@ public class FromParser implements Parser {
public void start(QueryTranslatorImpl q) { public void start(QueryTranslatorImpl q) {
entityName = null; entityName = null;
collectionName = null;
alias = null; alias = null;
afterIn = false; afterIn = false;
afterAs = false; afterAs = false;
@ -245,10 +288,18 @@ public class FromParser implements Parser {
expectingJoin = false; expectingJoin = false;
expectingIn = false; expectingIn = false;
expectingAs = false; expectingAs = false;
memberDeclarations = false;
expectingPathExpression = false;
afterMemberDeclarations = false;
joinType = NONE; joinType = NONE;
} }
public void end(QueryTranslatorImpl q) { public void end(QueryTranslatorImpl q) {
if( afterMemberDeclarations ){
//The exception throwned by the AST query translator contains the error token location, respensent by line and colum,
//but it hard to get that info here.
throw new QueryException("alias not specified for IN");
}
} }
} }

View File

@ -1,36 +0,0 @@
package org.hibernate.test.hql;
import java.util.HashSet;
import java.util.Set;
import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
@Entity
public class EntityBean {
@Id
@GeneratedValue
private Long id;
@OneToMany(cascade=CascadeType.ALL)
private Set<Item> items = new HashSet<Item>();
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public Set<Item> getItems() {
return items;
}
public void setItems(Set<Item> items) {
this.items = items;
}
}

View File

@ -1,39 +0,0 @@
package org.hibernate.test.hql;
import java.util.List;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.test.annotations.TestCase;
public class EntityBeanTest extends TestCase {
@Override
protected Class<?>[] getAnnotatedClasses() {
return new Class[]{EntityBean.class,Item.class};
}
public void testAAA(){
Session s=openSession();
s.beginTransaction();
Item item = new Item();
item.setItemValue("1");
EntityBean eb = new EntityBean();
eb.getItems().add(item);
item=new Item();
item.setItemValue("2");
eb.getItems().add(item);
s.persist(eb);
s.getTransaction().commit();
s.close();
s=openSession();
s.beginTransaction();
Query query = s.createQuery("SELECT o FROM EntityBean AS o, IN (o.items) l WHERE l.itemValue = '1'");
List list = query.list();
assertEquals(list.size(), 1);
s.getTransaction().commit();
s.close();
}
}

View File

@ -145,6 +145,19 @@ public class HQLTest extends QueryTranslatorTestCase {
assertTranslation( "select h from Human as h join fetch h.nickNames" ); assertTranslation( "select h from Human as h join fetch h.nickNames" );
} }
public void testCollectionMemberDeclarations() {
assertTranslation( "from Customer c, in(c.orders) o" );
assertTranslation( "from Customer c, in(c.orders) as o" );
assertTranslation( "select c.name from Customer c, in(c.orders) as o where c.id = o.id.customerId" );
}
public void testCollectionMemberDeclarationsFailureExpected(){
// both these two query translators throw exeptions for this HQL since
// IN asks an alias, but the difference is that the error message from AST
// contains the error token location (by lines and columns), which is hardly
// to get from Classic query translator --stliu
assertTranslation( "from Customer c, in(c.orders)" );
}
public void testCollectionJoinsInSubselect() { public void testCollectionJoinsInSubselect() {
// caused by some goofiness in FromElementFactory that tries to // caused by some goofiness in FromElementFactory that tries to
// handle correlated subqueries (but fails miserably) even though this // handle correlated subqueries (but fails miserably) even though this

View File

@ -1,32 +0,0 @@
package org.hibernate.test.hql;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
@Entity
public class Item {
@Id
@GeneratedValue
private Long id;
private String itemValue;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getItemValue() {
return itemValue;
}
public void setItemValue(String itemValue) {
this.itemValue = itemValue;
}
}