FileDocCategorySizeDatePackage
HqlSqlWalker.javaAPI DocHibernate 3.2.539192Thu Dec 07 07:51:00 GMT 2006org.hibernate.hql.ast

HqlSqlWalker

public class HqlSqlWalker extends org.hibernate.hql.antlr.HqlSqlBaseWalker implements ErrorReporter, ParameterBinder.NamedParameterSource
Implements methods used by the HQL->SQL tree transform grammar (a.k.a. the second phase).
  • Isolates the Hibernate API-specific code from the ANTLR generated code.
  • 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).
  • Uses SqlASTFactory to create customized AST nodes.
see
SqlASTFactory

Fields Summary
private static final Log
log
private final QueryTranslatorImpl
queryTranslatorImpl
private final HqlParser
hqlParser
private final org.hibernate.hql.ast.util.SessionFactoryHelper
sessionFactoryHelper
private final Map
tokenReplacements
private final org.hibernate.hql.ast.util.AliasGenerator
aliasGenerator
private final org.hibernate.hql.ast.util.LiteralProcessor
literalProcessor
private final ParseErrorHandler
parseErrorHandler
private final org.hibernate.hql.ast.util.ASTPrinter
printer
private final String
collectionFilterRole
private org.hibernate.hql.ast.tree.FromClause
currentFromClause
private org.hibernate.hql.ast.tree.SelectClause
selectClause
private Set
querySpaces
private int
parameterCount
private Map
namedParameters
private ArrayList
parameters
private int
numberOfParametersInSetClause
private int
positionalParameterCount
private ArrayList
assignmentSpecifications
private int
impliedJoinType
Constructors Summary
public HqlSqlWalker(QueryTranslatorImpl qti, org.hibernate.engine.SessionFactoryImplementor sfi, HqlParser parser, Map tokenReplacements, String collectionRole)
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.




	                                                                                        	 
	 
			 
			 
			 
			 
			  
		setASTFactory( new SqlASTFactory( this ) );
		this.parseErrorHandler = new ErrorCounter();
		this.queryTranslatorImpl = qti;
		this.sessionFactoryHelper = new SessionFactoryHelper( sfi );
		this.literalProcessor = new LiteralProcessor( this );
		this.tokenReplacements = tokenReplacements;
		this.hqlParser = parser;
		this.printer = new ASTPrinter( SqlTokenTypes.class );
		this.collectionFilterRole = collectionRole;
	
Methods Summary
public voidaddQuerySpaces(java.io.Serializable[] spaces)

		for ( int i = 0; i < spaces.length; i++ ) {
			querySpaces.add( spaces[i] );
		}
	
protected voidbeforeSelectClause()

		// Turn off includeSubclasses on all FromElements.
		FromClause from = getCurrentFromClause();
		List fromElements = from.getFromElements();
		for ( Iterator iterator = fromElements.iterator(); iterator.hasNext(); ) {
			FromElement fromElement = ( FromElement ) iterator.next();
			fromElement.setIncludeSubclasses( false );
		}
	
protected antlr.collections.ASTcreateFromElement(java.lang.String path, antlr.collections.AST alias, antlr.collections.AST propertyFetch)

		FromElement fromElement = currentFromClause.addFromElement( path, alias );
		fromElement.setAllPropertyFetch(propertyFetch!=null);
		return fromElement;
	
protected antlr.collections.ASTcreateFromFilterElement(antlr.collections.AST filterEntity, antlr.collections.AST alias)

		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 voidcreateFromJoinElement(antlr.collections.AST path, antlr.collections.AST alias, int joinType, antlr.collections.AST fetchNode, antlr.collections.AST propertyFetch, antlr.collections.AST with)

		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 --" ) );
		}
	
protected antlr.collections.ASTcreateIntoClause(java.lang.String path, antlr.collections.AST propertySpec)

		Queryable persister = ( Queryable ) getSessionFactoryHelper().requireClassPersister( path );

		IntoClause intoClause = ( IntoClause ) getASTFactory().create( INTO, persister.getEntityName() );
		intoClause.setFirstChild( propertySpec );
		intoClause.initialize( persister );

		addQuerySpaces( persister.getQuerySpaces() );

		return intoClause;
	
