📄 intoclause.java
字号:
// $Id: IntoClause.java 8050 2005-08-31 15:02:23Z steveebersole $package org.hibernate.hql.ast.tree;import java.util.ArrayList;import java.util.List;import java.sql.Types;import org.hibernate.QueryException;import org.hibernate.persister.entity.Queryable;import org.hibernate.type.Type;import org.hibernate.util.ArrayHelper;import antlr.collections.AST;/** * Represents an entity referenced in the INTO clause of an HQL * INSERT statement. * * @author Steve Ebersole */public class IntoClause extends HqlSqlWalkerNode implements DisplayableNode { private Queryable persister; private String columnSpec = ""; private Type[] types; private boolean discriminated; private boolean explicitIdInsertion; private boolean explicitVersionInsertion; public void initialize(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 void resetText() { setText( "into " + getTableName() + " ( " + columnSpec + " )" ); } public String getTableName() { return persister.getSubclassTableName( 0 ); } public Queryable getQueryable() { return persister; } public String getEntityName() { return persister.getEntityName(); } public Type[] getInsertionTypes() { return types; } public boolean isDiscriminated() { return discriminated; } public boolean isExplicitIdInsertion() { return explicitIdInsertion; } public boolean isExplicitVersionInsertion() { return explicitVersionInsertion; } public void prependIdColumnSpec() { columnSpec = persister.getIdentifierColumnNames()[0] + ", " + columnSpec; resetText(); } public void prependVersionColumnSpec() { columnSpec = persister.getPropertyColumnNames( persister.getVersionProperty() )[0] + ", " + columnSpec; resetText(); } public void validateTypes(SelectClause selectClause) throws QueryException { 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. } /** * Returns additional display text for the AST node. * * @return String - The additional display text. */ public String getDisplayText() { 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(); } private void initializeColumns() { AST propertySpec = getFirstChild(); List types = new ArrayList(); visitPropertySpecNodes( propertySpec.getFirstChild(), types ); this.types = ArrayHelper.toTypeArray( types ); columnSpec = columnSpec.substring( 0, columnSpec.length() - 2 ); } private void visitPropertySpecNodes(AST propertyNode, 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 ); } private void renderColumns(String[] columnNames) { for ( int i = 0; i < columnNames.length; i++ ) { columnSpec += columnNames[i] + ", "; } } private boolean isSuperclassProperty(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; } /** * 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. */ private boolean areCompatible(Type target, Type source) { 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 boolean areSqlTypesCompatible(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; } }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -