FileDocCategorySizeDatePackage
FromElementType.javaAPI DocHibernate 3.2.514376Thu Nov 16 12:33:20 GMT 2006org.hibernate.hql.ast.tree

FromElementType

public class FromElementType extends Object
Delegate that handles the type and join sequence information for a FromElement.
author
josh Feb 12, 2005 10:17:34 AM

Fields Summary
private static final Log
log
private FromElement
fromElement
private org.hibernate.type.EntityType
entityType
private org.hibernate.persister.entity.EntityPersister
persister
private org.hibernate.persister.collection.QueryableCollection
queryableCollection
private org.hibernate.persister.collection.CollectionPropertyMapping
collectionPropertyMapping
private org.hibernate.engine.JoinSequence
joinSequence
private String
collectionSuffix
Constructors Summary
public FromElementType(FromElement fromElement, org.hibernate.persister.entity.EntityPersister persister, org.hibernate.type.EntityType entityType)


	       
		this.fromElement = fromElement;
		this.persister = persister;
		this.entityType = entityType;
		if ( persister != null ) {
			fromElement.setText( ( ( Queryable ) persister ).getTableName() + " " + getTableAlias() );
		}
	
Methods Summary
private voidcheckInitialized()

		fromElement.checkInitialized();
	
private java.lang.StringextractTableName()

		// should be safe to only ever expect EntityPersister references here
		return fromElement.getQueryable().getTableName();
	
private static java.lang.StringgenerateSuffix(int size, int k)

		String suffix = size == 1 ? "" : Integer.toString( k ) + '_";
		return suffix;
	
public java.lang.StringgetCollectionSuffix()

		return collectionSuffix;
	
private java.lang.StringgetCollectionTableAlias()

		return fromElement.getCollectionTableAlias();
	
public org.hibernate.type.TypegetDataType()

		if ( persister == null ) {
			if ( queryableCollection == null ) {
				return null;
			}
			return queryableCollection.getType();
		}
		else {
			return entityType;
		}
	
public org.hibernate.persister.entity.EntityPersistergetEntityPersister()

		return persister;
	
public org.hibernate.engine.JoinSequencegetJoinSequence()

		if ( joinSequence != null ) {
			return joinSequence;
		}

		// Class names in the FROM clause result in a JoinSequence (the old FromParser does this).
		if ( persister instanceof Joinable ) {
			Joinable joinable = ( Joinable ) persister;
			return fromElement.getSessionFactoryHelper().createJoinSequence().setRoot( joinable, getTableAlias() );
		}
		else {
			return null;	// TODO: Should this really return null?  If not, figure out something better to do here.
		}
	
org.hibernate.persister.entity.PropertyMappinggetPropertyMapping(java.lang.String propertyName)

		checkInitialized();
		if ( queryableCollection == null ) {		// Not a collection?
			return ( PropertyMapping ) persister;	// Return the entity property mapping.
		}
		// If the property is a special collection property name, return a CollectionPropertyMapping.
		if ( CollectionProperties.isCollectionProperty( propertyName ) ) {
			if ( collectionPropertyMapping == null ) {
				collectionPropertyMapping = new CollectionPropertyMapping( queryableCollection );
			}
			return collectionPropertyMapping;
		}
		if ( queryableCollection.getElementType().isAnyType() ) {
			// collection of <many-to-any/> mappings...
			// used to circumvent the component-collection check below...
			return queryableCollection;

		}
		if ( queryableCollection.getElementType().isComponentType() ) {
			// Collection of components.
			if ( propertyName.equals( EntityPersister.ENTITY_ID ) ) {
				return ( PropertyMapping ) queryableCollection.getOwnerEntityPersister();
			}
		}
		return queryableCollection;
	
public org.hibernate.type.TypegetPropertyType(java.lang.String propertyName, java.lang.String propertyPath)
Returns the type of a property, given it's name (the last part) and the full path.

param
propertyName The last part of the full path to the property.
return
The type.
0param
propertyPath The full property path.

		checkInitialized();
		Type type = null;
		// If this is an entity and the property is the identifier property, then use getIdentifierType().
		//      Note that the propertyName.equals( propertyPath ) checks whether we have a component
		//      key reference, where the component class property name is the same as the
		//      entity id property name; if the two are not equal, this is the case and
		//      we'd need to "fall through" to using the property mapping.
		if ( persister != null && propertyName.equals( propertyPath ) && propertyName.equals( persister.getIdentifierPropertyName() ) ) {
			type = persister.getIdentifierType();
		}
		else {	// Otherwise, use the property mapping.
			PropertyMapping mapping = getPropertyMapping( propertyName );
			type = mapping.toType( propertyPath );
		}
		if ( type == null ) {
			throw new MappingException( "Property " + propertyName + " does not exist in " +
					( ( queryableCollection == null ) ? "class" : "collection" ) + " "
					+ ( ( queryableCollection == null ) ? fromElement.getClassName() : queryableCollection.getRole() ) );
		}
		return type;
	
