📄 hqlsqlwalker.java
字号:
// $Id: HqlSqlWalker.java,v 1.83 2005/04/10 18:43:48 oneovthafew Exp $package org.hibernate.hql.ast;import antlr.ASTFactory;import antlr.RecognitionException;import antlr.SemanticException;import antlr.collections.AST;import org.apache.commons.logging.Log;import org.apache.commons.logging.LogFactory;import org.hibernate.QueryException;import org.hibernate.engine.JoinSequence;import org.hibernate.engine.SessionFactoryImplementor;import org.hibernate.hql.QueryTranslator;import org.hibernate.hql.antlr.HqlSqlBaseWalker;import org.hibernate.hql.antlr.HqlTokenTypes;import org.hibernate.hql.antlr.SqlTokenTypes;import org.hibernate.persister.collection.QueryableCollection;import org.hibernate.persister.entity.Queryable;import org.hibernate.persister.entity.SingleTableEntityPersister;import org.hibernate.sql.JoinFragment;import org.hibernate.type.AssociationType;import org.hibernate.type.Type;import org.hibernate.util.ArrayHelper;import java.io.Serializable;import java.util.ArrayList;import java.util.HashMap;import java.util.HashSet;import java.util.Iterator;import java.util.List;import java.util.Map;import java.util.Set;/** * 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 { private static Log log = LogFactory.getLog( HqlSqlWalker.class ); /** * A delegate that handles the Hiberanate meta data model. */ private SessionFactoryHelper sessionFactoryHelper; /** * A delegate that handles literal constants. */ private LiteralProcessor literalProcessor; /** * Handles parser errors. */ private ParseErrorHandler parseErrorHandler; /** * The current context. */ private FromClause currentFromClause = null; /** * The top-level SelectClause. */ private SelectClause selectClause; /** * Generates alias names for tables. */ private AliasGenerator aliasGenerator = new AliasGenerator(); /** * The set of unique query spaces (a.k.a. table names). */ private Set querySpaces = new HashSet(); /** * A (string->string) map is used to substitute function names and literals. */ private Map tokenReplacements; private QueryTranslatorImpl queryTranslatorImpl; /** * The number of parameters encountered so far. */ private int parameterCount; /** * A map of lists which associates named and numbered parameters to a list of occurrences in the query. */ private Map namedParameters = new HashMap(); private boolean useThetaStyleImplicitJoins = true; /** * The filter collection role, or null if this isn't a filter compilation. */ private String filterCollectionRole; /** * The parser that performed phase 1 - parse the HQL into an HQL tree. */ private HqlParser hqlParser; private ASTPrinter printer; /** * The join type for any implied joins. */ 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 * @param tokenReplacements Registers the token replacement map with the walker. This map will * be used to substitute function names and constants. * @param collectionRole the role name of the collection used as the basis for the filter, NULL if this */ 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.filterCollectionRole = collectionRole; this.hqlParser = parser; this.printer = new ASTPrinter( SqlTokenTypes.class ); } protected void prepareFromClauseInputTree(AST fromClauseInput) { // Handle fiter compilation. // IMPORTANT NOTE: This is modifying the INPUT (HQL) tree, not the output tree! if ( isFilter() && !isSubQuery() ) { QueryableCollection persister = sessionFactoryHelper.getCollectionPersister( filterCollectionRole ); 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() ); } } private boolean isFilter() { return filterCollectionRole != null; } public SessionFactoryHelper getSessionFactoryHelper() { return sessionFactoryHelper; } public Map getTokenReplacements() { return tokenReplacements; } public AliasGenerator getAliasGenerator() { return aliasGenerator; } 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). */ 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( filterCollectionRole ); // 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( filterCollectionRole ); 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) throws SemanticException { boolean fetch = ( fetchNode != null ) ? true : false; // 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 ( log.isDebugEnabled() ) { log.debug( "createFromJoinElement() : " + getASTPrinter().showAsString( fromElement, "-- join tree --" ) ); } } /** * Sets the current 'FROM' context. * * @param fromNode The new 'FROM' context. * @param inputFromNode The from node from the input AST. */ protected void pushFromClause(AST fromNode, AST inputFromNode) { FromClause newFromClause = ( FromClause ) fromNode; newFromClause.setParentFromClause( currentFromClause ); currentFromClause = newFromClause; } /** * Returns to the previous 'FROM' context. */ private void popFromClause() { currentFromClause = currentFromClause.getParentFromClause(); } protected void lookupAlias(AST aliasRef) throws SemanticException { FromElement alias = currentFromClause.getFromElement( aliasRef.getText() ); FromReferenceNode aliasRefNode = ( FromReferenceNode ) aliasRef; aliasRefNode.setFromElement( alias ); } protected void setImpliedJoinType(int joinType) { impliedJoinType = JoinProcessor.toHibernateJoinType( joinType ); } int getImpliedJoinType() { return impliedJoinType; } protected AST lookupProperty(AST dot, boolean root, boolean inSelect) throws SemanticException {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -