FileDocCategorySizeDatePackage
IntoClause.javaAPI DocHibernate 3.2.57074Wed Aug 31 10:02:24 BST 2005org.hibernate.hql.ast.tree

IntoClause

public class IntoClause extends HqlSqlWalkerNode implements DisplayableNode
Represents an entity referenced in the INTO clause of an HQL INSERT statement.
author
Steve Ebersole

Fields Summary
private org.hibernate.persister.entity.Queryable
persister
private String
columnSpec
private org.hibernate.type.Type[]
types
private boolean
discriminated
private boolean
explicitIdInsertion
private boolean
explicitVersionInsertion
Constructors Summary
Methods Summary
private booleanareCompatible(org.hibernate.type.Type target, org.hibernate.type.Type source)
Determine whether the two types are "assignment compatible".

param
target The type defined in the into-clause.
param
source The type defined in the select clause.
return
True if they are assignment compatible.

		if ( target.equals( source ) ) {
			// if the types report logical equivalence, return true...
			return true;
		}

		// otherwise, perform a "deep equivalence" check...

		if ( !target.getReturnedClass().isAssignableFrom( source.getReturnedClass() ) ) {
			return false;
		}

		int[] targetDatatypes = target.sqlTypes( getSessionFactoryHelper().getFactory() );
		int[] sourceDatatypes = source.sqlTypes( getSessionFactoryHelper().getFactory() );

		if ( targetDatatypes.length != sourceDatatypes.length ) {
			return false;
		}

		for ( int i = 0; i < targetDatatypes.length; i++ ) {
			if ( !areSqlTypesCompatible( targetDatatypes[i], sourceDatatypes[i] ) ) {
				return false;
			}
		}

		return true;
	
private booleanareSqlTypesCompatible(int target, int source)

		switch ( target ) {
			case Types.TIMESTAMP:
				return source == Types.DATE || source == Types.TIME || source == Types.TIMESTAMP;
			case Types.DATE:
				return source == Types.DATE || source == Types.TIMESTAMP;
			case Types.TIME:
				return source == Types.TIME || source == Types.TIMESTAMP;
			default:
				return target == source;
		}
	
public java.lang.StringgetDisplayText()
Returns additional display text for the AST node.

return
String - The additional display text.

		StringBuffer buf = new StringBuffer();
		buf.append( "IntoClause{" );
		buf.append( "entityName=" ).append( getEntityName() );
		buf.append( ",tableName=" ).append( getTableName() );
		buf.append( ",columns={" ).append( columnSpec ).append( "}" );
		buf.append( "}" );
		return buf.toString();
	
public java.lang.StringgetEntityName()

		return persister.getEntityName();
	
public org.hibernate.type.Type[]getInsertionTypes()

		return types;
	
public org.hibernate.persister.entity.QueryablegetQueryable()

		return persister;
	
public java.lang.StringgetTableName()

		return persister.getSubclassTableName( 0 );
	
public voidinitialize(org.hibernate.persister.entity.Queryable persister)



	    
		if ( persister.isAbstract() ) {
			throw new QueryException( "cannot insert into abstract class (no table)" );
		}
		this.persister = persister;
		initializeColumns();

		if ( getWalker().getSessionFactoryHelper().hasPhysicalDiscriminatorColumn( persister ) ) {
			discriminated = true;
			columnSpec += ", " + persister.getDiscriminatorColumnName();
		}

		resetText();
	
private voidinitializeColumns()

		AST propertySpec = getFirstChild();
		List types = new ArrayList();
		visitPropertySpecNodes( propertySpec.getFirstChild(), types );
		this.types = ArrayHelper.toTypeArray( types );
		columnSpec = columnSpec.substring( 0, columnSpec.length() - 2 );
	
public booleanisDiscriminated()

		return discriminated;
	
public booleanisExplicitIdInsertion()

		return explicitIdInsertion;
	
public booleanisExplicitVersionInsertion()

		return explicitVersionInsertion;
	
private booleanisSuperclassProperty(java.lang.String propertyName)

		// really there are two situations where it should be ok to allow the insertion
		// into properties defined on a superclass:
		//      1) union-subclass with an abstract root entity
		//      2) discrim-subclass
		//
		// #1 is handled already because of the fact that
		// UnionSubclassPersister alreay always returns 0
		// for this call...
		//
		// we may want to disallow it for discrim-subclass just for
		// consistency-sake (currently does not work anyway)...
		return persister.getSubclassPropertyTableNumber( propertyName ) != 0;
	
public voidprependIdColumnSpec()

		columnSpec = persister.getIdentifierColumnNames()[0] + ", " + columnSpec;
		resetText();
	
public voidprependVersionColumnSpec()

		columnSpec = persister.getPropertyColumnNames( persister.getVersionProperty() )[0] + ", " + columnSpec;
		resetText();
	
private voidrenderColumns(java.lang.String[] columnNames)

		for ( int i = 0; i < columnNames.length; i++ ) {
			columnSpec += columnNames[i] + ", ";
		}
	
private voidresetText()

		setText( "into " + getTableName() + " ( " + columnSpec + " )" );
	
public voidvalidateTypes(SelectClause selectClause)

		Type[] selectTypes = selectClause.getQueryReturnTypes();
		if ( selectTypes.length != types.length ) {
			throw new QueryException( "number of select types did not match those for insert" );
		}

		for ( int i = 0; i < types.length; i++ ) {
			if ( !areCompatible( types[i], selectTypes[i] ) ) {
				throw new QueryException(
				        "insertion type [" + types[i] + "] and selection type [" +
				        selectTypes[i] + "] at position " + i + " are not compatible"
				);
			}
		}

		// otherwise, everything ok.
	
private voidvisitPropertySpecNodes(antlr.collections.AST propertyNode, java.util.List types)

		if ( propertyNode == null ) {
			return;
		}
		// TODO : we really need to be able to deal with component paths here also;
		// this is difficult because the hql-sql grammar expects all those node types
		// to be FromReferenceNodes.  One potential fix here would be to convert the
		// IntoClause to just use a FromClause/FromElement combo (as a child of the
		// InsertStatement) and move all this logic into the InsertStatement.  That's
		// probably the easiest approach (read: least amount of changes to the grammar
		// and code), but just doesn't feel right as then an insert would contain
		// 2 from-clauses
		String name = propertyNode.getText();
		if ( isSuperclassProperty( name ) ) {
			throw new QueryException( "INSERT statements cannot refer to superclass/joined properties [" + name + "]" );
		}

		if ( name.equals( persister.getIdentifierPropertyName() ) ) {
			explicitIdInsertion = true;
		}

		if ( persister.isVersioned() ) {
			if ( name.equals( persister.getPropertyNames()[ persister.getVersionProperty() ] ) ) {
				explicitVersionInsertion = true;
			}
		}

		String[] columnNames = persister.toColumns( name );
		renderColumns( columnNames );
		types.add( persister.toType( name ) );

		// visit width-first, then depth
		visitPropertySpecNodes( propertyNode.getNextSibling(), types );
		visitPropertySpecNodes( propertyNode.getFirstChild(), types );