FileDocCategorySizeDatePackage
WhereParser.javaAPI DocHibernate 3.2.516821Wed Aug 10 15:23:56 BST 2005org.hibernate.hql.classic

WhereParser

public class WhereParser extends Object implements Parser
Parses the where clause of a hibernate query and translates it to an SQL where clause.

Fields Summary
private final PathExpressionParser
pathExpressionParser
private static final Set
EXPRESSION_TERMINATORS
private static final Set
EXPRESSION_OPENERS
private static final Set
BOOLEAN_OPERATORS
private static final Map
NEGATIONS
private boolean
betweenSpecialCase
private boolean
negated
private boolean
inSubselect
private int
bracketsSinceSelect
private StringBuffer
subselect
private boolean
expectingPathContinuation
private int
expectingIndex
private LinkedList
nots
private LinkedList
joins
private LinkedList
booleanTests
Constructors Summary
Methods Summary
private voidaddJoin(org.hibernate.engine.JoinSequence joinSequence, QueryTranslatorImpl q)

		//JoinFragment fromClause = q.createJoinFragment(true);
		//fromClause.addJoins( join.toJoinFragment().toFromFragmentString(), StringHelper.EMPTY_STRING );
		q.addFromJoinOnly( pathExpressionParser.getName(), joinSequence );
		try {
			addToCurrentJoin( joinSequence.toJoinFragment( q.getEnabledFilters(), true ).toWhereFragmentString() );
		}
		catch ( MappingException me ) {
			throw new QueryException( me );
		}
	
private voidaddToCurrentJoin(java.lang.String sql)

		( ( StringBuffer ) joins.getLast() ).append( sql );
	
private voidaddToCurrentJoin(PathExpressionParser.CollectionElement ce)

		try {
			addToCurrentJoin( ce.joinSequence.toJoinFragment().toWhereFragmentString() + ce.indexValue.toString() );
		}
		catch ( MappingException me ) {
			throw new QueryException( me );
		}
	
voidappendToken(QueryTranslatorImpl q, java.lang.String token)

		if ( expectingIndex > 0 ) {
			pathExpressionParser.setLastCollectionElementIndexValue( token );
		}
		else {
			q.appendWhereToken( token );
		}
	
private voidcloseExpression(QueryTranslatorImpl q, java.lang.String lcToken)

		if ( ( ( Boolean ) booleanTests.removeLast() ).booleanValue() ) { //it was a boolean expression

			if ( booleanTests.size() > 0 ) {
				// the next one up must also be
				booleanTests.removeLast();
				booleanTests.addLast( Boolean.TRUE );
			}

			// Add any joins
			appendToken( q, ( joins.removeLast() ).toString() );

		}
		else {
			StringBuffer join = ( StringBuffer ) joins.removeLast();
			( ( StringBuffer ) joins.getLast() ).append( join.toString() );
		}

		if ( ( ( Boolean ) nots.removeLast() ).booleanValue() ) negated = !negated;

		if ( !")".equals( lcToken ) ) appendToken( q, ")" );
	
private booleancontinuePathExpression(java.lang.String token, QueryTranslatorImpl q)


		expectingPathContinuation = false;

		PathExpressionParser.CollectionElement element = pathExpressionParser.lastCollectionElement();

		if ( token.startsWith( "." ) ) { // the path expression continues after a ]

			doPathExpression( getElementName( element, q ) + token, q ); // careful with this!

			addToCurrentJoin( element );
			return true; //NOTE: EARLY EXIT!

		}

		else { // the path expression ends at the ]
			if ( element.elementColumns.length != 1 ) {
				throw new QueryException( "path expression ended in composite collection element" );
			}
			appendToken( q, element.elementColumns[0] );
			addToCurrentJoin( element );
			return false;
		}
	