private voidcreateSelectClauseFromFromClause(org.hibernate.hql.ast.tree.QueryNode qn)

		AST select = astFactory.create( SELECT_CLAUSE, "{derived select clause}" );
		AST sibling = qn.getFromClause();
		qn.setFirstChild( select );
		select.setNextSibling( sibling );
		selectClause = ( SelectClause ) select;
		selectClause.initializeDerivedSelectClause( currentFromClause );
		if ( log.isDebugEnabled() ) {
			log.debug( "Derived SELECT clause created." );
		}
	
protected voidevaluateAssignment(antlr.collections.AST eq)

		prepareLogicOperator( eq );
		Queryable persister = getCurrentFromClause().getFromElement().getQueryable();
		evaluateAssignment( eq, persister, -1 );
	
private voidevaluateAssignment(antlr.collections.AST eq, org.hibernate.persister.entity.Queryable persister, int targetIndex)

		if ( persister.isMultiTable() ) {
			// no need to even collect this information if the persister is considered multi-table
			AssignmentSpecification specification = new AssignmentSpecification( eq, persister );
			if ( targetIndex >= 0 ) {
				assignmentSpecifications.add( targetIndex, specification );
			}
			else {
				assignmentSpecifications.add( specification );
			}
			numberOfParametersInSetClause += specification.getParameters().length;
		}
	
protected antlr.collections.ASTgenerateNamedParameter(antlr.collections.AST delimiterNode, antlr.collections.AST nameNode)

		String name = nameNode.getText();
		trackNamedParameterPositions( name );

		// create the node initially with the param name so that it shows
		// appropriately in the "original text" attribute
		ParameterNode parameter = ( ParameterNode ) astFactory.create( NAMED_PARAM, name );
		parameter.setText( "?" );

		NamedParameterSpecification paramSpec = new NamedParameterSpecification(
				( ( Node ) delimiterNode ).getLine(),
		        ( ( Node ) delimiterNode ).getColumn(),
				name
		);
		parameter.setHqlParameterSpecification( paramSpec );
		parameters.add( paramSpec );
		return parameter;
	
protected antlr.collections.ASTgeneratePositionalParameter(antlr.collections.AST inputNode)

		if ( namedParameters.size() > 0 ) {
			throw new SemanticException( "cannot define positional parameter after any named parameters have been defined" );
		}
		ParameterNode parameter = ( ParameterNode ) astFactory.create( PARAM, "?" );
		PositionalParameterSpecification paramSpec = new PositionalParameterSpecification(
				( ( Node ) inputNode ).getLine(),
		        ( ( Node ) inputNode ).getColumn(),
				positionalParameterCount++
		);
		parameter.setHqlParameterSpecification( paramSpec );
		parameters.add( paramSpec );
		return parameter;
	
private antlr.collections.ASTgenerateSyntheticDotNodeForNonQualifiedPropertyRef(antlr.collections.AST property, org.hibernate.hql.ast.tree.FromElement fromElement)

		AST dot = getASTFactory().create( DOT, "{non-qualified-property-ref}" );
		// TODO : better way?!?
		( ( DotNode ) dot ).setPropertyPath( ( ( FromReferenceNode ) property ).getPath() );

		IdentNode syntheticAlias = ( IdentNode ) getASTFactory().create( IDENT, "{synthetic-alias}" );
		syntheticAlias.setFromElement( fromElement );
		syntheticAlias.setResolved();

		dot.setFirstChild( syntheticAlias );
		dot.addChild( property );

		return dot;
	
private antlr.collections.ASTgenerateVersionPropertyNode(org.hibernate.persister.entity.Queryable persister)

		String versionPropertyName = persister.getPropertyNames()[ persister.getVersionProperty() ];
		AST versionPropertyRef = getASTFactory().create( HqlSqlTokenTypes.IDENT, versionPropertyName );
		AST versionPropertyNode = lookupNonQualifiedProperty( versionPropertyRef );
		resolve( versionPropertyNode );
		return versionPropertyNode;
	