public org.hibernate.persister.entity.QueryablegetQueryable()
Returns the Hibernate queryable implementation for the HQL class.

return
the Hibernate queryable implementation for the HQL class.

		return ( persister instanceof Queryable ) ? ( Queryable ) persister : null;
	
public org.hibernate.persister.collection.QueryableCollectiongetQueryableCollection()

		return queryableCollection;
	
public org.hibernate.type.TypegetSelectType()

		if (entityType==null) return null;
		boolean shallow = fromElement.getFromClause().getWalker().isShallowQuery();
		return TypeFactory.manyToOne( entityType.getAssociatedEntityName(), shallow );
	
private java.lang.StringgetSuffix(int size, int sequence)

		return generateSuffix( size, sequence );
	
private java.lang.StringgetTableAlias()

		return fromElement.getTableAlias();
	
public booleanisCollectionOfValuesOrComponents()

		if ( persister == null ) {
			if ( queryableCollection == null ) {
				return false;
			}
			else {
				return !queryableCollection.getElementType().isEntityType();
			}
		}
		else {
			return false;
		}
	
private booleanisCorrelation()

		FromClause top = fromElement.getWalker().getFinalFromClause();
		return fromElement.getFromClause() != fromElement.getWalker().getCurrentFromClause() &&
	           fromElement.getFromClause() == top;
	
public booleanisEntity()

		return persister != null;
	
private booleanisMultiTable()

		// should be safe to only ever expect EntityPersister references here
		return fromElement.getQueryable() != null &&
	           fromElement.getQueryable().isMultiTable();
	
java.lang.StringrenderCollectionSelectFragment(int size, int k)

		if ( queryableCollection == null ) {
			return "";
		}
		else {
			if ( collectionSuffix == null ) {
				collectionSuffix = generateSuffix( size, k );
			}
			String fragment = queryableCollection.selectFragment( getCollectionTableAlias(), collectionSuffix );
			return trimLeadingCommaAndSpaces( fragment );
		}
	
java.lang.StringrenderIdentifierSelect(int size, int k)
Returns the identifier select SQL fragment.

