From: <hib...@li...> - 2006-06-08 21:07:07
|
Author: ste...@jb... Date: 2006-06-08 17:04:45 -0400 (Thu, 08 Jun 2006) New Revision: 10000 Added: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ExpectedTypeAwareNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/QueryTranslatorImpl.java trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BetweenOperatorNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryArithmeticOperatorNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/InLogicOperatorNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java trunk/Hibernate3/src/org/hibernate/hql/ast/util/ASTUtil.java Log: enums as constant literal in HQL Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/QueryTranslatorImpl.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/QueryTranslatorImpl.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/QueryTranslatorImpl.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -1,13 +1,6 @@ // $Id$ package org.hibernate.hql.ast; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - import antlr.ANTLRException; import antlr.RecognitionException; import antlr.TokenStreamException; @@ -38,17 +31,24 @@ import org.hibernate.hql.ast.tree.QueryNode; import org.hibernate.hql.ast.tree.Statement; import org.hibernate.hql.ast.util.ASTPrinter; +import org.hibernate.hql.ast.util.NodeTraverser; +import org.hibernate.hql.ast.util.ASTUtil; import org.hibernate.loader.hql.QueryLoader; import org.hibernate.persister.entity.Queryable; import org.hibernate.type.Type; import org.hibernate.util.IdentitySet; import org.hibernate.util.StringHelper; +import org.hibernate.util.ReflectHelper; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.ArrayList; + /** - * A QueryTranslator that uses an AST based parser. - * <br>User: josh - * <br>Date: Dec 31, 2003 - * <br>Time: 7:50:35 AM + * A QueryTranslator that uses an Antlr-based parser. * * @author Joshua Davis (pg...@so...) */ @@ -249,6 +249,10 @@ AST hqlAst = parser.getAST(); + JavaConstantConverter converter = new JavaConstantConverter(); + NodeTraverser walker = new NodeTraverser( converter ); + walker.traverseDepthFirst( hqlAst ); + showHqlAst( hqlAst ); parser.getParseErrorHandler().throwQueryException(); @@ -540,4 +544,34 @@ return paramTranslations; } + public static class JavaConstantConverter implements NodeTraverser.VisitationStrategy { + private AST dotRoot; + public void visit(AST node) { + if ( dotRoot != null ) { + // we are already processing a dot-structure + if ( ASTUtil.isSubtreeChild( dotRoot, node ) ) { + // igndore it... + return; + } + else { + // we are now at a new tree level + dotRoot = null; + } + } + + if ( dotRoot == null && node.getType() == HqlTokenTypes.DOT ) { + dotRoot = node; + handleDotStructure( dotRoot ); + } + } + private void handleDotStructure(AST dotStructureRoot) { + String expression = ASTUtil.getPathText( dotStructureRoot ); + Object constant = ReflectHelper.getConstantValue( expression ); + if ( constant != null ) { + dotStructureRoot.setFirstChild( null ); + dotStructureRoot.setType( HqlTokenTypes.JAVA_CONSTANT ); + dotStructureRoot.setText( expression ); + } + } + } } Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/SqlASTFactory.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -37,6 +37,8 @@ import org.hibernate.hql.ast.tree.BetweenOperatorNode; import org.hibernate.hql.ast.tree.UnaryLogicOperatorNode; import org.hibernate.hql.ast.tree.InLogicOperatorNode; +import org.hibernate.hql.ast.tree.JavaConstantNode; +import org.hibernate.hql.ast.tree.SessionFactoryAwareNode; import java.lang.reflect.Constructor; @@ -44,9 +46,8 @@ * Custom AST factory the intermediate tree that causes ANTLR to create specialized * AST nodes, given the AST node type (from HqlSqlTokenTypes). HqlSqlWalker registers * this factory with itself when it is initialized. - * <br>User: josh - * <br>Date: Nov 22, 2003 - * <br>Time: 3:34:28 PM + * + * @author Joshua */ public class SqlASTFactory extends ASTFactory implements HqlSqlTokenTypes { private HqlSqlWalker walker; @@ -119,6 +120,8 @@ case TRUE: case FALSE: return LiteralNode.class; + case JAVA_CONSTANT: + return JavaConstantNode.class; case ORDER: return OrderByClause.class; case PLUS: @@ -189,6 +192,9 @@ InitializeableNode initializeableNode = ( InitializeableNode ) t; initializeableNode.initialize( walker ); } + if ( t instanceof SessionFactoryAwareNode ) { + ( ( SessionFactoryAwareNode ) t ).setSessionFactory( walker.getSessionFactoryHelper().getFactory() ); + } } /** Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/SqlGenerator.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -13,13 +13,13 @@ import org.hibernate.hql.antlr.SqlGeneratorBase; import org.hibernate.hql.ast.tree.MethodNode; import org.hibernate.hql.ast.tree.FromElement; -import org.hibernate.hql.ast.tree.ImpliedFromElement; +import org.hibernate.hql.ast.tree.JavaConstantNode; /** * Generates SQL by overriding callback methods in the base class, which does * the actual SQL AST walking. * - * @author josh Jun 23, 2004 6:49:55 AM + * @author Joshua */ public class SqlGenerator extends SqlGeneratorBase implements ErrorReporter { /** @@ -44,6 +44,15 @@ writer.clause( s ); } + protected void out(AST n) { + if ( n instanceof JavaConstantNode ) { + out( ( ( JavaConstantNode ) n ).getSqlText() ); + } + else { + super.out( n ); + } + } + protected void commaBetweenParameters(String comma) { writer.commaBetweenParameters( comma ); } Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BetweenOperatorNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BetweenOperatorNode.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BetweenOperatorNode.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -7,7 +7,7 @@ /** * Contract for nodes representing logcial BETWEEN (ternary) operators. * - * @author <a href="mailto:st...@hi...">Steve Ebersole </a> + * @author Steve Ebersole */ public class BetweenOperatorNode extends SqlNode implements OperatorNode { @@ -47,7 +47,7 @@ } private void check(Node check, Node first, Node second) { - if ( ParameterNode.class.isAssignableFrom( check.getClass() ) ) { + if ( ExpectedTypeAwareNode.class.isAssignableFrom( check.getClass() ) ) { Type expectedType = null; if ( SqlNode.class.isAssignableFrom( first.getClass() ) ) { expectedType = ( ( SqlNode ) first ).getDataType(); @@ -55,8 +55,7 @@ if ( expectedType == null && SqlNode.class.isAssignableFrom( second.getClass() ) ) { expectedType = ( ( SqlNode ) second ).getDataType(); } - ( ( ParameterNode ) check ).getHqlParameterSpecification().setExpectedType( expectedType ); - ( ( ParameterNode ) check ).setDataType( expectedType ); + ( ( ExpectedTypeAwareNode ) check ).setExpectedType( expectedType ); } } } Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryArithmeticOperatorNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryArithmeticOperatorNode.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryArithmeticOperatorNode.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -28,7 +28,7 @@ Type lhType = ( lhs instanceof SqlNode ) ? ( ( SqlNode ) lhs ).getDataType() : null; Type rhType = ( rhs instanceof SqlNode ) ? ( ( SqlNode ) rhs ).getDataType() : null; - if ( ParameterNode.class.isAssignableFrom( lhs.getClass() ) && rhType != null ) { + if ( ExpectedTypeAwareNode.class.isAssignableFrom( lhs.getClass() ) && rhType != null ) { Type expectedType = null; // we have something like : "? [op] rhs" if ( isDateTimeType( rhType ) ) { @@ -42,7 +42,7 @@ else { expectedType = rhType; } - ( ( ParameterNode ) lhs ).getHqlParameterSpecification().setExpectedType( expectedType ); + ( ( ExpectedTypeAwareNode ) lhs ).setExpectedType( expectedType ); } else if ( ParameterNode.class.isAssignableFrom( rhs.getClass() ) && lhType != null ) { Type expectedType = null; @@ -61,7 +61,7 @@ else { expectedType = lhType; } - ( ( ParameterNode ) rhs ).getHqlParameterSpecification().setExpectedType( expectedType ); + ( ( ExpectedTypeAwareNode ) rhs ).setExpectedType( expectedType ); } } Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/BinaryLogicOperatorNode.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -7,7 +7,7 @@ /** * Contract for nodes representing binary operators. * - * @author <a href="mailto:st...@hi...">Steve Ebersole </a> + * @author Steve Ebersole */ public class BinaryLogicOperatorNode extends SqlNode implements BinaryOperatorNode { /** @@ -23,17 +23,13 @@ if ( rhs == null ) { throw new SemanticException( "right-hand operand of a binary operator was null" ); } - if ( ParameterNode.class.isAssignableFrom( lhs.getClass() ) + if ( ExpectedTypeAwareNode.class.isAssignableFrom( lhs.getClass() ) && SqlNode.class.isAssignableFrom( rhs.getClass() ) ) { - ( ( ParameterNode ) lhs ).getHqlParameterSpecification().setExpectedType( - ( ( SqlNode ) rhs ).getDataType() - ); + ( ( ExpectedTypeAwareNode ) lhs ).setExpectedType( ( ( SqlNode ) rhs ).getDataType() ); } - else if ( ParameterNode.class.isAssignableFrom( rhs.getClass() ) + else if ( ExpectedTypeAwareNode.class.isAssignableFrom( rhs.getClass() ) && SqlNode.class.isAssignableFrom( lhs.getClass() ) ) { - ( ( ParameterNode ) rhs ).getHqlParameterSpecification().setExpectedType( - ( ( SqlNode ) lhs ).getDataType() - ); + ( ( ExpectedTypeAwareNode ) rhs ).setExpectedType( ( ( SqlNode ) lhs ).getDataType() ); } } Added: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ExpectedTypeAwareNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ExpectedTypeAwareNode.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ExpectedTypeAwareNode.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -0,0 +1,14 @@ +package org.hibernate.hql.ast.tree; + +import org.hibernate.type.Type; + +/** + * Interface for nodes which wish to be made aware of any determined "expected + * type" based on the context within they appear in the query. + * + * @author Steve Ebersole + */ +public interface ExpectedTypeAwareNode { + public void setExpectedType(Type expectedType); + public Type getExpectedType(); +} Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/InLogicOperatorNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/InLogicOperatorNode.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/InLogicOperatorNode.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -5,7 +5,7 @@ import org.hibernate.type.Type; /** - * @author <a href="mailto:st...@hi...">Steve Ebersole </a> + * @author Steve Ebersole */ public class InLogicOperatorNode extends BinaryLogicOperatorNode implements BinaryOperatorNode { @@ -30,8 +30,8 @@ Type lhsType = ( ( SqlNode ) lhs ).getDataType(); AST inListChild = inList.getFirstChild(); while ( inListChild != null ) { - if ( ParameterNode.class.isAssignableFrom( inListChild.getClass() ) ) { - ( ( ParameterNode ) inListChild ).getHqlParameterSpecification().setExpectedType( lhsType ); + if ( ExpectedTypeAwareNode.class.isAssignableFrom( inListChild.getClass() ) ) { + ( ( ExpectedTypeAwareNode ) inListChild ).setExpectedType( lhsType ); } inListChild = inListChild.getNextSibling(); } Added: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/JavaConstantNode.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -0,0 +1,66 @@ +package org.hibernate.hql.ast.tree; + +import org.hibernate.type.Type; +import org.hibernate.type.TypeFactory; +import org.hibernate.type.LiteralType; +import org.hibernate.util.ReflectHelper; +import org.hibernate.util.StringHelper; +import org.hibernate.engine.SessionFactoryImplementor; +import org.hibernate.dialect.Dialect; +import org.hibernate.QueryException; +import org.hibernate.hql.QueryTranslator; + +/** + * A node representing a static Java constant. + * + * @author Steve Ebersole + */ +public class JavaConstantNode extends Node implements ExpectedTypeAwareNode, SessionFactoryAwareNode { + + private SessionFactoryImplementor factory; + + private String constantExpression; + private Object constantValue; + private Type heuristicType; + + private Type expectedType; + + public void setText(String s) { + // for some reason the antlr.CommonAST initialization routines force + // this method to get called twice. The first time with an empty string + if ( StringHelper.isNotEmpty( s ) ) { + constantExpression = s; + constantValue = ReflectHelper.getConstantValue( s ); + heuristicType = TypeFactory.heuristicType( constantValue.getClass().getName() ); + super.setText( s ); + } + } + + public void setExpectedType(Type expectedType) { + this.expectedType = expectedType; + } + + public Type getExpectedType() { + return expectedType; + } + + public void setSessionFactory(SessionFactoryImplementor factory) { + this.factory = factory; + } + + public String getSqlText() { + Type type = expectedType == null ? heuristicType : expectedType; + return resolveToLiteralString( type ); + } + + private String resolveToLiteralString(Type type) { + try { + LiteralType literalType = ( LiteralType ) type; + Dialect dialect = factory.getDialect(); + return literalType.objectToSQLString( constantValue, dialect ); + } + catch ( Throwable t ) { + throw new QueryException( QueryTranslator.ERROR_CANNOT_FORMAT_LITERAL + constantExpression, t ); + } + } +} Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/ParameterNode.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -2,13 +2,14 @@ package org.hibernate.hql.ast.tree; import org.hibernate.param.ParameterSpecification; +import org.hibernate.type.Type; /** * Implementation of ParameterNode. * * @author Steve Ebersole */ -public class ParameterNode extends HqlSqlWalkerNode implements DisplayableNode { +public class ParameterNode extends HqlSqlWalkerNode implements DisplayableNode, ExpectedTypeAwareNode { private ParameterSpecification parameterSpecification; public ParameterSpecification getHqlParameterSpecification() { @@ -22,4 +23,13 @@ public String getDisplayText() { return "{" + ( parameterSpecification == null ? "???" : parameterSpecification.renderDisplayInfo() ) + "}"; } + + public void setExpectedType(Type expectedType) { + getHqlParameterSpecification().setExpectedType( expectedType ); + setDataType( expectedType ); + } + + public Type getExpectedType() { + return getHqlParameterSpecification() == null ? null : getHqlParameterSpecification().getExpectedType(); + } } Added: trunk/Hibernate3/src/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/tree/SessionFactoryAwareNode.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -0,0 +1,12 @@ +package org.hibernate.hql.ast.tree; + +import org.hibernate.engine.SessionFactoryImplementor; + +/** + * Interface for nodes which require access to the SessionFactory + * + * @author Steve Ebersole + */ +public interface SessionFactoryAwareNode { + public void setSessionFactory(SessionFactoryImplementor sessionFactory); +} Modified: trunk/Hibernate3/src/org/hibernate/hql/ast/util/ASTUtil.java =================================================================== --- trunk/Hibernate3/src/org/hibernate/hql/ast/util/ASTUtil.java 2006-06-08 20:52:40 UTC (rev 9999) +++ trunk/Hibernate3/src/org/hibernate/hql/ast/util/ASTUtil.java 2006-06-08 21:04:45 UTC (rev 10000) @@ -178,6 +178,48 @@ } /** + * Determine if a given node (test) is a direct (throtle to one level down) + * child of another given node (fixture). + * + * @param fixture The node against which to testto be checked for children. + * @param test The node to be tested as being a child of the parent. + * @return True if test is contained in the fixtures's direct children; + * false otherwise. + */ + public static boolean isDirectChild(AST fixture, AST test) { + AST n = fixture.getFirstChild(); + while ( n != null ) { + if ( n == test ) { + return true; + } + n = n.getNextSibling(); + } + return false; + } + + /** + * Determine if a given node (test) is contained anywhere in the subtree + * of another given node (fixture). + * + * @param fixture The node against which to testto be checked for children. + * @param test The node to be tested as being a subtree child of the parent. + * @return True if child is contained in the parent's collection of children. + */ + public static boolean isSubtreeChild(AST fixture, AST test) { + AST n = fixture.getFirstChild(); + while ( n != null ) { + if ( n == test ) { + return true; + } + if ( n.getFirstChild() != null && isSubtreeChild( n, test ) ) { + return true; + } + n = n.getNextSibling(); + } + return false; + } + + /** * Makes the child node a sibling of the parent, reconnecting all siblings. * * @param parent the parent |