public org.hibernate.hql.ast.util.ASTPrintergetASTPrinter()

		return printer;
	
public org.hibernate.hql.ast.util.AliasGeneratorgetAliasGenerator()

		return aliasGenerator;
	
public java.util.ArrayListgetAssignmentSpecifications()

		return assignmentSpecifications;
	
public org.hibernate.hql.ast.tree.FromClausegetCurrentFromClause()

		return currentFromClause;
	
public java.util.MapgetEnabledFilters()

		return queryTranslatorImpl.getEnabledFilters();
	
public org.hibernate.hql.ast.tree.FromClausegetFinalFromClause()

		FromClause top = currentFromClause;
		while ( top.getParentFromClause() != null ) {
			top = top.getParentFromClause();
		}
		return top;
	
public intgetImpliedJoinType()

		return impliedJoinType;
	
public org.hibernate.hql.ast.util.LiteralProcessorgetLiteralProcessor()

		return literalProcessor;
	
public int[]getNamedParameterLocations(java.lang.String name)
Returns the locations of all occurrences of the named parameter.

		Object o = namedParameters.get( name );
		if ( o == null ) {
			QueryException qe = new QueryException( QueryTranslator.ERROR_NAMED_PARAMETER_DOES_NOT_APPEAR + name );
			qe.setQueryString( queryTranslatorImpl.getQueryString() );
			throw qe;
		}
		if ( o instanceof Integer ) {
			return new int[]{( ( Integer ) o ).intValue()};
		}
		else {
			return ArrayHelper.toIntArray( ( ArrayList ) o );
		}
	
public intgetNumberOfParametersInSetClause()

		return numberOfParametersInSetClause;
	
public java.util.ArrayListgetParameters()

		return parameters;
	
public ParseErrorHandlergetParseErrorHandler()

		return parseErrorHandler;
	
public java.util.SetgetQuerySpaces()
Returns the set of unique query spaces (a.k.a. table names) that occurred in the query.

return
A set of table names (Strings).

		return querySpaces;
	
public java.lang.String[]getReturnAliases()

		return selectClause.getQueryReturnAliases();
	
public org.hibernate.type.Type[]getReturnTypes()

		return selectClause.getQueryReturnTypes();
	
public org.hibernate.hql.ast.tree.SelectClausegetSelectClause()

		return selectClause;
	
public org.hibernate.hql.ast.util.SessionFactoryHelpergetSessionFactoryHelper()

		return sessionFactoryHelper;
	
public java.util.MapgetTokenReplacements()

		return tokenReplacements;
	
private voidhandleWithFragment(org.hibernate.hql.ast.tree.FromElement fromElement, antlr.collections.AST hqlWithNode)

		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() );
			fromElement.setWithClauseFragment( visitor.getJoinAlias(), "(" + sql.getSQL() + ")" );

		}
		catch( SemanticException e ) {
			throw e;
		}
		catch( InvalidWithClauseException e ) {
			throw e;
		}
		catch ( Exception e) {
			throw new SemanticException( e.getMessage() );
		}
	
private booleanisDatabaseGeneratedTimestamp(org.hibernate.type.Type type)

		// currently only the Hibernate-supplied DbTimestampType is supported here
		return DbTimestampType.class.isAssignableFrom( type.getClass() );
	
public booleanisFilter()

		return collectionFilterRole != null;
	
private booleanisIntegral(org.hibernate.type.Type type)

		return Long.class.isAssignableFrom( type.getReturnedClass() )
		       || Integer.class.isAssignableFrom( type.getReturnedClass() )
		       || long.class.isAssignableFrom( type.getReturnedClass() )
		       || int.class.isAssignableFrom( type.getReturnedClass() );
	
protected booleanisNonQualifiedPropertyRef(antlr.collections.AST ident)

		final String identText = ident.getText();
		if ( currentFromClause.isFromElementAlias( identText ) ) {
			return false;
		}

		List fromElements = currentFromClause.getExplicitFromElements();
		if ( fromElements.size() == 1 ) {
			final FromElement fromElement = ( FromElement ) fromElements.get( 0 );
			try {
				log.trace( "attempting to resolve property [" + identText + "] as a non-qualified ref" );
				return fromElement.getPropertyMapping( identText ).toType( identText ) != null;
			}
			catch( QueryException e ) {
				// Should mean that no such property was found
			}
		}

		return false;
	
