📄 hqlsqlwalker.java
字号:
// $Id: HqlSqlWalker.java 10945 2006-12-07 14:50:42Z steve.ebersole@jboss.com $package org.hibernate.hql.ast;import java.io.Serializable;import java.util.ArrayList;import java.util.Date;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.hibernate.QueryException;import org.hibernate.HibernateException;import org.hibernate.engine.JoinSequence;import org.hibernate.engine.ParameterBinder;import org.hibernate.engine.SessionFactoryImplementor;import org.hibernate.hql.QueryTranslator;import org.hibernate.hql.antlr.HqlSqlBaseWalker;import org.hibernate.hql.antlr.HqlSqlTokenTypes;import org.hibernate.hql.antlr.HqlTokenTypes;import org.hibernate.hql.antlr.SqlTokenTypes;import org.hibernate.hql.ast.tree.AssignmentSpecification;import org.hibernate.hql.ast.tree.CollectionFunction;import org.hibernate.hql.ast.tree.ConstructorNode;import org.hibernate.hql.ast.tree.DeleteStatement;import org.hibernate.hql.ast.tree.DotNode;import org.hibernate.hql.ast.tree.FromClause;import org.hibernate.hql.ast.tree.FromElement;import org.hibernate.hql.ast.tree.FromReferenceNode;import org.hibernate.hql.ast.tree.IdentNode;import org.hibernate.hql.ast.tree.IndexNode;import org.hibernate.hql.ast.tree.InsertStatement;import org.hibernate.hql.ast.tree.IntoClause;import org.hibernate.hql.ast.tree.MethodNode;import org.hibernate.hql.ast.tree.ParameterNode;import org.hibernate.hql.ast.tree.QueryNode;import org.hibernate.hql.ast.tree.ResolvableNode;import org.hibernate.hql.ast.tree.RestrictableStatement;import org.hibernate.hql.ast.tree.SelectClause;import org.hibernate.hql.ast.tree.SelectExpression;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.util.ASTPrinter;import org.hibernate.hql.ast.util.ASTUtil;import org.hibernate.hql.ast.util.AliasGenerator;import org.hibernate.hql.ast.util.JoinProcessor;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;import org.hibernate.param.NamedParameterSpecification;import org.hibernate.param.ParameterSpecification;import org.hibernate.param.PositionalParameterSpecification;import org.hibernate.param.VersionTypeSeedParameterSpecification;import org.hibernate.param.CollectionFilterKeyParameterSpecification;import org.hibernate.persister.collection.QueryableCollection;import org.hibernate.persister.entity.Queryable;import org.hibernate.sql.JoinFragment;import org.hibernate.type.AssociationType;import org.hibernate.type.Type;import org.hibernate.type.VersionType;import org.hibernate.type.DbTimestampType;import org.hibernate.usertype.UserVersionType;import org.hibernate.util.ArrayHelper;import antlr.ASTFactory;import antlr.RecognitionException;import antlr.SemanticException;import antlr.collections.AST;/** * Implements methods used by the HQL->SQL tree transform grammar (a.k.a. the second phase). * <ul> * <li>Isolates the Hibernate API-specific code from the ANTLR generated code.</li> * <li>Handles the SQL framgents generated by the persisters in order to create the SELECT and FROM clauses, * taking into account the joins and projections that are implied by the mappings (persister/queryable).</li> * <li>Uses SqlASTFactory to create customized AST nodes.</li> * </ul> * * @see SqlASTFactory */public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, ParameterBinder.NamedParameterSource { private static final Logger log = LoggerFactory.getLogger( HqlSqlWalker.class ); private final QueryTranslatorImpl queryTranslatorImpl; private final HqlParser hqlParser; private final SessionFactoryHelper sessionFactoryHelper; private final Map tokenReplacements; private final AliasGenerator aliasGenerator = new AliasGenerator(); private final LiteralProcessor literalProcessor; private final ParseErrorHandler parseErrorHandler; private final ASTPrinter printer; private final String collectionFilterRole; private FromClause currentFromClause = null; private SelectClause selectClause; private Set querySpaces = new HashSet(); private int parameterCount; private Map namedParameters = new HashMap(); private ArrayList parameters = new ArrayList(); private int numberOfParametersInSetClause; private int positionalParameterCount; private ArrayList assignmentSpecifications = new ArrayList(); private int impliedJoinType; /** * Create a new tree transformer. * * @param qti Back pointer to the query translator implementation that is using this tree transform. * @param sfi The session factory implementor where the Hibernate mappings can be found. * @param parser A reference to the phase-1 parser * @param tokenReplacements Registers the token replacement map with the walker. This map will * be used to substitute function names and constants. * @param collectionRole The collection role name of the collection used as the basis for the * filter, NULL if this is not a collection filter compilation. */ public HqlSqlWalker( QueryTranslatorImpl qti, SessionFactoryImplementor sfi, HqlParser parser, Map tokenReplacements, String collectionRole) { setASTFactory( new SqlASTFactory( this ) ); // Initialize the error handling delegate. this.parseErrorHandler = new ErrorCounter(); this.queryTranslatorImpl = qti; this.sessionFactoryHelper = new SessionFactoryHelper( sfi ); this.literalProcessor = new LiteralProcessor( this ); this.tokenReplacements = tokenReplacements; this.collectionFilterRole = collectionRole; this.hqlParser = parser; this.printer = new ASTPrinter( SqlTokenTypes.class ); } protected void prepareFromClauseInputTree(AST fromClauseInput) { if ( !isSubQuery() ) {// // inject param specifications to account for dynamic filter param values// if ( ! getEnabledFilters().isEmpty() ) {// Iterator filterItr = getEnabledFilters().values().iterator();// while ( filterItr.hasNext() ) {// FilterImpl filter = ( FilterImpl ) filterItr.next();// if ( ! filter.getFilterDefinition().getParameterNames().isEmpty() ) {// Iterator paramItr = filter.getFilterDefinition().getParameterNames().iterator();// while ( paramItr.hasNext() ) {// String parameterName = ( String ) paramItr.next();// // currently param filters *only* work with single-column parameter types;// // if that limitation is ever lifted, this logic will need to change to account for that// ParameterNode collectionFilterKeyParameter = ( ParameterNode ) astFactory.create( PARAM, "?" );// DynamicFilterParameterSpecification paramSpec = new DynamicFilterParameterSpecification(// filter.getName(),// parameterName,// filter.getFilterDefinition().getParameterType( parameterName ),// positionalParameterCount++// );// collectionFilterKeyParameter.setHqlParameterSpecification( paramSpec );// parameters.add( paramSpec );// }// }// }// } if ( isFilter() ) { // Handle collection-fiter compilation. // IMPORTANT NOTE: This is modifying the INPUT (HQL) tree, not the output tree! QueryableCollection persister = sessionFactoryHelper.getCollectionPersister( collectionFilterRole ); Type collectionElementType = persister.getElementType(); if ( !collectionElementType.isEntityType() ) { throw new QueryException( "collection of values in filter: this" ); } String collectionElementEntityName = persister.getElementPersister().getEntityName(); ASTFactory inputAstFactory = hqlParser.getASTFactory(); AST fromElement = ASTUtil.create( inputAstFactory, HqlTokenTypes.FILTER_ENTITY, collectionElementEntityName ); ASTUtil.createSibling( inputAstFactory, HqlTokenTypes.ALIAS, "this", fromElement ); fromClauseInput.addChild( fromElement ); // Show the modified AST. if ( log.isDebugEnabled() ) { log.debug( "prepareFromClauseInputTree() : Filter - Added 'this' as a from element..." ); } queryTranslatorImpl.showHqlAst( hqlParser.getAST() ); // Create a parameter specification for the collection filter... Type collectionFilterKeyType = sessionFactoryHelper.requireQueryableCollection( collectionFilterRole ).getKeyType(); ParameterNode collectionFilterKeyParameter = ( ParameterNode ) astFactory.create( PARAM, "?" ); CollectionFilterKeyParameterSpecification collectionFilterKeyParameterSpec = new CollectionFilterKeyParameterSpecification( collectionFilterRole, collectionFilterKeyType, positionalParameterCount++ ); collectionFilterKeyParameter.setHqlParameterSpecification( collectionFilterKeyParameterSpec ); parameters.add( collectionFilterKeyParameterSpec ); } } } public boolean isFilter() { return collectionFilterRole != null; } public SessionFactoryHelper getSessionFactoryHelper() { return sessionFactoryHelper; } public Map getTokenReplacements() { return tokenReplacements; } public AliasGenerator getAliasGenerator() { return aliasGenerator; } public FromClause getCurrentFromClause() { return currentFromClause; } public ParseErrorHandler getParseErrorHandler() { return parseErrorHandler; } public void reportError(RecognitionException e) { parseErrorHandler.reportError( e ); // Use the delegate. } public void reportError(String s) { parseErrorHandler.reportError( s ); // Use the delegate. } public void reportWarning(String s) { parseErrorHandler.reportWarning( s ); } /** * Returns the set of unique query spaces (a.k.a. * table names) that occurred in the query. * * @return A set of table names (Strings). */ public Set getQuerySpaces() { return querySpaces; } protected AST createFromElement(String path, AST alias, AST propertyFetch) throws SemanticException { FromElement fromElement = currentFromClause.addFromElement( path, alias ); fromElement.setAllPropertyFetch(propertyFetch!=null); return fromElement; } protected AST createFromFilterElement(AST filterEntity, AST alias) throws SemanticException { FromElement fromElement = currentFromClause.addFromElement( filterEntity.getText(), alias ); FromClause fromClause = fromElement.getFromClause(); QueryableCollection persister = sessionFactoryHelper.getCollectionPersister( collectionFilterRole ); // Get the names of the columns used to link between the collection // owner and the collection elements. String[] keyColumnNames = persister.getKeyColumnNames(); String fkTableAlias = persister.isOneToMany() ? fromElement.getTableAlias() : fromClause.getAliasGenerator().createName( collectionFilterRole ); JoinSequence join = sessionFactoryHelper.createJoinSequence(); join.setRoot( persister, fkTableAlias ); if ( !persister.isOneToMany() ) { join.addJoin( ( AssociationType ) persister.getElementType(), fromElement.getTableAlias(), JoinFragment.INNER_JOIN, persister.getElementColumnNames( fkTableAlias ) ); } join.addCondition( fkTableAlias, keyColumnNames, " = ?" ); fromElement.setJoinSequence( join ); fromElement.setFilter( true ); if ( log.isDebugEnabled() ) { log.debug( "createFromFilterElement() : processed filter FROM element." ); } return fromElement; } protected void createFromJoinElement( AST path, AST alias, int joinType, AST fetchNode, AST propertyFetch, AST with) throws SemanticException { boolean fetch = fetchNode != null; if ( fetch && isSubQuery() ) { throw new QueryException( "fetch not allowed in subquery from-elements" ); } // The path AST should be a DotNode, and it should have been evaluated already. if ( path.getType() != SqlTokenTypes.DOT ) { throw new SemanticException( "Path expected for join!" ); } DotNode dot = ( DotNode ) path; int hibernateJoinType = JoinProcessor.toHibernateJoinType( joinType ); dot.setJoinType( hibernateJoinType ); // Tell the dot node about the join type. dot.setFetch( fetch ); // Generate an explicit join for the root dot node. The implied joins will be collected and passed up // to the root dot node. dot.resolve( true, false, alias == null ? null : alias.getText() ); FromElement fromElement = dot.getImpliedJoin(); fromElement.setAllPropertyFetch(propertyFetch!=null); if ( with != null ) { if ( fetch ) { throw new SemanticException( "with-clause not allowed on fetched associations; use filters" ); } handleWithFragment( fromElement, with ); } if ( log.isDebugEnabled() ) { log.debug( "createFromJoinElement() : " + getASTPrinter().showAsString( fromElement, "-- join tree --" ) ); } } private void handleWithFragment(FromElement fromElement, AST hqlWithNode) throws SemanticException { 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 InvalidWithClauseException( "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() );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -