|
From: <hib...@li...> - 2006-06-30 05:58:32
|
Author: ste...@jb...
Date: 2006-06-30 01:55:55 -0400 (Fri, 30 Jun 2006)
New Revision: 10070
Added:
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/HqlParser.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/ParseLexer.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/PathCollector.java
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/NormalImplicitJoinContext.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/PersisterReferenceBuilder.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
Removed:
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverAware.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/SessionFactoryAwareNode.java
Modified:
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java
branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/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/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/util/ReflectHelper.java
Log:
redid parse phase and simplified portions of resolve phase
Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/HqlParser.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/HqlParser.java 2006-06-30 05:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/HqlParser.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -0,0 +1,384 @@
+package org.hibernate.hql.ast.parse;
+
+import org.hibernate.hql.antlr.GeneratedHqlParser;
+import org.hibernate.hql.antlr.ParseTokenTypes;
+import org.hibernate.hql.ast.util.ASTUtil;
+import org.hibernate.hql.ast.util.ASTPrinter;
+import org.hibernate.hql.ast.HqlToken;
+import org.hibernate.hql.ast.ErrorCounter;
+import org.hibernate.hql.ast.HqlASTFactory;
+import org.hibernate.hql.ast.ParseErrorHandler;
+import org.hibernate.QueryException;
+import org.hibernate.util.ReflectHelper;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import java.io.StringReader;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+import antlr.collections.AST;
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import antlr.Token;
+import antlr.ASTPair;
+import antlr.MismatchedTokenException;
+
+/**
+ * The parser used by Hibernate to generate an AST given an input
+ * HQL string (a "stream parser"). The produced AST is then used
+ * (and mutated) by later phases/parsers to apply semantic resolution;
+ * this parser, however, is all about syntax resolution.
+ *
+ * @author Steve Ebersole
+ */
+public class HqlParser extends GeneratedHqlParser {
+
+ public static final Log log = LogFactory.getLog( HqlParser.class );
+
+ private final ParseErrorHandler parseErrorHandler = new ErrorCounter();
+ private final ASTPrinter printer = new ASTPrinter( ParseTokenTypes.class );
+
+ public HqlParser(String hql) {
+ super( new ParseLexer( new StringReader( hql ) ) );
+ setASTFactory( new HqlASTFactory() );
+ }
+
+
+ // overrides of Antlr infastructure methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ public void reportError(RecognitionException e) {
+ parseErrorHandler.reportError( e );
+ }
+
+ public void reportError(String s) {
+ parseErrorHandler.reportError( s );
+ }
+
+ public void reportWarning(String s) {
+ parseErrorHandler.reportWarning( s );
+ }
+
+ public ParseErrorHandler getParseErrorHandler() {
+ return parseErrorHandler;
+ }
+
+ static public void panic() {
+ //overriden to avoid System.exit
+ throw new QueryException( "Parser: panic" );
+ }
+
+
+ // various AST output methods ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ public void dumpAst(AST ast) {
+ dumpAst( ast, "DUMP" );
+ }
+
+ public void dumpAst(AST ast, String header) {
+ log.info( printer.showAsString( ast, header ) );
+ }
+
+ public void showAst(AST ast, PrintStream out) {
+ showAst( ast, new PrintWriter( out ) );
+ }
+
+ private void showAst(AST ast, PrintWriter pw) {
+ printer.showAst( ast, pw );
+ }
+
+
+ // overrides of grammar semantic actions ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ public String extractEntityName(AST node) throws RecognitionException {
+ dumpAst( node, "expected entity name path" );
+ return PathCollector.getPath( node );
+ }
+
+ public String extractDynamicInstantiationPojoName(AST node) {
+ return PathCollector.getPath( node );
+ }
+
+ public String extractJavaConstantReference(AST node) throws RecognitionException {
+ return PathCollector.getPath( node );
+ }
+
+ public boolean isJavaConstant() throws RecognitionException, TokenStreamException {
+ if ( LA( 2 ) != DOT ) {
+ return false;
+ }
+ String path = LT( 1 ).getText() + "." + LT( 3 ).getText();
+ int currentLaPotion = 5;
+ while ( LA( currentLaPotion - 1 ) == DOT ) {
+ path += "." + LT( currentLaPotion ).getText();
+ currentLaPotion += 2;
+ }
+ return isJavaConstant( path );
+ }
+
+ public boolean isJavaConstant(AST dotStructure) throws RecognitionException, TokenStreamException {
+ return isJavaConstant( PathCollector.getPath( dotStructure ) );
+ }
+
+ private boolean isJavaConstant(String path) {
+ try {
+ log.trace( "Testing path [" + path + "] as potential java constant" );
+ Object value = ReflectHelper.getConstantValueStrictly( path );
+ log.trace( "Resolved path to java constant [" + value + "]" );
+ return true;
+ }
+ catch( Throwable t ) {
+ log.trace( "Path did not resolve to java constant : " + t );
+ return false;
+ }
+ }
+
+ /**
+ * Overrides the base behavior to retry keywords as identifiers.
+ *
+ * @param token The token.
+ * @param ex The recognition exception.
+ * @return AST - The new AST.
+ * @throws antlr.RecognitionException if the substitution was not possible.
+ * @throws antlr.TokenStreamException if the substitution was not possible.
+ */
+ public AST handleIdentifierError(Token token, RecognitionException ex) throws RecognitionException, TokenStreamException {
+ // If the token can tell us if it could be an identifier...
+ if ( token instanceof HqlToken ) {
+ HqlToken hqlToken = ( HqlToken ) token;
+ // ... and the token could be an identifer and the error is
+ // a mismatched token error ...
+ if ( hqlToken.isPossibleID() && ex instanceof MismatchedTokenException ) {
+ MismatchedTokenException mte = ( MismatchedTokenException ) ex;
+ // ... and the expected token type was an identifier, then:
+ if ( mte.expecting == IDENT ) {
+ // Use the token as an identifier.
+ reportWarning(
+ "Keyword '"+ token.getText()
+ + "' is being interpreted as an identifier due to: "
+ + mte.getMessage()
+ );
+ // Add the token to the AST.
+ ASTPair currentAST = new ASTPair();
+ token.setType( WEIRD_IDENT );
+ astFactory.addASTChild( currentAST, astFactory.create( token ) );
+ consume();
+ return currentAST.root;
+ }
+ }
+ }
+ return super.handleIdentifierError( token, ex );
+ }
+
+ public void handleDotIdent() throws TokenStreamException {
+ // This handles HHH-354, where there is a strange property name in a where clause.
+ // If the lookahead contains a DOT then something that isn't an IDENT...
+ if ( LA( 1 ) == DOT && LA( 2 ) != IDENT ) {
+ // See if the second lookahed token can be an identifier.
+ if ( ( ( HqlToken ) LT( 2 ) ).isPossibleID() ) {
+ // Set it!
+ LT( 2 ).setType( IDENT );
+ if ( log.isDebugEnabled() ) {
+ log.debug( "handleDotIdent() : new LT(2) token - " + LT( 1 ) );
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns an equivalent tree for (NOT (a relop b) ), for example:<pre>
+ * (NOT (GT a b) ) => (LE a b)
+ * </pre>
+ *
+ * @param x The sub tree to transform, the parent is assumed to be NOT.
+ * @return AST - The equivalent sub-tree.
+ */
+ public AST negateNode(AST x) {
+ //TODO: switch statements are always evil! We already had bugs because
+ // of forgotten token types. Use polymorphism for this!
+ switch ( x.getType() ) {
+ case OR:
+ x.setType(AND);
+ x.setText("{and}");
+ negateNode( x.getFirstChild() );
+ negateNode( x.getFirstChild().getNextSibling() );
+ return x;
+ case AND:
+ x.setType(OR);
+ x.setText("{or}");
+ negateNode( x.getFirstChild() );
+ negateNode( x.getFirstChild().getNextSibling() );
+ return x;
+ case EQ:
+ x.setType( NE );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (EQ a b) ) => (NE a b)
+ case NE:
+ x.setType( EQ );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (NE a b) ) => (EQ a b)
+ case GT:
+ x.setType( LE );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (GT a b) ) => (LE a b)
+ case LT:
+ x.setType( GE );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (LT a b) ) => (GE a b)
+ case GE:
+ x.setType( LT );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (GE a b) ) => (LT a b)
+ case LE:
+ x.setType( GT );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (LE a b) ) => (GT a b)
+ case LIKE:
+ x.setType( NOT_LIKE );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (LIKE a b) ) => (NOT_LIKE a b)
+ case NOT_LIKE:
+ x.setType( LIKE );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (NOT_LIKE a b) ) => (LIKE a b)
+ case IN:
+ x.setType( NOT_IN );
+ x.setText( "{not}" + x.getText() );
+ return x;
+ case NOT_IN:
+ x.setType( IN );
+ x.setText( "{not}" + x.getText() );
+ return x;
+ case IS_NULL:
+ x.setType( IS_NOT_NULL );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (IS_NULL a b) ) => (IS_NOT_NULL a b)
+ case IS_NOT_NULL:
+ x.setType( IS_NULL );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (IS_NOT_NULL a b) ) => (IS_NULL a b)
+ case BETWEEN:
+ x.setType( NOT_BETWEEN );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (BETWEEN a b) ) => (NOT_BETWEEN a b)
+ case NOT_BETWEEN:
+ x.setType( BETWEEN );
+ x.setText( "{not}" + x.getText() );
+ return x; // (NOT (NOT_BETWEEN a b) ) => (BETWEEN a b)
+/* This can never happen because this rule will always eliminate the child NOT.
+ case NOT:
+ return x.getFirstChild(); // (NOT (NOT x) ) => (x)
+*/
+ default:
+ return super.negateNode( x ); // Just add a 'not' parent.
+ }
+ }
+
+ /**
+ * Post process equality expressions, clean up the subtree.
+ *
+ * @param x The equality expression.
+ * @return AST - The clean sub-tree.
+ */
+ public AST processEqualityExpression(AST x) {
+ if ( x == null ) {
+ log.warn( "processEqualityExpression() : No expression to process!" );
+ return null;
+ }
+
+ int type = x.getType();
+ if ( type == EQ || type == NE ) {
+ boolean negated = type == NE;
+ if ( x.getNumberOfChildren() == 2 ) {
+ AST a = x.getFirstChild();
+ AST b = a.getNextSibling();
+ // (EQ NULL b) => (IS_NULL b)
+ if ( a.getType() == NULL && b.getType() != NULL ) {
+ return createIsNullParent( b, negated );
+ }
+ // (EQ a NULL) => (IS_NULL a)
+ else if ( b.getType() == NULL && a.getType() != NULL ) {
+ return createIsNullParent( a, negated );
+ }
+ else if ( b.getType() == EMPTY ) {
+ return processIsEmpty( a, negated );
+ }
+ else {
+ return x;
+ }
+ }
+ else {
+ return x;
+ }
+ }
+ else {
+ return x;
+ }
+ }
+
+ private AST createIsNullParent(AST node, boolean negated) {
+ node.setNextSibling( null );
+ int type = negated ? IS_NOT_NULL : IS_NULL;
+ String text = negated ? "is not null" : "is null";
+ return ASTUtil.createParent( astFactory, type, text, node );
+ }
+
+ private AST processIsEmpty(AST node, boolean negated) {
+ node.setNextSibling( null );
+ // NOTE: Because we're using ASTUtil.createParent(), the tree must be created from the bottom up.
+ // IS EMPTY x => (EXISTS (QUERY (SELECT_FROM (FROM x) ) ) )
+ AST ast = createSubquery( node );
+ ast = ASTUtil.createParent( astFactory, EXISTS, "exists", ast );
+ // Add NOT if it's negated.
+ if ( !negated ) {
+ ast = ASTUtil.createParent( astFactory, NOT, "not", ast );
+ }
+ return ast;
+ }
+
+ private AST createSubquery(AST node) {
+ AST ast = ASTUtil.createParent( astFactory, RANGE, "RANGE", node );
+ ast = ASTUtil.createParent( astFactory, FROM, "from", ast );
+ ast = ASTUtil.createParent( astFactory, SELECT_FROM, "SELECT_FROM", ast );
+ ast = ASTUtil.createParent( astFactory, QUERY, "QUERY", ast );
+ return ast;
+ }
+
+ public void weakKeywords() throws TokenStreamException {
+ int t = LA( 1 );
+ switch ( t ) {
+ case ORDER:
+ case GROUP:
+ // Case 1: Multi token keywords GROUP BY and ORDER BY
+ // The next token ( LT(2) ) should be 'by'... otherwise, this is just an ident.
+ if ( LA( 2 ) != LITERAL_by ) {
+ LT( 1 ).setType( IDENT );
+ if ( log.isDebugEnabled() ) {
+ log.debug( "weakKeywords() : new LT(1) token - " + LT( 1 ) );
+ }
+ }
+ break;
+ default:
+ // Case 2: The current token is after FROM and before '.'.
+ if (LA(0) == FROM && t != IDENT && LA(2) == DOT) {
+ HqlToken hqlToken = (HqlToken)LT(1);
+ if (hqlToken.isPossibleID()) {
+ hqlToken.setType(IDENT);
+ if ( log.isDebugEnabled() ) {
+ log.debug( "weakKeywords() : new LT(1) token - " + LT( 1 ) );
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ public void processMemberOf(Token n, AST p, ASTPair currentAST) {
+ AST inAst = n == null ? astFactory.create( IN, "in" ) : astFactory.create( NOT_IN, "not in" );
+ astFactory.makeASTRoot( currentAST, inAst );
+ AST ast = createSubquery( p );
+ ast = ASTUtil.createParent( astFactory, IN_LIST, "inList", ast );
+ inAst.addChild( ast );
+ }
+
+}
Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/ParseLexer.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/ParseLexer.java 2006-06-30 05:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/ParseLexer.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -0,0 +1,53 @@
+package org.hibernate.hql.ast.parse;
+
+import org.hibernate.hql.antlr.GeneratedParseLexer;
+import org.hibernate.hql.ast.HqlToken;
+import org.hibernate.QueryException;
+
+import java.io.InputStream;
+import java.io.Reader;
+
+import antlr.Token;
+
+/**
+ * The HQL parse lexer
+ *
+ * @author Steve Ebersole
+ */
+public class ParseLexer extends GeneratedParseLexer {
+ private boolean possibleID = false;
+
+ public ParseLexer(InputStream in) {
+ super( in );
+ }
+
+ public ParseLexer(Reader in) {
+ super( in );
+ }
+
+ public void setTokenObjectClass(String cl) {
+ // Ignore the token class name parameter, and use a specific token class.
+ super.setTokenObjectClass( HqlToken.class.getName() );
+ }
+
+ protected void setPossibleID(boolean possibleID) {
+ this.possibleID = possibleID;
+ }
+
+ protected Token makeToken(int i) {
+ HqlToken token = ( HqlToken ) super.makeToken( i );
+ token.setPossibleID( possibleID );
+ possibleID = false;
+ return token;
+ }
+
+ public void panic() {
+ //overriden to avoid System.exit
+ panic( "CharScanner: panic" );
+ }
+
+ public void panic(String s) {
+ //overriden to avoid System.exit
+ throw new QueryException( s );
+ }
+}
Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/PathCollector.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/PathCollector.java 2006-06-30 05:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/parse/PathCollector.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -0,0 +1,34 @@
+package org.hibernate.hql.ast.parse;
+
+import org.hibernate.hql.ast.util.NodeTraverser;
+import org.hibernate.hql.antlr.ParseTokenTypes;
+import antlr.collections.AST;
+
+/**
+ * Utilizes a NodeTraverser in order to collect a path from
+ * a (expecting dot-structure) an AST.
+ *
+ * @author Steve Ebersole
+ */
+public class PathCollector implements NodeTraverser.VisitationStrategy, ParseTokenTypes {
+ private String path = "";
+
+ public void visit(AST node) {
+ if ( node.getType() != DOT ) {
+ path += "." + node.getText();
+ }
+ }
+
+ private PathCollector() {
+ }
+
+ public static String getPath(AST dotStructure) {
+ if ( dotStructure.getType() == IDENT ) {
+ return dotStructure.getText();
+ }
+ PathCollector collector = new PathCollector();
+ NodeTraverser walker = new NodeTraverser( collector );
+ walker.traverseDepthFirst( dotStructure );
+ return collector.path.substring( 1 );
+ }
+}
Added: 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:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/AbstractImplicitJoinContext.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -0,0 +1,49 @@
+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);
+ }
+}
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java 2006-06-30 05:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/CollectionPersisterReference.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -12,9 +12,8 @@
/**
* @author Steve Ebersole
*/
-public class CollectionPersisterReference extends EntityPersisterReference implements ResolverAware {
+public class CollectionPersisterReference extends EntityPersisterReference {
- private HqlResolver resolver;
private String role;
private String alias;
private QueryableCollection persister;
@@ -26,7 +25,7 @@
public QueryableCollection getCollectionPersister() {
if ( persister == null ) {
- persister = ( QueryableCollection ) resolver.getSessionFactory().getCollectionPersister( role );
+ persister = ( QueryableCollection ) getSessionFactory().getCollectionPersister( role );
}
return persister;
}
@@ -34,7 +33,7 @@
public Queryable getEntityPersister() {
if ( getCollectionPersister().getElementType().isEntityType() ) {
EntityType elementEntityType = ( EntityType ) getCollectionPersister().getElementType();
- return ( Queryable ) elementEntityType.getAssociatedJoinable( resolver.getSessionFactory() );
+ return ( Queryable ) elementEntityType.getAssociatedJoinable( getSessionFactory() );
}
else {
throw new QueryException( "not a collection of entities" );
@@ -65,7 +64,7 @@
EntityType elementEntityType = ( EntityType ) elementType;
try {
Queryable elementEntityPersister = ( Queryable ) elementEntityType
- .getAssociatedJoinable( resolver.getSessionFactory() );
+ .getAssociatedJoinable( getSessionFactory() );
return elementEntityPersister.getPropertyType( propertyName );
}
catch( Throwable t ) {
@@ -97,12 +96,9 @@
return false;
}
- public void setHqlResolver(HqlResolver resolver) {
- this.resolver = resolver;
- }
-
public String toString() {
return "CollectionPersisterReference {role=" + getName() + ", alias=" + getAlias() +
", element-type=" + getCollectionPersister().getElementType() + "}";
}
-}
+
+}
\ No newline at end of file
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-06-30 05:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/EntityPersisterReference.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -3,26 +3,29 @@
import org.hibernate.type.AssociationType;
import org.hibernate.type.Type;
import org.hibernate.persister.entity.Queryable;
+import org.hibernate.engine.SessionFactoryImplementor;
+import org.hibernate.hql.ast.tree.SessionFactoryAwareNode;
/**
* @author Steve Ebersole
*/
-public class EntityPersisterReference extends PersisterReference implements ResolverAware {
+public class EntityPersisterReference extends PersisterReference implements SessionFactoryAwareNode {
private String entityName;
private String alias;
+ private boolean propertyFetch;
- private HqlResolver resolver;
-
+ private SessionFactoryImplementor sessionFactory;
private transient Queryable persister;
- public void initialize(String entityName, String alias) {
+ public void initialize(String entityName, String alias, boolean propertyFetch) {
this.entityName = entityName;
this.alias = alias;
+ this.propertyFetch = propertyFetch;
}
public Queryable getEntityPersister() {
if ( persister == null ) {
- persister = ( Queryable ) resolver.getSessionFactory().getEntityPersister( entityName );
+ persister = ( Queryable ) sessionFactory.getEntityPersister( entityName );
}
return persister;
}
@@ -35,6 +38,10 @@
return alias;
}
+ public boolean isPropertyFetch() {
+ return propertyFetch;
+ }
+
public AssociationType getPersisterType() {
return ( AssociationType ) getEntityPersister().getType();
}
@@ -56,7 +63,11 @@
return "EntityPersisterReference {entity-name=" + entityName + ", alias=" + alias + "}";
}
- public void setHqlResolver(HqlResolver resolver) {
- this.resolver = resolver;
+ public void setSessionFactory(SessionFactoryImplementor sessionFactory) {
+ this.sessionFactory = sessionFactory;
}
+
+ protected SessionFactoryImplementor getSessionFactory() {
+ return sessionFactory;
+ }
}
Added: 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:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/FromClauseImplicitJoinContext.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -0,0 +1,98 @@
+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
+ );
+ }
+ }
+}
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-06-30 05:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -1,35 +1,42 @@
package org.hibernate.hql.ast.resolve;
-import org.hibernate.hql.antlr.HqlBaseResolver;
-import org.hibernate.hql.CollectionProperties;
+import org.hibernate.hql.antlr.GeneratedHqlResolver;
import org.hibernate.engine.SessionFactoryImplementor;
import org.hibernate.QueryException;
-import org.hibernate.type.Type;
-import org.hibernate.type.ComponentType;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import antlr.collections.AST;
+import java.util.LinkedList;
+
/**
- * Adds specific semantic action behavior needed to perform useful resolution.
+ * Actual {@link GeneratedHqlResolver} implementation used in the query translator
+ * providing semantic action implementation.
*
* @author Joshua Davis
* @author Steve Ebersole
*/
-public class HqlResolver extends HqlBaseResolver {
+public class HqlResolver extends GeneratedHqlResolver implements HqlResolverASTFactory.Context {
private static Log log = LogFactory.getLog( HqlResolver.class );
private final SessionFactoryImplementor sessionFactory;
+ private final PersisterReferenceBuilder persisterReferenceBuilder;
+
private StatementNode currentStatement;
+ private ImplicitJoinContextTracker implicitJoinContextTracker = new ImplicitJoinContextTracker();
public HqlResolver(SessionFactoryImplementor sessionFactory) {
super();
this.sessionFactory = sessionFactory;
setASTFactory( new HqlResolverASTFactory( this ) );
+ persisterReferenceBuilder = new PersisterReferenceBuilder( getASTFactory(), sessionFactory );
}
+
+ // HqlResolverASTFactory.Context implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
@@ -38,115 +45,94 @@
return currentStatement;
}
+
+ // semantic action implementations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ /**
+ * 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 : " + currentStatement + " -> " + statementNode );
StatementNode statement = ( StatementNode ) statementNode;
+ statement.setPersisterReferenceBuilder( persisterReferenceBuilder );
+ implicitJoinContextTracker.push(
+ new NormalImplicitJoinContext( statement, persisterReferenceBuilder, getASTFactory() )
+ );
if ( currentStatement != null ) {
currentStatement.pushChild( statement );
}
currentStatement = statement;
}
+ /**
+ * Semantic action called whenever we complete processing a statement.
+ */
protected void popStatement() {
log.trace( "popping statement context : " + currentStatement + " -> " + currentStatement.getParentStatement() );
currentStatement = currentStatement.getParentStatement();
+ implicitJoinContextTracker.pop();
}
- protected AST buildEntityPersisterReference(String entityName, AST alias) {
- return currentStatement.buildEntityPersisterReference( entityName, alias == null ? null : alias.getText() );
+ protected void pushExplicitJoinContext(AST joinTypeNode, AST fetch, AST alias, AST propertyFetch) {
+ log.debug( "pushing explicit (from-clause) implicit join context" );
+ implicitJoinContextTracker.push(
+ new FromClauseImplicitJoinContext(
+ currentStatement,
+ persisterReferenceBuilder,
+ resolveJoinType( joinTypeNode ),
+ textOrNull( alias ),
+ fetch != null,
+ propertyFetch != null
+ )
+ );
}
- private JoinNode createJoinNode(JoinType type, JoinSource source, boolean fetch, PersisterReference rhs) {
- JoinNode node = ( JoinNode ) getASTFactory().create( JOIN, "join" );
- node.initialize( type, source, fetch, rhs );
- rhs.addChild( node );
- return node;
+ protected void popExplicitJoinContext() {
+ log.debug( "popping implicit join context" );
+ implicitJoinContextTracker.pop();
}
/**
- * Parser has recognized an explicit join based on a "property join".
- * <p/>
- * For example, something like: <tt>from Animal a join a.mother</tt> or
- * <tt>from Animal a join a.mother.mother as gm</tt> or even
- * <tt>from Animal join mother</tt>
- * <p/>
- * Here, we will need to resolve the explicit join, as well as handle any
- * implied joins.
- * </p>
- * Note that any implicit joins here are handled rather differently than
- * implicit joins in any clause other than an explicit join. See
- * {@link #resolveCompoundPropertyReference} for the differences. Mainly, the
- * differences are:<ul>
- * </ul>
+ * Semantic action called to perform generation of an {@link EntityPersisterReference}
+ * representing a "root" persister reference.
*
- * @param propertyPath The property(s) being joined to, which may indicate
- * additional implicit joins are intended.
- * @param aliasNode The alias to be applied to the generated persister reference
- * @param joinTypeNode The type of join indicated
- * @param fetchNode Was relation fetching specified?
- * @param propertyFetchNode Was property fetching specified?
- * @param withClauseNode Any with clause.
+ * @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 void handleExplicitPropertyJoin(
- AST propertyPath,
- AST aliasNode,
- AST joinTypeNode,
- AST fetchNode,
- AST propertyFetchNode,
- AST withClauseNode) {
- JoinType joinType = resolveJoinType( joinTypeNode );
- String alias = aliasNode == null ? null : aliasNode.getText();
- boolean relationFetch = fetchNode != null;
- boolean propertyFetch = propertyFetchNode != null;
+ protected AST buildEntityPersisterReference(AST entityName, AST alias, AST propertyFetch) {
+ return buildEntityPersisterReference( entityName.getText(), textOrNull( alias ), propertyFetch != null );
+ }
- // propertyPath should be a "flattened" dot node structure, which always have at least one child
- AST next = null;
- String firstPathExpression = propertyPath.getFirstChild().getText();
- EntityPersisterReference root = resolveRootAsAlias( firstPathExpression );
- if ( root != null ) {
- // the root of the path expression is an alias referencing a persister reference,
- // so the alias itself has essentially been resolved already, so "consume it"
- next = propertyPath.getFirstChild().getNextSibling();
- }
- else {
- // otherwise, the expectation is that the root of the path expression is an
- // unqualified property reference, in which case we essentially use the
- // root as a look ahead, and now need to actually resolve it
- root = resolveRootAsUnqualified( firstPathExpression );
- if ( root == null ) {
- throw new QueryException( "unable to determine root of path expression [" + reconstitutePathString( propertyPath ) + "]" );
- }
- next = propertyPath.getFirstChild();
- }
+ private EntityPersisterReference buildEntityPersisterReference(String entityName, String alias, boolean propertyFetching) {
+// return currentStatement.buildEntityPersisterReference( entityName, alias, propertyFetching );
+ return persisterReferenceBuilder.buildEntityPersisterReference( entityName, alias, propertyFetching );
+ }
- // At this point, we know the persister which acts as the root or base (root) of the
- // path structure (propertyPath), as well as the first actual path expression which
- // needs resolving (next). So now, we need to start iterating all the path
- // expressions and performing the resolutions.
- PersisterReference lhs = root;
- JoinSource joinSource = JoinSource.EXPLICIT;
- boolean firstPass = true;
- while ( next != null ) {
- // todo : components?
- boolean isLast = next.getNextSibling() == null;
+ private String textOrNull(AST node) {
+ return node == null ? null : node.getText();
+ }
- JoinNode joinNode = createJoinNode( joinType, joinSource, relationFetch, lhs );
- PersisterReference rhs = currentStatement.getPersisterReference( lhs, next.getText(), isLast ? alias : null );
- joinNode.addChild( rhs );
+ private JoinNode createJoinNode(JoinType type, JoinSource source, boolean fetch, PersisterReference rhs) {
+ JoinNode node = ( JoinNode ) getASTFactory().create( JOIN, "join" );
+ node.initialize( type, source, fetch, rhs );
+ rhs.addChild( node );
+ return node;
+ }
- if ( isLast && withClauseNode != null ) {
- joinNode.addChild( withClauseNode );
- }
- if ( firstPass ) {
- firstPass = false;
- joinSource = JoinSource.IMPLICIT;
- }
+ protected void handleIntermediatePathPart(AST name) {
+ log.debug( "handling intermediate path part [" + name.getText() + "]" );
+ implicitJoinContextTracker.getCurrent().handleIntermediatePathPart( name.getText() );
+ }
- lhs = rhs;
- next = next.getNextSibling();
- }
-
+ protected AST handleTerminalPathPart(AST name) {
+ log.debug( "handling terminal path part [" + name.getText() + "]" );
+ return implicitJoinContextTracker.getCurrent().handleTerminalPathPart( name.getText() );
}
protected void handleAdHocJoinNode(AST persisterReference, AST joinType, AST onClause) {
@@ -175,23 +161,6 @@
throw new QueryException( "Unrecognized join type [" + joinType.getText() + "]" );
}
- public PersisterReference buildPropertyJoin(PersisterReference source, String propertyName, String alias) {
- JoinNode join = createJoinNode( JoinType.INNER, JoinSource.IMPLICIT, false, source );
- PersisterReference persisterReference = currentStatement.getPersisterReference( source, propertyName, alias );
- join.addChild( persisterReference );
- return persisterReference;
- }
-
- protected boolean isEntityName(String test) {
- try {
- return sessionFactory.getEntityPersister( test ) != null;
- }
- catch( Throwable t ) {
- // ignore it...
- }
- return false;
- }
-
protected String reconstitutePathString(AST propertyReference) {
AST child = propertyReference.getFirstChild();
String prefix = "";
@@ -204,265 +173,22 @@
return buffer.toString();
}
- protected AST resolveAtomicPropertyReference(AST propertyNode) {
- EntityPersisterReference persisterReference = resolveRootAsUnqualified( propertyNode.getText() );
- return generatePropertyReference( persisterReference, propertyNode.getText() );
- }
+ private class ImplicitJoinContextTracker {
+ private LinkedList stack = new LinkedList();
- private PropertyReference generatePropertyReference(PersisterReference persisterReference, String propertyName) {
- PropertyReference propertyReferenceNode = ( PropertyReference ) getASTFactory()
- .create( PROPERTY_REF, persisterReference.getAlias() + "." + propertyName );
-
- AST aliasNode = getASTFactory().create( ALIAS, persisterReference.getAlias() );
- propertyReferenceNode.addChild( aliasNode );
-
- AST propertyNameNode = getASTFactory().create( IDENT, propertyName );
- propertyReferenceNode.addChild( propertyNameNode );
-
- return propertyReferenceNode;
- }
-
- protected AST resolveCompoundPropertyReference(AST dotStructure) {
- PersisterReference persisterReference;
- AST next;
-
- // first, resolve root origin
- String firstPathExpression = dotStructure.getFirstChild().getText();
- if ( dotStructure.getNumberOfChildren() == 1 ) {
- // can only really represent an unqualified simple property ref
- EntityPersisterReference match = resolveRootAsUnqualified( firstPathExpression );
- if ( match == null ) {
- throw new QueryException( "unable to resolve property [" + firstPathExpression + "] as unqualified reference" );
- }
- persisterReference = match;
- // the root of the path expression is an alias referencing a persister reference,
- // so the alias itself has essentially been resolved already, so "consume it"
- next = dotStructure.getFirstChild();
+ public ImplicitJoinContextTracker() {
}
- else {
- // need to decide whether 'firstPathExpression' refers to a from-clause alias, or
- // an unqualified property name. from-clause alias has a higher precedence
- // for matching purposes, so try to resolve as alias first
- EntityPersisterReference match = resolveRootAsAlias( firstPathExpression );
- if ( match != null ) {
- // the root of the path expression is an alias referencing a persister reference,
- // so the alias itself has essentially been resolved already, so "consume it"
- next = dotStructure.getFirstChild().getNextSibling();
- }
- else {
- // then try as unqualified
- match = resolveRootAsUnqualified( firstPathExpression );
- if ( match != null ) {
- // the root of the path expression is an unqualified property reference,
- // in which case we essentially use the root as a look ahead, and now
- // need to actually resolve it
- next = dotStructure.getFirstChild();
- }
- else {
- throw new QueryException( "unable to determine root of path expression [" + reconstitutePathString( dotStructure ) + "]" );
- }
- }
- persisterReference = match;
- }
- PropertyPathPart propertySource = new PropertyPathRoot( ( EntityPersisterReference ) persisterReference );
- String pathSoFar = persisterReference.getAlias();
-
- while ( next != null && next.getNextSibling() != null ) {
- String propertyName = next.getText();
- pathSoFar += ( "." + propertyName );
-
- PersisterReference built = currentStatement.locatePersisterReferenceByPath( pathSoFar );
- if ( built != null ) {
- propertySource = new PropertyPathRoot( ( EntityPersisterReference ) built );
- }
- else {
- propertySource = propertySource.handleIntermediatePathPart( propertyName );
- }
-
- next = next.getNextSibling();
+ public void push(ImplicitJoinContext context) {
+ stack.addFirst( context );
}
- if ( next == null ) {
- throw new QueryException( "illegal parser state" );
+ public void pop() {
+ stack.removeFirst();
}
- return propertySource.handleLeafPathPart( next.getText() );
- }
- private EntityPersisterReference resolveRootAsAlias(String firstPathExpression) {
- return ( EntityPersisterReference ) currentStatement.locatePersisterReferenceByAlias( firstPathExpression );
- }
-
- private EntityPersisterReference resolveRootAsUnqualified(String firstPathExpression) {
- return currentStatement.locatePersisterReferenceExposingProperty( firstPathExpression );
- }
-
- private PropertyPathPart determineAppropriatePartType(EntityPersisterReference origin, String propertyName) {
- Type propertyType = origin.getPropertyType( propertyName );
- if ( propertyType.isComponentType() ) {
- return new ComponentPropertyReference( origin, propertyName, ( ComponentType ) propertyType );
+ public ImplicitJoinContext getCurrent() {
+ return ( ImplicitJoinContext ) stack.getFirst();
}
- else if ( propertyType.isEntityType() ) {
- return new EntityPropertyReference( origin, propertyName, false );
- }
- else if ( propertyType.isCollectionType() ) {
- return new CollectionPropertyReference( origin, propertyName );
- }
- else {
- return new SimplePropertyReference( origin, propertyName );
- }
}
-
- private int locateComponentPropertyIndex(ComponentType componentType, String subPropertyName) {
- String[] componentPropertyNames = componentType.getPropertyNames();
- for ( int i = 0; i < componentPropertyNames.length; i++ ) {
- if ( componentPropertyNames[i].equals( subPropertyName ) ) {
- return i;
- }
- }
- throw new QueryException( "could not locate component property [" + subPropertyName + "]" );
- }
-
- // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- // todo : this stuff needs to be finished up.
- // specific things needing to be completed:
- // (1) only dereference an actual entity association property into a
- // join when it is further dereferenced (already handled) or when
- // occuring in select clause
- // (2) properly handle "collection properties"
- // (3) properly handle components
- // (4) properly handle index operations
- //
- // todo : look at utilizing this from handleExplicitPropertyJoin(...) also
-
- /**
- * Contract for handling delegation for a particular portion of an implicit
- * join structure (aka property path).
- */
- private interface PropertyPathPart {
- public PropertyPathPart handleIntermediatePathPart(String name);
- public PropertyReference handleLeafPathPart(String name);
- }
-
- private class PropertyPathRoot implements PropertyPathPart {
- private final EntityPersisterReference persisterReference;
-
- public PropertyPathRoot(EntityPersisterReference persisterReference) {
- this.persisterReference = persisterReference;
- }
-
- public PropertyPathPart handleIntermediatePathPart(String name) {
- return determineAppropriatePartType( persisterReference, name );
- }
-
- public PropertyReference handleLeafPathPart(String name) {
- // todo : this really needs to consider whether a join might be needed
- // based on the property type and type of clause
- return generatePropertyReference( persisterReference, name );
- }
-
- }
-
- private class SimplePropertyReference implements PropertyPathPart {
- private final EntityPersisterReference origin;
- private final String propertyName;
-
- public SimplePropertyReference(EntityPersisterReference origin, String propertyName) {
- this.origin = origin;
- this.propertyName = propertyName;
- }
-
- public PropertyPathPart handleIntermediatePathPart(String name) {
- throw new QueryException( "cannot perform implicit join based on simple property" );
- }
-
- public PropertyReference handleLeafPathPart(String name) {
- throw new QueryException( "cannot perform implicit join based on simple property" );
- }
- }
-
- private class ComponentPropertyReference implements PropertyPathPart {
- private final EntityPersisterReference origin;
- private final String componentPropertyName;
- private final ComponentType componentType;
-
- public ComponentPropertyReference(EntityPersisterReference origin, String componentPropertyName) {
- this( origin, componentPropertyName, ( ComponentType ) origin.getPropertyType( componentPropertyName ) );
- }
-
- public ComponentPropertyReference(EntityPersisterReference origin, String componentPropertyName, ComponentType componentType) {
- this.origin = origin;
- this.componentPropertyName = componentPropertyName;
- this.componentType = componentType;
- }
-
- public PropertyPathPart handleIntermediatePathPart(String propertyName) {
- int index = locateComponentPropertyIndex( componentType, propertyName );
- String path = buildDerefPath( propertyName );
- Type propertyType = componentType.getSubtypes()[index];
- if ( propertyType.isComponentType() ) {
- return new ComponentPropertyReference( origin, path, ( ComponentType ) propertyType );
- }
- else if ( propertyType.isEntityType() ) {
- return new EntityPropertyReference( origin, path, false );
- }
- else {
- return new SimplePropertyReference( origin, path );
- }
- }
-
- public PropertyReference handleLeafPathPart(String name) {
- return generatePropertyReference( origin, buildDerefPath( name ) );
- }
-
- private String buildDerefPath(String subPropertyName) {
- return componentPropertyName + "." + subPropertyName;
- }
- }
-
- private class EntityPropertyReference implements PropertyPathPart {
- private final EntityPersisterReference origin;
- private final String propertyName;
-
- private boolean joined;
-
- public EntityPropertyReference(EntityPersisterReference origin, String propertyName, boolean joined) {
- this.origin = origin;
- this.propertyName = propertyName;
- this.joined = joined;
- }
-
- public PropertyPathPart handleIntermediatePathPart(String name) {
- EntityPersisterReference joinedPersister = ( EntityPersisterReference ) buildPropertyJoin( origin, propertyName, null );
- return determineAppropriatePartType( joinedPersister, name );
- }
-
- public PropertyReference handleLeafPathPart(String name) {
- // not always needed (i.e. : .id)
- EntityPersisterReference joinedPersister = ( EntityPersisterReference ) buildPropertyJoin( origin, propertyName, null );
- return generatePropertyReference( joinedPersister, name );
- }
- }
-
- private class CollectionPropertyReference implements PropertyPathPart {
- private final EntityPersisterReference origin;
- private final String collectionPropertyName;
-
- public CollectionPropertyReference(EntityPersisterReference origin, String collectionPropertyName) {
- this.origin = origin;
- this.collectionPropertyName = collectionPropertyName;
- }
-
- public PropertyPathPart handleIntermediatePathPart(String name) {
- throw new QueryException( "illegal attempt to perform implicit join across collection property" );
- }
-
- public PropertyReference handleLeafPathPart(String name) {
- if ( CollectionProperties.isAnyCollectionProperty( name ) ) {
- CollectionPersisterReference joinedPersister = ( CollectionPersisterReference ) buildPropertyJoin( origin, collectionPropertyName, null );
- return generatePropertyReference( joinedPersister, name );
- }
- throw new QueryException( "illegal attempt to perform implicit join across collection property" );
- }
- }
}
Modified: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java
===================================================================
--- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java 2006-06-30 05:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -1,24 +1,33 @@
package org.hibernate.hql.ast.resolve;
-import org.hibernate.hql.antlr.HqlRTokenTypes;
+import org.hibernate.hql.antlr.ResolveTokenTypes;
import org.hibernate.hql.ast.HqlASTFactory;
+import org.hibernate.hql.ast.tree.SessionFactoryAwareNode;
+import org.hibernate.hql.ast.tree.PersisterReferenceContextAwareNode;
+import org.hibernate.hql.ast.tree.ASTFactoryAwareNode;
import org.hibernate.engine.SessionFactoryImplementor;
import antlr.collections.AST;
import antlr.Token;
/**
* AST factory for the resolver phase.
- * <br>User: Joshua Davis
- * Date: Apr 3, 2006
- * Time: 7:58:16 AM
+ *
+ * @author Joshua Davis
+ * @author Steve Ebersole
*/
-public class HqlResolverASTFactory extends HqlASTFactory implements HqlRTokenTypes {
- private final HqlResolver resolver;
+public class HqlResolverASTFactory extends HqlASTFactory implements ResolveTokenTypes {
- public HqlResolverASTFactory(HqlResolver resolver) {
- this.resolver = resolver;
+ public static interface Context {
+ public SessionFactoryImplementor getSessionFactory();
+ public PersisterReferenceContext getPersisterReferenceContext();
}
+ private final Context context;
+
+ public HqlResolverASTFactory(Context context) {
+ this.context = context;
+ }
+
public Class getASTNodeType(int tokenType) {
// Statement nodes:
switch (tokenType) {
@@ -55,11 +64,14 @@
}
private void prepare(AST node) {
- if ( node instanceof SessionFactoryAwareNode ) {
- ( ( SessionFactoryAwareNode ) node ).setSessionFactory( resolver.getSessionFactory() );
+ if ( node instanceof org.hibernate.hql.ast.tree.SessionFactoryAwareNode ) {
+ ( ( SessionFactoryAwareNode ) node ).setSessionFactory( context.getSessionFactory() );
}
- if ( node instanceof ResolverAware ) {
- ( ( ResolverAware ) node ).setHqlResolver( resolver );
+ if ( node instanceof PersisterReferenceContextAwareNode ) {
+ ( ( PersisterReferenceContextAwareNode ) node ).setPersisterReferenceContext( context.getPersisterReferenceContext() );
}
+ if ( node instanceof ASTFactoryAwareNode ) {
+ ( ( ASTFactoryAwareNode ) node ).setASTFactory( this );
+ }
}
}
Added: 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-06-30 05:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ImplicitJoinContext.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -0,0 +1,11 @@
+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);
+}
Added: 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:54:36 UTC (rev 10069)
+++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/NormalImplicitJoinContext.java 2006-06-30 05:55:55 UTC (rev 10070)
@@ -0,0 +1,236 @@
+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.compone...
[truncated message content] |