private voiddoPathExpression(java.lang.String token, QueryTranslatorImpl q)


		preprocess( token, q );

		StringTokenizer tokens = new StringTokenizer( token, ".", true );
		pathExpressionParser.start( q );
		while ( tokens.hasMoreTokens() ) {
			pathExpressionParser.token( tokens.nextToken(), q );
		}
		pathExpressionParser.end( q );
		if ( pathExpressionParser.isCollectionValued() ) {
			openExpression( q, "" );
			appendToken( q, pathExpressionParser.getCollectionSubquery( q.getEnabledFilters() ) );
			closeExpression( q, "" );
			// this is ugly here, but needed because its a subquery
			q.addQuerySpaces( q.getCollectionPersister( pathExpressionParser.getCollectionRole() ).getCollectionSpaces() );
		}
		else {
			if ( pathExpressionParser.isExpectingCollectionIndex() ) {
				expectingIndex++;
			}
			else {
				addJoin( pathExpressionParser.getWhereJoin(), q );
				appendToken( q, pathExpressionParser.getWhereColumn() );
			}
		}
	
private voiddoToken(java.lang.String token, QueryTranslatorImpl q)

		if ( q.isName( StringHelper.root( token ) ) ) { //path expression
			doPathExpression( q.unalias( token ), q );
		}
		else if ( token.startsWith( ParserHelper.HQL_VARIABLE_PREFIX ) ) { //named query parameter
			q.addNamedParameter( token.substring( 1 ) );
			appendToken( q, "?" );
		}
		else {
			Queryable persister = q.getEntityPersisterUsingImports( token );
			if ( persister != null ) { // the name of a class
				final String discrim = persister.getDiscriminatorSQLValue();
				if ( InFragment.NULL.equals(discrim) || InFragment.NOT_NULL.equals(discrim) ) {
					throw new QueryException( "subclass test not allowed for null or not null discriminator" );
				}
				else {
					appendToken( q, discrim );
				}
			}
			else {
				Object constant;
				if (
						token.indexOf( '." ) > -1 &&
						( constant = ReflectHelper.getConstantValue( token ) ) != null
				) {
					Type type;
					try {
						type = TypeFactory.heuristicType( constant.getClass().getName() );
					}
					catch ( MappingException me ) {
						throw new QueryException( me );
					}
					if ( type == null ) throw new QueryException( QueryTranslator.ERROR_CANNOT_DETERMINE_TYPE + token );
					try {
						appendToken( q, ( ( LiteralType ) type ).objectToSQLString( constant, q.getFactory().getDialect() ) );
					}
					catch ( Exception e ) {
						throw new QueryException( QueryTranslator.ERROR_CANNOT_FORMAT_LITERAL + token, e );
					}
				}
				else { //anything else

					String negatedToken = negated ? ( String ) NEGATIONS.get( token.toLowerCase() ) : null;
					if ( negatedToken != null && ( !betweenSpecialCase || !"or".equals( negatedToken ) ) ) {
						appendToken( q, negatedToken );
					}
					else {
						appendToken( q, token );
					}
				}
			}
		}
	
public voidend(QueryTranslatorImpl q)

		if ( expectingPathContinuation ) {
			expectingPathContinuation = false;
			PathExpressionParser.CollectionElement element = pathExpressionParser.lastCollectionElement();
			if ( element.elementColumns.length != 1 ) throw new QueryException( "path expression ended in composite collection element" );
			appendToken( q, element.elementColumns[0] );
			addToCurrentJoin( element );
		}
		token( ")", q );
	
private java.lang.StringgetElementName(PathExpressionParser.CollectionElement element, QueryTranslatorImpl q)

   //a flag indicating if the subexpression is known to be boolean

	        
		String name;
		if ( element.isOneToMany ) {
			name = element.alias;
		}
		else {
			Type type = element.elementType;
			if ( type.isEntityType() ) { //ie. a many-to-many
				String entityName = ( ( EntityType ) type ).getAssociatedEntityName();
				name = pathExpressionParser.continueFromManyToMany( entityName, element.elementColumns, q );
			}
			else {
				throw new QueryException( "illegally dereferenced collection element" );
			}
		}
		return name;
	
private voidopenExpression(QueryTranslatorImpl q, java.lang.String lcToken)

		nots.addLast( Boolean.FALSE );
		booleanTests.addLast( Boolean.FALSE );
		joins.addLast( new StringBuffer() );
		if ( !"(".equals( lcToken ) ) appendToken( q, "(" );
	
private voidpreprocess(java.lang.String token, QueryTranslatorImpl q)

		// ugly hack for cases like "elements(foo.bar.collection)"
		// (multi-part path expression ending in elements or indices)
		String[] tokens = StringHelper.split( ".", token, true );
		if (
				tokens.length > 5 &&
				( CollectionPropertyNames.COLLECTION_ELEMENTS.equals( tokens[tokens.length - 1] )
				|| CollectionPropertyNames.COLLECTION_INDICES.equals( tokens[tokens.length - 1] ) )
		) {
			pathExpressionParser.start( q );
			for ( int i = 0; i < tokens.length - 3; i++ ) {
				pathExpressionParser.token( tokens[i], q );
			}
			pathExpressionParser.token( null, q );
			pathExpressionParser.end( q );
			addJoin( pathExpressionParser.getWhereJoin(), q );
			pathExpressionParser.ignoreInitialJoin();
		}
	
private voidspecialCasesAfter(java.lang.String lcToken)

		if ( betweenSpecialCase && lcToken.equals( "and" ) ) {
			betweenSpecialCase = false;
		}
	
private voidspecialCasesBefore(java.lang.String lcToken)

		if ( lcToken.equals( "between" ) || lcToken.equals( "not between" ) ) {
			betweenSpecialCase = true;
		}
	
public voidstart(QueryTranslatorImpl q)

		token( "(", q );
	
public voidtoken(java.lang.String token, QueryTranslatorImpl q)


		String lcToken = token.toLowerCase();

		//Cope with [,]
		if ( token.equals( "[" ) && !expectingPathContinuation ) {
			expectingPathContinuation = false;
			if ( expectingIndex == 0 ) throw new QueryException( "unexpected [" );
			return;
		}
		else if ( token.equals( "]" ) ) {
			expectingIndex--;
			expectingPathContinuation = true;
			return;
		}

		//Cope with a continued path expression (ie. ].baz)
		if ( expectingPathContinuation ) {
			boolean pathExpressionContinuesFurther = continuePathExpression( token, q );
			if ( pathExpressionContinuesFurther ) return; //NOTE: early return
		}

		//Cope with a subselect
		if ( !inSubselect && ( lcToken.equals( "select" ) || lcToken.equals( "from" ) ) ) {
			inSubselect = true;
			subselect = new StringBuffer( 20 );
		}
		if ( inSubselect && token.equals( ")" ) ) {
			bracketsSinceSelect--;

			if ( bracketsSinceSelect == -1 ) {
				QueryTranslatorImpl subq = new QueryTranslatorImpl(
				        subselect.toString(),
						q.getEnabledFilters(),
						q.getFactory()
				);
				try {
					subq.compile( q );
				}
				catch ( MappingException me ) {
					throw new QueryException( "MappingException occurred compiling subquery", me );
				}
				appendToken( q, subq.getSQLString() );
				inSubselect = false;
				bracketsSinceSelect = 0;
			}
		}
		if ( inSubselect ) {
			if ( token.equals( "(" ) ) bracketsSinceSelect++;
			subselect.append( token ).append( ' " );
			return;
		}

		//Cope with special cases of AND, NOT, ()
		specialCasesBefore( lcToken );

		//Close extra brackets we opened
		if ( !betweenSpecialCase && EXPRESSION_TERMINATORS.contains( lcToken ) ) {
			closeExpression( q, lcToken );
		}

		//take note when this is a boolean expression
		if ( BOOLEAN_OPERATORS.contains( lcToken ) ) {
			booleanTests.removeLast();
			booleanTests.addLast( Boolean.TRUE );
		}

		if ( lcToken.equals( "not" ) ) {
			nots.addLast( new Boolean( !( ( Boolean ) nots.removeLast() ).booleanValue() ) );
			negated = !negated;
			return; //NOTE: early return
		}

		//process a token, mapping OO path expressions to SQL expressions
		doToken( token, q );

		//Open any extra brackets we might need.
		if ( !betweenSpecialCase && EXPRESSION_OPENERS.contains( lcToken ) ) {
			openExpression( q, lcToken );
		}

		//Cope with special cases of AND, NOT, )
		specialCasesAfter( lcToken );