[hibernate-commits] Hibernate SVN: r11003 - in branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast: . resolve resolve/path tree

hibernate-commits at lists.jboss.org hibernate-commits at lists.jboss.org
Tue Dec 19 14:08:30 EST 2006


Author: steve.ebersole at jboss.com
Date: 2006-12-19 14:08:27 -0500 (Tue, 19 Dec 2006)
New Revision: 11003

Added:
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/PhaseContext.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/DeleteStatementNode.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/InsertStatementNode.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/JoinType.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/PersisterReferenceBuilder.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceContext.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/src/org/hibernate/hql/ast/resolve/UpdateStatementNode.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/PhaseContextAwareNode.java
Removed:
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyReferenceSource.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/ASTFactoryAwareNode.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/PersisterReferenceContextAwareNode.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java
Modified:
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/Aliasable.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceContextAwareNode.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolutionContext.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolutionContextAwareNode.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/path/AbstractPathResolutionStrategy.java
   branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/path/BasicPathResolutionStrategySupport.java
Log:
switched to a more in-line resolution of path expressions using org.hibernate.hql.ast.resolve.path.PathResolutionStrategy

Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/PhaseContext.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/PhaseContext.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/PhaseContext.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,27 @@
+package org.hibernate.hql.ast;
+
+import antlr.ASTFactory;
+
+import org.hibernate.engine.SessionFactoryImplementor;
+
+/**
+ * Defines services which are available to any HQL translation phase.
+ *
+ * @author Steve Ebersole
+ */
+public interface PhaseContext {
+	/**
+	 * Retrieve a reference to the factory associated with this context for
+	 * creating AST/Node instances.
+	 *
+	 * @return The ASTFactory.
+	 */
+	public ASTFactory getASTFactory();
+
+	/**
+	 * Retrieve a reference to the session factory associated with this context.
+	 *
+	 * @return The session factory.
+	 */
+	public SessionFactoryImplementor getSessionFactory();
+}

Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/Aliasable.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/Aliasable.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/Aliasable.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -1,10 +1,15 @@
 package org.hibernate.hql.ast.resolve;
 
 /**
- * {@inheritDoc}
+ * Contract for things which can be aliased by other parts of an HQL query.
  *
  * @author Steve Ebersole
  */
 public interface Aliasable {
+	/**
+	 * Get the alias by which other parts of an HQL query can refer to this.
+	 *
+	 * @return The alias.
+	 */
 	public String getAlias();
 }

