From: <ste...@us...> - 2006-02-24 22:11:56
|
Update of /cvsroot/hibernate/Hibernate3/src/org/hibernate/hql/ast In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv22750/src/org/hibernate/hql/ast Modified Files: HqlSqlWalker.java Log Message: HHH-1520 : with clause improvements Index: HqlSqlWalker.java =================================================================== RCS file: /cvsroot/hibernate/Hibernate3/src/org/hibernate/hql/ast/HqlSqlWalker.java,v retrieving revision 1.117 retrieving revision 1.118 diff -u -d -r1.117 -r1.118 --- HqlSqlWalker.java 16 Feb 2006 19:23:22 -0000 1.117 +++ HqlSqlWalker.java 24 Feb 2006 22:11:53 -0000 1.118 @@ -14,6 +14,7 @@ import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.hibernate.QueryException; +import org.hibernate.HibernateException; import org.hibernate.engine.JoinSequence; import org.hibernate.engine.ParameterBinder; import org.hibernate.engine.SessionFactoryImplementor; @@ -44,6 +45,8 @@ import org.hibernate.hql.ast.tree.UpdateStatement; import org.hibernate.hql.ast.tree.Node; import org.hibernate.hql.ast.tree.OperatorNode; +import org.hibernate.hql.ast.tree.BinaryLogicOperatorNode; +import org.hibernate.hql.ast.tree.InLogicOperatorNode; import org.hibernate.hql.ast.util.ASTPrinter; import org.hibernate.hql.ast.util.ASTUtil; import org.hibernate.hql.ast.util.AliasGenerator; @@ -51,6 +54,7 @@ import org.hibernate.hql.ast.util.LiteralProcessor; import org.hibernate.hql.ast.util.SessionFactoryHelper; import org.hibernate.hql.ast.util.SyntheticAndFactory; +import org.hibernate.hql.ast.util.NodeTraverser; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.PostInsertIdentifierGenerator; import org.hibernate.id.SequenceGenerator; @@ -334,15 +338,80 @@ try { withClause( hqlWithNode ); AST hqlSqlWithNode = returnAST; + if ( log.isDebugEnabled() ) { + log.debug( "handleWithFragment() : " + getASTPrinter().showAsString( hqlSqlWithNode, "-- with clause --" ) ); + } + WithClauseVisitor visitor = new WithClauseVisitor(); + NodeTraverser traverser = new NodeTraverser( visitor ); + traverser.traverseDepthFirst( hqlSqlWithNode ); + FromElement referencedFromElement = visitor.getReferencedFromElement(); + if ( referencedFromElement != fromElement ) { + throw new SemanticException( "with-clause expressions did not reference from-clause element to which the with-clause was associated" ); + } SqlGenerator sql = new SqlGenerator( getSessionFactoryHelper().getFactory() ); sql.whereExpr( hqlSqlWithNode.getFirstChild() ); - fromElement.setAdHocOnClauseFragment( "(" + sql.getSQL() + ")" ); + fromElement.setWithClauseFragment( visitor.getJoinAlias(), "(" + sql.getSQL() + ")" ); - } catch ( Exception e) { + } + catch( SemanticException e ) { + throw e; + } + catch ( Exception e) { throw new SemanticException( e.getMessage() ); } } + private static class WithClauseVisitor implements NodeTraverser.VisitationStrategy { + private FromElement referencedFromElement; + private String joinAlias; + + public void visit(AST node) { + // todo : currently expects that the individual with expressions apply to the same sql table join. + // This may not be the case for joined-subclass where the property values + // might be coming from different tables in the joined hierarchy. At some + // point we should expand this to support that capability. However, that has + // some difficulties: + // 1) the biggest is how to handle ORs when the individual comparisons are + // linked to different sql joins. + // 2) here we would need to track each comparison individually, along with + // the join alias to which it applies and then pass that information + // back to the FromElement so it can pass it along to the JoinSequence + + if ( node instanceof DotNode ) { + DotNode dotNode = ( DotNode ) node; + FromElement fromElement = dotNode.getFromElement(); + if ( referencedFromElement != null ) { + if ( fromElement != referencedFromElement ) { + throw new HibernateException( "with-clause referenced two different from-clause elements" ); + } + } + else { + referencedFromElement = fromElement; + joinAlias = extractAppliedAlias( dotNode ); + // todo : temporary + // needed because currently persister is the one that + // creates and renders the join fragments for inheritence + // hierarchies... + if ( !joinAlias.equals( referencedFromElement.getTableAlias() ) ) { + throw new HibernateException( "with clause can only reference columns in the driving table" ); + } + } + } + } + + private String extractAppliedAlias(DotNode dotNode) { + return dotNode.getText().substring( 0, dotNode.getText().indexOf( '.' ) ); + } + + public FromElement getReferencedFromElement() { + return referencedFromElement; + } + + public String getJoinAlias() { + return joinAlias; + } + } + /** * Sets the current 'FROM' context. * |