Author: pgmjsd Date: 2006-04-12 09:12:03 -0400 (Wed, 12 Apr 2006) New Revision: 9742 Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ 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/RangeNode.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContext.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContextImpl.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/StatementNode.java Removed: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolver.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolverASTFactory.java branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/StatementNode.java Modified: branches/HQL_ANTLR_2/Hibernate3/grammar/hql-resolve.g branches/HQL_ANTLR_2/Hibernate3/test/org/hibernate/test/hql/HqlResolverTest.java Log: Moved the resolver stuff into it's own package. The unit test now resolves 'FROM Animal'. Modified: branches/HQL_ANTLR_2/Hibernate3/grammar/hql-resolve.g =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/grammar/hql-resolve.g 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/grammar/hql-resolve.g 2006-04-12 13:12:03 UTC (rev 9742) @@ -40,34 +40,13 @@ { private static Log log = LogFactory.getLog( HqlBaseResolver.class ); - private int level = 0; - private List inputContext = new ArrayList(); - private List outputContext = new ArrayList(); + // Semantic action methods, overridden in subclasses for clarity. - protected void pushContext(AST outputAst,AST inputAst) { - level++; - inputContext.add(inputAst); - outputContext.add(outputAst); - if (log.isDebugEnabled()) { - log.debug("Pushed context: level = " + level + " input is " + inputAst.toStringTree()); - } - } + protected void pushContext(AST outputAst,AST inputAst) { } - protected void popContext() { - level--; - AST n = (AST)inputContext.remove(inputContext.size() - 1); - outputContext.remove(outputContext.size() - 1); - if (log.isDebugEnabled()) { - log.debug("Popped context: level = " + level + " input was " + n.toStringTree()); - } - } + protected void popContext() { } - protected AST getCurrentContext(boolean input) { - return (AST)((input) ? inputContext.get(inputContext.size() - 1) - : outputContext.get(outputContext.size() - 1)); - } - - protected int getLevel() { return level; } + protected void defineRange(AST range,String path,AST alias, AST fetch) { } } // The main statement rule. @@ -120,8 +99,15 @@ : #(f:FROM { pushContext(#fromClause,f); } ( range | join | filter ) * ) ; +// Antlr note: The '!' prevents the automatic creation of the output AST, so the semantic action can do it. range - : #(RANGE path (ALIAS)? (FETCH)? ) + { + String p = ""; + } + : #(RANGE p=pathAsString! (a:ALIAS!)? (f:FETCH!)? ) + { + defineRange(#range,p,a,f); // Set up the output tree. + } ; join @@ -178,6 +164,20 @@ | #(DOT path identifier) ; +// Matches a path and returns the normalized string for the path (usually +// fully qualified a class name). +pathAsString returns [String p] { + p = "???"; + String x = "?x?"; + } + : a:identifier { p = a.getText(); } + | #(DOT x=pathAsString y:identifier) { + StringBuffer buf = new StringBuffer(); + buf.append(x).append(".").append(y.getText()); + p = buf.toString(); + } + ; + identifier : (IDENT | WEIRD_IDENT) ; Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolver.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolver.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolver.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -1,16 +0,0 @@ -package org.hibernate.hql.ast; - -import org.hibernate.hql.antlr.HqlBaseResolver; - -/** - * Implements the methods for the HqlBaseResolver. - * <br>User: Joshua Davis - * Date: Apr 1, 2006 - * Time: 7:40:42 AM - */ -public class HqlResolver extends HqlBaseResolver { - public HqlResolver() { - super(); - setASTFactory(new HqlResolverASTFactory()); // Create nodes that track line and column number. - } -} Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolverASTFactory.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolverASTFactory.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolverASTFactory.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -1,24 +0,0 @@ -package org.hibernate.hql.ast; - -import org.hibernate.hql.antlr.HqlRTokenTypes; -import org.hibernate.hql.ast.tree.StatementNode; - -/** - * AST factory for the resolver phase. - * <br>User: Joshua Davis - * Date: Apr 3, 2006 - * Time: 7:58:16 AM - */ -public class HqlResolverASTFactory extends HqlASTFactory implements HqlRTokenTypes { - public Class getASTNodeType(int tokenType) { - // Statement nodes: - switch (tokenType) { - case QUERY : - case UPDATE: - case DELETE: - case INSERT: - return StatementNode.class; - } - return super.getASTNodeType(tokenType); - } -} Copied: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java (from rev 9741, branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolver.java) =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolver.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolver.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -0,0 +1,68 @@ +package org.hibernate.hql.ast.resolve; + +import org.hibernate.hql.antlr.HqlBaseResolver; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; +import java.util.List; +import java.util.ArrayList; + +import antlr.collections.AST; + +/** + * Implements the methods for the HqlBaseResolver. + * <br>User: Joshua Davis + * Date: Apr 1, 2006 + * Time: 7:40:42 AM + */ +public class HqlResolver extends HqlBaseResolver { + private static Log log = LogFactory.getLog( HqlResolver.class ); + + private int level = 0; + private List inputContext = new ArrayList(); + private List outputContext = new ArrayList(); + private ResolverContext context; // Provides acces to the session factory via an interface. + + public HqlResolver() { + super(); + setASTFactory(new HqlResolverASTFactory()); // Create nodes that track line and column number. + } + + + protected void pushContext(AST outputAst,AST inputAst) { + level++; + inputContext.add(inputAst); + outputContext.add(outputAst); + if (log.isDebugEnabled()) { + log.debug("Pushed context: level = " + level + " input is " + inputAst.toStringTree()); + } + } + + protected void popContext() { + level--; + AST n = (AST)inputContext.remove(inputContext.size() - 1); + outputContext.remove(outputContext.size() - 1); + if (log.isDebugEnabled()) { + log.debug("Popped context: level = " + level + " input was " + n.toStringTree()); + } + } + + protected AST getCurrentContext(boolean input) { + return (AST)((input) ? inputContext.get(inputContext.size() - 1) + : outputContext.get(outputContext.size() - 1)); + } + + protected int getLevel() { return level; } + + protected void defineRange(AST range, String path, AST alias, AST fetch) { + RangeNode r = (RangeNode) range; + r.setPath(path); + r.setPersister(context.lookupPersister(path)); + r.setFetch(fetch != null); + r.setAlias(alias != null ? alias.getText() : null); + } + + public void initialize(ResolverContext resolverContext) { + context = resolverContext; + } +} Copied: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java (from rev 9741, branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolverASTFactory.java) =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/HqlResolverASTFactory.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/HqlResolverASTFactory.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -0,0 +1,26 @@ +package org.hibernate.hql.ast.resolve; + +import org.hibernate.hql.antlr.HqlRTokenTypes; +import org.hibernate.hql.ast.HqlASTFactory; + +/** + * AST factory for the resolver phase. + * <br>User: Joshua Davis + * Date: Apr 3, 2006 + * Time: 7:58:16 AM + */ +public class HqlResolverASTFactory extends HqlASTFactory implements HqlRTokenTypes { + public Class getASTNodeType(int tokenType) { + // Statement nodes: + switch (tokenType) { + case QUERY : + case UPDATE: + case DELETE: + case INSERT: + return StatementNode.class; + case RANGE: + return RangeNode.class; + } + return super.getASTNodeType(tokenType); + } +} Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/RangeNode.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/RangeNode.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/RangeNode.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -0,0 +1,64 @@ +package org.hibernate.hql.ast.resolve; + +import org.hibernate.hql.ast.tree.Node; +import org.hibernate.hql.ast.tree.DisplayableNode; +import org.hibernate.persister.entity.EntityPersister; + +/** + * Represents an element of a FROM clause, e.g. "from Animal a" + * <br>User: Joshua Davis + * Date: Apr 12, 2006 + * Time: 7:31:17 AM + */ +public class RangeNode extends Node implements DisplayableNode { + private String path; + private String alias; + private EntityPersister persister; + private boolean fetch = false; + + public String getPath() { + return path; + } + + public void setPath(String path) { + this.path = path; + } + + public EntityPersister getPersister() { + return persister; + } + + public void setPersister(EntityPersister persister) { + this.persister = persister; + } + + public boolean isFetch() { + return fetch; + } + + public void setFetch(boolean fetch) { + this.fetch = fetch; + } + + public String getAlias() { + return alias; + } + + public void setAlias(String alias) { + this.alias = alias; + } + + + public String toString() { + return "RangeNode{" + + "path='" + path + '\'' + + ", alias='" + alias + '\'' + + ", persister=" + persister + + ", fetch=" + fetch + + '}'; + } + + public String getDisplayText() { + return toString(); + } +} Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContext.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContext.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContext.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -0,0 +1,13 @@ +package org.hibernate.hql.ast.resolve; + +import org.hibernate.persister.entity.EntityPersister; + +/** + * Looks up persisters and other things by name. + * <br>User: Joshua Davis + * Date: Apr 12, 2006 + * Time: 7:34:11 AM + */ +public interface ResolverContext { + EntityPersister lookupPersister(String path); +} Added: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContextImpl.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContextImpl.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/ResolverContextImpl.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -0,0 +1,36 @@ +package org.hibernate.hql.ast.resolve; + +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.MappingException; +import org.hibernate.persister.entity.EntityPersister; + +/** + * Implements the resolver's context with a session factory. + * <br>User: Joshua Davis + * Date: Apr 12, 2006 + * Time: 7:35:31 AM + */ +public class ResolverContextImpl implements ResolverContext { + private SessionFactoryImplementor sfi; + + public ResolverContextImpl(SessionFactoryImplementor sfi) { + this.sfi = sfi; + } + + public EntityPersister lookupPersister(String name) { + // First, try to get the persister using the class name directly. + try { + return sfi.getEntityPersister( name ); + } + catch ( MappingException ignore ) { + // unable to locate it using this name + } + + // If that didn't work, try using the 'import' name. + String importedClassName = sfi.getImportedClassName( name ); + if ( importedClassName == null ) { + return null; + } + return sfi.getEntityPersister( importedClassName ); + } +} Copied: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/StatementNode.java (from rev 9741, branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/StatementNode.java) =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/StatementNode.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/resolve/StatementNode.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -0,0 +1,12 @@ +package org.hibernate.hql.ast.resolve; + +import org.hibernate.hql.ast.tree.Node; + +/** + * Represents a statement (SELECT, UPDATE, INSERT, DELETE) in the resolved HQL tree. + * <br>User: Joshua Davis + * Date: Apr 3, 2006 + * Time: 8:00:55 AM + */ +public class StatementNode extends Node { +} Deleted: branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/StatementNode.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/StatementNode.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/src/org/hibernate/hql/ast/tree/StatementNode.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -1,10 +0,0 @@ -package org.hibernate.hql.ast.tree; - -/** - * Represents a statement (SELECT, UPDATE, INSERT, DELETE) in the resolved HQL tree. - * <br>User: Joshua Davis - * Date: Apr 3, 2006 - * Time: 8:00:55 AM - */ -public class StatementNode extends Node { -} Modified: branches/HQL_ANTLR_2/Hibernate3/test/org/hibernate/test/hql/HqlResolverTest.java =================================================================== --- branches/HQL_ANTLR_2/Hibernate3/test/org/hibernate/test/hql/HqlResolverTest.java 2006-04-11 11:57:40 UTC (rev 9741) +++ branches/HQL_ANTLR_2/Hibernate3/test/org/hibernate/test/hql/HqlResolverTest.java 2006-04-12 13:12:03 UTC (rev 9742) @@ -4,12 +4,14 @@ import antlr.TokenStreamException; import antlr.collections.AST; import junit.framework.Test; -import junit.framework.TestCase; import junit.framework.TestSuite; import org.hibernate.hql.antlr.HqlRTokenTypes; -import org.hibernate.hql.ast.HqlResolver; -import org.hibernate.hql.ast.tree.StatementNode; +import org.hibernate.hql.ast.resolve.HqlResolver; +import org.hibernate.hql.ast.resolve.StatementNode; +import org.hibernate.hql.ast.resolve.ResolverContextImpl; import org.hibernate.hql.ast.util.ASTPrinter; +import org.hibernate.test.TestCase; +import org.hibernate.engine.SessionFactoryImplementor; /** * Tests the new HQL resolver phase. @@ -24,7 +26,6 @@ super(n); } - public void testSimpleHql() throws Exception { // First, get an AST by parsing some HQL text. AST ast = resolve("from Animal"); @@ -38,13 +39,67 @@ // Now, pass it though the resolver phase, which yeilds // a processed HQL AST. HqlResolver resolver = new HqlResolver(); + ResolverContextImpl context = new ResolverContextImpl(getSessionFactoryImplementor()); + resolver.initialize(context); // Give the resolver a fake context. resolver.statement(hqlAst); AST resolvedHql = resolver.getAST(); - System.out.println(hqlrPrinter.showAsString(resolvedHql,"Resolved AST : " + resolvedHql.toStringTree() + "" )); + System.out.println(hqlrPrinter.showAsString(resolvedHql, + "Resolved AST : " + resolvedHql.toStringTree() + "" )); return resolvedHql; } + protected SessionFactoryImplementor getSessionFactoryImplementor() { + SessionFactoryImplementor factory = ( SessionFactoryImplementor ) getSessions(); + if ( factory == null ) { + throw new NullPointerException( "Unable to create factory!" ); + } + return factory; + } + public static Test suite() { return new TestSuite(HqlResolverTest.class); } + + protected String[] getMappings() { + return new String[]{ + "hql/Animal.hbm.xml", + "hql/EntityWithCrazyCompositeKey.hbm.xml", + "batchfetch/ProductLine.hbm.xml", + "cid/Customer.hbm.xml", + "cid/Order.hbm.xml", + "cid/LineItem.hbm.xml", + "cid/Product.hbm.xml", + "legacy/Baz.hbm.xml", + "legacy/Category.hbm.xml", + "legacy/Commento.hbm.xml", + "legacy/Container.hbm.xml", + "legacy/Custom.hbm.xml", + "legacy/Eye.hbm.xml", + "legacy/Fee.hbm.xml", + "legacy/FooBar.hbm.xml", + "legacy/Fum.hbm.xml", + "legacy/Glarch.hbm.xml", + "legacy/Holder.hbm.xml", + "legacy/Many.hbm.xml", + "legacy/Marelo.hbm.xml", + "legacy/MasterDetail.hbm.xml", + "legacy/Middle.hbm.xml", + "legacy/Multi.hbm.xml", + "legacy/Nameable.hbm.xml", + "legacy/One.hbm.xml", + "legacy/Qux.hbm.xml", + "legacy/Simple.hbm.xml", + "legacy/SingleSeveral.hbm.xml", + "legacy/WZ.hbm.xml", + "legacy/UpDown.hbm.xml", + "compositeelement/Parent.hbm.xml", + "onetoone/joined/Person.hbm.xml", + "hql/CrazyIdFieldNames.hbm.xml" + }; + } + + protected boolean recreateSchema() { + // we do not need to create the schema for these parser tests + return false; + } } |