Added: 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-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,146 @@
+package org.hibernate.hql.ast.resolve;
+
+import org.hibernate.HibernateException;
+import org.hibernate.hql.CollectionProperties;
+import org.hibernate.persister.collection.CollectionPropertyMapping;
+import org.hibernate.persister.collection.QueryableCollection;
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.ComponentType;
+import org.hibernate.type.EntityType;
+import org.hibernate.type.Type;
+
+/**
+ * A reference to an {@link org.hibernate.persister.collection.CollectionPersister}.
+ *
+ * @author Steve Ebersole
+ */
+public class CollectionPersisterReference extends EntityPersisterReference {
+
+	private String role;
+	private transient QueryableCollection persister;
+	private transient CollectionPropertyMapping propertyMapping;
+
+	/**
+	 * Initializes the structure of this persister reference node.
+	 * <p/>
+	 * TODO : better to have these injected via constructor?
+	 *
+	 * @param role The role name of the corresponding {@link org.hibernate.persister.collection.CollectionPersister}.
+	 * @param alias The HQL alias for this persister reference.
+	 * @param propertyFetch Whether lazy property fetching should be applied.
+	 */
+	public void initialize(String role, String alias, boolean propertyFetch) {
+		this.role = role;
+		super.initialize( alias, propertyFetch );
+	}
+
+	/**
+	 * Retrieve a reference to the underlying collection persister.
+	 *
+	 * @return The collection persister.
+	 */
+	public QueryableCollection getCollectionPersister() {
+		if ( persister == null ) {
+			persister = ( QueryableCollection ) getSessionFactory().getCollectionPersister( role );
+		}
+		return persister;
+	}
+
+	/**
+	 * Retrieve the entity persister for the elements of this collection if
+	 * the elements happen to be entities.
+	 * <p/>
+	 * TODO : perhaps we should just return null here in the case of non-entity elements?
+	 *
+	 * @return The element's entity persister.
+	 * @throws HibernateException If the collection is not a collection of entities.
+	 */
+	public Queryable getEntityPersister() {
+		if ( getCollectionPersister().getElementType().isEntityType() ) {
+			EntityType elementEntityType = ( EntityType ) getCollectionPersister().getElementType();
+			return ( Queryable ) elementEntityType.getAssociatedJoinable( getSessionFactory() );
+		}
+		else {
+			throw new HibernateException( "not a collection of entities" );
+		}
+	}
+
+	/**
+	 *
+	 * Retrieves the logical name; here the collection role of the underlying
+	 * {@link org.hibernate.persister.collection.CollectionPersister}.
+	 *
+	 * @return The collection role.
+	 */
+	public String getName() {
+		return role;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public AssociationType getPersisterType() {
+		return ( AssociationType ) getCollectionPersister().getElementType();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Type getPropertyType(String propertyName) {
+		if ( CollectionProperties.isAnyCollectionProperty( propertyName ) ) {
+			if ( propertyMapping == null ) {
+				propertyMapping = new CollectionPropertyMapping( getCollectionPersister() );
+			}
+			return propertyMapping.toType( propertyName );
+		}
+		else {
+			Type elementType = getCollectionPersister().getElementType();
+			if ( elementType.isAssociationType() ) {
+				// a collection of entities
+				EntityType elementEntityType = ( EntityType ) elementType;
+				try {
+					Queryable elementEntityPersister = ( Queryable ) elementEntityType
+							.getAssociatedJoinable( 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;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean containsProperty(String propertyName) {
+		// 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;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public String toString() {
+		return "CollectionPersisterReference {role=" + getName() + ", alias=" + getAlias() +
+		       ", element-type=" + getCollectionPersister().getElementType() + "}";
+	}
+}

Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/DeleteStatementNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/DeleteStatementNode.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/DeleteStatementNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,27 @@
+package org.hibernate.hql.ast.resolve;
+
+import org.hibernate.HibernateException;
+import org.hibernate.hql.ast.resolve.path.BasicPathResolutionStrategySupport;
+import org.hibernate.hql.ast.resolve.path.PathResolutionStrategy;
+
+/**
+ * Specialized statement node for representing DELETE statements
+ *
+ * @author Steve Ebersole
+ */
+public class DeleteStatementNode extends StatementNode {
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public PathResolutionStrategy buildBasicPathResolutionStrategy(ResolutionContext resolutionContext) {
+		return new BasicPathResolutionStrategySupport( resolutionContext ) {
+			protected void validateJoinCreation(PersisterReference origin, String property) {
+				throw new HibernateException(
+						"delete statement cannot contain path expressions resolving to implicit joins"
+				);
+			}
+		};
+	}
+
+}

Added: 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-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,113 @@
+package org.hibernate.hql.ast.resolve;
+
+import org.hibernate.persister.entity.Queryable;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.Type;
+
+/**
+ * A reference to an {@link org.hibernate.persister.entity.EntityPersister}.
+ *
+ * @author Steve Ebersole
+ */
+public class EntityPersisterReference extends PersisterReference  {
+
+	private String entityName;
+	private String alias;
+	private boolean propertyFetch;
+	private transient Queryable persister;
+
+	/**
+	 * Initializes the structure of this persister reference node.
+	 * <p/>
+	 * TODO : better to have these injected via constructor?
+	 *
+	 * @param entityName The entity-name of the corresponding {@link org.hibernate.persister.entity.EntityPersister}.
+	 * @param alias The HQL alias for this persister reference.
+	 * @param propertyFetch Whether lazy property fetching should be applied.
+	 */
+	public void initialize(String entityName, String alias, boolean propertyFetch) {
+		this.entityName = entityName;
+		initialize( alias, propertyFetch );
+	}
+
+	protected void initialize(String alias, boolean propertyFetch) {
+		this.alias = alias;
+		this.propertyFetch = propertyFetch;
+	}
+
+	/**
+	 * Retrieves a reference to the underlying entity persister.
+	 *
+	 * @return The underlying entity persister.
+	 */
+	public Queryable getEntityPersister() {
+		if ( persister == null ) {
+			persister = ( Queryable ) getSessionFactory().getEntityPersister( entityName );
+		}
+		return persister;
+	}
+
+	/**
+	 * Retrieves the logical name; here the entity-name of the underlying
+	 * {@link org.hibernate.persister.entity.EntityPersister}.
+	 *
+	 * @return The entity-name.
+	 */
+	public String getName() {
+		return entityName;
+	}
+
+	/**
+	 * Retrieve the alias by which the persister reference can be located from the
+	 * {@link PersisterReferenceContext}.
+	 *
+	 * @return The HQL alias.
+	 */
+	public String getAlias() {
+		return alias;
+	}
+
+	/**
+	 * Is lazy property fetching enabled for this persister reference.
+	 *
+	 * @return True if this persister reference indicates that lazy properties
+	 * be immediately fetched; false otherwise.
+	 */
+	public boolean isPropertyFetch() {
+		return propertyFetch;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public AssociationType getPersisterType() {
+		return ( AssociationType ) getEntityPersister().getType();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public Type getPropertyType(String propertyName) {
+		try {
+			return getEntityPersister().getPropertyType( propertyName );
+		}
+		catch( Throwable t ) {
+			return null;
+		}
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public boolean containsProperty(String propertyName) {
+		return getPropertyType( propertyName ) != null;
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public String toString() {
+		return "EntityPersisterReference {entity-name=" + entityName + ", alias=" + alias + "}";
+	}
+
+}

Added: 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-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,254 @@
+package org.hibernate.hql.ast.resolve;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.hql.antlr.GeneratedHqlResolver;
+import org.hibernate.hql.antlr.ResolveTokenTypes;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.hql.ast.resolve.path.PathResolutionStrategyStack;
+import org.hibernate.hql.ast.resolve.path.PathResolutionStrategy;
+import org.hibernate.hql.ast.resolve.path.PropertyPathPart;
+import org.hibernate.hql.ast.resolve.path.FromClausePathResolutionStrategy;
+import org.hibernate.hql.ast.resolve.path.OnFragmentPathResolutionStrategy;
+import org.hibernate.hql.ast.resolve.path.WithFragmentPathResolutionStrategy;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.QueryException;
+
+import antlr.collections.AST;
+
+/**
+ * Actual resolver implementation used in the query translator providing
+ * semantic action implementation.
+ *
+ * @author Joshua Davis
+ * @author Steve Ebersole
+ */
+public class HqlResolver extends GeneratedHqlResolver implements ResolutionContext {
+
+	private static final Log log = LogFactory.getLog( HqlResolver.class );
+	private static final ASTPrinter printer = new ASTPrinter( ResolveTokenTypes.class ).setShowClassNames( false );
+
+	private final SessionFactoryImplementor sessionFactory;
+	private final PersisterReferenceBuilder persisterReferenceBuilder;
+
+	private StatementNode currentStatement;
+	private PathResolutionStrategyStack pathResolutionStrategyStack = new PathResolutionStrategyStack();
+
+	public HqlResolver(SessionFactoryImplementor sessionFactory) {
+		super();
+		this.sessionFactory = sessionFactory;
+		setASTFactory( new HqlResolverASTFactory( this ) );
+		persisterReferenceBuilder = new PersisterReferenceBuilder( this );
+	}
+
+
+	// ResolutionContext implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	public SessionFactoryImplementor getSessionFactory() {
+		return sessionFactory;
+	}
+
+	public PersisterReferenceContext getCurrentPersisterReferenceContext() {
+		return currentStatement.getPersisterReferenceContext();
+	}
+
+	public PersisterReferenceBuilder getPersisterReferenceBuilder() {
+		return persisterReferenceBuilder;
+	}
+
+	public PathResolutionStrategy getCurrentPathResolutionStrategy() {
+		return pathResolutionStrategyStack.getCurrent();
+	}
+
+
+	// semantic action overrides ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	protected boolean isPersisterReferenceAlias(AST alias) {
+		log.trace( "Checking [" + textOrNull( alias ) + "] as persister-ref alias" );
+		return getCurrentPersisterReferenceContext().isContainedAlias( alias.getText() );
+	}
+
+	protected AST resolveAlias(AST alias) {
+		log.trace( "resolving property reference alias [" + textOrNull( alias ) + "]" );
+		return getCurrentPersisterReferenceContext().locatePersisterReferenceByAlias( alias.getText() );
+	}
+
+	protected boolean isUnqualifiedPropertyReference(AST property) {
+		log.trace( "Checking [" + textOrNull( property ) + "] as unqualified-prop-ref" );
+		return getCurrentPersisterReferenceContext().isContainedExposedProperty( property.getText() );
+	}
+
+	protected AST buildUnqualifiedPropertyReference(AST propertyNameNode) {
+		String propertyName = propertyNameNode.getText();
+		log.trace( "building unqualified property reference [" + propertyName + "]" );
+		PropertyPathPart root = pathResolutionStrategyStack.getCurrent().resolveRoot( getCurrentPersisterReferenceContext().locatePersisterReferenceExposingProperty( propertyName ) );
+		return root.resolveTerminalPathPart( propertyName );
+	}
+
+	protected AST resolvePropertyPathTerminus(AST source, AST propertyNameNode) {
+		log.trace( "resolving terminal path expression [" + textOrNull( propertyNameNode ) + "]" );
+		return pathResolutionStrategyStack.getCurrent().resolveTerminalPathPart( ( PropertyPathPart ) source, textOrNull( propertyNameNode ) );
+	}
+
+	protected AST resolvePropertyPathIntermediary(AST source, AST propertyNameNode) {
+		log.trace( "resolving intermediate path expression [" + textOrNull( propertyNameNode ) + "]" );
+		return pathResolutionStrategyStack.getCurrent().resolveIntermediatePathPart( ( PropertyPathPart ) source, textOrNull( propertyNameNode ) );
+	}
+
+	protected void validateIndexOperationOperands(AST collectionPropertyRef, AST selector) {
+		// TODO : temporary implementation...
+		log.trace( "Validating index op : collection = [" + textOrNull( collectionPropertyRef ) + "]; selector = [" + textOrNull( selector ) + "]" );
+		super.validateIndexOperationOperands( collectionPropertyRef, selector );
+	}
+
+    protected AST resolveQualifiedRoot(AST alias) {
+		log.debug( "resolving path expression root as alias [" + alias.getText() + "]" );
+		return pathResolutionStrategyStack.getCurrent().resolveRoot( getCurrentPersisterReferenceContext().locatePersisterReferenceByAlias( alias.getText() ) );
+    }
+
+    protected AST resolveUnqualifiedRoot(AST propertyName) {
+		log.debug( "resolving path expression root as unqualified property [" + propertyName.getText() + "]" );
+		PropertyPathPart root = pathResolutionStrategyStack.getCurrent().resolveRoot( getCurrentPersisterReferenceContext().locatePersisterReferenceExposingProperty( propertyName.getText() ) );
+		return root.resolveIntermediatePathPart( propertyName.getText() );
+	}
+
+    protected AST resolveIndexedRoot(AST indexNode) {
+		// TODO : need to resolve the INDEX_OP node to the referenced persister and have the path resolution strategy encode that as the root...
+		return indexNode;
+    }
+
+	/**
+	 * Semantic action called whenever we start a new statement (i.e top-level statement vs. subquery)
+	 *
+	 * @param statementNode The statement we are starting to process.
+	 */
+	protected void pushStatement(AST statementNode) {
+		log.trace( "pushing new statement context [" + statementNode + "]" );
+		StatementNode statement = ( StatementNode ) statementNode;
+		if ( currentStatement != null ) {
+			currentStatement.pushChild( statement );
+		}
+		currentStatement = statement;
+		pathResolutionStrategyStack.push( currentStatement.buildBasicPathResolutionStrategy( this ) );
+	}
+
+	/**
+	 * Semantic action called whenever we complete processing a statement.
+	 */
+	protected void popStatement() {
+		log.trace( "popping statement context : " + currentStatement + " -> " + currentStatement.getParentStatement() );
+		currentStatement = currentStatement.getParentStatement();
+		pathResolutionStrategyStack.pop();
+	}
+
+	protected void pushFromClausePropertyPathContext(AST joinTypeNode, AST fetch, AST alias, AST propertyFetch) {
+		log.debug( "pushing explicit (from clause) property path context" );
+		pathResolutionStrategyStack.push(
+				new FromClausePathResolutionStrategy(
+						this,
+						resolveJoinType( joinTypeNode ),
+						propertyFetch != null,
+						fetch != null,
+						textOrNull( alias )
+				)
+		);
+	}
+
+	protected void popFromClausePropertyPathContext() {
+		log.debug( "popping explicit (from clause) property path context" );
+		pathResolutionStrategyStack.pop();
+	}
+
+	protected void pushOnFragmentPropertyPathContext(AST rhsPersisterReference) {
+		log.debug( "pushing on-fragment path handler [rhs=" + rhsPersisterReference.getText() + "]" );
+		OnFragmentPathResolutionStrategy strategy = new OnFragmentPathResolutionStrategy( this, ( PersisterReference ) rhsPersisterReference );
+		pathResolutionStrategyStack.push( strategy );
+	}
+
+	protected void popOnFragmentPropertyPathContext() {
+		log.debug( "popping on-fragment path handler" );
+		pathResolutionStrategyStack.pop();
+	}
+
+	protected void pushWithFragmentPropertyPathContext(AST rhsPropertyReference) {
+		log.debug( "pushing with-fragment path handler" );
+		// can only be used in conjunction with property reference generated
+		// directly from FromClausePropertyPathHandler...
+		FromClausePathResolutionStrategy.PropertyReferenceAdapter propertyAdapter = ( FromClausePathResolutionStrategy.PropertyReferenceAdapter ) rhsPropertyReference;
+		WithFragmentPathResolutionStrategy strategy = new WithFragmentPathResolutionStrategy( this, propertyAdapter.getOrigination(), propertyAdapter.getRhs() );
+		pathResolutionStrategyStack.push( strategy );
+	}
+
+	protected void popWithFragmentPropertyPathContext() {
+		log.debug( "popping on-fragment path handler" );
+		pathResolutionStrategyStack.pop();
+	}
+
+	/**
+	 * Semantic action called to perform generation of an {@link EntityPersisterReference}
+	 * representing a "root" persister reference.
+	 *
+	 * @param entityName The name of the entity.
+	 * @param alias An (optional) alias for later qualification-resolution to the generated
+	 * persister reference.
+	 * @param propertyFetch Was property fetching explicitly specified.
+	 * @return The generated reference.
+	 */
+	protected AST buildEntityPersisterReference(AST entityName, AST alias, AST propertyFetch) {
+		return buildEntityPersisterReference( entityName.getText(), textOrNull( alias ), propertyFetch != null );
+	}
+
+	private EntityPersisterReference buildEntityPersisterReference(String entityName, String alias, boolean propertyFetching) {
+		return persisterReferenceBuilder.buildEntityPersisterReference( entityName, alias, propertyFetching );
+	}
+
+	private String textOrNull(AST node) {
+		return node == null ? null : node.getText();
+	}
+
+	protected AST buildAdHocJoinNode(AST rhs, AST joinTypeNode, AST onClause) {
+		log.debug( printer.showAsString( onClause, "ON fragment for ad-hoc-join building" ) );
+		JoinType joinType = resolveJoinType( joinTypeNode );
+		OnFragmentPathResolutionStrategy strategy = ( OnFragmentPathResolutionStrategy ) pathResolutionStrategyStack.getCurrent();
+		PersisterReference lhs = strategy.getDiscoveredLHS();
+		if ( lhs == null ) {
+			throw new QueryException( "Unable to discover left hand side of ad-hoc-join" );
+		}
+		return getPersisterReferenceBuilder().buildJoinNode( lhs, ( PersisterReference ) rhs, joinType, null, false );
+	}
+
+	protected void applyWithFragment(AST withFragment) {
+		log.debug( printer.showAsString( withFragment, "WITH fragment" ) );
+		WithFragmentPathResolutionStrategy strategy = ( WithFragmentPathResolutionStrategy ) pathResolutionStrategyStack.getCurrent();
+		strategy.applyWithFragment( withFragment );
+	}
+
+	private JoinType resolveJoinType(AST joinType) {
+		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;
+		}
+		// if no match found, throw exception
+		throw new QueryException( "Unrecognized join type [" + joinType.getText() + "]" );
+	}
+
+	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();
+	}
+}

Added: 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-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,69 @@
+package org.hibernate.hql.ast.resolve;
+
+import antlr.collections.AST;
+import antlr.Token;
+
+import org.hibernate.hql.ast.HqlASTFactory;
+import org.hibernate.hql.ast.tree.PhaseContextAwareNode;
+import org.hibernate.hql.antlr.ResolveTokenTypes;
+
+/**
+ * AST factory for the resolver phase.
+ *
+ * @author Joshua Davis
+ * @author Steve Ebersole
+ */
+public class HqlResolverASTFactory extends HqlASTFactory implements ResolveTokenTypes {
+
+	private final ResolutionContext context;
+
+	public HqlResolverASTFactory(ResolutionContext context) {
+		this.context = context;
+	}
+
+	public Class getASTNodeType(int tokenType) {
+		switch (tokenType) {
+			case QUERY:
+				return SelectStatementNode.class;
+			case UPDATE:
+				return UpdateStatementNode.class;
+			case DELETE:
+				return DeleteStatementNode.class;
+			case INSERT:
+				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 );
+	}
+
+	protected AST createUsingCtor(Token token, String string) {
+		AST node = super.createUsingCtor( token, string );
+		prepare( node );
+		return node;
+	}
+
+	protected AST create(Class aClass) {
+		AST node = super.create( aClass );
+		prepare( node );
+		return node;
+	}
+
+	private void prepare(AST node) {
+		if ( node instanceof PhaseContextAwareNode ) {
+			( ( PhaseContextAwareNode ) node ).injectPhaseContext( context );
+		}
+		if ( node instanceof ResolutionContextAwareNode ) {
+			( ( ResolutionContextAwareNode ) node ).injectResolutionContext( context );
+		}
+		if ( node instanceof PersisterReferenceContextAwareNode ) {
+			( ( PersisterReferenceContextAwareNode ) node ).injectPersisterReferenceContext( context.getCurrentPersisterReferenceContext() );
+		}
+	}
+}

Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/InsertStatementNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/InsertStatementNode.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/InsertStatementNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,27 @@
+package org.hibernate.hql.ast.resolve;
+
+import org.hibernate.HibernateException;
+import org.hibernate.hql.ast.resolve.path.BasicPathResolutionStrategySupport;
+import org.hibernate.hql.ast.resolve.path.PathResolutionStrategy;
+
+/**
+ * Specialized statement node for representing INSERT statements
+ *
+ * @author Steve Ebersole
+ */
+public class InsertStatementNode extends StatementNode {
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public PathResolutionStrategy buildBasicPathResolutionStrategy(ResolutionContext resolutionContext) {
+		return new BasicPathResolutionStrategySupport( resolutionContext ) {
+			protected void validateJoinCreation(PersisterReference origin, String property) {
+				throw new HibernateException(
+						"insert statement cannot contain path expressions resolving to implicit joins"
+				);
+			}
+		};
+	}
+
+}

Added: 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-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,78 @@
+package org.hibernate.hql.ast.resolve;
+
+import antlr.collections.AST;
+
+import org.hibernate.hql.ast.tree.Node;
+import org.hibernate.hql.ast.tree.DisplayableNode;
+
+/**
+ * Represents an HQL join.  The coneptualization here is strictly that of
+ * the join in terms of the context of the HQL query.
+ * <p/>
+ * The structure here is such that the JoinNode has a mandatory child which is
+ * a {@link org.hibernate.hql.ast.resolve.PersisterReference} representing the
+ * right-hand-side (RHS) of the join.  Optionally, it may contain an additional
+ * child which would represent a subtree of join conditions; these join conditions
+ * would be in addition to the defined property-join conditions.
+ * <p/>
+ * The left-hand-side (LHS) of the JoinNode is actually the parent of the
+ * JoinNode.  Antlr, however, does not maintain this bi-directionality, so here
+ * we keep a referenc to our parent (the LHS) as an inst var so that we can
+ * refer to it as need be later.
+ *
+ * @author Steve Ebersole
+ */
+public class JoinNode extends Node implements DisplayableNode {
+
+	private JoinType joinType;
+	private String propertyName;
+	private PersisterReference lhs;
+
+	public JoinNode() {
+		super.setText( "join" );
+	}
+
+	public void initialize(JoinType joinType, String propertyName, PersisterReference lhs) {
+		this.joinType = joinType;
+		this.propertyName = propertyName;
+		this.lhs = lhs;
+	}
+
+	public JoinType getJoinType() {
+		return joinType;
+	}
+
+	public void setJoinType(JoinType joinType) {
+		this.joinType = joinType;
+	}
+
+	public PersisterReference getLhs() {
+		return lhs;
+	}
+
+	public PersisterReference getRhs() {
+		return ( PersisterReference ) getFirstChild();
+	}
+
+	public String getPropertyName() {
+		return propertyName;
+	}
+
+	public AST getExplicitJoinConditions() {
+		return getFirstChild().getNextSibling();
+	}
+
+	public void applyExplicitJoinConditions(AST conditions) {
+		getFirstChild().setNextSibling( conditions );
+	}
+
+	public String getDisplayText() {
+		return "{" + "type=" + joinType +
+		       ", lhs=" + ( lhs == null ? "???" : lhs.getAlias() ) +
+		       ", property=" + ( propertyName == null ? "n/a" : propertyName ) + "}";
+	}
+
+	public String toString() {
+		return "JoinNode " + getDisplayText();
+	}
+}

Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinType.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinType.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinType.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,62 @@
+package org.hibernate.hql.ast.resolve;
+
+import java.io.Serializable;
+import java.util.HashMap;
+
+/**
+ * Represents a canonical join type.
+ * <p/>
+ * Note that currently HQL really only supports inner and left outer joins
+ * (though cross joins can also be achieved).  This is because joins in HQL
+ * are always defined in relation to a mapped association.  However, when we
+ * start allowing users to specify ad-hoc joins this may need to change to
+ * allow the full spectrum of join types.  Thus the others are provided here
+ * currently just for completeness and for future expansion.
+ *
+ * @author Steve Ebersole
+ */
+public class JoinType implements Serializable {
+	/**
+	 * Represents an inner join.
+	 */
+	public static final JoinType INNER = new JoinType( "inner" );
+	/**
+	 * Represents a left outer join.
+	 */
+	public static final JoinType LEFT = new JoinType( "left outer" );
+	/**
+	 * Represents a right outer join.
+	 */
+	public static final JoinType RIGHT = new JoinType( "right outer" );
+	/**
+	 * Represents a cross join (aka a cartesian product).
+	 */
+	public static final JoinType CROSS = new JoinType( "cross" );
+	/**
+	 * Represents a full join.
+	 */
+	public static final JoinType FULL = new JoinType( "full" );
+
+	private static final HashMap INSTANCES = new HashMap();
+	static {
+		INSTANCES.put( INNER.name, INNER );
+		INSTANCES.put( LEFT.name, LEFT );
+		INSTANCES.put( RIGHT.name, RIGHT );
+		INSTANCES.put( CROSS.name, CROSS );
+		INSTANCES.put( FULL.name, FULL );
+	}
+
+	private final String name;
+
+	private JoinType(String name) {
+		this.name = name;
+	}
+
+	public String toString() {
+		return name;
+	}
+
+	private Object readResolve() {
+		return INSTANCES.get( name );
+	}
+}

Added: 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-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReference.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,96 @@
+package org.hibernate.hql.ast.resolve;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import org.hibernate.hql.ast.tree.Node;
+import org.hibernate.type.AssociationType;
+import org.hibernate.type.Type;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.AssertionFailure;
+
+/**
+ * Represents a reference to a persister (either entity or collection) within
+ * an HQL statement.
+ *
+ * @author Steve Ebersole
+ */
+public abstract class PersisterReference extends Node implements Aliasable, ResolutionContextAwareNode {
+
+	private ResolutionContext resolutionContext;
+	private final Map reusableJoinsByProperty = new HashMap();
+
+	/**
+	 * Retrieve the logical name of this persister reference.  Used in logging
+	 * operations.
+	 *
+	 * @return The logical persister reference name.
+	 */
+	public abstract String getName();
+
+	/**
+	 * The type represented by this persister reference.
+	 *
+	 * @return The type.
+	 */
+	public abstract AssociationType getPersisterType();
+
+	/**
+	 * Does the underlying persister contain such a named property?
+	 *
+	 * @param propertyName The property name to check.
+	 * @return True if the persister contains a property with that name; false
+	 * otherwise.
+	 */
+	public abstract boolean containsProperty(String propertyName);
+
+	/**
+	 * Retrieve the type of the given named property rooted at the underlying
+	 * persister; will be <tt>null</tt> if {@link #containsProperty} is false.
+	 *
+	 * @param propertyName The name of the property.
+	 * @return The property's type, or null.
+	 */
+	public abstract Type getPropertyType(String propertyName);
+
+	/**
+	 * Get the loggable text of this persister reference.
+	 *
+	 * @return The loggable text.
+	 */
+	public String getText() {
+		return getName() + " (" + getAlias() + ")";
+	}
+
+	/**
+	 * Locate a previously {@link #registerReusableJoinByProperty registered}
+	 * implicit join by the property name/path.
+	 *
+	 * @param propertyName The name/path of the property.
+	 * @return The previously registered persister reference; or null.
+	 */
+	public JoinNode locateReusableJoinByProperty(String propertyName) {
+		return ( JoinNode ) reusableJoinsByProperty.get( propertyName );
+	}
+
+	/**
+	 * Register a join by property as being reusable.
+	 *
+	 * @param propertyName The name of the property which the join represents.
+	 * @param join The join.
+	 */
+	public void registerReusableJoinByProperty(String propertyName, JoinNode join) {
+		reusableJoinsByProperty.put( propertyName, join );
+	}
+
+	protected final SessionFactoryImplementor getSessionFactory() {
+		if ( resolutionContext == null ) {
+			throw new AssertionFailure( "resolution context was null on attempt to retrieve session factory reference" );
+		}
+		return resolutionContext.getSessionFactory();
+	}
+
+	public void injectResolutionContext(ResolutionContext resolutionContext) {
+		this.resolutionContext = resolutionContext;
+	}
+}

Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceBuilder.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceBuilder.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceBuilder.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,117 @@
+package org.hibernate.hql.ast.resolve;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.MappingException;
+import org.hibernate.hql.antlr.ResolveTokenTypes;
+import org.hibernate.persister.entity.EntityPersister;
+
+/**
+ * A helper for building {@link PersisterReference} AST structures.
+ *
+ * @author Steve Ebersole
+ */
+public class PersisterReferenceBuilder {
+
+	public static final Log log = LogFactory.getLog( PersisterReferenceBuilder.class );
+
+	private final AliasBuilder aliasBuilder = new AliasBuilder();
+	private final ResolutionContext resolutionContext;
+
+
+	public PersisterReferenceBuilder(ResolutionContext resolutionContext) {
+		this.resolutionContext = resolutionContext;
+	}
+
+	// exposed services ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+	/**
+	 * Builds an entity persister reference
+	 *
+	 * @param entityName The entity name to which to build a PersisterReference.
+	 * @param alias The alias (or null) to apply to the built PersisterReference.
+	 * @param propertyFetching Whether lazy property fetching should be enabled.
+	 * @return The built PersisterReference
+	 */
+	public EntityPersisterReference buildEntityPersisterReference(
+			String entityName,
+			String alias,
+			boolean propertyFetching) {
+		EntityPersister persister = lookupEntityPersister( entityName );
+		alias = determineAlias( alias );
+		EntityPersisterReference persisterReference = ( EntityPersisterReference )
+				resolutionContext.getASTFactory().create( ResolveTokenTypes.ENTITY_PERSISTER_REF, persister.getEntityName() );
+		persisterReference.initialize( persister.getEntityName(), alias, propertyFetching );
+		resolutionContext.getCurrentPersisterReferenceContext().registerPersisterReference( persisterReference );
+		return persisterReference;
+	}
+
+	public CollectionPersisterReference buildCollectionPersisterReference(String collectionRole, String alias, boolean propertyFetching) {
+		alias = determineAlias( alias );
+		CollectionPersisterReference persisterReference = ( CollectionPersisterReference )
+				resolutionContext.getASTFactory().create( ResolveTokenTypes.COLLECTION_PERSISTER_REF, collectionRole );
+		persisterReference.initialize( collectionRole, alias, propertyFetching );
+		resolutionContext.getCurrentPersisterReferenceContext().registerPersisterReference( persisterReference );
+		return persisterReference;
+	}
+
+	public JoinNode buildJoinNode(
+			PersisterReference lhs,
+			PersisterReference rhs,
+			JoinType joinType,
+			String propertyName,
+			boolean fetching) {
+		JoinNode join = ( JoinNode ) resolutionContext.getASTFactory().create( ResolveTokenTypes.JOIN, "join" );
+		join.initialize( joinType, propertyName, lhs );
+		lhs.addChild( join );
+		join.setFirstChild( rhs );
+		if ( fetching ) {
+			resolutionContext.getCurrentPersisterReferenceContext().registerFetch( rhs );
+		}
+		if ( join.getPropertyName() != null && AliasBuilder.isNonExplicitAlias( join.getRhs().getAlias() ) ) {
+			join.getLhs().registerReusableJoinByProperty( join.getPropertyName(), join );
+		}
+		return join;
+	}
+
+	private EntityPersister lookupEntityPersister(String name) {
+		// First, try to get the persister using the class name directly.
+		try {
+			return resolutionContext.getSessionFactory().getEntityPersister( name );
+		}
+		catch ( MappingException ignore ) {
+			// unable to locate it using this name
+		}
+
+		// If that didn't work, try using the 'import' name.
+		String importedClassName = resolutionContext.getSessionFactory().getImportedClassName( name );
+		if ( importedClassName == null ) {
+			return null;
+		}
+		return resolutionContext.getSessionFactory().getEntityPersister( importedClassName );
+	}
+
+	private String determineAlias(String alias) {
+		if ( alias == null ) {
+			alias = aliasBuilder.buildUniqueImplicitAlias();
+		}
+		return alias;
+	}
+
+	public static boolean isNonExplicitAlias(String alias) {
+		return AliasBuilder.isNonExplicitAlias( alias );
+	}
+
+	private static class AliasBuilder {
+		private int unaliasedCount = 0;
+
+		private synchronized String buildUniqueImplicitAlias() {
+			return "<gen:" + unaliasedCount++ + ">";
+		}
+
+		private static boolean isNonExplicitAlias(String alias) {
+			return alias == null || ( alias.startsWith( "<gen:" ) && alias.endsWith( ">" ) );
+		}
+	}
+}

Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceContext.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceContext.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceContext.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,108 @@
+package org.hibernate.hql.ast.resolve;
+
+import java.util.List;
+import java.util.ArrayList;
+import java.util.Map;
+import java.util.HashMap;
+import java.util.Iterator;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.hibernate.QueryException;
+import org.hibernate.hql.ast.tree.Node;
+
+/**
+ * Defines the contract for implementors of a "context" or a "scope" for
+ * references to persisters.  Generally speaking, this maps to the notion
+ * of a FROM clause in a SELECT statement.  However, DML operations also
+ * have a notion of a persister reference.  This, then, acts as the
+ * abstraction of these grouped references to persisters.
+ *
+ * @see PersisterReference
+ *
+ * @author Steve Ebersole
+ */
+public class PersisterReferenceContext extends Node {
+	private static final Log log = LogFactory.getLog( PersisterReferenceContext.class );
+
+	private List persisterReferences = new ArrayList();
+	private Map aliasXref = new HashMap();
+	private List fetches = new ArrayList();
+
+	protected PersisterReferenceContext() {
+	}
+
+	public boolean isContainedAlias(String alias) {
+		return aliasXref.containsKey( alias );
+	}
+
+	public boolean isContainedExposedProperty(String propertyName) {
+		// a matching alias always takes precedence...
+		return ( ! isContainedAlias( propertyName ) )
+				&& locatePersisterReferenceExposingProperty( propertyName ) != null;
+	}
+
+	public PersisterReference locatePersisterReference(String aliasOrPropertyName) {
+		PersisterReference pRef = locatePersisterReferenceByAlias( aliasOrPropertyName );
+		if ( pRef == null ) {
+			pRef = locatePersisterReferenceExposingProperty( aliasOrPropertyName );
+		}
+		return pRef;
+	}
+
+	/**
+	 * Locate a {@link PersisterReference} by alias.
+	 *
+	 * @param alias The alias by which to locate the persister reference.
+	 * @return The persister reference, or null.
+	 */
+	public PersisterReference locatePersisterReferenceByAlias(String alias) {
+		log.trace( "attempting to resolve [" + alias + "] as persister reference alias" );
+		return ( PersisterReference ) aliasXref.get( alias );
+	}
+
+	/**
+	 * Locate an persister reference in this context which exposes the
+	 * specified property.
+	 *
+	 * @param propertyName The name of the property.
+	 * @return The persister reference, or null.
+	 */
+	public PersisterReference locatePersisterReferenceExposingProperty(String propertyName) {
+		log.trace( "attempting to resolve [" + propertyName + "] as unqualified property" );
+		EntityPersisterReference pRef = null;
+		Iterator itr = persisterReferences.iterator();
+		while( itr.hasNext() ) {
+			final EntityPersisterReference test = ( EntityPersisterReference ) itr.next();
+			if ( test.containsProperty( propertyName ) ) {
+				if ( pRef != null ) {
+					throw new QueryException( "multiple persisters contained property [" + propertyName + "]" );
+				}
+				pRef = test;
+			}
+		}
+		return pRef;
+	}
+
+	/**
+	 * Registers a persister reference in this context.  It is
+	 * assumed the passed persisterReference represents a "root"
+	 * persister reference within the query.
+	 *
+	 * @param persisterReference The persister reference to register.
+	 */
+	public void registerPersisterReference(PersisterReference persisterReference) {
+		if ( persisterReference.getAlias() == null ) {
+			throw new IllegalArgumentException( "unexpected null persister-reference alias" );
+		}
+		persisterReferences.add( persisterReference );
+		aliasXref.put( persisterReference.getAlias(), persisterReference );
+		// TODO : should we inject the persisterReference into the AST here?
+	}
+
+	public void registerFetch(PersisterReference persisterReference) {
+		fetches.add( persisterReference );
+	}
+
+}

Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceContextAwareNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceContextAwareNode.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceContextAwareNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -1,10 +1,16 @@
 package org.hibernate.hql.ast.resolve;
 
 /**
- * todo: describe PersisterReferenceContextAwareNode
+ * Injection service contract for nodes which require access to the exact
+ * {@link PersisterReferenceContext} in effect at the time they were created.
  *
  * @author Steve Ebersole
  */
 public interface PersisterReferenceContextAwareNode {
-	public void setPersisterReferenceContext(PersisterReferenceContext persisterReferenceContext);
+	/**
+	 * Injects a reference to the current {@link PersisterReferenceContext}.
+	 * 
+	 * @param persisterReferenceContext The current {@link PersisterReferenceContext}.
+	 */
+	public void injectPersisterReferenceContext(PersisterReferenceContext persisterReferenceContext);
 }

Added: 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-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyReference.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,66 @@
+package org.hibernate.hql.ast.resolve;
+
+import org.hibernate.hql.ast.tree.Node;
+import org.hibernate.hql.ast.tree.DisplayableNode;
+import org.hibernate.type.Type;
+import org.hibernate.HibernateException;
+
+/**
+ * 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 class PropertyReference extends Node implements PersisterReferenceContextAwareNode, DisplayableNode {
+
+	private PersisterReferenceContext persisterContext;
+
+	// caches
+	private String alias;
+	private String propertyName;
+	private Type propertyType;
+	private PersisterReference origin;
+
+	public String getOriginationAlias() {
+		if ( alias == null ) {
+			alias = getFirstChild().getText();
+		}
+		return alias;
+	}
+
+	public String getPropertyName() {
+		if ( propertyName == null ) {
+			propertyName = getFirstChild().getNextSibling().getText();
+		}
+		return propertyName;
+	}
+
+	public PersisterReference getOrigination() {
+		if ( origin == null ) {
+			if ( persisterContext == null ) {
+				throw new HibernateException( "PersisterReferenceContext not yet injected" );
+			}
+			origin = persisterContext.locatePersisterReferenceByAlias( getOriginationAlias() );
+		}
+		return origin;
+	}
+
+	public Type getPropertyType() {
+		if ( propertyType == null ) {
+			propertyType = getOrigination().getPropertyType( getPropertyName() );
+		}
+		return propertyType;
+	}
+
+	public void injectPersisterReferenceContext(PersisterReferenceContext persisterContext) {
+		this.persisterContext = persisterContext;
+	}
+
+	public String getDisplayText() {
+		return " {origin=" + getOrigination().getText() + ", name=" + getPropertyName() + ", type=" + getPropertyType().getName() + "}";
+	}
+}

Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyReferenceSource.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyReferenceSource.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyReferenceSource.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -1,43 +0,0 @@
-package org.hibernate.hql.ast.resolve;
-
-import org.hibernate.type.Type;
-
-/**
- * Contract for things which can be the source of a property reference in an
- * HQL query.  This contract is used to resolve dot-structures.
- *
- * @author Steve Ebersole
- */
-public interface PropertyReferenceSource {
-	/**
-	 * Retrieves the type that this source represents.
-	 *
-	 * @return The source's type.
-	 */
-	public Type getRootType();
-
-	/**
-	 * Any path information "backing" this source.  Used for componnent
-	 * resolution, where this source represents a component value.
-	 *
-	 * @return The component property path
-	 */
-	public String getPropertyPath();
-
-	/**
-	 * Again, used in component resolutions.  The persister from which the
-	 * {@link #getPropertyPath} is relative.
-	 *
-	 * @return
-	 */
-	public PersisterReference getPropertyPathRoot();
-
-	public Type getPropertyType(String propertyName);
-
-	public void prepareLHS(ResolutionContext resolutionContext, String rhsPropertyName);
-
-	public JoinNode locateImplicitJoinByProperty(String propertyName);
-
-	public void registerImplicitJoinByProperty(String propertyName, JoinNode join);
-
-}

Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolutionContext.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolutionContext.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolutionContext.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -1,35 +1,15 @@
 package org.hibernate.hql.ast.resolve;
 
-import antlr.ASTFactory;
-
-import org.hibernate.engine.SessionFactoryImplementor;
 import org.hibernate.hql.ast.resolve.path.PathResolutionStrategy;
+import org.hibernate.hql.ast.PhaseContext;
 
 /**
- * Defines the basic contract for a resolution context.
- * <p/>
- * Essentially used to define a series of services that components
- * operating within said context can rely upon.
+ * Defines the basic contract for service context for the resolution phase.
  *
  * @author Steve Ebersole
  */
-public interface ResolutionContext {
+public interface ResolutionContext extends PhaseContext {
 	/**
-	 * Retrieve a reference to the factory associated with this context for
-	 * creating AST/Node instances.
-	 *
-	 * @return The ASTFactory.
-	 */
-	public ASTFactory getASTFactory();
-
-	/**
-	 * Retrieve a reference to the session factory associated with this context.
-	 *
-	 * @return The session factory.
-	 */
-	public SessionFactoryImplementor getSessionFactory();
-
-	/**
 	 * Retrieve a reference to the {@link PersisterReference} builder associated
 	 * with this context.
 	 *

Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolutionContextAwareNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolutionContextAwareNode.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolutionContextAwareNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -6,5 +6,5 @@
  * @author Steve Ebersole
  */
 public interface ResolutionContextAwareNode {
-	public void setResolutionContext(ResolutionContext resolutionContext);
+	public void injectResolutionContext(ResolutionContext resolutionContext);
 }

Added: 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-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/StatementNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,65 @@
+package org.hibernate.hql.ast.resolve;
+
+import java.util.List;
+import java.util.Iterator;
+import java.util.ArrayList;
+
+import org.hibernate.hql.ast.tree.Node;
+import org.hibernate.util.EmptyIterator;
+import org.hibernate.QueryException;
+import org.hibernate.hql.ast.resolve.path.PathResolutionStrategy;
+
+/**
+ * Base node class for HQL statements.
+ *
+ * @author Joshua Davis
+ * @author Steve Ebersole
+ */
+public abstract class StatementNode extends Node {
+
+	private StatementNode parentStatement;
+	private List childStatements;
+	private PersisterReferenceContext persisterReferenceContext = new HierarchicalPersisterReferenceContext();
+
+	public StatementNode getParentStatement() {
+		return parentStatement;
+	}
+
+	public boolean isTopLevelStatement() {
+		return parentStatement == null;
+	}
+
+	public StatementNode getTopLevelStatement() {
+		StatementNode topLevel = this;
+		while ( topLevel.getParentStatement() != null ) {
+			topLevel = topLevel.getParentStatement();
+		}
+		return topLevel;
+	}
+
+	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;
+		this.persisterReferenceContext = new HierarchicalPersisterReferenceContext( parentStatement.getPersisterReferenceContext() );
+	}
+
+	public PersisterReferenceContext getPersisterReferenceContext() {
+		return persisterReferenceContext;
+	}
+
+	public abstract PathResolutionStrategy buildBasicPathResolutionStrategy(ResolutionContext resolutionContext);
+}

Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/UpdateStatementNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/UpdateStatementNode.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/UpdateStatementNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,25 @@
+package org.hibernate.hql.ast.resolve;
+
+import org.hibernate.hql.ast.resolve.path.PathResolutionStrategy;
+import org.hibernate.hql.ast.resolve.path.BasicPathResolutionStrategySupport;
+import org.hibernate.HibernateException;
+
+/**
+ * Specialized statement node for representing UPDATE statements
+ *
+ * @author Steve Ebersole
+ */
+public class UpdateStatementNode extends StatementNode {
+
+	/**
+	 * {@inheritDoc}
+	 */
+	public PathResolutionStrategy buildBasicPathResolutionStrategy(ResolutionContext resolutionContext) {
+		return new BasicPathResolutionStrategySupport(resolutionContext) {
+			protected void validateJoinCreation(PersisterReference origin, String property) {
+				throw new HibernateException( "update statement cannot contain path expressions resolving to implicit joins" );
+			}
+		};
+	}
+}
+

Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/path/AbstractPathResolutionStrategy.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/path/AbstractPathResolutionStrategy.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/path/AbstractPathResolutionStrategy.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -60,7 +60,7 @@
 	}
 
 	protected final void preparePropertyReference(PropertyReference propertyReferenceNode, PersisterReference persisterReference, String propertyPath) {
-		propertyReferenceNode.setPersisterReferenceContext( resolutionContext.getCurrentPersisterReferenceContext() );
+		propertyReferenceNode.injectPersisterReferenceContext( resolutionContext.getCurrentPersisterReferenceContext() );
 
 		propertyReferenceNode.setText( persisterReference.getAlias() + "." + propertyPath );
 		propertyReferenceNode.setType( ResolveTokenTypes.PROPERTY_REF );

Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/path/BasicPathResolutionStrategySupport.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/path/BasicPathResolutionStrategySupport.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/path/BasicPathResolutionStrategySupport.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -191,7 +191,7 @@
 		private JoinNode resolveLhsJoin() {
 			EntityType type = ( EntityType ) lhs.getPropertyType( propertyName );
 			validateJoinCreation( lhs, propertyName );
-			JoinNode join  = lhs.locateImplicitJoinByProperty( propertyName );
+			JoinNode join  = lhs.locateReusableJoinByProperty( propertyName );
 			if ( join == null ) {
 				String entityName = type.getAssociatedEntityName( resolutionContext.getSessionFactory() );
 				PersisterReference joinRhs = resolutionContext.getPersisterReferenceBuilder().buildEntityPersisterReference( entityName, null, false );

Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/ASTFactoryAwareNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/ASTFactoryAwareNode.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/ASTFactoryAwareNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -1,12 +0,0 @@
-package org.hibernate.hql.ast.tree;
-
-import antlr.ASTFactory;
-
-/**
- * todo: describe ASTFactoryAwareNode
- *
- * @author Steve Ebersole
- */
-public interface ASTFactoryAwareNode {
-	public void setASTFactory(ASTFactory astFactory);
-}

Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/PersisterReferenceContextAwareNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/PersisterReferenceContextAwareNode.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/PersisterReferenceContextAwareNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -1,12 +0,0 @@
-package org.hibernate.hql.ast.tree;
-
-import org.hibernate.hql.ast.resolve.PersisterReferenceContext;
-
-/**
- * todo: describe PersisterReferenceContextAwareNode
- *
- * @author Steve Ebersole
- */
-public interface PersisterReferenceContextAwareNode {
-	public void setPersisterReferenceContext(PersisterReferenceContext persisterReferenceContext);
-}

Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/PhaseContextAwareNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/PhaseContextAwareNode.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/PhaseContextAwareNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -0,0 +1,18 @@
+package org.hibernate.hql.ast.tree;
+
+import org.hibernate.hql.ast.PhaseContext;
+
+/**
+ * Injection service contract for nodes which require access to the current
+ * phase context during their lifetime.
+ *
+ * @author Steve Ebersole
+ */
+public interface PhaseContextAwareNode {
+	/**
+	 * Inject a reference to the current {@link PhaseContext}.
+	 *
+	 * @param context The current {@link PhaseContext}
+	 */
+	public void injectPhaseContext(PhaseContext context);
+}

Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java	2006-12-19 18:09:33 UTC (rev 11002)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java	2006-12-19 19:08:27 UTC (rev 11003)
@@ -1,13 +0,0 @@
-package org.hibernate.hql.ast.tree;
-
-import org.hibernate.engine.SessionFactoryImplementor;
-
-/**
- * Marking interface for nodes which want access to the
- * {@link org.hibernate.engine.SessionFactoryImplementor session factory}.
- *
- * @author Steve Ebersole
- */
-public interface SessionFactoryAwareNode {
-	public void setSessionFactory(SessionFactoryImplementor sessionFactory);
-}




More information about the hibernate-commits mailing list