Author: steve.ebersole(a)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);
-}