public booleanisShallowQuery()

		// select clauses for insert statements should alwasy be treated as shallow
		return getStatementType() == INSERT || queryTranslatorImpl.isShallowQuery();
	
protected voidlookupAlias(antlr.collections.AST aliasRef)

		FromElement alias = currentFromClause.getFromElement( aliasRef.getText() );
		FromReferenceNode aliasRefNode = ( FromReferenceNode ) aliasRef;
		aliasRefNode.setFromElement( alias );
	
protected antlr.collections.ASTlookupNonQualifiedProperty(antlr.collections.AST property)

		final FromElement fromElement = ( FromElement ) currentFromClause.getExplicitFromElements().get( 0 );
		AST syntheticDotNode = generateSyntheticDotNodeForNonQualifiedPropertyRef( property, fromElement );
		return lookupProperty( syntheticDotNode, false, getCurrentClauseType() == HqlSqlTokenTypes.SELECT );
	
protected antlr.collections.ASTlookupProperty(antlr.collections.AST dot, boolean root, boolean inSelect)

		DotNode dotNode = ( DotNode ) dot;
		FromReferenceNode lhs = dotNode.getLhs();
		AST rhs = lhs.getNextSibling();
		switch ( rhs.getType() ) {
			case SqlTokenTypes.ELEMENTS:
			case SqlTokenTypes.INDICES:
				if ( log.isDebugEnabled() ) {
					log.debug( "lookupProperty() " + dotNode.getPath() + " => " + rhs.getText() + "(" + lhs.getPath() + ")" );
				}
				CollectionFunction f = ( CollectionFunction ) rhs;
				// Re-arrange the tree so that the collection function is the root and the lhs is the path.
				f.setFirstChild( lhs );
				lhs.setNextSibling( null );
				dotNode.setFirstChild( f );
				resolve( lhs );			// Don't forget to resolve the argument!
				f.resolve( inSelect );	// Resolve the collection function now.
				return f;
			default:
				// Resolve everything up to this dot, but don't resolve the placeholders yet.
				dotNode.resolveFirstChild();
				return dotNode;
		}
	
public static voidpanic()

		throw new QueryException( "TreeWalker: panic" );
	
private voidpopFromClause()
Returns to the previous 'FROM' context.

		currentFromClause = currentFromClause.getParentFromClause();
	
protected voidpostProcessDML(org.hibernate.hql.ast.tree.RestrictableStatement statement)

		statement.getFromClause().resolve();

		FromElement fromElement = ( FromElement ) statement.getFromClause().getFromElements().get( 0 );
		Queryable persister = fromElement.getQueryable();
		// Make #@%$^#^&# sure no alias is applied to the table name
		fromElement.setText( persister.getTableName() );

		// append any filter fragments; the EMPTY_MAP is used under the assumption that
		// currently enabled filters should not affect this process
		if ( persister.getDiscriminatorType() != null ) {
			new SyntheticAndFactory( getASTFactory() ).addDiscriminatorWhereFragment(
			        statement,
			        persister,
			        java.util.Collections.EMPTY_MAP,
			        fromElement.getTableAlias()
			);
		}

	
protected voidpostProcessDelete(antlr.collections.AST delete)

		postProcessDML( ( DeleteStatement ) delete );
	
