FileDocCategorySizeDatePackage
JoinProcessor.javaAPI DocHibernate 3.2.56402Thu Nov 16 12:33:20 GMT 2006org.hibernate.hql.ast.util

JoinProcessor

public class JoinProcessor extends Object implements org.hibernate.hql.antlr.SqlTokenTypes
Performs the post-processing of the join information gathered during semantic analysis. The join generating classes are complex, this encapsulates some of the JoinSequence-related code.
author
Joshua Davis

Fields Summary
private static final Log
log
private org.hibernate.hql.ast.QueryTranslatorImpl
queryTranslatorImpl
private SyntheticAndFactory
andFactory
Constructors Summary
public JoinProcessor(antlr.ASTFactory astFactory, org.hibernate.hql.ast.QueryTranslatorImpl queryTranslatorImpl)
Constructs a new JoinProcessor.

param
astFactory The factory for AST node creation.
param
queryTranslatorImpl The query translator.


	      		            	 
	     
		this.andFactory = new SyntheticAndFactory( astFactory );
		this.queryTranslatorImpl = queryTranslatorImpl;
	
Methods Summary
private voidaddJoinNodes(org.hibernate.hql.ast.tree.QueryNode query, org.hibernate.engine.JoinSequence join, org.hibernate.hql.ast.tree.FromElement fromElement, boolean inSubquery)

		// Generate FROM and WHERE fragments for the from element.
		JoinFragment joinFragment = join.toJoinFragment(
				inSubquery ? Collections.EMPTY_MAP : queryTranslatorImpl.getEnabledFilters(),
				fromElement.useFromFragment() || fromElement.isDereferencedBySuperclassOrSubclassProperty(),
				fromElement.getWithClauseFragment(),
				fromElement.getWithClauseJoinAlias()
		);

		String frag = joinFragment.toFromFragmentString();
		String whereFrag = joinFragment.toWhereFragmentString();

		// If the from element represents a JOIN_FRAGMENT and it is
		// a theta-style join, convert its type from JOIN_FRAGMENT
		// to FROM_FRAGMENT
		if ( fromElement.getType() == JOIN_FRAGMENT &&
				( join.isThetaStyle() || StringHelper.isNotEmpty( whereFrag ) ) ) {
			fromElement.setType( FROM_FRAGMENT );
			fromElement.getJoinSequence().setUseThetaStyle( true ); // this is used during SqlGenerator processing
		}

		// If there is a FROM fragment and the FROM element is an explicit, then add the from part.
		if ( fromElement.useFromFragment() /*&& StringHelper.isNotEmpty( frag )*/ ) {
			String fromFragment = processFromFragment( frag, join );
			if ( log.isDebugEnabled() ) {
				log.debug( "Using FROM fragment [" + fromFragment + "]" );
			}
			fromElement.setText( fromFragment.trim() ); // Set the text of the fromElement.
		}
		andFactory.addWhereFragment( joinFragment, whereFrag, query, fromElement );
	
private java.lang.StringprocessFromFragment(java.lang.String frag, org.hibernate.engine.JoinSequence join)

		String fromFragment = frag.trim();
		// The FROM fragment will probably begin with ', '.  Remove this if it is present.
		if ( fromFragment.startsWith( ", " ) ) {
			fromFragment = fromFragment.substring( 2 );
		}
		return fromFragment;
	
public voidprocessJoins(org.hibernate.hql.ast.tree.QueryNode query, boolean inSubquery)

		final FromClause fromClause = query.getFromClause();

		final List fromElements;
		if ( DotNode.useThetaStyleImplicitJoins ) {
			// for regression testing against output from the old parser...
			// found it easiest to simply reorder the FromElements here into ascending order
			// in terms of injecting them into the resulting sql ast in orders relative to those
			// expected by the old parser; this is definitely another of those "only needed
			// for regression purposes".  The SyntheticAndFactory, then, simply injects them as it
			// encounters them.
			fromElements = new ArrayList();
			ListIterator liter = fromClause.getFromElements().listIterator( fromClause.getFromElements().size() );
			while ( liter.hasPrevious() ) {
				fromElements.add( liter.previous() );
			}
		}
		else {
			fromElements = fromClause.getFromElements();
		}

		// Iterate through the alias,JoinSequence pairs and generate SQL token nodes.
		Iterator iter = fromElements.iterator();
		while ( iter.hasNext() ) {
			final FromElement fromElement = ( FromElement ) iter.next();
			JoinSequence join = fromElement.getJoinSequence();
			join.setSelector(
					new JoinSequence.Selector() {
						public boolean includeSubclasses(String alias) {
							// The uber-rule here is that we need to include  subclass joins if
							// the FromElement is in any way dereferenced by a property from
							// the subclass table; otherwise we end up with column references
							// qualified by a non-existent table reference in the resulting SQL...
							boolean containsTableAlias = fromClause.containsTableAlias( alias );
							if ( fromElement.isDereferencedBySubclassProperty() ) {
								// TODO : or should we return 'containsTableAlias'??
								log.trace( "forcing inclusion of extra joins [alias=" + alias + ", containsTableAlias=" + containsTableAlias + "]" );
								return true;
							}
							boolean shallowQuery = queryTranslatorImpl.isShallowQuery();
							boolean includeSubclasses = fromElement.isIncludeSubclasses();
							boolean subQuery = fromClause.isSubQuery();
							return includeSubclasses && containsTableAlias && !subQuery && !shallowQuery;
						}
					}
			);
			addJoinNodes( query, join, fromElement, inSubquery );
		}

	
public static inttoHibernateJoinType(int astJoinType)
Translates an AST join type (i.e., the token type) into a JoinFragment.XXX join type.

param
astJoinType The AST join type (from HqlSqlTokenTypes or SqlTokenTypes)
return
a JoinFragment.XXX join type.
see
JoinFragment
see
SqlTokenTypes

		switch ( astJoinType ) {
			case LEFT_OUTER:
				return JoinFragment.LEFT_OUTER_JOIN;
			case INNER:
				return JoinFragment.INNER_JOIN;
			case RIGHT_OUTER:
				return JoinFragment.RIGHT_OUTER_JOIN;
			default:
				throw new AssertionFailure( "undefined join type " + astJoinType );
		}