FileDocCategorySizeDatePackage
FromParser.javaAPI DocHibernate 3.2.57421Sun Feb 13 04:50:12 GMT 2005org.hibernate.hql.classic

FromParser

public class FromParser extends Object implements Parser
Parses the from clause of a hibernate query, looking for tables and aliases for the SQL query.

Fields Summary
private final PathExpressionParser
peParser
private String
entityName
private String
alias
private boolean
afterIn
private boolean
afterAs
private boolean
afterClass
private boolean
expectingJoin
private boolean
expectingIn
private boolean
expectingAs
private boolean
afterJoinType
private int
joinType
private boolean
afterFetch
private static final int
NONE
private static final Map
JOIN_TYPES
Constructors Summary
Methods Summary
public voidend(QueryTranslatorImpl q)

	
public voidstart(QueryTranslatorImpl q)

		entityName = null;
		alias = null;
		afterIn = false;
		afterAs = false;
		afterClass = false;
		expectingJoin = false;
		expectingIn = false;
		expectingAs = false;
		joinType = NONE;
	
public voidtoken(java.lang.String token, QueryTranslatorImpl q)


	 
		JOIN_TYPES.put( "left", new Integer( JoinFragment.LEFT_OUTER_JOIN ) );
		JOIN_TYPES.put( "right", new Integer( JoinFragment.RIGHT_OUTER_JOIN ) );
		JOIN_TYPES.put( "full", new Integer( JoinFragment.FULL_JOIN ) );
		JOIN_TYPES.put( "inner", new Integer( JoinFragment.INNER_JOIN ) );
	

		// start by looking for HQL keywords...
		String lcToken = token.toLowerCase();
		if ( lcToken.equals( "," ) ) {
			if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: ," );
			expectingJoin = false;
			expectingAs = false;
		}
		else if ( lcToken.equals( "join" ) ) {
			if ( !afterJoinType ) {
				if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: join" );
				// inner joins can be abbreviated to 'join'
				joinType = JoinFragment.INNER_JOIN;
				expectingJoin = false;
				expectingAs = false;
			}
			else {
				afterJoinType = false;
			}
		}
		else if ( lcToken.equals( "fetch" ) ) {
			if ( q.isShallowQuery() ) throw new QueryException( QueryTranslator.ERROR_CANNOT_FETCH_WITH_ITERATE );
			if ( joinType == NONE ) throw new QueryException( "unexpected token: fetch" );
			if ( joinType == JoinFragment.FULL_JOIN || joinType == JoinFragment.RIGHT_OUTER_JOIN ) {
				throw new QueryException( "fetch may only be used with inner join or left outer join" );
			}
			afterFetch = true;
		}
		else if ( lcToken.equals( "outer" ) ) {
			// 'outer' is optional and is ignored
			if ( !afterJoinType ||
					( joinType != JoinFragment.LEFT_OUTER_JOIN && joinType != JoinFragment.RIGHT_OUTER_JOIN )
			) {
				throw new QueryException( "unexpected token: outer" );
			}
		}
		else if ( JOIN_TYPES.containsKey( lcToken ) ) {
			if ( !( expectingJoin | expectingAs ) ) throw new QueryException( "unexpected token: " + token );
			joinType = ( ( Integer ) JOIN_TYPES.get( lcToken ) ).intValue();
			afterJoinType = true;
			expectingJoin = false;
			expectingAs = false;
		}
		else if ( lcToken.equals( "class" ) ) {
			if ( !afterIn ) throw new QueryException( "unexpected token: class" );
			if ( joinType != NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
			afterClass = true;
		}
		else if ( lcToken.equals( "in" ) ) {
			if ( !expectingIn ) throw new QueryException( "unexpected token: in" );
			afterIn = true;
			expectingIn = false;
		}
		else if ( lcToken.equals( "as" ) ) {
			if ( !expectingAs ) throw new QueryException( "unexpected token: as" );
			afterAs = true;
			expectingAs = false;
		}
		else {

			if ( afterJoinType ) throw new QueryException( "join expected: " + token );
			if ( expectingJoin ) throw new QueryException( "unexpected token: " + token );
			if ( expectingIn ) throw new QueryException( "in expected: " + token );

			// now anything that is not a HQL keyword

			if ( afterAs || expectingAs ) {

				// (AS is always optional, for consistency with SQL/OQL)

				// process the "new" HQL style where aliases are assigned
				// _after_ the class name or path expression ie. using
				// the AS construction

				if ( entityName != null ) {
					q.setAliasName( token, entityName );
				}
				else {
					throw new QueryException( "unexpected: as " + token );
				}
				afterAs = false;
				expectingJoin = true;
				expectingAs = false;
				entityName = null;

			}
			else if ( afterIn ) {

				// process the "old" HQL style where aliases appear _first_
				// ie. using the IN or IN CLASS constructions

				if ( alias == null ) throw new QueryException( "alias not specified for: " + token );

				if ( joinType != NONE ) throw new QueryException( "outer or full join must be followed by path expression" );

				if ( afterClass ) {
					// treat it as a classname
					Queryable p = q.getEntityPersisterUsingImports( token );
					if ( p == null ) throw new QueryException( "persister not found: " + token );
					q.addFromClass( alias, p );
				}
				else {
					// treat it as a path expression
					peParser.setJoinType( JoinFragment.INNER_JOIN );
					peParser.setUseThetaStyleJoin( true );
					ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
					if ( !peParser.isCollectionValued() ) throw new QueryException( "path expression did not resolve to collection: " + token );
					String nm = peParser.addFromCollection( q );
					q.setAliasName( alias, nm );
				}

				alias = null;
				afterIn = false;
				afterClass = false;
				expectingJoin = true;
			}
			else {

				// handle a path expression or class name that
				// appears at the start, in the "new" HQL
				// style or an alias that appears at the start
				// in the "old" HQL style

				Queryable p = q.getEntityPersisterUsingImports( token );
				if ( p != null ) {
					// starts with the name of a mapped class (new style)
					if ( joinType != NONE ) throw new QueryException( "outer or full join must be followed by path expression" );
					entityName = q.createNameFor( p.getEntityName() );
					q.addFromClass( entityName, p );
					expectingAs = true;
				}
				else if ( token.indexOf( '." ) < 0 ) {
					// starts with an alias (old style)
					// semi-bad thing about this: can't re-alias another alias.....
					alias = token;
					expectingIn = true;
				}
				else {

					// starts with a path expression (new style)

					// force HQL style: from Person p inner join p.cars c
					//if (joinType==NONE) throw new QueryException("path expression must be preceded by full, left, right or inner join");

					//allow ODMG OQL style: from Person p, p.cars c
					if ( joinType != NONE ) {
						peParser.setJoinType( joinType );
					}
					else {
						peParser.setJoinType( JoinFragment.INNER_JOIN );
					}
					peParser.setUseThetaStyleJoin( q.isSubquery() );

					ParserHelper.parse( peParser, q.unalias( token ), ParserHelper.PATH_SEPARATORS, q );
					entityName = peParser.addFromAssociation( q );

					joinType = NONE;
					peParser.setJoinType( JoinFragment.INNER_JOIN );

					if ( afterFetch ) {
						peParser.fetch( q, entityName );
						afterFetch = false;
					}

					expectingAs = true;

				}
			}
		}