protected voidpostProcessInsert(antlr.collections.AST insert)

		InsertStatement insertStatement = ( InsertStatement ) insert;
		insertStatement.validate();

		SelectClause selectClause = insertStatement.getSelectClause();
		Queryable persister = insertStatement.getIntoClause().getQueryable();

		if ( !insertStatement.getIntoClause().isExplicitIdInsertion() ) {
			// We need to generate ids as part of this bulk insert.
			//
			// Note that this is only supported for sequence-style generators and
			// post-insert-style generators; basically, only in-db generators
			IdentifierGenerator generator = persister.getIdentifierGenerator();
			if ( !supportsIdGenWithBulkInsertion( generator ) ) {
				throw new QueryException( "can only generate ids as part of bulk insert with either sequence or post-insert style generators" );
			}

			AST idSelectExprNode = null;

			if ( SequenceGenerator.class.isAssignableFrom( generator.getClass() ) ) {
				String seqName = ( String ) ( ( SequenceGenerator ) generator ).generatorKey();
				String nextval = sessionFactoryHelper.getFactory().getDialect().getSelectSequenceNextValString( seqName );
				idSelectExprNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, nextval );
			}
			else {
				//Don't need this, because we should never ever be selecting no columns in an insert ... select...
				//and because it causes a bug on DB2
				/*String idInsertString = sessionFactoryHelper.getFactory().getDialect().getIdentityInsertString();
				if ( idInsertString != null ) {
					idSelectExprNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, idInsertString );
				}*/
			}

			if ( idSelectExprNode != null ) {
				AST currentFirstSelectExprNode = selectClause.getFirstChild();
				selectClause.setFirstChild( idSelectExprNode );
				idSelectExprNode.setNextSibling( currentFirstSelectExprNode );

				insertStatement.getIntoClause().prependIdColumnSpec();
			}
		}

		final boolean includeVersionProperty = persister.isVersioned() &&
				!insertStatement.getIntoClause().isExplicitVersionInsertion() &&
				persister.isVersionPropertyInsertable();
		if ( includeVersionProperty ) {
			// We need to seed the version value as part of this bulk insert
			VersionType versionType = persister.getVersionType();
			AST versionValueNode = null;

			if ( sessionFactoryHelper.getFactory().getDialect().supportsParametersInInsertSelect() ) {
				versionValueNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" );
				ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType );
				( ( ParameterNode ) versionValueNode ).setHqlParameterSpecification( paramSpec );
				parameters.add( 0, paramSpec );
			}
			else {
				if ( isIntegral( versionType ) ) {
					try {
						Object seedValue = versionType.seed( null );
						versionValueNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, seedValue.toString() );
					}
					catch( Throwable t ) {
						throw new QueryException( "could not determine seed value for version on bulk insert [" + versionType + "]" );
					}
				}
				else if ( isDatabaseGeneratedTimestamp( versionType ) ) {
					String functionName = sessionFactoryHelper.getFactory().getDialect().getCurrentTimestampSQLFunctionName();
					versionValueNode = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, functionName );
				}
				else {
					throw new QueryException( "cannot handle version type [" + versionType + "] on bulk inserts with dialects not supporting parameters in insert-select statements" );
				}
			}

			AST currentFirstSelectExprNode = selectClause.getFirstChild();
			selectClause.setFirstChild( versionValueNode );
			versionValueNode.setNextSibling( currentFirstSelectExprNode );

			insertStatement.getIntoClause().prependVersionColumnSpec();
		}

		if ( insertStatement.getIntoClause().isDiscriminated() ) {
			String sqlValue = insertStatement.getIntoClause().getQueryable().getDiscriminatorSQLValue();
			AST discrimValue = getASTFactory().create( HqlSqlTokenTypes.SQL_TOKEN, sqlValue );
			insertStatement.getSelectClause().addChild( discrimValue );
		}

	
protected voidpostProcessUpdate(antlr.collections.AST update)

		UpdateStatement updateStatement = ( UpdateStatement ) update;

		postProcessDML( updateStatement );
	
protected voidprepareArithmeticOperator(antlr.collections.AST operator)

		( ( OperatorNode ) operator ).initialize();
	
protected voidprepareFromClauseInputTree(antlr.collections.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 );
			}
		}
	
protected voidprepareLogicOperator(antlr.collections.AST operator)

		( ( OperatorNode ) operator ).initialize();
	