param
size The total number of returned types.
param
k The sequence of the current returned type.
return
the identifier select SQL fragment.

		checkInitialized();
		// Render the identifier select fragment using the table alias.
		if ( fromElement.getFromClause().isSubQuery() ) {
			// TODO: Replace this with a more elegant solution.
			String[] idColumnNames = ( persister != null ) ?
					( ( Queryable ) persister ).getIdentifierColumnNames() : new String[0];
			StringBuffer buf = new StringBuffer();
			for ( int i = 0; i < idColumnNames.length; i++ ) {
				buf.append( fromElement.getTableAlias() ).append( '." ).append( idColumnNames[i] );
				if ( i != idColumnNames.length - 1 ) buf.append( ", " );
			}
			return buf.toString();
		}
		else {
			if (persister==null) {
				throw new QueryException( "not an entity" );
			}
			String fragment = ( ( Queryable ) persister ).identifierSelectFragment( getTableAlias(), getSuffix( size, k ) );
			return trimLeadingCommaAndSpaces( fragment );
		}
	
java.lang.StringrenderPropertySelect(int size, int k, boolean allProperties)
Returns the property select SQL fragment.

param
size The total number of returned types.
param
k The sequence of the current returned type.
return
the property select SQL fragment.

		checkInitialized();
		if ( persister == null ) {
			return "";
		}
		else {
			String fragment =  ( ( Queryable ) persister ).propertySelectFragment(
					getTableAlias(),
					getSuffix( size, k ),
					allProperties
				);
			return trimLeadingCommaAndSpaces( fragment );
		}
	
java.lang.StringrenderScalarIdentifierSelect(int i)
Render the identifier select, but in a 'scalar' context (i.e. generate the column alias).

param
i the sequence of the returned type
return
the identifier select with the column alias.

		checkInitialized();
		String[] cols = getPropertyMapping( EntityPersister.ENTITY_ID ).toColumns( getTableAlias(), EntityPersister.ENTITY_ID );
		StringBuffer buf = new StringBuffer();
		// For property references generate <tablealias>.<columnname> as <projectionalias>
		for ( int j = 0; j < cols.length; j++ ) {
			String column = cols[j];
			if ( j > 0 ) {
				buf.append( ", " );
			}
			buf.append( column ).append( " as " ).append( NameGenerator.scalarName( i, j ) );
		}
		return buf.toString();
	
public java.lang.StringrenderValueCollectionSelectFragment(int size, int k)

		if ( queryableCollection == null ) {
			return "";
		}
		else {
			if ( collectionSuffix == null ) {
				collectionSuffix = generateSuffix( size, k );
			}
			String fragment =  queryableCollection.selectFragment( getTableAlias(), collectionSuffix );
			return trimLeadingCommaAndSpaces( fragment );
		}
	
public voidsetCollectionSuffix(java.lang.String suffix)

		collectionSuffix = suffix;
	
public voidsetJoinSequence(org.hibernate.engine.JoinSequence joinSequence)

		this.joinSequence = joinSequence;
	
public voidsetQueryableCollection(org.hibernate.persister.collection.QueryableCollection queryableCollection)

		if ( this.queryableCollection != null ) {
			throw new IllegalStateException( "QueryableCollection is already defined for " + this + "!" );
		}
		this.queryableCollection = queryableCollection;
		if ( !queryableCollection.isOneToMany() ) {
			// For many-to-many joins, use the tablename from the queryable collection for the default text.
			fromElement.setText( queryableCollection.getTableName() + " " + getTableAlias() );
		}
	
java.lang.String[]toColumns(java.lang.String tableAlias, java.lang.String path, boolean inSelect)

		return toColumns( tableAlias, path, inSelect, false );
	
java.lang.String[]toColumns(java.lang.String tableAlias, java.lang.String path, boolean inSelect, boolean forceAlias)

		checkInitialized();
		PropertyMapping propertyMapping = getPropertyMapping( path );
		// If this from element is a collection and the path is a collection property (maxIndex, etc.) then
		// generate a sub-query.
		if ( !inSelect && queryableCollection != null && CollectionProperties.isCollectionProperty( path ) ) {
			Map enabledFilters = fromElement.getWalker().getEnabledFilters();
			String subquery = CollectionSubqueryFactory.createCollectionSubquery(
					joinSequence,
			        enabledFilters,
					propertyMapping.toColumns( tableAlias, path )
			);
			if ( log.isDebugEnabled() ) {
				log.debug( "toColumns(" + tableAlias + "," + path + ") : subquery = " + subquery );
			}
			return new String[]{"(" + subquery + ")"};
		}
		else {
			if ( forceAlias ) {
				return propertyMapping.toColumns( tableAlias, path );
			}
			else if ( fromElement.getWalker().getStatementType() == HqlSqlTokenTypes.SELECT ) {
				return propertyMapping.toColumns( tableAlias, path );
			}
			else if ( fromElement.getWalker().getCurrentClauseType() == HqlSqlTokenTypes.SELECT ) {
				return propertyMapping.toColumns( tableAlias, path );
			}
			else if ( fromElement.getWalker().isSubQuery() ) {
				// for a subquery, the alias to use depends on a few things (we
				// already know this is not an overall SELECT):
				//      1) if this FROM_ELEMENT represents a correlation to the
				//          outer-most query
				//              A) if the outer query represents a multi-table
				//                  persister, we need to use the given alias
				//                  in anticipation of one of the multi-table
				//                  executors being used (as this subquery will
				//                  actually be used in the "id select" phase
				//                  of that multi-table executor)
				//              B) otherwise, we need to use the persister's
				//                  table name as the column qualification
				//      2) otherwise (not correlated), use the given alias
				if ( isCorrelation() ) {
					if ( isMultiTable() ) {
						return propertyMapping.toColumns( tableAlias, path );
					}
					else {
						return propertyMapping.toColumns( extractTableName(), path );
					}
				}
				else {
					return propertyMapping.toColumns( tableAlias, path );
				}
			}
			else {
				String[] columns = propertyMapping.toColumns( path );
				log.trace( "Using non-qualified column reference [" + path + " -> (" + ArrayHelper.toString( columns ) + ")]" );
				return columns;
			}
		}
	
private static java.lang.StringtrimLeadingCommaAndSpaces(java.lang.String fragment)
This accounts for a quirk in Queryable, where it sometimes generates ', ' in front of the SQL fragment. :-P

param
fragment An SQL fragment.
return
The fragment, without the leading comma and spaces.

		if ( fragment.length() > 0 && fragment.charAt( 0 ) == '," ) {
			fragment = fragment.substring( 1 );
		}
		fragment = fragment.trim();
		return fragment.trim();