Author: ste...@jb... Date: 2006-07-06 10:59:36 -0400 (Thu, 06 Jul 2006) New Revision: 10088 Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractPropertyPathHandler.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClausePropertyPathHandler.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalPropertyPathHandler.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/OnFragmentPropertyPathHandler.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PropertyPathHandler.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/WithFragmentPropertyPathHandler.java Removed: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractImplicitJoinContext.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClauseImplicitJoinContext.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ImplicitJoinContext.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinSource.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalImplicitJoinContext.java Modified: branches/HQL_ANTLR_2/Hibernate3/g2/parse.g branches/HQL_ANTLR_2/Hibernate3/g2/resolve.g branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinNode.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReference.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceBuilder.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/util/ASTPrinter.java branches/HQL_ANTLR_2/Hibernate3/test/org/hibernate/test/hql/redesign/ResolverTest.java Log: implemented handling of both on and with fragments Modified: branches/HQL_ANTLR_2/Hibernate3/g2/parse.g =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/g2/parse.g 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/g2/parse.g 2006-07-06 14:59:36 UTC (rev 10088) @@ -198,6 +198,10 @@ return node.getText(); } + public boolean isEntityName(AST node) { + return false; + } + public boolean isJavaConstant() throws RecognitionException, TokenStreamException { return false; } @@ -286,7 +290,6 @@ : c:path { weakKeywords(); } (a:asAlias)? (p:propertyFetch)? { String entityName = extractEntityName( #c ); AST en = #( [ENTITY_NAME, entityName] ); - en.initialize( #c ); #fromClassOrOuterQueryPath = #([RANGE, "RANGE"], [ENTITY_NAME, entityName], #a, #p); } ; @@ -313,10 +316,37 @@ //fromJoin // : ( ( ( LEFT | RIGHT ) (OUTER)? ) | FULL | INNER )? JOIN^ (FETCH)? path (asAlias)? (propertyFetch)? (withClause)? // ; +//fromJoin! +// : (jt:joinType)? j:JOIN (f:FETCH)? p:path (a:asAlias)? (pf:propertyFetch)? (w:withClause)? { +// #fromJoin = #( #j, #jt, #f, #a, #pf, #p, #w ); +// } +// ; + fromJoin! - : (jt:joinType)? j:JOIN (f:FETCH)? p:path (a:asAlias)? (pf:propertyFetch)? (w:withClause)? { - #fromJoin = #( #j, #jt, #f, #a, #pf, #p, #w ); - } + : (jt:joinType)? j:JOIN (f:FETCH)? p:path (a:asAlias)? + ( + // try to use the ON keyword to disambiguate + o:onFragment { + if ( #f != null ) { + throw new org.hibernate.QueryException( "Cannot use fetch keyword in conjunction with an ad hoc join" ); + } + String entityName = extractEntityName( #p ); + AST en = #( [ENTITY_NAME, entityName] ); + #fromJoin = #( #j, #jt, #en, #a, #o ); + } + // otherwise, we need to actually check the recognized path + | { isEntityName( #p ) }? { + if ( #f != null ) { + throw new org.hibernate.QueryException( "Cannot use fetch keyword in conjunction with an ad hoc join" ); + } + String entityName = extractEntityName( #p ); + AST en = #( [ENTITY_NAME, entityName] ); + #fromJoin = #( #j, #jt, #en, #a ); + } + | (pf:propertyFetch)? (w:withClause)? { + #fromJoin = #( #j, #jt, #f, #a, #pf, #p, #w ); + } + ) ; joinType @@ -329,6 +359,9 @@ : WITH^ logicalExpression ; +onFragment + : ON^ logicalExpression + ; // Alias rule - Parses the optional 'as' token and forces an AST identifier node. asAlias Modified: branches/HQL_ANTLR_2/Hibernate3/g2/resolve.g =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/g2/resolve.g 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/g2/resolve.g 2006-07-06 14:59:36 UTC (rev 10088) @@ -60,23 +60,39 @@ } - // implicit join context pushing/popping ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // property-path context pushing/popping ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - protected void pushExplicitJoinContext(AST joinType, AST fetch, AST alias, AST propertyFetch) { + protected void pushFromClausePropertyPathContext(AST joinType, AST fetch, AST alias, AST propertyFetch) { } - protected void popExplicitJoinContext() { + protected void popFromClausePropertyPathContext() { } + protected void pushOnFragmentPropertyPathContext(AST rhsPersisterReference) { + } + + protected void popOnFragmentPropertyPathContext() { + } + + protected void pushWithFragmentPropertyPathContext(AST rhsPersisterReference) { + } + + protected void popWithFragmentPropertyPathContext() { + } + + // persister reference handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ protected AST buildEntityPersisterReference(AST entityName, AST alias, AST propertyFetch) { return null; } - protected void handleAdHocJoinNode(AST persisterReference, AST joinType, AST onClause) { + protected AST buildAdHocJoinNode(AST persisterReference, AST joinType, AST withFragment) { + return null; } + protected void applyWithFragment(AST withFragment) { + } // property reference handling ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -133,12 +149,12 @@ fromClause - : #( f:FROM range ( explicitJoin | range )* ) + : #( f:FROM rootFromElement ( explicitJoin | rootFromElement )* ) ; -range! +rootFromElement! : #( RANGE e:entityPersisterReference ) { - #range = #e; + #rootFromElement = #e; } ; @@ -149,18 +165,22 @@ ; explicitJoin! - : #(JOIN (jt:joinType)? joinRhs[jt] ) + : #( + j:JOIN (jt:joinType)? + ( + e:entityPersisterReference (on:onFragment[#e])? { + buildAdHocJoinNode( #e, #jt, #on ); + if ( on != null ) { + popOnFragmentPropertyPathContext(); + } + } + | (f:FETCH)? (a:ALIAS)? (pf:PROP_FETCH)? { pushFromClausePropertyPathContext( jt, #f, #a, #pf ); } prop:propertyPath (with:withFragment[#prop])? { + popFromClausePropertyPathContext(); + } + ) + ) ; -joinRhs! [AST joinType] - : e:entityPersisterReference (on:ON)? { - handleAdHocJoinNode( #e, joinType, on ); - } - | (f:FETCH)? (a:ALIAS)? (pf:PROP_FETCH)? { pushExplicitJoinContext( joinType, #f, #a, #pf ); } prop:propertyPath (with:WITH)? { - popExplicitJoinContext(); - } - ; - // TODO : still need to account for index operators in this series of rules... propertyPath : singlePartPropertyPath @@ -202,6 +222,21 @@ | INNER ; +onFragment[ AST rhsPersisterReference ] + : #( o:ON { pushOnFragmentPropertyPathContext( rhsPersisterReference ); } le:logicalExpr ) { + #onFragment = #( o, le ); + } + ; + +withFragment[ AST rhsPropertyReference ] + : #( w:WITH { pushWithFragmentPropertyPathContext( rhsPropertyReference ); } le:logicalExpr ) { + #withFragment = #( w, le ); + applyWithFragment( #withFragment ); + popWithFragmentPropertyPathContext(); + } + ; + + intoClause : #(i:INTO (subtree)* ) ; Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractImplicitJoinContext.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractImplicitJoinContext.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractImplicitJoinContext.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -1,49 +0,0 @@ -package org.hibernate.hql.ast.resolve; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * Provides basic templating around how the two {@link org.hibernate.hql.ast.resolve.ImplicitJoinContext} - * method calls need to be interpreted and handled in different scenarios. - * - * @author Steve Ebersole - */ -public abstract class AbstractImplicitJoinContext implements ImplicitJoinContext { - - public static final Log log = LogFactory.getLog( AbstractImplicitJoinContext.class ); - - private PropertyPathPart prior; - - protected abstract PropertyPathPart handleRoot(String rootPathPart); - protected abstract PropertyReference handleRootAsTerminus(String pathPart); - - public final void handleIntermediatePathPart(String pathPart) { - if ( prior == null ) { - prior = handleRoot( pathPart ); - } - else { - prior = prior.handleIntermediatePathPart( pathPart ); - } - } - - public final PropertyReference handleTerminalPathPart(String pathPart) { - try { - if ( prior == null ) { - return handleRootAsTerminus( pathPart ); - } - else { - return prior.handleTerminalPathPart( pathPart ); - } - } - finally { - // clear our processing state in preparation for any future path expression - prior = null; - } - } - - protected static interface PropertyPathPart { - public PropertyPathPart handleIntermediatePathPart(String name); - public PropertyReference handleTerminalPathPart(String name); - } -} Copied: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractPropertyPathHandler.java (from rev 10070, branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractImplicitJoinContext.java) =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractImplicitJoinContext.java 2006-06-30 05:55:55 UTC (rev 10070) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractPropertyPathHandler.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -0,0 +1,72 @@ +package org.hibernate.hql.ast.resolve; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.hql.antlr.ResolveTokenTypes; +import antlr.collections.AST; +import antlr.ASTFactory; + +/** + * Provides basic templating around how the two {@link org.hibernate.hql.ast.resolve.PropertyPathHandler} + * method calls need to be interpreted and handled in different scenarios. + * + * @author Steve Ebersole + */ +public abstract class AbstractPropertyPathHandler implements PropertyPathHandler { + + public static final Log log = LogFactory.getLog( AbstractPropertyPathHandler.class ); + + private PropertyPathPart prior; + + protected abstract PropertyPathPart handleRoot(String rootPathPart); + protected abstract PropertyReference handleRootAsTerminus(String pathPart); + + protected void cleanup() { + } + + public final void handleIntermediatePathPart(String pathPart) { + if ( prior == null ) { + prior = handleRoot( pathPart ); + } + else { + prior = prior.handleIntermediatePathPart( pathPart ); + } + } + + public final PropertyReference handleTerminalPathPart(String pathPart) { + try { + if ( prior == null ) { + return handleRootAsTerminus( pathPart ); + } + else { + return prior.handleTerminalPathPart( pathPart ); + } + } + finally { + // clear our processing state in preparation for any future path expression + prior = null; + cleanup(); + } + } + + + protected final PropertyReference generatePropertyReference( + PersisterReference persisterReference, + String propertyName, + ASTFactory astFactory) { + PropertyReference propertyReferenceNode = ( PropertyReference ) astFactory.create( ResolveTokenTypes.PROPERTY_REF, persisterReference.getAlias() + "." + propertyName ); + + AST aliasNode = astFactory.create( ResolveTokenTypes.ALIAS, persisterReference.getAlias() ); + propertyReferenceNode.addChild( aliasNode ); + + AST propertyNameNode = astFactory.create( ResolveTokenTypes.IDENT, propertyName ); + propertyReferenceNode.addChild( propertyNameNode ); + + return propertyReferenceNode; + } + + protected static interface PropertyPathPart { + public PropertyPathPart handleIntermediatePathPart(String name); + public PropertyReference handleTerminalPathPart(String name); + } +} Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -47,18 +47,26 @@ } public Type getPropertyType(String propertyName) { - return getEntityPersister().getPropertyType( propertyName ); - } - - public boolean containsProperty(String propertyName) { try { - return getPropertyType( propertyName ) != null; + return getEntityPersister().getPropertyType( propertyName ); } catch( Throwable t ) { - return false; + return null; } } + protected PersisterReference producePersisterReference( + String propertyName, + String alias, + boolean propertyFetching, + PersisterReferenceBuilder builder) { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + + public boolean containsProperty(String propertyName) { + return getPropertyType( propertyName ) != null; + } + public String toString() { return "EntityPersisterReference {entity-name=" + entityName + ", alias=" + alias + "}"; } Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClauseImplicitJoinContext.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClauseImplicitJoinContext.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClauseImplicitJoinContext.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -1,98 +0,0 @@ -package org.hibernate.hql.ast.resolve; - -import org.hibernate.QueryException; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -/** - * todo: describe FromClauseImplicitJoinContext - * - * @author Steve Ebersole - */ -public class FromClauseImplicitJoinContext extends AbstractImplicitJoinContext { - - public static final Log log = LogFactory.getLog( FromClauseImplicitJoinContext.class ); - - private final PersisterReferenceContext persisterReferenceContext; - private final PersisterReferenceBuilder persisterReferenceBuilder; - - private final JoinType joinType; - private final String alias; - private final boolean fetching; - private final boolean propertyFetching; - - public FromClauseImplicitJoinContext( - PersisterReferenceContext persisterReferenceContext, - PersisterReferenceBuilder persisterReferenceBuilder, - JoinType joinType, - String alias, - boolean fetching, - boolean propertyFetching) { - this.persisterReferenceContext = persisterReferenceContext; - this.persisterReferenceBuilder = persisterReferenceBuilder; - this.joinType = joinType; - this.alias = alias; - this.fetching = fetching; - this.propertyFetching = propertyFetching; - } - - protected PropertyPathPart handleRoot(String rootPathPart) { - log.debug( "attempting to resolve [" + rootPathPart + "] as alias" ); - PersisterReference ref = persisterReferenceContext.locatePersisterReferenceByAlias( rootPathPart ); - if ( ref == null ) { - log.debug( "attempting to resolve [" + rootPathPart + "] as unqualified property reference" ); - ref = persisterReferenceContext.locatePersisterReferenceExposingProperty( rootPathPart ); - if ( ref == null ) { - throw new QueryException( "unable to resolve path expression root [" + rootPathPart + "]" ); - } - else { - ref = ( PersisterReference ) persisterReferenceBuilder - .buildPropertyJoin( ref, rootPathPart, joinType, null, fetching, false ) - .getFirstChild(); - } - } - return new PathPart( ref ); - } - - protected PropertyReference handleRootAsTerminus(String pathPart) { - // this should only ever mean that we have a simple unqualified property reference - log.debug( "attempting to resolve [" + pathPart + "] as unqualified property reference" ); - PersisterReference ref = persisterReferenceContext.locatePersisterReferenceExposingProperty( pathPart ); - if ( ref == null ) { - throw new QueryException( "unable to resolve unqualified property reference [" + pathPart + "]" ); - } - persisterReferenceBuilder.buildPropertyJoin( ref, pathPart, joinType, alias, fetching, propertyFetching ); - - // for joins in the from clause, we dont care about the property ref... - return null; - } - - private class PathPart implements PropertyPathPart { - private final PersisterReference persisterReference; - - public PathPart(PersisterReference persisterReference) { - this.persisterReference = persisterReference; - } - - public PropertyPathPart handleIntermediatePathPart(String name) { - return new PathPart( ( PersisterReference ) buildJoin( name, null, false ).getFirstChild() ); - } - - public PropertyReference handleTerminalPathPart(String name) { - buildJoin( name, alias, propertyFetching ); - // for joins in the from clause, we dont care about the property ref... - return null; - } - - private JoinNode buildJoin(String name, String alias, boolean propertyFetching) { - return persisterReferenceBuilder.buildPropertyJoin( - persisterReference, - name, - joinType, - alias, - fetching, - propertyFetching - ); - } - } -} Copied: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClausePropertyPathHandler.java (from rev 10070, branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClauseImplicitJoinContext.java) =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClauseImplicitJoinContext.java 2006-06-30 05:55:55 UTC (rev 10070) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClausePropertyPathHandler.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -0,0 +1,134 @@ +package org.hibernate.hql.ast.resolve; + +import org.hibernate.QueryException; +import org.hibernate.type.Type; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * todo: describe FromClausePropertyPathHandler + * + * @author Steve Ebersole + */ +public class FromClausePropertyPathHandler extends AbstractPropertyPathHandler { + + public static final Log log = LogFactory.getLog( FromClausePropertyPathHandler.class ); + + private final PersisterReferenceContext persisterReferenceContext; + private final PersisterReferenceBuilder persisterReferenceBuilder; + + private final JoinType joinType; + private final String alias; + private final boolean fetching; + private final boolean propertyFetching; + + public FromClausePropertyPathHandler( + PersisterReferenceContext persisterReferenceContext, + PersisterReferenceBuilder persisterReferenceBuilder, + JoinType joinType, + String alias, + boolean fetching, + boolean propertyFetching) { + this.persisterReferenceContext = persisterReferenceContext; + this.persisterReferenceBuilder = persisterReferenceBuilder; + this.joinType = joinType; + this.alias = alias; + this.fetching = fetching; + this.propertyFetching = propertyFetching; + } + + protected PropertyPathPart handleRoot(String rootPathPart) { + log.debug( "attempting to resolve [" + rootPathPart + "] as alias" ); + PersisterReference ref = persisterReferenceContext.locatePersisterReferenceByAlias( rootPathPart ); + if ( ref == null ) { + log.debug( "attempting to resolve [" + rootPathPart + "] as unqualified property reference" ); + ref = persisterReferenceContext.locatePersisterReferenceExposingProperty( rootPathPart ); + if ( ref == null ) { + throw new QueryException( "unable to resolve path expression root [" + rootPathPart + "]" ); + } + else { + ref = ( PersisterReference ) persisterReferenceBuilder + .buildPropertyJoin( ref, rootPathPart, joinType, null, fetching, false ) + .getFirstChild(); + } + } + return new PathPart( ref ); + } + + protected PropertyReference handleRootAsTerminus(String pathPart) { + // this should only ever mean that we have a simple unqualified property reference + log.debug( "attempting to resolve [" + pathPart + "] as unqualified property reference" ); + PersisterReference ref = persisterReferenceContext.locatePersisterReferenceExposingProperty( pathPart ); + if ( ref == null ) { + throw new QueryException( "unable to resolve unqualified property reference [" + pathPart + "]" ); + } + JoinNode join = persisterReferenceBuilder.buildPropertyJoin( ref, pathPart, joinType, alias, fetching, propertyFetching ); + + return new PropertyReferenceAdapter( ref, pathPart, join.getRhs() ); + } + + private class PathPart implements PropertyPathPart { + private final PersisterReference persisterReference; + + public PathPart(PersisterReference persisterReference) { + this.persisterReference = persisterReference; + } + + public PropertyPathPart handleIntermediatePathPart(String name) { + return new PathPart( ( PersisterReference ) buildJoin( name, null, false ).getFirstChild() ); + } + + public PropertyReference handleTerminalPathPart(String name) { + JoinNode join = buildJoin( name, alias, propertyFetching ); + return new PropertyReferenceAdapter( persisterReference, name, join.getRhs() ); + } + + private JoinNode buildJoin(String name, String alias, boolean propertyFetching) { + return persisterReferenceBuilder.buildPropertyJoin( + persisterReference, + name, + joinType, + alias, + fetching, + propertyFetching + ); + } + } + + public static class PropertyReferenceAdapter extends PropertyReference { + + private final PersisterReference lhs; + private final String propertyName; + private final PersisterReference rhs; + + public PropertyReferenceAdapter(PersisterReference lhs, String propertyName, PersisterReference rhs) { + this.lhs = lhs; + this.propertyName = propertyName; + this.rhs = rhs; + } + + public String getOriginationAlias() { + return lhs.getAlias(); + } + + public String getPropertyName() { + return propertyName; + } + + public PersisterReference getOrigination() { + return lhs; + } + + public Type getPropertyType() { + return lhs.getPropertyType( propertyName ); + } + + public PersisterReference getRhs() { + return rhs; + } + + public String getDisplayText() { + return " ADPATER : SHOULD NEVER END UP IN TREE {origin=" + getOrigination().getText() + ", name=" + getPropertyName() + ", type=" + getPropertyType().getName() + "}"; + } + } +} Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -1,6 +1,8 @@ package org.hibernate.hql.ast.resolve; import org.hibernate.hql.antlr.GeneratedHqlResolver; +import org.hibernate.hql.antlr.ResolveTokenTypes; +import org.hibernate.hql.ast.util.ASTPrinter; import org.hibernate.engine.SessionFactoryImplementor; import org.hibernate.QueryException; @@ -8,6 +10,7 @@ import org.apache.commons.logging.LogFactory; import antlr.collections.AST; +import antlr.Token; import java.util.LinkedList; @@ -18,24 +21,26 @@ * @author Joshua Davis * @author Steve Ebersole */ -public class HqlResolver extends GeneratedHqlResolver implements HqlResolverASTFactory.Context { +public class HqlResolver extends GeneratedHqlResolver + implements HqlResolverASTFactory.InjectionContext, PersisterReferenceBuilder.Listener { private static 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 ImplicitJoinContextTracker implicitJoinContextTracker = new ImplicitJoinContextTracker(); + private PropertyPathHandlerStack propertyPathHandlerStack = new PropertyPathHandlerStack(); public HqlResolver(SessionFactoryImplementor sessionFactory) { super(); this.sessionFactory = sessionFactory; setASTFactory( new HqlResolverASTFactory( this ) ); - persisterReferenceBuilder = new PersisterReferenceBuilder( getASTFactory(), sessionFactory ); + persisterReferenceBuilder = new PersisterReferenceBuilder( getASTFactory(), sessionFactory, this ); } - // HqlResolverASTFactory.Context implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // HqlResolverASTFactory.InjectionContext implementation ~~~~~~~~~~~~~~~~~~ public SessionFactoryImplementor getSessionFactory() { return sessionFactory; @@ -46,6 +51,13 @@ } + // PersisterReferenceBuilder.Listener implementation ~~~~~~~~~~~~~~~~~~~~~~ + + public void persisterReferenceBuilt(PersisterReference persisterReference) { + currentStatement.registerPersisterReference( persisterReference ); + } + + // semantic action implementations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ /** @@ -56,9 +68,8 @@ protected void pushStatement(AST statementNode) { log.trace( "pushing new statement context : " + currentStatement + " -> " + statementNode ); StatementNode statement = ( StatementNode ) statementNode; - statement.setPersisterReferenceBuilder( persisterReferenceBuilder ); - implicitJoinContextTracker.push( - new NormalImplicitJoinContext( statement, persisterReferenceBuilder, getASTFactory() ) + propertyPathHandlerStack.push( + new NormalPropertyPathHandler( statement, persisterReferenceBuilder, getASTFactory() ) ); if ( currentStatement != null ) { currentStatement.pushChild( statement ); @@ -72,13 +83,13 @@ protected void popStatement() { log.trace( "popping statement context : " + currentStatement + " -> " + currentStatement.getParentStatement() ); currentStatement = currentStatement.getParentStatement(); - implicitJoinContextTracker.pop(); + propertyPathHandlerStack.pop( NormalPropertyPathHandler.class ); } - protected void pushExplicitJoinContext(AST joinTypeNode, AST fetch, AST alias, AST propertyFetch) { - log.debug( "pushing explicit (from-clause) implicit join context" ); - implicitJoinContextTracker.push( - new FromClauseImplicitJoinContext( + protected void pushFromClausePropertyPathContext(AST joinTypeNode, AST fetch, AST alias, AST propertyFetch) { + log.debug( "pushing explicit (from clause) property path context" ); + propertyPathHandlerStack.push( + new FromClausePropertyPathHandler( currentStatement, persisterReferenceBuilder, resolveJoinType( joinTypeNode ), @@ -89,11 +100,49 @@ ); } - protected void popExplicitJoinContext() { - log.debug( "popping implicit join context" ); - implicitJoinContextTracker.pop(); + protected void popFromClausePropertyPathContext() { + log.debug( "popping explicit (from clause) property path context" ); + propertyPathHandlerStack.pop( FromClausePropertyPathHandler.class ); } + protected void pushOnFragmentPropertyPathContext(AST rhsPersisterReference) { + propertyPathHandlerStack.push( + new OnFragmentPropertyPathHandler( + currentStatement, + ( PersisterReference ) rhsPersisterReference, + astFactory, + sessionFactory + ) + ); + log.debug( "pushing on-fragment path handler [rhs=" + rhsPersisterReference.getText() + "]" ); + } + + protected void popOnFragmentPropertyPathContext() { + log.debug( "popping on-fragment path handler" ); + propertyPathHandlerStack.pop( OnFragmentPropertyPathHandler.class ); + } + + protected void pushWithFragmentPropertyPathContext(AST rhsPropertyReference) { + // can only be used in conjunction with property reference generated + // directly from FromClausePropertyPathHandler... + FromClausePropertyPathHandler.PropertyReferenceAdapter propertyReference = ( FromClausePropertyPathHandler.PropertyReferenceAdapter ) rhsPropertyReference; + propertyPathHandlerStack.push( + new WithFragmentPropertyPathHandler( + currentStatement, + propertyReference.getOrigination(), + propertyReference.getRhs(), + astFactory, + sessionFactory + ) + ); + log.debug( "pushing with-fragment path handler" ); + } + + protected void popWithFragmentPropertyPathContext() { + log.debug( "popping on-fragment path handler" ); + propertyPathHandlerStack.pop( WithFragmentPropertyPathHandler.class ); + } + /** * Semantic action called to perform generation of an {@link EntityPersisterReference} * representing a "root" persister reference. @@ -117,34 +166,40 @@ return node == null ? null : node.getText(); } - private JoinNode createJoinNode(JoinType type, JoinSource source, boolean fetch, PersisterReference rhs) { + private JoinNode createJoinNode(JoinType type, String propertyName, boolean fetch, PersisterReference lhs) { JoinNode node = ( JoinNode ) getASTFactory().create( JOIN, "join" ); - node.initialize( type, source, fetch, rhs ); - rhs.addChild( node ); + node.initialize( type, propertyName, fetch, lhs ); + lhs.addChild( node ); return node; } protected void handleIntermediatePathPart(AST name) { log.debug( "handling intermediate path part [" + name.getText() + "]" ); - implicitJoinContextTracker.getCurrent().handleIntermediatePathPart( name.getText() ); + propertyPathHandlerStack.getCurrent().handleIntermediatePathPart( name.getText() ); } protected AST handleTerminalPathPart(AST name) { log.debug( "handling terminal path part [" + name.getText() + "]" ); - return implicitJoinContextTracker.getCurrent().handleTerminalPathPart( name.getText() ); + return propertyPathHandlerStack.getCurrent().handleTerminalPathPart( name.getText() ); } - protected void handleAdHocJoinNode(AST persisterReference, AST joinType, AST onClause) { - // todo : need to be able to resolve the lhs join operand - EntityPersisterReference other = null; - JoinNode join = createJoinNode( resolveJoinType( joinType ), JoinSource.AD_HOC, false, other ); - join.setFirstChild( persisterReference ); - if ( onClause != null ) { - join.addChild( onClause ); - } + 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 ); + OnFragmentPropertyPathHandler handler = ( OnFragmentPropertyPathHandler ) propertyPathHandlerStack.getCurrent(); + EntityPersisterReference lhs = ( EntityPersisterReference ) handler.getDiscoveredLhs(); + JoinNode join = createJoinNode( joinType, null, false, lhs ); + join.setFirstChild( rhs ); + join.applyExplicitJoinConditions( onClause ); + return join; } + protected void applyWithFragment(AST withFragment) { + WithFragmentPropertyPathHandler handler = ( WithFragmentPropertyPathHandler ) propertyPathHandlerStack.getCurrent(); + handler.applyWithFragment( withFragment ); + } + private JoinType resolveJoinType(AST joinType) { int joinTypeType = joinType == null ? INNER : joinType.getType(); switch ( joinTypeType ) { @@ -173,22 +228,30 @@ return buffer.toString(); } - private class ImplicitJoinContextTracker { + private class PropertyPathHandlerStack { private LinkedList stack = new LinkedList(); - public ImplicitJoinContextTracker() { + public PropertyPathHandlerStack() { } - public void push(ImplicitJoinContext context) { + public void push(PropertyPathHandler context) { stack.addFirst( context ); } - public void pop() { - stack.removeFirst(); + public void pop(Class expectedCurrentHandlerClass) { + PropertyPathHandler handler = ( PropertyPathHandler ) stack.removeFirst(); + if ( !expectedCurrentHandlerClass.isInstance( handler ) ) { + throw new IllegalStateException( + "INTERNAL PARSER ERROR : unexpected property path handler type encountered on pop" + + " [expecting=" + expectedCurrentHandlerClass.getName() + + ", encountered=" + handler.getClass().getName() + "]" + ); + } + log.debug( "popped path handler; current now : " + ( stack.isEmpty() ? null : getCurrent() ) ); } - public ImplicitJoinContext getCurrent() { - return ( ImplicitJoinContext ) stack.getFirst(); + public PropertyPathHandler getCurrent() { + return ( PropertyPathHandler ) stack.getFirst(); } } } Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -17,14 +17,14 @@ */ public class HqlResolverASTFactory extends HqlASTFactory implements ResolveTokenTypes { - public static interface Context { + public static interface InjectionContext { public SessionFactoryImplementor getSessionFactory(); public PersisterReferenceContext getPersisterReferenceContext(); } - private final Context context; + private final InjectionContext context; - public HqlResolverASTFactory(Context context) { + public HqlResolverASTFactory(InjectionContext context) { this.context = context; } Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ImplicitJoinContext.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ImplicitJoinContext.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ImplicitJoinContext.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -1,11 +0,0 @@ -package org.hibernate.hql.ast.resolve; - -/** - * Contract for how implicit joins are handled. - * - * @author Steve Ebersole - */ -public interface ImplicitJoinContext { - public void handleIntermediatePathPart(String pathPart); - public PropertyReference handleTerminalPathPart(String pathPart); -} Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinNode.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinNode.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinNode.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -1,6 +1,7 @@ package org.hibernate.hql.ast.resolve; import antlr.Token; +import antlr.collections.AST; import org.hibernate.hql.ast.tree.Node; import org.hibernate.hql.ast.tree.DisplayableNode; @@ -18,7 +19,7 @@ // to both the left-hand and right-hand persister references private JoinType joinType; - private JoinSource source; + private String propertyName; private boolean fetch; private PersisterReference lhs; @@ -26,14 +27,9 @@ super.setText( "join" ); } - public JoinNode(Token tok) { - super( tok ); - super.setText( "join" ); - } - - public void initialize(JoinType joinType, JoinSource source, boolean fetch, PersisterReference lhs) { + public void initialize(JoinType joinType, String propertyName, boolean fetch, PersisterReference lhs) { this.joinType = joinType; - this.source = source; + this.propertyName = propertyName; this.fetch = fetch; this.lhs = lhs; } @@ -46,14 +42,6 @@ this.joinType = joinType; } - public JoinSource getSource() { - return source; - } - - public void setSource(JoinSource source) { - this.source = source; - } - public boolean isFetch() { return fetch; } @@ -62,8 +50,27 @@ this.fetch = fetch; } + public PersisterReference getLhs() { + return lhs; + } + + public PersisterReference getRhs() { + return ( PersisterReference ) getFirstChild(); + } + + public AST getExplicitJoinConditions() { + return getFirstChild().getNextSibling(); + } + + public void applyExplicitJoinConditions(AST conditions) { + getFirstChild().setNextSibling( conditions ); + } + public String getDisplayText() { - return "{" + "type=" + joinType + ", source=" + source + ", fetch=" + fetch + ", lhs=" + lhs.getAlias() + "}"; + return "{" + "type=" + joinType + + ", fetch=" + fetch + + ", lhs=" + ( lhs == null ? "???" : lhs.getAlias() ) + + ", property=" + ( propertyName == null ? "n/a" : propertyName ) + "}"; } public String toString() { Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinSource.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinSource.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/JoinSource.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -1,55 +0,0 @@ -package org.hibernate.hql.ast.resolve; - -import java.util.HashMap; -import java.io.Serializable; - -/** - * Represents the source of a join, in the context of the HQL query. - * - * @author Steve Ebersole - */ -public class JoinSource implements Serializable { - - /** - * Indicates a join using the HQL explicit join syntax (i.e. the join keyword). - */ - public static final JoinSource EXPLICIT = new JoinSource( "explicit" ); - /** - * Indicates a join defined by implicit syntax (i.e. a path expression). - */ - public static final JoinSource IMPLICIT = new JoinSource( "implicit" ); - /** - * Indicates a join that is the result of an indexed operation (i.e. []) - * on an indexed or keyed collection (list or map). - */ - public static final JoinSource INDEXED = new JoinSource( "indexed" ); - /** - * Indicates a theta-style join (i.e. from A a, B b where a.id = b.id...) - */ - public static final JoinSource THETA = new JoinSource( "theta" ); - - public static final JoinSource AD_HOC = new JoinSource( "ad_hoc" ); - - private static final HashMap INSTANCES = new HashMap(); - static { - INSTANCES.put( EXPLICIT.name, EXPLICIT ); - INSTANCES.put( IMPLICIT.name, IMPLICIT ); - INSTANCES.put( INDEXED.name, INDEXED ); - INSTANCES.put( THETA.name, THETA ); - INSTANCES.put( AD_HOC.name, AD_HOC ); - } - - private final String name; - - private JoinSource(String name) { - this.name = name; - } - - public String toString() { - return name; - } - - private Object readResolve() { - return INSTANCES.get( name ); - } -} Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalImplicitJoinContext.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalImplicitJoinContext.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalImplicitJoinContext.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -1,236 +0,0 @@ -package org.hibernate.hql.ast.resolve; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.hibernate.hql.antlr.ResolveTokenTypes; -import org.hibernate.hql.CollectionProperties; -import org.hibernate.QueryException; -import org.hibernate.type.Type; -import org.hibernate.type.ComponentType; -import antlr.ASTFactory; -import antlr.collections.AST; - -/** - * Defines the behavior of how implicit joins are normally handled. - * <p/> - * All other implementations of {@link org.hibernate.hql.ast.resolve.ImplicitJoinContext} are - * considered special cases. - * - * @author Steve Ebersole - */ -public class NormalImplicitJoinContext extends AbstractImplicitJoinContext { - - public static final Log log = LogFactory.getLog( NormalImplicitJoinContext.class ); - - private final PersisterReferenceContext persisterReferenceContext; - private final PersisterReferenceBuilder persisterReferenceBuilder; - private final ASTFactory astFactory; - - private PropertyPathPart prior; - - public NormalImplicitJoinContext( - PersisterReferenceContext persisterReferenceContext, - PersisterReferenceBuilder persisterReferenceBuilder, - ASTFactory astFactory) { - this.persisterReferenceContext = persisterReferenceContext; - this.persisterReferenceBuilder = persisterReferenceBuilder; - this.astFactory = astFactory; - } - - protected PropertyPathPart handleRoot(String pathPart) { - PersisterReference persisterReference = resolveAsAlias( pathPart ); - if ( persisterReference != null ) { - return new PropertyPathRoot( ( EntityPersisterReference ) persisterReference ); - } - - persisterReference = resolveAsUnqualified( pathPart ); - if ( persisterReference != null ) { - return new EntityPropertyReference( ( EntityPersisterReference ) persisterReference, pathPart, false ); - } - - throw new QueryException( "unable to resolve path expression root [" + pathPart + "]" ); - } - - protected PropertyReference handleRootAsTerminus(String pathPart) { - PersisterReference ref = resolveAsUnqualified( pathPart ); - return generatePropertyReference( ref, pathPart ); - } - - - - - private PropertyReference generatePropertyReference(PersisterReference persisterReference, String propertyName) { - PropertyReference propertyReferenceNode = ( PropertyReference ) astFactory.create( ResolveTokenTypes.PROPERTY_REF, persisterReference.getAlias() + "." + propertyName ); - - AST aliasNode = astFactory.create( ResolveTokenTypes.ALIAS, persisterReference.getAlias() ); - propertyReferenceNode.addChild( aliasNode ); - - AST propertyNameNode = astFactory.create( ResolveTokenTypes.IDENT, propertyName ); - propertyReferenceNode.addChild( propertyNameNode ); - - return propertyReferenceNode; - } - - private EntityPersisterReference resolveAsAlias(String name) { - return ( EntityPersisterReference ) persisterReferenceContext.locatePersisterReferenceByAlias( name ); - } - - private EntityPersisterReference resolveAsUnqualified(String firstPathExpression) { - return persisterReferenceContext.locatePersisterReferenceExposingProperty( firstPathExpression ); - } - - private PropertyPathPart determineAppropriatePartType(EntityPersisterReference origin, String propertyName) { - Type propertyType = origin.getPropertyType( propertyName ); - if ( propertyType.isComponentType() ) { - return new ComponentPropertyReference( origin, propertyName, ( ComponentType ) propertyType ); - } - else if ( propertyType.isEntityType() ) { - return new EntityPropertyReference( origin, propertyName, false ); - } - else if ( propertyType.isCollectionType() ) { - return new CollectionPropertyReference( origin, propertyName ); - } - else { - return new SimplePropertyReference( origin, propertyName ); - } - } - - private int locateComponentPropertyIndex(ComponentType componentType, String subPropertyName) { - String[] componentPropertyNames = componentType.getPropertyNames(); - for ( int i = 0; i < componentPropertyNames.length; i++ ) { - if ( componentPropertyNames[i].equals( subPropertyName ) ) { - return i; - } - } - throw new QueryException( "could not locate component property [" + subPropertyName + "]" ); - } - - private class PropertyPathRoot implements PropertyPathPart { - private final EntityPersisterReference persisterReference; - - public PropertyPathRoot(EntityPersisterReference persisterReference) { - this.persisterReference = persisterReference; - } - - public PropertyPathPart handleIntermediatePathPart(String name) { - return determineAppropriatePartType( persisterReference, name ); - } - - public PropertyReference handleTerminalPathPart(String name) { - // todo : this really needs to consider whether a join might be needed - // based on the property type and type of clause - return generatePropertyReference( persisterReference, name ); - } - - } - - private class SimplePropertyReference implements PropertyPathPart { - private final EntityPersisterReference origin; - private final String propertyName; - - public SimplePropertyReference(EntityPersisterReference origin, String propertyName) { - this.origin = origin; - this.propertyName = propertyName; - } - - public PropertyPathPart handleIntermediatePathPart(String name) { - throw new QueryException( "cannot perform implicit join based on simple property" ); - } - - public PropertyReference handleTerminalPathPart(String name) { - throw new QueryException( "cannot perform implicit join based on simple property" ); - } - } - - private class ComponentPropertyReference implements PropertyPathPart { - private final EntityPersisterReference origin; - private final String componentPropertyName; - private final ComponentType componentType; - - public ComponentPropertyReference(EntityPersisterReference origin, String componentPropertyName) { - this( origin, componentPropertyName, ( ComponentType ) origin.getPropertyType( componentPropertyName ) ); - } - - public ComponentPropertyReference(EntityPersisterReference origin, String componentPropertyName, ComponentType componentType) { - this.origin = origin; - this.componentPropertyName = componentPropertyName; - this.componentType = componentType; - } - - public PropertyPathPart handleIntermediatePathPart(String propertyName) { - int index = locateComponentPropertyIndex( componentType, propertyName ); - String path = buildDerefPath( propertyName ); - Type propertyType = componentType.getSubtypes()[index]; - if ( propertyType.isComponentType() ) { - return new ComponentPropertyReference( origin, path, ( ComponentType ) propertyType ); - } - else if ( propertyType.isEntityType() ) { - return new EntityPropertyReference( origin, path, false ); - } - else { - return new SimplePropertyReference( origin, path ); - } - } - - public PropertyReference handleTerminalPathPart(String name) { - return generatePropertyReference( origin, buildDerefPath( name ) ); - } - - private String buildDerefPath(String subPropertyName) { - return componentPropertyName + "." + subPropertyName; - } - } - - private class EntityPropertyReference implements PropertyPathPart { - private final EntityPersisterReference origin; - private final String propertyName; - - private boolean joined; - - public EntityPropertyReference(EntityPersisterReference origin, String propertyName, boolean joined) { - this.origin = origin; - this.propertyName = propertyName; - this.joined = joined; - } - - public PropertyPathPart handleIntermediatePathPart(String name) { - EntityPersisterReference joinedPersister = ( EntityPersisterReference ) buildPropertyJoin( origin, propertyName ); - return determineAppropriatePartType( joinedPersister, name ); - } - - public PropertyReference handleTerminalPathPart(String name) { - // not always needed (i.e. : .id) - EntityPersisterReference joinedPersister = ( EntityPersisterReference ) buildPropertyJoin( origin, propertyName ); - return generatePropertyReference( joinedPersister, name ); - } - } - - private class CollectionPropertyReference implements PropertyPathPart { - private final EntityPersisterReference origin; - private final String collectionPropertyName; - - public CollectionPropertyReference(EntityPersisterReference origin, String collectionPropertyName) { - this.origin = origin; - this.collectionPropertyName = collectionPropertyName; - } - - public PropertyPathPart handleIntermediatePathPart(String name) { - throw new QueryException( "illegal attempt to perform implicit join across collection property" ); - } - - public PropertyReference handleTerminalPathPart(String name) { - if ( CollectionProperties.isAnyCollectionProperty( name ) ) { - CollectionPersisterReference joinedPersister = ( CollectionPersisterReference ) buildPropertyJoin( origin, collectionPropertyName ); - return generatePropertyReference( joinedPersister, name ); - } - throw new QueryException( "illegal attempt to perform implicit join across collection property" ); - } - } - - - private PersisterReference buildPropertyJoin(EntityPersisterReference origin, String propertyName) { - return ( PersisterReference ) persisterReferenceBuilder - .buildPropertyJoin( origin, propertyName, JoinType.INNER, null, false, false ) - .getFirstChild(); - } -} Copied: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalPropertyPathHandler.java (from rev 10070, branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalImplicitJoinContext.java) =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalImplicitJoinContext.java 2006-06-30 05:55:55 UTC (rev 10070) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalPropertyPathHandler.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -0,0 +1,218 @@ +package org.hibernate.hql.ast.resolve; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.hql.CollectionProperties; +import org.hibernate.QueryException; +import org.hibernate.type.Type; +import org.hibernate.type.ComponentType; +import antlr.ASTFactory; + +/** + * Defines the behavior of how implicit joins are normally handled. + * <p/> + * All other implementations of {@link org.hibernate.hql.ast.resolve.PropertyPathHandler} are + * considered special cases. + * + * @author Steve Ebersole + */ +public class NormalPropertyPathHandler extends AbstractPropertyPathHandler { + + public static final Log log = LogFactory.getLog( NormalPropertyPathHandler.class ); + + private final PersisterReferenceContext persisterReferenceContext; + private final PersisterReferenceBuilder persisterReferenceBuilder; + private final ASTFactory astFactory; + + public NormalPropertyPathHandler( + PersisterReferenceContext persisterReferenceContext, + PersisterReferenceBuilder persisterReferenceBuilder, + ASTFactory astFactory) { + this.persisterReferenceContext = persisterReferenceContext; + this.persisterReferenceBuilder = persisterReferenceBuilder; + this.astFactory = astFactory; + } + + protected PropertyPathPart handleRoot(String pathPart) { + PersisterReference persisterReference = resolveAsAlias( pathPart ); + if ( persisterReference != null ) { + return new PropertyPathRoot( ( EntityPersisterReference ) persisterReference ); + } + + persisterReference = resolveAsUnqualified( pathPart ); + if ( persisterReference != null ) { + return new EntityPropertyReference( ( EntityPersisterReference ) persisterReference, pathPart, false ); + } + + throw new QueryException( "unable to resolve path expression root [" + pathPart + "]" ); + } + + protected PropertyReference handleRootAsTerminus(String pathPart) { + PersisterReference ref = resolveAsUnqualified( pathPart ); + return generatePropertyReference( ref, pathPart, astFactory ); + } + + + private EntityPersisterReference resolveAsAlias(String name) { + return ( EntityPersisterReference ) persisterReferenceContext.locatePersisterReferenceByAlias( name ); + } + + private EntityPersisterReference resolveAsUnqualified(String firstPathExpression) { + return persisterReferenceContext.locatePersisterReferenceExposingProperty( firstPathExpression ); + } + + private PropertyPathPart determineAppropriatePartType(EntityPersisterReference origin, String propertyName) { + Type propertyType = origin.getPropertyType( propertyName ); + if ( propertyType.isComponentType() ) { + return new ComponentPropertyReference( origin, propertyName, ( ComponentType ) propertyType ); + } + else if ( propertyType.isEntityType() ) { + return new EntityPropertyReference( origin, propertyName, false ); + } + else if ( propertyType.isCollectionType() ) { + return new CollectionPropertyReference( origin, propertyName ); + } + else { + return new SimplePropertyReference( origin, propertyName ); + } + } + + private int locateComponentPropertyIndex(ComponentType componentType, String subPropertyName) { + String[] componentPropertyNames = componentType.getPropertyNames(); + for ( int i = 0; i < componentPropertyNames.length; i++ ) { + if ( componentPropertyNames[i].equals( subPropertyName ) ) { + return i; + } + } + throw new QueryException( "could not locate component property [" + subPropertyName + "]" ); + } + + private class PropertyPathRoot implements PropertyPathPart { + private final EntityPersisterReference persisterReference; + + public PropertyPathRoot(EntityPersisterReference persisterReference) { + this.persisterReference = persisterReference; + } + + public PropertyPathPart handleIntermediatePathPart(String name) { + return determineAppropriatePartType( persisterReference, name ); + } + + public PropertyReference handleTerminalPathPart(String name) { + // todo : this really needs to consider whether a join might be needed + // based on the property type and type of clause + return generatePropertyReference( persisterReference, name, astFactory ); + } + + } + + private class SimplePropertyReference implements PropertyPathPart { + private final EntityPersisterReference origin; + private final String propertyName; + + public SimplePropertyReference(EntityPersisterReference origin, String propertyName) { + this.origin = origin; + this.propertyName = propertyName; + } + + public PropertyPathPart handleIntermediatePathPart(String name) { + throw new QueryException( "cannot perform implicit join based on simple property" ); + } + + public PropertyReference handleTerminalPathPart(String name) { + throw new QueryException( "cannot perform implicit join based on simple property" ); + } + } + + private class ComponentPropertyReference implements PropertyPathPart { + private final EntityPersisterReference origin; + private final String componentPropertyName; + private final ComponentType componentType; + + public ComponentPropertyReference(EntityPersisterReference origin, String componentPropertyName) { + this( origin, componentPropertyName, ( ComponentType ) origin.getPropertyType( componentPropertyName ) ); + } + + public ComponentPropertyReference(EntityPersisterReference origin, String componentPropertyName, ComponentType componentType) { + this.origin = origin; + this.componentPropertyName = componentPropertyName; + this.componentType = componentType; + } + + public PropertyPathPart handleIntermediatePathPart(String propertyName) { + int index = locateComponentPropertyIndex( componentType, propertyName ); + String path = buildDerefPath( propertyName ); + Type propertyType = componentType.getSubtypes()[index]; + if ( propertyType.isComponentType() ) { + return new ComponentPropertyReference( origin, path, ( ComponentType ) propertyType ); + } + else if ( propertyType.isEntityType() ) { + return new EntityPropertyReference( origin, path, false ); + } + else { + return new SimplePropertyReference( origin, path ); + } + } + + public PropertyReference handleTerminalPathPart(String name) { + return generatePropertyReference( origin, buildDerefPath( name ), astFactory ); + } + + private String buildDerefPath(String subPropertyName) { + return componentPropertyName + "." + subPropertyName; + } + } + + private class EntityPropertyReference implements PropertyPathPart { + private final EntityPersisterReference origin; + private final String propertyName; + + private boolean joined; + + public EntityPropertyReference(EntityPersisterReference origin, String propertyName, boolean joined) { + this.origin = origin; + this.propertyName = propertyName; + this.joined = joined; + } + + public PropertyPathPart handleIntermediatePathPart(String name) { + EntityPersisterReference joinedPersister = ( EntityPersisterReference ) buildPropertyJoin( origin, propertyName ); + return determineAppropriatePartType( joinedPersister, name ); + } + + public PropertyReference handleTerminalPathPart(String name) { + // not always needed (i.e. : .id) + EntityPersisterReference joinedPersister = ( EntityPersisterReference ) buildPropertyJoin( origin, propertyName ); + return generatePropertyReference( joinedPersister, name, astFactory ); + } + } + + private class CollectionPropertyReference implements PropertyPathPart { + private final EntityPersisterReference origin; + private final String collectionPropertyName; + + public CollectionPropertyReference(EntityPersisterReference origin, String collectionPropertyName) { + this.origin = origin; + this.collectionPropertyName = collectionPropertyName; + } + + public PropertyPathPart handleIntermediatePathPart(String name) { + throw new QueryException( "illegal attempt to perform implicit join across collection property" ); + } + + public PropertyReference handleTerminalPathPart(String name) { + if ( CollectionProperties.isAnyCollectionProperty( name ) ) { + CollectionPersisterReference joinedPersister = ( CollectionPersisterReference ) buildPropertyJoin( origin, collectionPropertyName ); + return generatePropertyReference( joinedPersister, name, astFactory ); + } + throw new QueryException( "illegal attempt to perform implicit join across collection property" ); + } + } + + + private PersisterReference buildPropertyJoin(EntityPersisterReference origin, String propertyName) { + return ( PersisterReference ) persisterReferenceBuilder + .buildPropertyJoin( origin, propertyName, JoinType.INNER, null, false, false ) + .getFirstChild(); + } +} Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/OnFragmentPropertyPathHandler.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/OnFragmentPropertyPathHandler.java 2006-07-06 12:21:30 UTC (rev 10087) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/OnFragmentPropertyPathHandler.java 2006-07-06 14:59:36 UTC (rev 10088) @@ -0,0 +1,159 @@ +package org.hibernate.hql.ast.resolve; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import org.hibernate.type.Type; +import org.hibernate.QueryException; +import org.hibernate.engine.SessionFactoryImplementor; +import antlr.ASTFactory; + +/** + * todo: describe OnFragmentPropertyPathHandler + * + * @author Steve Ebersole + */ +public class OnFragmentPropertyPathHandler extends AbstractPropertyPathHandler { + + public static final Log log = LogFactory.getLog( OnFragmentPropertyPathHandler.class ); + + private final PersisterReferenceContext persisterReferenceContext; + private final PersisterReference joinRhs; + private final ASTFactory astFactory; + private final SessionFactoryImplementor sessionFactory; + + private PersisterReference joinLhs; + + public OnFragmentPropertyPathHandler( + PersisterReferenceContext persisterReferenceContext, + PersisterReference joinRhs, + ASTFactory astFactory, + SessionFactoryImplementor sessionFactory) { + this.astFactory = astFactory; + this.persisterReferenceContext = persisterReferenceContext; + this.joinRhs = joinRhs; + this.sessionFactory = sessionFactory; + } + + public PersisterReference getDiscoveredLhs() { + return joinLhs; + } + + protected PropertyPathPart handleRoot(String rootPathPart) { + // might indicte a number of situations: + // 1) alias to joinRhs + // 2) unq... [truncated message content] |