protected voidprepareVersioned(antlr.collections.AST updateNode, antlr.collections.AST versioned)

		UpdateStatement updateStatement = ( UpdateStatement ) updateNode;
		FromClause fromClause = updateStatement.getFromClause();
		if ( versioned != null ) {
			// Make sure that the persister is versioned
			Queryable persister = fromClause.getFromElement().getQueryable();
			if ( !persister.isVersioned() ) {
				throw new SemanticException( "increment option specified for update of non-versioned entity" );
			}

			VersionType versionType = persister.getVersionType();
			if ( versionType instanceof UserVersionType ) {
				throw new SemanticException( "user-defined version types not supported for increment option" );
			}

			AST eq = getASTFactory().create( HqlSqlTokenTypes.EQ, "=" );
			AST versionPropertyNode = generateVersionPropertyNode( persister );

			eq.setFirstChild( versionPropertyNode );

			AST versionIncrementNode = null;
			if ( Date.class.isAssignableFrom( versionType.getReturnedClass() ) ) {
				versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PARAM, "?" );
				ParameterSpecification paramSpec = new VersionTypeSeedParameterSpecification( versionType );
				( ( ParameterNode ) versionIncrementNode ).setHqlParameterSpecification( paramSpec );
				parameters.add( 0, paramSpec );
			}
			else {
				// Not possible to simply re-use the versionPropertyNode here as it causes
				// OOM errors due to circularity :(
				versionIncrementNode = getASTFactory().create( HqlSqlTokenTypes.PLUS, "+" );
				versionIncrementNode.setFirstChild( generateVersionPropertyNode( persister ) );
				versionIncrementNode.addChild( getASTFactory().create( HqlSqlTokenTypes.IDENT, "1" ) );
			}

			eq.addChild( versionIncrementNode );

			evaluateAssignment( eq, persister, 0 );

			AST setClause = updateStatement.getSetClause();
			AST currentFirstSetElement = setClause.getFirstChild();
			setClause.setFirstChild( eq );
			eq.setNextSibling( currentFirstSetElement );
		}
	
protected voidprocessBoolean(antlr.collections.AST constant)

		literalProcessor.processBoolean( constant );  // Use the delegate.
	
protected voidprocessConstant(antlr.collections.AST constant)

		literalProcessor.processConstant( constant, true );  // Use the delegate, resolve identifiers as FROM element aliases.
	
protected voidprocessConstructor(antlr.collections.AST constructor)

		ConstructorNode constructorNode = ( ConstructorNode ) constructor;
		constructorNode.prepare();
	
protected voidprocessFunction(antlr.collections.AST functionCall, boolean inSelect)

		MethodNode methodNode = ( MethodNode ) functionCall;
		methodNode.resolve( inSelect );
	
protected voidprocessIndex(antlr.collections.AST indexOp)

		IndexNode indexNode = ( IndexNode ) indexOp;
		indexNode.resolve( true, true );
	
protected voidprocessNumericLiteral(antlr.collections.AST literal)

		literalProcessor.processNumeric( literal );
	
protected voidprocessQuery(antlr.collections.AST select, antlr.collections.AST query)

		if ( log.isDebugEnabled() ) {
			log.debug( "processQuery() : " + query.toStringTree() );
		}

		try {
			QueryNode qn = ( QueryNode ) query;

			// Was there an explicit select expression?
			boolean explicitSelect = select != null && select.getNumberOfChildren() > 0;

			if ( !explicitSelect ) {
				// No explicit select expression; render the id and properties
				// projection lists for every persister in the from clause into
				// a single 'token node'.
				//TODO: the only reason we need this stuff now is collection filters,
				//      we should get rid of derived select clause completely!
				createSelectClauseFromFromClause( qn );
			}
			else {
				// Use the explicitly declared select expression; determine the
				// return types indicated by each select token
				useSelectClause( select );
			}

			// After that, process the JOINs.
			// Invoke a delegate to do the work, as this is farily complex.
			JoinProcessor joinProcessor = new JoinProcessor( astFactory, queryTranslatorImpl );
			joinProcessor.processJoins( qn, isSubQuery() );

			// Attach any mapping-defined "ORDER BY" fragments
			Iterator itr = qn.getFromClause().getProjectionList().iterator();
			while ( itr.hasNext() ) {
				final FromElement fromElement = ( FromElement ) itr.next();
//			if ( fromElement.isFetch() && fromElement.isCollectionJoin() ) {
				if ( fromElement.isFetch() && fromElement.getQueryableCollection() != null ) {
					// Does the collection referenced by this FromElement
					// specify an order-by attribute?  If so, attach it to
					// the query's order-by
					if ( fromElement.getQueryableCollection().hasOrdering() ) {
						String orderByFragment = fromElement
								.getQueryableCollection()
								.getSQLOrderByString( fromElement.getCollectionTableAlias() );
						qn.getOrderByClause().addOrderFragment( orderByFragment );
					}
					if ( fromElement.getQueryableCollection().hasManyToManyOrdering() ) {
						String orderByFragment = fromElement.getQueryableCollection()
								.getManyToManyOrderByString( fromElement.getTableAlias() );
						qn.getOrderByClause().addOrderFragment( orderByFragment );
					}
				}
			}
		}
		finally {
			popFromClause();
		}
	
