|
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
|