|
From: <hib...@li...> - 2006-05-02 14:29:35
|
Author: ste...@jb...
Date: 2006-05-02 10:26:06 -0400 (Tue, 02 May 2006)
New Revision: 9851
Removed:
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/RangeNode.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContext.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContextImpl.java
Modified:
branches/HQL_ANTLR_2/Hibernate3/grammar/hql-resolve.g
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinNode.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReference.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyReference.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/StatementNode.java
branches/HQL_ANTLR_2/Hibernate3/test/org/hibernate/test/hql/HqlResolverTest.java
Log:
further join structure work plus property-reference stuff
Modified: branches/HQL_ANTLR_2/Hibernate3/grammar/hql-resolve.g
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/grammar/hql-resolve.g 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/grammar/hql-resolve.g 2006-05-02 14:26:06 UTC (rev 9851)
@@ -4,8 +4,6 @@
package org.hibernate.hql.antlr;
import java.util.*;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
}
/**
@@ -41,34 +39,50 @@
// -- Declarations --
{
- private static Log log = LogFactory.getLog( HqlBaseResolver.class );
- // Semantic action methods, overridden in subclasses for clarity.
+ // Statement node BEGIN/END handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- protected void pushContext(AST outputAst,AST inputAst) { }
+ protected void pushStatement(AST statementNode) {
+ }
- protected void popContext() { }
+ protected void popStatement() {
+ }
- protected void defineRange(AST range,String path,AST alias, AST fetch) { }
+ // persister reference handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
protected AST buildEntityPersisterReference(String entityName, AST alias) {
return null;
}
- protected AST buildThetaJoinNode(AST persisterReference) {
- return null;
+ protected void handleExplicitPropertyJoin(
+ AST propertyReference,
+ AST alias,
+ AST joinType,
+ AST fetch,
+ AST propertyFetch,
+ AST withClause) {
}
- protected AST buildExplicitPropertyJoinNode(AST propertyReference, AST alias, AST joinType, AST fetch, AST propertyFetch, AST withClause) {
- return null;
+ protected void handleAdHocJoinNode(
+ AST persisterReference,
+ AST joinType,
+ AST onClause) {
}
- protected AST buildAdHocJoinNode(AST persisterReference, AST joinType, AST onClause) {
+ protected boolean isEntityName(String test) {
+ return false;
+ }
+
+
+ // property reference handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ protected AST resolveAtomicPropertyReference(AST propertyIdent) {
return null;
}
- protected boolean isEntityName(String test) {
- return false;
+ protected AST resolveCompoundPropertyReference(AST dotStructure) {
+ return null;
}
}
@@ -84,22 +98,19 @@
;
updateStatement
- : #(UPDATE (VERSIONED)? fromClause setClause (whereClause)?
- { popContext(); } )
+ : #(UPDATE { pushStatement( #updateStatement ); } (VERSIONED)? fromClause setClause (whereClause)? { popStatement(); })
;
deleteStatement
- : #(DELETE fromClause (whereClause)?
- { popContext(); } )
+ : #(DELETE { pushStatement( #deleteStatement ); } fromClause (whereClause)? { popStatement(); })
;
insertStatement
- : #(INSERT intoClause query
- { popContext(); } )
+ : #(INSERT { pushStatement( #insertStatement ); } intoClause query { popStatement(); })
;
query
- : #(QUERY
+ : #(QUERY { pushStatement( #query ); }
// The first phase places the FROM first to make processing the SELECT simpler.
#(SELECT_FROM
fromClause
@@ -107,8 +118,9 @@
)
(whereClause)?
(groupClause)?
- (orderClause)?
- { popContext(); }
+ (orderClause)? {
+ popStatement();
+ }
)
;
@@ -120,8 +132,7 @@
fromClause
-// : #( f:FROM { pushContext(#fromClause, f); } entityPersisterReference ( thetaJoin | explicitJoin )* )
- : #( f:FROM { pushContext(#fromClause, f); } range ( thetaJoin | explicitJoin )* )
+ : #( f:FROM ( range | explicitJoin )* )
;
range!
@@ -138,28 +149,28 @@
}
;
-thetaJoin!
-// : #( COMMA e:entityPersisterReference ) {
-// #thetaJoin = buildThetaJoinNode( e );
-// }
- : r:range {
- #thetaJoin = buildThetaJoinNode( #r );
- }
- ;
-
explicitJoin!
: #(JOIN (jt:joinType)? joinRhs[jt] )
;
-joinRhs [AST joinType]
+joinRhs! [AST joinType]
: { isEntityName( pathAsString( _t ) ) }? e:entityPersisterReference (on:ON)? {
- buildAdHocJoinNode( #e, joinType, on );
+ handleAdHocJoinNode( #e, joinType, on );
}
- | (f:FETCH)? ref:propertyRef[true] (a:ALIAS)? (pf:FETCH)? (with:WITH)? {
- buildExplicitPropertyJoinNode( #ref, a, joinType, f, pf, with );
+ | (f:FETCH)? prop:joinedProperty (a:ALIAS)? (pf:FETCH)? (with:WITH)? {
+ handleExplicitPropertyJoin( #prop, a, joinType, f, pf, with );
}
;
+joinedProperty!
+ : i:identifier {
+ #joinedProperty = #( [DOT, "."], i );
+ }
+ | d:dotRootStructure {
+ #joinedProperty = #d;
+ }
+ ;
+
// TODO : need to add cross joins
joinType
: ( (LEFT | RIGHT) (OUTER)? )
@@ -168,7 +179,7 @@
;
intoClause
- : #(i:INTO { pushContext(#intoClause,i); } (subtree)* )
+ : #(i:INTO (subtree)* )
;
whereClause
@@ -232,8 +243,8 @@
;
collectionFunction
- : #(ELEMENTS propertyRef [true] )
- | #(INDICES propertyRef [true] )
+ : #( ELEMENTS propertyRef )
+ | #( INDICES propertyRef )
;
count
@@ -270,7 +281,7 @@
;
addrExpr
- : propertyRef [true]
+ : propertyRef
| #(INDEX_OP addrExprLhs expr)
;
@@ -303,27 +314,62 @@
| #(AGGREGATE aggregateExpr )
;
-propertyRef! [ boolean root ]
+// property references come in 3 basic flavors:
+// (1) "simple" (either qualified or unqualified) : represents a reference to
+// a value-type property
+// (2) "nested" (either qualified or unqualified) : represents a series of
+// property references which result in "implicit joins" being
+// generated
+// (3) "indexed" (either qualified or unqualified) : represents indexed access
+// into an indexed collection such as a map or list
+//
+// an additional consideration when dealing with property references is the question
+// of qualified vs unqualified references. Qualified references are "rooted" at an
+// alias pointing to a particular persister reference, while unqualified references
+// do not start with any such alias. Thus the "root" of the property reference
+// structure may or may not begin with an explicit reference to a persister
+// (via an alias). If qualified, the appropriate persister reference is simply looked
+// up based on the alias. If unqualified, all non-aliased persister references are
+// searched for one containing the indicated property; if one (and only one) is found
+// then it is assumed to be the referenced persister; all other cases here are an error.
+//
+// Both "nested" and "indexed" property references may result in additional joins
+// being added to the current from-clause structure implicitly.
+propertyRef!
: i:identifier {
- if (root) { // Make the tree very regular, property refs always have a child.
- #propertyRef = #([PROPERTY_REF,#i.getText()],#i);
- }
- else { // Otherwise, just construct the tree.
- #propertyRef = #i;
- }
+ #propertyRef = resolveAtomicPropertyReference( #i );
}
- | #(d:DOT lhs:propertyRef [ false ] rhs:propertyName ) {
- // Flatten nested DOTs...
+ | d:dotRootStructure {
+ #propertyRef = resolveCompoundPropertyReference( #d );
+ }
+ ;
+
+dotRootStructure!
+ : #( d:DOT lhs:dotSubStructure rhs:dotStructureAtomic ) {
AST first = (#lhs.getType() == DOT) ? #lhs.getFirstChild() : #lhs;
- if (root) { // If this is the root of the path tree, then make a property ref node.
- #propertyRef = #([PROPERTY_REF,#d.getText()],first,#rhs);
- }
- else { // If this is not the root of the path tree, then just flatten it.
- #propertyRef = #(#d,first,#rhs);
- }
+ #dotRootStructure = #( [DOT, "."], first, #rhs );
}
;
+// reuseable rule to provide DOT structure flattening;
+// eventually, this will get moved to the first phase as DOT
+// structures are recognized there, but that needs to wait till
+// we integrate this phase into the overall translation...
+dotSubStructure!
+ : i:identifier {
+ // indicates we are at the base IDENT of the dot structure
+ #dotSubStructure = #i;
+ }
+ | #( d:DOT lhs:dotSubStructure rhs:dotStructureAtomic ) {
+ AST first = (#lhs.getType() == DOT) ? #lhs.getFirstChild() : #lhs;
+ #dotSubStructure = #( #d, first, #rhs );
+ }
+ ;
+
+dotStructureAtomic
+ : propertyName
+ ;
+
propertyName
: identifier
| CLASS
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -1,34 +1,108 @@
package org.hibernate.hql.ast.resolve;
import org.hibernate.type.AssociationType;
-import org.hibernate.hql.ast.tree.Node;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+import org.hibernate.type.ComponentType;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.hql.CollectionProperties;
+import org.hibernate.QueryException;
/**
* @author Steve Ebersole
*/
-public class CollectionPersisterReference extends Node implements PersisterReference {
- // TODO : implement
+public class CollectionPersisterReference extends EntityPersisterReference implements ResolverAware {
+
+ private HqlResolver resolver;
+ private String role;
+ private String alias;
+ private QueryableCollection persister;
+
+ public void initialize(String role, String alias) {
+ this.role = role;
+ this.alias = alias;
+ }
+
+ public QueryableCollection getCollectionPersister() {
+ if ( persister == null ) {
+ persister = ( QueryableCollection ) resolver.getSessionFactory().getCollectionPersister( role );
+ }
+ return persister;
+ }
+
+ public Queryable getEntityPersister() {
+ if ( getCollectionPersister().getElementType().isEntityType() ) {
+ EntityType elementEntityType = ( EntityType ) getCollectionPersister().getElementType();
+ return ( Queryable ) elementEntityType.getAssociatedJoinable( resolver.getSessionFactory() );
+ }
+ else {
+ throw new QueryException( "not a collection of entities" );
+ }
+ }
+
public String getName() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ return role;
}
public String getAlias() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ return alias;
}
public AssociationType getPersisterType() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ return ( AssociationType ) getEntityPersister().getType();
}
+ public Type getPropertyType(String propertyName) {
+ if ( CollectionProperties.isAnyCollectionProperty( propertyName ) ) {
+ // todo
+ return null;
+ }
+ else {
+ Type elementType = getCollectionPersister().getElementType();
+ if ( elementType.isAssociationType() ) {
+ // a collection of entities
+ EntityType elementEntityType = ( EntityType ) elementType;
+ try {
+ Queryable elementEntityPersister = ( Queryable ) elementEntityType
+ .getAssociatedJoinable( resolver.getSessionFactory() );
+ return elementEntityPersister.getPropertyType( propertyName );
+ }
+ catch( Throwable t ) {
+ // ignore
+ }
+ }
+ else if ( elementType.isComponentType() ) {
+ ComponentType elementComponentType = ( ComponentType ) elementType;
+ String[] subPropertyNames = elementComponentType.getPropertyNames();
+ for ( int i = 0; i < subPropertyNames.length; i++ ) {
+ if ( subPropertyNames[i].equals( propertyName ) ) {
+ return elementComponentType.getSubtypes()[i];
+ }
+ }
+ }
+ }
+ return null;
+ }
+
public boolean containsProperty(String propertyName) {
- return false; //To change body of implemented methods use File | Settings | File Templates.
+ // this should not be called for "collection properties" (i.e., size, index, etc)
+ // so we make that assumption here...
+ try {
+ return getPropertyType( propertyName ) != null;
+ }
+ catch( Throwable t ) {
+ // ignore
+ }
+ return false;
}
- public PropertyReference retrievePropertyReference(String propertyName) {
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ public void setHqlResolver(HqlResolver resolver) {
+ this.resolver = resolver;
}
- public String getDisplayText() {
- return null; //To change body of implemented methods use File | Settings | File Templates.
+ public String toString() {
+ return "CollectionPersisterReference {role=" + getName() + ", alias=" + getAlias() +
+ ", element-type=" + getCollectionPersister().getElementType() + "}";
}
}
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -1,39 +1,34 @@
package org.hibernate.hql.ast.resolve;
import org.hibernate.type.AssociationType;
+import org.hibernate.type.Type;
import org.hibernate.persister.entity.Queryable;
-import org.hibernate.hql.antlr.HqlRTokenTypes;
-import org.hibernate.hql.ast.tree.Node;
-import org.hibernate.engine.SessionFactoryImplementor;
/**
* @author Steve Ebersole
*/
-public class EntityPersisterReference extends Node implements PersisterReference, SessionFactoryAwareNode {
+public class EntityPersisterReference extends PersisterReference implements ResolverAware {
private String entityName;
private String alias;
- private SessionFactoryImplementor sessionFactory;
- private transient Queryable persister;
- public EntityPersisterReference() {
- super();
- super.setType( HqlRTokenTypes.ENTITY_PERSISTER_REF );
- }
+ private HqlResolver resolver;
+ private transient Queryable persister;
+
public void initialize(String entityName, String alias) {
this.entityName = entityName;
this.alias = alias;
}
- public Queryable getPersister() {
+ public Queryable getEntityPersister() {
if ( persister == null ) {
- persister = ( Queryable ) sessionFactory.getEntityPersister( entityName );
+ persister = ( Queryable ) resolver.getSessionFactory().getEntityPersister( entityName );
}
return persister;
}
public String getName() {
- return alias == null ? entityName : entityName + " (" + alias + ")";
+ return entityName;
}
public String getAlias() {
@@ -41,34 +36,27 @@
}
public AssociationType getPersisterType() {
- return ( AssociationType ) persister.getType();
+ return ( AssociationType ) getEntityPersister().getType();
}
+ public Type getPropertyType(String propertyName) {
+ return getEntityPersister().getPropertyType( propertyName );
+ }
+
public boolean containsProperty(String propertyName) {
try {
- return persister.getPropertyType( propertyName ) != null;
+ return getPropertyType( propertyName ) != null;
}
catch( Throwable t ) {
return false;
}
}
- public PropertyReference retrievePropertyReference(String propertyName) {
- return null;
- }
-
- public String getDisplayText() {
- return "{" +
- "entityName='" + entityName + '\'' +
- ", alias='" + alias + '\'' +
- '}';
- }
-
public String toString() {
- return "EntityPersisterReference" + getDisplayText();
+ return "EntityPersisterReference {entity-name=" + entityName + ", alias=" + alias + "}";
}
- public void setSessionFactory(SessionFactoryImplementor sessionFactory) {
- this.sessionFactory = sessionFactory;
+ public void setHqlResolver(HqlResolver resolver) {
+ this.resolver = resolver;
}
}
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -1,128 +1,187 @@
package org.hibernate.hql.ast.resolve;
import org.hibernate.hql.antlr.HqlBaseResolver;
+import org.hibernate.hql.CollectionProperties;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.QueryException;
+import org.hibernate.type.Type;
+import org.hibernate.type.ComponentType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
-import java.util.List;
-import java.util.ArrayList;
import antlr.collections.AST;
/**
- * Implements the methods for the HqlBaseResolver.
- * <br>User: Joshua Davis
- * Date: Apr 1, 2006
- * Time: 7:40:42 AM
+ * Adds specific semantic action behavior needed to perform useful resolution.
+ *
+ * @author Joshua Davis
+ * @author Steve Ebersole
*/
public class HqlResolver extends HqlBaseResolver {
private static Log log = LogFactory.getLog( HqlResolver.class );
private final SessionFactoryImplementor sessionFactory;
- private final ResolverContext resolverContext;
+ private StatementNode currentStatement;
- private int level = 0;
- private List inputContext = new ArrayList();
- private List outputContext = new ArrayList();
-
public HqlResolver(SessionFactoryImplementor sessionFactory) {
super();
this.sessionFactory = sessionFactory;
- setASTFactory( new HqlResolverASTFactory( sessionFactory ) );
- this.resolverContext = new ResolverContextImpl( sessionFactory, getASTFactory() );
+ setASTFactory( new HqlResolverASTFactory( this ) );
}
+ public SessionFactoryImplementor getSessionFactory() {
+ return sessionFactory;
+ }
- protected void pushContext(AST outputAst,AST inputAst) {
- level++;
- inputContext.add(inputAst);
- outputContext.add(outputAst);
- if (log.isDebugEnabled()) {
- log.debug("Pushed context: level = " + level + " input is " + inputAst.toStringTree());
- }
+ public PersisterReferenceContext getPersisterReferenceContext() {
+ return currentStatement;
}
- protected void popContext() {
- level--;
- AST n = (AST)inputContext.remove(inputContext.size() - 1);
- outputContext.remove(outputContext.size() - 1);
- if (log.isDebugEnabled()) {
- log.debug("Popped context: level = " + level + " input was " + n.toStringTree());
+ protected void pushStatement(AST statementNode) {
+ log.trace( "pushing new statement context : " + currentStatement + " -> " + statementNode );
+ StatementNode statement = ( StatementNode ) statementNode;
+ if ( currentStatement != null ) {
+ currentStatement.pushChild( statement );
}
+ currentStatement = statement;
}
- protected AST getCurrentContext(boolean input) {
- return (AST)((input) ? inputContext.get(inputContext.size() - 1)
- : outputContext.get(outputContext.size() - 1));
+ protected void popStatement() {
+ log.trace( "popping statement context : " + currentStatement + " -> " + currentStatement.getParentStatement() );
+ currentStatement = currentStatement.getParentStatement();
}
- protected int getLevel() { return level; }
-
- protected void defineRange(AST range, String path, AST alias, AST fetch) {
- RangeNode r = (RangeNode) range;
- r.setPath(path);
- r.setPersisterReference( resolverContext.getEntityPersisterReference( path, alias == null ? null : alias.getText() ) );
- r.setFetch(fetch != null);
- r.setAlias(alias != null ? alias.getText() : null);
- }
-
protected AST buildEntityPersisterReference(String entityName, AST alias) {
- return resolverContext.getEntityPersisterReference( entityName, alias == null ? null : alias.getText() );
+ return currentStatement.buildEntityPersisterReference( entityName, alias == null ? null : alias.getText() );
}
- protected AST buildThetaJoinNode(AST persisterReference) {
- JoinNode join = createJoinNode( JoinType.FULL, JoinSource.THETA, false );
- join.setFirstChild( persisterReference );
- return join;
- }
-
- private JoinNode createJoinNode(JoinType type, JoinSource source, boolean fetch) {
+ private JoinNode createJoinNode(JoinType type, JoinSource source, boolean fetch, PersisterReference rhs) {
JoinNode node = ( JoinNode ) getASTFactory().create( JOIN, "join" );
- node.initialize( type, source, fetch );
+ node.initialize( type, source, fetch, rhs );
+ rhs.addChild( node );
return node;
}
- protected AST buildExplicitPropertyJoinNode(
- AST propertyReference,
- AST alias,
- AST joinType,
- AST fetch,
- AST propertyFetch,
- AST withClause) {
- JoinNode join = createJoinNode( resolveJoinType( joinType ), JoinSource.EXPLICIT, fetch != null );
- join.setFirstChild( propertyReference );
- if ( withClause != null ) {
- join.addChild( withClause );
+ /**
+ * Parser has recognized an explicit join based on a "property join".
+ * <p/>
+ * For example, something like: <tt>from Animal a join a.mother</tt> or
+ * <tt>from Animal a join a.mother.mother as gm</tt> or even
+ * <tt>from Animal join mother</tt>
+ * <p/>
+ * Here, we will need to resolve the explicit join, as well as handle any
+ * implied joins.
+ * </p>
+ * Note that any implicit joins here are handled rather differently than
+ * implicit joins in any clause other than an explicit join. See
+ * {@link #resolveCompoundPropertyReference} for the differences. Mainly, the
+ * differences are:<ul>
+ * </ul>
+ *
+ * @param propertyPath The property(s) being joined to, which may indicate
+ * additional implicit joins are intended.
+ * @param aliasNode The alias to be applied to the generated persister reference
+ * @param joinTypeNode The type of join indicated
+ * @param fetchNode Was relation fetching specified?
+ * @param propertyFetchNode Was property fetching specified?
+ * @param withClauseNode Any with clause.
+ */
+ protected void handleExplicitPropertyJoin(
+ AST propertyPath,
+ AST aliasNode,
+ AST joinTypeNode,
+ AST fetchNode,
+ AST propertyFetchNode,
+ AST withClauseNode) {
+ JoinType joinType = resolveJoinType( joinTypeNode );
+ String alias = aliasNode == null ? null : aliasNode.getText();
+ boolean relationFetch = fetchNode != null;
+ boolean propertyFetch = propertyFetchNode != null;
+
+ // propertyPath should be a "flattened" dot node structure, which always have at least one child
+ AST next = null;
+ String firstPathExpression = propertyPath.getFirstChild().getText();
+ EntityPersisterReference root = resolveRootAsAlias( firstPathExpression );
+ if ( root != null ) {
+ // the root of the path expression is an alias referencing a persister reference,
+ // so the alias itself has essentially been resolved already, so "consume it"
+ next = propertyPath.getFirstChild().getNextSibling();
}
- return join;
+ else {
+ // otherwise, the expectation is that the root of the path expression is an
+ // unqualified property reference, in which case we essentially use the
+ // root as a look ahead, and now need to actually resolve it
+ root = resolveRootAsUnqualified( firstPathExpression );
+ if ( root == null ) {
+ throw new QueryException( "unable to determine root of path expression [" + reconstitutePathString( propertyPath ) + "]" );
+ }
+ next = propertyPath.getFirstChild();
+ }
+
+ // At this point, we know the persister which acts as the root or base (root) of the
+ // path structure (propertyPath), as well as the first actual path expression which
+ // needs resolving (next). So now, we need to start iterating all the path
+ // expressions and performing the resolutions.
+ PersisterReference lhs = root;
+ JoinSource joinSource = JoinSource.EXPLICIT;
+ boolean firstPass = true;
+ while ( next != null ) {
+ // todo : components?
+ boolean isLast = next.getNextSibling() == null;
+
+ JoinNode joinNode = createJoinNode( joinType, joinSource, relationFetch, lhs );
+ PersisterReference rhs = currentStatement.getPersisterReference( lhs, next.getText(), isLast ? alias : null );
+ joinNode.addChild( rhs );
+
+ if ( isLast && withClauseNode != null ) {
+ joinNode.addChild( withClauseNode );
+ }
+
+ if ( firstPass ) {
+ firstPass = false;
+ joinSource = JoinSource.IMPLICIT;
+ }
+
+ lhs = rhs;
+ next = next.getNextSibling();
+ }
+
}
- protected AST buildAdHocJoinNode(AST persisterReference, AST joinType, AST onClause) {
- JoinNode join = createJoinNode( resolveJoinType( joinType ), JoinSource.AD_HOC, false );
+ protected void handleAdHocJoinNode(AST persisterReference, AST joinType, AST onClause) {
+ // todo : need to be able to resolve the lhs join operand
+ EntityPersisterReference other = null;
+ JoinNode join = createJoinNode( resolveJoinType( joinType ), JoinSource.AD_HOC, false, other );
join.setFirstChild( persisterReference );
if ( onClause != null ) {
join.addChild( onClause );
}
- return join;
}
private JoinType resolveJoinType(AST joinType) {
- if ( joinType.getType() == LEFT ) {
- return JoinType.LEFT;
+ int joinTypeType = joinType == null ? INNER : joinType.getType();
+ switch ( joinTypeType ) {
+ case INNER:
+ return JoinType.INNER;
+ case LEFT:
+ return JoinType.LEFT;
+ case RIGHT:
+ return JoinType.RIGHT;
+ case FULL:
+ return JoinType.FULL;
}
- else if ( joinType.getType() == RIGHT ) {
- return JoinType.RIGHT;
- }
- else if ( joinType.getType() == FULL ) {
- return JoinType.FULL;
- }
- else {
- throw new QueryException( "Unrecognized join type [" + joinType.getText() + "]" );
- }
+ // if no match found, throw exception
+ throw new QueryException( "Unrecognized join type [" + joinType.getText() + "]" );
}
+ public PersisterReference buildPropertyJoin(PersisterReference source, String propertyName, String alias) {
+ JoinNode join = createJoinNode( JoinType.INNER, JoinSource.IMPLICIT, false, source );
+ PersisterReference persisterReference = currentStatement.getPersisterReference( source, propertyName, alias );
+ join.addChild( persisterReference );
+ return persisterReference;
+ }
+
protected boolean isEntityName(String test) {
try {
return sessionFactory.getEntityPersister( test ) != null;
@@ -133,4 +192,277 @@
return false;
}
+ protected String reconstitutePathString(AST propertyReference) {
+ AST child = propertyReference.getFirstChild();
+ String prefix = "";
+ StringBuffer buffer = new StringBuffer();
+ while ( child != null ) {
+ buffer.append( prefix ).append( child.getText() );
+ prefix = ".";
+ child = child.getNextSibling();
+ }
+ return buffer.toString();
+ }
+
+ protected AST resolveAtomicPropertyReference(AST propertyNode) {
+ EntityPersisterReference persisterReference = resolveRootAsUnqualified( propertyNode.getText() );
+ return generatePropertyReference( persisterReference, propertyNode.getText() );
+ }
+
+ private PropertyReference generatePropertyReference(PersisterReference persisterReference, String propertyName) {
+ PropertyReference propertyReferenceNode = ( PropertyReference ) getASTFactory()
+ .create( PROPERTY_REF, persisterReference.getAlias() + "." + propertyName );
+
+ AST aliasNode = getASTFactory().create( ALIAS, persisterReference.getAlias() );
+ propertyReferenceNode.addChild( aliasNode );
+
+ AST propertyNameNode = getASTFactory().create( IDENT, propertyName );
+ propertyReferenceNode.addChild( propertyNameNode );
+
+ return propertyReferenceNode;
+ }
+
+ protected AST resolveCompoundPropertyReference(AST dotStructure) {
+ PersisterReference persisterReference;
+ AST next;
+
+ // first, resolve root origin
+ String firstPathExpression = dotStructure.getFirstChild().getText();
+ if ( dotStructure.getNumberOfChildren() == 1 ) {
+ // can only really represent an unqualified simple property ref
+ EntityPersisterReference match = resolveRootAsUnqualified( firstPathExpression );
+ if ( match == null ) {
+ throw new QueryException( "unable to resolve property [" + firstPathExpression + "] as unqualified reference" );
+ }
+ persisterReference = match;
+ // the root of the path expression is an alias referencing a persister reference,
+ // so the alias itself has essentially been resolved already, so "consume it"
+ next = dotStructure.getFirstChild();
+ }
+ else {
+ // need to decide whether 'firstPathExpression' refers to a from-clause alias, or
+ // an unqualified property name. from-clause alias has a higher precedence
+ // for matching purposes, so try to resolve as alias first
+ EntityPersisterReference match = resolveRootAsAlias( firstPathExpression );
+ if ( match != null ) {
+ // the root of the path expression is an alias referencing a persister reference,
+ // so the alias itself has essentially been resolved already, so "consume it"
+ next = dotStructure.getFirstChild().getNextSibling();
+ }
+ else {
+ // then try as unqualified
+ match = resolveRootAsUnqualified( firstPathExpression );
+ if ( match != null ) {
+ // the root of the path expression is an unqualified property reference,
+ // in which case we essentially use the root as a look ahead, and now
+ // need to actually resolve it
+ next = dotStructure.getFirstChild();
+ }
+ else {
+ throw new QueryException( "unable to determine root of path expression [" + reconstitutePathString( dotStructure ) + "]" );
+ }
+ }
+ persisterReference = match;
+ }
+
+ PropertyPathPart propertySource = new PropertyPathRoot( ( EntityPersisterReference ) persisterReference );
+ String pathSoFar = persisterReference.getAlias();
+
+ while ( next != null && next.getNextSibling() != null ) {
+ String propertyName = next.getText();
+ pathSoFar += ( "." + propertyName );
+
+ PersisterReference built = currentStatement.locatePersisterReferenceByPath( pathSoFar );
+ if ( built != null ) {
+ propertySource = new PropertyPathRoot( ( EntityPersisterReference ) built );
+ }
+ else {
+ propertySource = propertySource.handleIntermediatePathPart( propertyName );
+ }
+
+ next = next.getNextSibling();
+ }
+
+ if ( next == null ) {
+ throw new QueryException( "illegal parser state" );
+ }
+ return propertySource.handleLeafPathPart( next.getText() );
+ }
+
+ private EntityPersisterReference resolveRootAsAlias(String firstPathExpression) {
+ return ( EntityPersisterReference ) currentStatement.locatePersisterReferenceByAlias( firstPathExpression );
+ }
+
+ private EntityPersisterReference resolveRootAsUnqualified(String firstPathExpression) {
+ return currentStatement.locatePersisterReferenceExposingProperty( firstPathExpression );
+ }
+
+ private PropertyPathPart determineAppropriatePartType(EntityPersisterReference origin, String propertyName) {
+ Type propertyType = origin.getPropertyType( propertyName );
+ if ( propertyType.isComponentType() ) {
+ return new ComponentPropertyReference( origin, propertyName, ( ComponentType ) propertyType );
+ }
+ else if ( propertyType.isEntityType() ) {
+ return new EntityPropertyReference( origin, propertyName, false );
+ }
+ else if ( propertyType.isCollectionType() ) {
+ return new CollectionPropertyReference( origin, propertyName );
+ }
+ else {
+ return new SimplePropertyReference( origin, propertyName );
+ }
+ }
+
+ private int locateComponentPropertyIndex(ComponentType componentType, String subPropertyName) {
+ String[] componentPropertyNames = componentType.getPropertyNames();
+ for ( int i = 0; i < componentPropertyNames.length; i++ ) {
+ if ( componentPropertyNames[i].equals( subPropertyName ) ) {
+ return i;
+ }
+ }
+ throw new QueryException( "could not locate component property [" + subPropertyName + "]" );
+ }
+
+ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // todo : this stuff needs to be finished up.
+ // specific things needing to be completed:
+ // (1) only dereference an actual entity association property into a
+ // join when it is further dereferenced (already handled) or when
+ // occuring in select clause
+ // (2) properly handle "collection properties"
+ // (3) properly handle components
+ // (4) properly handle index operations
+ //
+ // todo : look at utilizing this from handleExplicitPropertyJoin(...) also
+
+ /**
+ * Contract for handling delegation for a particular portion of an implicit
+ * join structure (aka property path).
+ */
+ private interface PropertyPathPart {
+ public PropertyPathPart handleIntermediatePathPart(String name);
+ public PropertyReference handleLeafPathPart(String name);
+ }
+
+ private class PropertyPathRoot implements PropertyPathPart {
+ private final EntityPersisterReference persisterReference;
+
+ public PropertyPathRoot(EntityPersisterReference persisterReference) {
+ this.persisterReference = persisterReference;
+ }
+
+ public PropertyPathPart handleIntermediatePathPart(String name) {
+ return determineAppropriatePartType( persisterReference, name );
+ }
+
+ public PropertyReference handleLeafPathPart(String name) {
+ // todo : this really needs to consider whether a join might be needed
+ // based on the property type and type of clause
+ return generatePropertyReference( persisterReference, name );
+ }
+
+ }
+
+ private class SimplePropertyReference implements PropertyPathPart {
+ private final EntityPersisterReference origin;
+ private final String propertyName;
+
+ public SimplePropertyReference(EntityPersisterReference origin, String propertyName) {
+ this.origin = origin;
+ this.propertyName = propertyName;
+ }
+
+ public PropertyPathPart handleIntermediatePathPart(String name) {
+ throw new QueryException( "cannot perform implicit join based on simple property" );
+ }
+
+ public PropertyReference handleLeafPathPart(String name) {
+ throw new QueryException( "cannot perform implicit join based on simple property" );
+ }
+ }
+
+ private class ComponentPropertyReference implements PropertyPathPart {
+ private final EntityPersisterReference origin;
+ private final String componentPropertyName;
+ private final ComponentType componentType;
+
+ public ComponentPropertyReference(EntityPersisterReference origin, String componentPropertyName) {
+ this( origin, componentPropertyName, ( ComponentType ) origin.getPropertyType( componentPropertyName ) );
+ }
+
+ public ComponentPropertyReference(EntityPersisterReference origin, String componentPropertyName, ComponentType componentType) {
+ this.origin = origin;
+ this.componentPropertyName = componentPropertyName;
+ this.componentType = componentType;
+ }
+
+ public PropertyPathPart handleIntermediatePathPart(String propertyName) {
+ int index = locateComponentPropertyIndex( componentType, propertyName );
+ String path = buildDerefPath( propertyName );
+ Type propertyType = componentType.getSubtypes()[index];
+ if ( propertyType.isComponentType() ) {
+ return new ComponentPropertyReference( origin, path, ( ComponentType ) propertyType );
+ }
+ else if ( propertyType.isEntityType() ) {
+ return new EntityPropertyReference( origin, path, false );
+ }
+ else {
+ return new SimplePropertyReference( origin, path );
+ }
+ }
+
+ public PropertyReference handleLeafPathPart(String name) {
+ return generatePropertyReference( origin, buildDerefPath( name ) );
+ }
+
+ private String buildDerefPath(String subPropertyName) {
+ return componentPropertyName + "." + subPropertyName;
+ }
+ }
+
+ private class EntityPropertyReference implements PropertyPathPart {
+ private final EntityPersisterReference origin;
+ private final String propertyName;
+
+ private boolean joined;
+
+ public EntityPropertyReference(EntityPersisterReference origin, String propertyName, boolean joined) {
+ this.origin = origin;
+ this.propertyName = propertyName;
+ this.joined = joined;
+ }
+
+ public PropertyPathPart handleIntermediatePathPart(String name) {
+ EntityPersisterReference joinedPersister = ( EntityPersisterReference ) buildPropertyJoin( origin, propertyName, null );
+ return determineAppropriatePartType( joinedPersister, name );
+ }
+
+ public PropertyReference handleLeafPathPart(String name) {
+ // not always needed (i.e. : .id)
+ EntityPersisterReference joinedPersister = ( EntityPersisterReference ) buildPropertyJoin( origin, propertyName, null );
+ return generatePropertyReference( joinedPersister, name );
+ }
+ }
+
+ private class CollectionPropertyReference implements PropertyPathPart {
+ private final EntityPersisterReference origin;
+ private final String collectionPropertyName;
+
+ public CollectionPropertyReference(EntityPersisterReference origin, String collectionPropertyName) {
+ this.origin = origin;
+ this.collectionPropertyName = collectionPropertyName;
+ }
+
+ public PropertyPathPart handleIntermediatePathPart(String name) {
+ throw new QueryException( "illegal attempt to perform implicit join across collection property" );
+ }
+
+ public PropertyReference handleLeafPathPart(String name) {
+ if ( CollectionProperties.isAnyCollectionProperty( name ) ) {
+ CollectionPersisterReference joinedPersister = ( CollectionPersisterReference ) buildPropertyJoin( origin, collectionPropertyName, null );
+ return generatePropertyReference( joinedPersister, name );
+ }
+ throw new QueryException( "illegal attempt to perform implicit join across collection property" );
+ }
+ }
}
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -13,30 +13,33 @@
* Time: 7:58:16 AM
*/
public class HqlResolverASTFactory extends HqlASTFactory implements HqlRTokenTypes {
- private final SessionFactoryImplementor factory;
+ private final HqlResolver resolver;
- public HqlResolverASTFactory(SessionFactoryImplementor factory) {
- this.factory = factory;
+ public HqlResolverASTFactory(HqlResolver resolver) {
+ this.resolver = resolver;
}
public Class getASTNodeType(int tokenType) {
// Statement nodes:
switch (tokenType) {
- case QUERY :
+ case QUERY:
+ return SelectStatementNode.class;
case UPDATE:
+ return UpdateStatementNode.class;
case DELETE:
+ return DeleteStatementNode.class;
case INSERT:
- return StatementNode.class;
- case RANGE:
- return RangeNode.class;
+ return InsertStatementNode.class;
case ENTITY_PERSISTER_REF:
return EntityPersisterReference.class;
case COLLECTION_PERSISTER_REF:
return CollectionPersisterReference.class;
case JOIN:
return JoinNode.class;
+ case PROPERTY_REF:
+ return PropertyReference.class;
}
- return super.getASTNodeType(tokenType);
+ return super.getASTNodeType( tokenType );
}
protected AST createUsingCtor(Token token, String string) {
@@ -53,7 +56,10 @@
private void prepare(AST node) {
if ( node instanceof SessionFactoryAwareNode ) {
- ( ( SessionFactoryAwareNode ) node ).setSessionFactory( factory );
+ ( ( SessionFactoryAwareNode ) node ).setSessionFactory( resolver.getSessionFactory() );
}
+ if ( node instanceof ResolverAware ) {
+ ( ( ResolverAware ) node ).setHqlResolver( resolver );
+ }
}
}
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinNode.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinNode.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -20,19 +20,22 @@
private JoinType joinType;
private JoinSource source;
private boolean fetch;
+ private PersisterReference lhs;
public JoinNode() {
+ super.setText( "join" );
}
public JoinNode(Token tok) {
super( tok );
+ super.setText( "join" );
}
- public void initialize(JoinType joinType, JoinSource source, boolean fetch) {
+ public void initialize(JoinType joinType, JoinSource source, boolean fetch, PersisterReference lhs) {
this.joinType = joinType;
this.source = source;
this.fetch = fetch;
- super.setText( "join" );
+ this.lhs = lhs;
}
public JoinType getJoinType() {
@@ -60,10 +63,10 @@
}
public String getDisplayText() {
- return "{" + "type=" + joinType + ", source=" + source + "fetch=" + fetch + "}";
+ return "{" + "type=" + joinType + ", source=" + source + ", fetch=" + fetch + ", lhs=" + lhs.getAlias() + "}";
}
public String toString() {
- return "JoinNode" + getDisplayText();
+ return "JoinNode " + getDisplayText();
}
}
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReference.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReference.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReference.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -1,7 +1,8 @@
package org.hibernate.hql.ast.resolve;
import org.hibernate.type.AssociationType;
-import org.hibernate.hql.ast.tree.DisplayableNode;
+import org.hibernate.type.Type;
+import org.hibernate.hql.ast.tree.Node;
/**
* Represents a reference to a persister (either entity or collection) within
@@ -9,11 +10,13 @@
*
* @author Steve Ebersole
*/
-public interface PersisterReference extends DisplayableNode {
- public String getName();
- public String getAlias();
- public AssociationType getPersisterType();
+public abstract class PersisterReference extends Node {
+ public abstract String getName();
+ public abstract String getAlias();
+ public abstract AssociationType getPersisterType();
+ public abstract Type getPropertyType(String propertyName);
- public boolean containsProperty(String propertyName);
- public PropertyReference retrievePropertyReference(String propertyName);
+ public String getText() {
+ return getName() + " (" + getAlias() + ")";
+ }
}
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyReference.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyReference.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyReference.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -1,16 +1,57 @@
package org.hibernate.hql.ast.resolve;
import org.hibernate.type.Type;
-import org.hibernate.hql.ast.tree.DisplayableNode;
+import org.hibernate.hql.ast.tree.Node;
/**
- * Represents a reference to a particular persister-managed property; also
- * some special cases such as a collection property reference (e.g., size).
+ * Represents a reference to a particular property.
+ * <p/>
+ * The sub-tree structure of this node is such that its first child is an ALIAS
+ * node representing an alias pointing to the specific persister reference from
+ * which the property reference originates. The other child is the property name,
+ * as an IDENT
*
* @author Steve Ebersole
*/
-public interface PropertyReference extends DisplayableNode {
- public String getPropertyName();
- public Type getPropertyType();
- public PersisterReference getPersisterReference();
+public class PropertyReference extends Node implements ResolverAware {
+
+ private HqlResolver resolver;
+
+ // caches
+ private String alias;
+ private String propertyName;
+ private Type propertyType;
+ private PersisterReference origin;
+
+ public String getPersisterReferenceAlias() {
+ if ( alias == null ) {
+ alias = getFirstChild().getText();
+ }
+ return alias;
+ }
+
+ public String getPropertyName() {
+ if ( propertyName == null ) {
+ propertyName = getFirstChild().getNextSibling().getText();
+ }
+ return propertyName;
+ }
+
+ public PersisterReference getPropertyOrigination() {
+ if ( origin == null ) {
+ origin = resolver.getPersisterReferenceContext().locatePersisterReferenceByAlias( getPersisterReferenceAlias() );
+ }
+ return origin;
+ }
+
+ public Type getPropertyType() {
+ if ( propertyType == null ) {
+ propertyType = getPropertyOrigination().getPropertyType( getPropertyName() );
+ }
+ return propertyType;
+ }
+
+ public void setHqlResolver(HqlResolver resolver) {
+ this.resolver = resolver;
+ }
}
Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/RangeNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/RangeNode.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/RangeNode.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -1,69 +0,0 @@
-package org.hibernate.hql.ast.resolve;
-
-import org.hibernate.hql.ast.tree.Node;
-import org.hibernate.hql.ast.tree.DisplayableNode;
-
-/**
- * Represents a "top-level" element in a FROM clause (e.g. "from Animal a"). These
- * "top-level" nodes are then contained in a RANGE node within the FROM node.
- *
- *
- * @author Joshua Davis
- */
-public class RangeNode extends Node implements DisplayableNode {
- // TODO : would like to remove this range concept;
- // a "range" is really just a series of full joins (unless further
- // qualified in the where-clause, in which case they'd become inner
- // joins) specified using old "theta join" syntax from SQL, so
- // represent them as join structures
- private String path;
- private String alias;
- private EntityPersisterReference persisterReference;
- private boolean fetch = false;
-
- public String getPath() {
- return path;
- }
-
- public void setPath(String path) {
- this.path = path;
- }
-
- public EntityPersisterReference getPersisterReference() {
- return persisterReference;
- }
-
- public void setPersisterReference(EntityPersisterReference persisterReference) {
- this.persisterReference = persisterReference;
- }
-
- public boolean isFetch() {
- return fetch;
- }
-
- public void setFetch(boolean fetch) {
- this.fetch = fetch;
- }
-
- public String getAlias() {
- return alias;
- }
-
- public void setAlias(String alias) {
- this.alias = alias;
- }
-
-
- public String toString() {
- return "RangeNode{" +
- "path='" + path + '\'' +
- ", alias='" + alias + '\'' +
- ", reference=" + persisterReference +
- ", fetch=" + fetch +
- '}';
- }
-
- public String getDisplayText() {
- return toString();
- }
-}
Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContext.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContext.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContext.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -1,19 +0,0 @@
-package org.hibernate.hql.ast.resolve;
-
-import org.hibernate.persister.entity.EntityPersister;
-
-import java.util.List;
-
-/**
- * Looks up persisters and other things by name.
- * <br>User: Joshua Davis
- * Date: Apr 12, 2006
- * Time: 7:34:11 AM
- */
-public interface ResolverContext {
- public EntityPersister lookupPersister(String path);
- public PersisterReference locatePersisterReferenceByAlias(String alias);
- public List collectPersisterReferences();
- public EntityPersisterReference getEntityPersisterReference(String entityName, String alias);
- public CollectionPersisterReference getCollectionPersisterReference(String collectionRole, String alias);
-}
Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContextImpl.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContextImpl.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContextImpl.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -1,74 +0,0 @@
-package org.hibernate.hql.ast.resolve;
-
-import org.hibernate.engine.SessionFactoryImplementor;
-import org.hibernate.MappingException;
-import org.hibernate.hql.antlr.HqlRTokenTypes;
-import org.hibernate.persister.entity.EntityPersister;
-
-import java.util.Map;
-import java.util.HashMap;
-import java.util.List;
-import java.util.ArrayList;
-import java.util.Collections;
-
-import antlr.ASTFactory;
-
-/**
- * Implements the resolver's context with a session factory.
- * <br>User: Joshua Davis
- * Date: Apr 12, 2006
- * Time: 7:35:31 AM
- */
-public class ResolverContextImpl implements ResolverContext {
- private Map persisterReferencesByAlias = new HashMap();
- private List persisterReferences = new ArrayList();
- private final SessionFactoryImplementor sessionFactory;
- private final ASTFactory astFactory;
-
- public ResolverContextImpl(SessionFactoryImplementor sessionFactory, ASTFactory astFactory) {
- this.sessionFactory = sessionFactory;
- this.astFactory = astFactory;
- }
-
- public EntityPersister lookupPersister(String name) {
- // First, try to get the persister using the class name directly.
- try {
- return sessionFactory.getEntityPersister( name );
- }
- catch ( MappingException ignore ) {
- // unable to locate it using this name
- }
-
- // If that didn't work, try using the 'import' name.
- String importedClassName = sessionFactory.getImportedClassName( name );
- if ( importedClassName == null ) {
- return null;
- }
- return sessionFactory.getEntityPersister( importedClassName );
- }
-
- public PersisterReference locatePersisterReferenceByAlias(String alias) {
- return ( PersisterReference ) persisterReferencesByAlias.get( alias );
- }
-
- public List collectPersisterReferences() {
- return Collections.unmodifiableList( persisterReferences );
- }
-
- public EntityPersisterReference getEntityPersisterReference(String entityName, String alias) {
- EntityPersister persister = lookupPersister( entityName );
- EntityPersisterReference persisterReference = ( EntityPersisterReference ) astFactory.create( HqlRTokenTypes.ENTITY_PERSISTER_REF, persister.getEntityName() );
- persisterReference.initialize( persister.getEntityName(), alias );
- persisterReferences.add( persisterReference );
- if ( alias != null ) {
- persisterReferencesByAlias.put( alias, persisterReference );
- }
- return persisterReference;
- }
-
- public CollectionPersisterReference getCollectionPersisterReference(String collectionRole, String alias) {
- // TODO : implement; for now returns null...
- return null;
- }
-
-}
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/StatementNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/StatementNode.java 2006-05-02 11:07:06 UTC (rev 9850)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/StatementNode.java 2006-05-02 14:26:06 UTC (rev 9851)
@@ -1,12 +1,220 @@
package org.hibernate.hql.ast.resolve;
import org.hibernate.hql.ast.tree.Node;
+import org.hibernate.hql.antlr.HqlRTokenTypes;
+import org.hibernate.util.EmptyIterator;
+import org.hibernate.QueryException;
+import org.hibernate.MappingException;
+import org.hibernate.type.Type;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.CollectionType;
+import org.hibernate.persister.entity.EntityPersister;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+
+import antlr.ASTFactory;
+
/**
- * Represents a statement (SELECT, UPDATE, INSERT, DELETE) in the resolved HQL tree.
- * <br>User: Joshua Davis
- * Date: Apr 3, 2006
- * Time: 8:00:55 AM
+ * Base node class for hql statements (SELECT, DELETE, INSERT, UPDATE).
+ *
+ * @author Joshua Davis
+ * @author Steve Ebersole
*/
-public class StatementNode extends Node {
+public abstract class StatementNode extends Node implements ResolverAware, PersisterReferenceContext {
+
+ private static final Log log = LogFactory.getLog( StatementNode.class );
+
+ private StatementNode parentStatement;
+ private List childStatements;
+ private HqlResolver resolver;
+
+ public StatementNode getParentStatement() {
+ return parentStatement;
+ }
+
+ public Iterator iterateChildStatements() {
+ return childStatements == null ? EmptyIterator.INSTANCE : childStatements.iterator();
+ }
+
+ public void pushChild(StatementNode childStatement) {
+ childStatement.setParent( this );
+ if ( childStatements == null ) {
+ childStatements = new ArrayList();
+ }
+ childStatements.add( childStatement );
+ }
+
+ private void setParent(StatementNode parentStatement) {
+ if ( this.parentStatement != null ) {
+ throw new QueryException( "statement already had an associated parent" );
+ }
+ this.parentStatement = parentStatement;
+ }
+
+ public void setHqlResolver(HqlResolver resolver) {
+ this.resolver = resolver;
+ // todo : temp (see below)
+ this.sessionFactory = resolver.getSessionFactory();
+ this.astFactory = resolver.getASTFactory();
+ }
+
+
+ // todo : temp impl of PersisterReferenceContext ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ // still need to handle hierarchical lookups as well as proper scoping rules between
+ // statement types
+
+ private int unaliasedCount = 0;
+ private Map persisterReferencesByAlias = new HashMap();
+ private Map persisterReferencesByPath = new HashMap();
+ private List persisterReferences = new ArrayList();
+ private SessionFactoryImplementor sessionFactory;
+ private ASTFactory astFactory;
+
+ public EntityPersister lookupPersister(String name) {
+ // First, try to get the persister using the class name directly.
+ try {
+ return sessionFactory.getEntityPersister( name );
+ }
+ catch ( MappingException ignore ) {
+ // unable to locate it using this name
+ }
+
+ // If that didn't work, try using the 'import' name.
+ String importedClassName = sessionFactory.getImportedClassName( name );
+ if ( importedClassName == null ) {
+ return null;
+ }
+ return sessionFactory.getEntityPersister( importedClassName );
+ }
+
+ public void registerPersisterReferenceAgainstPath(String path, PersisterReference persisterReference) {
+ if ( persisterReferencesByPath.containsKey( path ) ) {
+ throw new QueryException( "persister reference already registered for path [" + path + "]" );
+ }
+ }
+
+ public PersisterReference locatePersisterReferenceByPath(String path) {
+ return ( PersisterReference ) persisterReferencesByPath.get( path );
+ }
+
+ public PersisterReference locatePersisterReferenceByAlias(String alias) {
+ return ( PersisterReference ) persisterReferencesByAlias.get( alias );
+ }
+
+ public EntityPersisterReference locatePersisterReferenceExposingProperty(String firstPathExpression) {
+ log.trace( "trying to locate persister exposing property [" + firstPathExpression + "]" );
+ EntityPersisterReference match = null;
+ Iterator itr = persisterReferences.iterator();
+ while( itr.hasNext() ) {
+ final EntityPersisterReference test = ( EntityPersisterReference ) itr.next();
+ if ( test.containsProperty( firstPathExpression ) ) {
+ if ( match != null ) {
+ throw new QueryException( "multiple referenced persisters contained property [" + firstPathExpression + "]" );
+ }
+ match = test;
+ }
+ }
+ return match;
+ }
+
+ public EntityPersisterReference buildEntityPersisterReference(String entityName, String alias) {
+ EntityPersister persister = lookupPersister( entityName );
+ alias = determineAlias( alias );
+ EntityPersisterReference persisterReference = ( EntityPersisterReference ) astFactory.create( HqlRTokenTypes.ENTITY_PERSISTER_REF, persister.getEntityName() );
+ persisterReference.initialize( persister.getEntityName(), alias );
+ persisterReferenceBuilt( alias, persisterReference );
+ return persisterReference;
+ }
+
+ private String determineAlias(String alias) {
+ if ( alias == null ) {
+ alias = "<gen:" + unaliasedCount++ + ">";
+ }
+ return alias;
+ }
+
+ public PersisterReference getPersisterReference(PersisterReference source, String propertyName, String alias) {
+ alias = determineAlias( alias );
+ if ( source.getPersisterType().isEntityType() ) {
+ return buildPersisterReferenceFromEntity( ( EntityPersisterReference ) source, propertyName, alias );
+ }
+ else {
+ return buildPersisterReferenceFromCollection( ( CollectionPersisterReference ) source, propertyName, alias );
+ }
+ }
+
+ private PersisterReference buildPersisterReferenceFromCollection(
+ CollectionPersisterReference collectionPersisterReference,
+ String propertyName,
+ String alias) {
+ // todo : we may need two different forms of CollectionPersisterReference,
+ // the distinction being which "properties" are available from each...
+ // (1) represents nodes built from explicit joins (properties from
+ // the underlying collection elements are available
+ // (2) represents nodes built from implicit joins (only
+ // "collection properties" are available (size, index, etc)
+ return null;
+ }
+
+ private PersisterReference buildPersisterReferenceFromEntity(
+ EntityPersisterReference source,
+ String propertyName,
+ String alias ) {
+ Type type = null;
+ PersisterReference ref = null;
+ try {
+ type = source.getEntityPersister().getPropertyType( propertyName );
+ }
+ catch( Throwable t ) {
+ throw new QueryException( "could not resolve property [" + propertyName + "] on " + source.getEntityPersister().getEntityName() );
+ }
+
+ if ( type.isEntityType() ) {
+ EntityType entityType = ( EntityType ) type;
+ EntityPersisterReference entityPersisterReference = ( EntityPersisterReference )
+ astFactory.create( HqlRTokenTypes.ENTITY_PERSISTER_REF, entityType.getAssociatedEntityName() );
+ entityPersisterReference.initialize( entityType.getAssociatedEntityName(), alias );
+ ref = entityPersisterReference;
+ }
+ else if ( type.isCollectionType() ) {
+ CollectionType collectionType = ( CollectionType ) type;
+ CollectionPersisterReference collectionPersisterReference = ( CollectionPersisterReference )
+ astFactory.create( HqlRTokenTypes.COLLECTION_PERSISTER_REF, "" );
+ collectionPersisterReference.initialize( collectionType.getRole(), alias );
+ ref = collectionPersisterReference;
+ }
+ else {
+ throw new QueryException(
+ "cannot dereference property [" + propertyName +
+ "] from persister [" + source.getEntityPersister().getEntityName() +
+ "] as part of path expression"
+ );
+ }
+
+ persisterReferenceBuilt( alias, ref );
+ return ref;
+ }
+
+ private void persisterReferenceBuilt(String alias, PersisterReference reference) {
+ persisterReferen...
[truncated message content] |