protected voidpushFromClause(antlr.collections.AST fromNode, antlr.collections.AST inputFromNode)
Sets the current 'FROM' context.

param
fromNode The new 'FROM' context.
param
inputFromNode The from node from the input AST.

		FromClause newFromClause = ( FromClause ) fromNode;
		newFromClause.setParentFromClause( currentFromClause );
		currentFromClause = newFromClause;
	
public voidreportError(java.lang.String s)

		parseErrorHandler.reportError( s ); // Use the delegate.
	
public voidreportError(antlr.RecognitionException e)

		parseErrorHandler.reportError( e ); // Use the delegate.
	
public voidreportWarning(java.lang.String s)

		parseErrorHandler.reportWarning( s );
	
protected voidresolve(antlr.collections.AST node)

		if ( node != null ) {
			// This is called when it's time to fully resolve a path expression.
			ResolvableNode r = ( ResolvableNode ) node;
			if ( isInFunctionCall() ) {
				r.resolveInFunctionCall( false, true );
			}
			else {
				r.resolve( false, true );	// Generate implicit joins, only if necessary.
			}
		}
	
protected voidresolveSelectExpression(antlr.collections.AST node)

		// This is called when it's time to fully resolve a path expression.
		int type = node.getType();
		switch ( type ) {
			case DOT:
				DotNode dot = ( DotNode ) node;
				dot.resolveSelectExpression();
				break;
			case ALIAS_REF:
				// Notify the FROM element that it is being referenced by the select.
				FromReferenceNode aliasRefNode = ( FromReferenceNode ) node;
				//aliasRefNode.resolve( false, false, aliasRefNode.getText() ); //TODO: is it kosher to do it here?
				aliasRefNode.resolve( false, false ); //TODO: is it kosher to do it here?
				FromElement fromElement = aliasRefNode.getFromElement();
				if ( fromElement != null ) {
					fromElement.setIncludeSubclasses( true );
				}
			default:
				break;
		}
	
protected voidsetAlias(antlr.collections.AST selectExpr, antlr.collections.AST ident)

        ((SelectExpression) selectExpr).setAlias(ident.getText());
    
protected voidsetImpliedJoinType(int joinType)

		impliedJoinType = JoinProcessor.toHibernateJoinType( joinType );
	
public static booleansupportsIdGenWithBulkInsertion(org.hibernate.id.IdentifierGenerator generator)

		return SequenceGenerator.class.isAssignableFrom( generator.getClass() )
		        || PostInsertIdentifierGenerator.class.isAssignableFrom( generator.getClass() );
	
private voidtrackNamedParameterPositions(java.lang.String name)

		Integer loc = new Integer( parameterCount++ );
		Object o = namedParameters.get( name );
		if ( o == null ) {
			namedParameters.put( name, loc );
		}
		else if ( o instanceof Integer ) {
			ArrayList list = new ArrayList( 4 );
			list.add( o );
			list.add( loc );
			namedParameters.put( name, list );
		}
		else {
			( ( ArrayList ) o ).add( loc );
		}
	
private voiduseSelectClause(antlr.collections.AST select)

		selectClause = ( SelectClause ) select;
		selectClause.initializeExplicitSelectClause( currentFromClause );