📄 dotnode.java
字号:
// $Id: DotNode.java 9046 2006-01-13 03:10:57Z steveebersole $
package org.hibernate.hql.ast.tree;
import org.hibernate.QueryException;
import org.hibernate.engine.JoinSequence;
import org.hibernate.hql.CollectionProperties;
import org.hibernate.hql.antlr.SqlTokenTypes;
import org.hibernate.hql.ast.util.ASTPrinter;
import org.hibernate.hql.ast.util.ASTUtil;
import org.hibernate.hql.ast.util.ColumnHelper;
import org.hibernate.persister.collection.QueryableCollection;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.sql.JoinFragment;
import org.hibernate.type.CollectionType;
import org.hibernate.type.EntityType;
import org.hibernate.type.Type;
import org.hibernate.util.StringHelper;
import antlr.SemanticException;
import antlr.collections.AST;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Represents a reference to a property or alias expression. This should duplicate the relevant behaviors in
* PathExpressionParser.
* <hr>
* User: josh<br>
* Date: Dec 16, 2003<br>
* Time: 8:03:09 AM
*/
public class DotNode extends FromReferenceNode implements DisplayableNode, SelectExpression {
/**
* A logger for this class.
*/
private static final Log log = LogFactory.getLog( DotNode.class );
private static final int DEREF_UNKNOWN = 0;
private static final int DEREF_ENTITY = 1;
private static final int DEREF_COMPONENT = 2;
private static final int DEREF_COLLECTION = 3;
private static final int DEREF_PRIMITIVE = 4;
private static final int DEREF_IDENTIFIER = 5;
private static final int DEREF_JAVA_CONSTANT = 6;
/**
* The identifier that is the name of the property.
*/
private String propertyName;
/**
* The full path, to the root alias of this dot node.
*/
private String path;
/**
* The unresolved property path relative to this dot node.
*/
private String propertyPath;
/**
* The column names that this resolves to.
*/
private String[] columns;
/**
* The type of join to create. Default is an inner join.
*/
private int joinType = JoinFragment.INNER_JOIN;
/**
* Fetch join or not.
*/
private boolean fetch = false;
/**
* The type of dereference that hapened (DEREF_xxx).
*/
private int dereferenceType = DEREF_UNKNOWN;
private FromElement impliedJoin;
/**
* Sets the join type for the '.' node (JoinFragment.XXX).
*
* @param joinType
* @see JoinFragment
*/
public void setJoinType(int joinType) {
this.joinType = joinType;
}
private String[] getColumns() throws QueryException {
if ( columns == null ) {
// Use the table fromElement and the property name to get the array of column names.
String tableAlias = getLhs().getFromElement().getTableAlias();
columns = getFromElement().toColumns( tableAlias, propertyPath, false );
}
return columns;
}
public String getDisplayText() {
StringBuffer buf = new StringBuffer();
FromElement fromElement = getFromElement();
buf.append( "{propertyName=" ).append( propertyName );
buf.append( ",dereferenceType=" ).append( ASTPrinter.getConstantName( getClass(), dereferenceType ) );
buf.append( ",propertyPath=" ).append( propertyPath );
buf.append( ",path=" ).append( getPath() );
if ( fromElement != null ) {
buf.append( ",tableAlias=" ).append( fromElement.getTableAlias() );
buf.append( ",className=" ).append( fromElement.getClassName() );
buf.append( ",classAlias=" ).append( fromElement.getClassAlias() );
}
else {
buf.append( ",no from element" );
}
buf.append( '}' );
return buf.toString();
}
/**
* Resolves the left hand side of the DOT.
*
* @throws SemanticException
*/
public void resolveFirstChild() throws SemanticException {
FromReferenceNode lhs = ( FromReferenceNode ) getFirstChild();
SqlNode property = ( SqlNode ) lhs.getNextSibling();
// Set the attributes of the property reference expression.
String propName = property.getText();
propertyName = propName;
// If the uresolved property path isn't set yet, just use the property name.
if ( propertyPath == null ) {
propertyPath = propName;
}
// Resolve the LHS fully, generate implicit joins. Pass in the property name so that the resolver can
// discover foreign key (id) properties.
lhs.resolve( true, true, null, this );
setFromElement( lhs.getFromElement() ); // The 'from element' that the property is in.
}
public void resolveInFunctionCall(boolean generateJoin, boolean implicitJoin) throws SemanticException {
if ( isResolved() ) {
return;
}
Type propertyType = prepareLhs(); // Prepare the left hand side and get the data type.
if ( propertyType!=null && propertyType.isCollectionType() ) {
resolveIndex(null);
}
else {
resolveFirstChild();
super.resolve(generateJoin, implicitJoin);
}
}
public void resolveIndex(AST parent) throws SemanticException {
if ( isResolved() ) {
return;
}
Type propertyType = prepareLhs(); // Prepare the left hand side and get the data type.
dereferenceCollection( ( CollectionType ) propertyType, true, true, null, parent );
}
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent)
throws SemanticException {
// If this dot has already been resolved, stop now.
if ( isResolved() ) {
return;
}
Type propertyType = prepareLhs(); // Prepare the left hand side and get the data type.
// If there is no data type for this node, and we're at the end of the path (top most dot node), then
// this might be a Java constant.
if ( propertyType == null ) {
if ( parent == null ) {
getWalker().getLiteralProcessor().lookupConstant( this );
}
// If the propertyType is null and there isn't a parent, just
// stop now... there was a problem resolving the node anyway.
return;
}
// The property is a component...
if ( propertyType.isComponentType() ) {
checkLhsIsNotCollection();
dereferenceComponent( parent );
initText();
}
// The property is another class..
else if ( propertyType.isEntityType() ) {
checkLhsIsNotCollection();
dereferenceEntity( ( EntityType ) propertyType, implicitJoin, classAlias, generateJoin, parent );
initText();
}
// The property is a collection...
else if ( propertyType.isCollectionType() ) {
checkLhsIsNotCollection();
dereferenceCollection( ( CollectionType ) propertyType, implicitJoin, false, classAlias, parent );
}
else { // Otherwise, this is a primitive type.
dereferenceType = DEREF_PRIMITIVE;
initText();
}
setResolved();
}
private void initText() {
String[] cols = getColumns();
String text = StringHelper.join( ", ", cols );
if ( cols.length > 1 && getWalker().isComparativeExpressionClause() ) {
text = "(" + text + ")";
}
setText( text );
}
private Type prepareLhs() throws SemanticException {
FromReferenceNode lhs = getLhs();
lhs.prepareForDot( propertyName );
Type propertyType = getDataType();
return propertyType;
}
private void dereferenceCollection(CollectionType collectionType, boolean implicitJoin, boolean indexed, String classAlias, AST parent)
throws SemanticException {
dereferenceType = DEREF_COLLECTION;
String role = collectionType.getRole();
//foo.bars.size (also handles deprecated stuff like foo.bars.maxelement for backwardness)
boolean isSizeProperty = getNextSibling()!=null &&
CollectionProperties.isAnyCollectionProperty( getNextSibling().getText() );
if ( isSizeProperty ) indexed = true; //yuck!
QueryableCollection queryableCollection = getSessionFactoryHelper().requireQueryableCollection( role );
String propName = getPath();
FromClause currentFromClause = getWalker().getCurrentFromClause();
if ( getWalker().getStatementType() != SqlTokenTypes.SELECT && indexed && classAlias == null ) {
// should indicate that we are processing an INSERT/UPDATE/DELETE
// query with a subquery implied via a collection property
// function. Here, we need to use the table name itself as the
// qualification alias.
// TODO : verify this works for all databases...
// TODO : is this also the case in non-"indexed" scenarios?
String alias = getLhs().getFromElement().getQueryable().getTableName();
columns = getFromElement().toColumns( alias, propertyPath, false, true );
}
//We do not look for an existing join on the same path, because
//it makes sense to join twice on the same collection role
FromElementFactory factory = new FromElementFactory(
currentFromClause,
getLhs().getFromElement(),
propName,
classAlias,
getColumns(),
implicitJoin
);
FromElement elem = factory.createCollection( queryableCollection, role, joinType, fetch, indexed );
if ( log.isDebugEnabled() ) {
log.debug( "dereferenceCollection() : Created new FROM element for " + propName + " : " + elem );
}
setImpliedJoin( elem );
setFromElement( elem ); // This 'dot' expression now refers to the resulting from element.
if ( isSizeProperty ) {
elem.setText("");
elem.setUseWhereFragment(false);
}
if ( !implicitJoin ) {
EntityPersister entityPersister = elem.getEntityPersister();
if ( entityPersister != null ) {
getWalker().addQuerySpaces( entityPersister.getQuerySpaces() );
}
}
getWalker().addQuerySpaces( queryableCollection.getCollectionSpaces() ); // Always add the collection's query spaces.
}
private void dereferenceEntity(EntityType entityType, boolean implicitJoin, String classAlias, boolean generateJoin, AST parent) throws SemanticException {
checkForCorrelatedSubquery( "dereferenceEntity" );
// If this is an entity inside a component reference, then generate the join.
// if ( unresolvedComponent( generateJoin ) ) {
// if ( log.isDebugEnabled() ) {
// log.debug( "dereferenceEntity() : resolving unresolved component '" + propertyPath + "' ... " );
// }
// dereferenceEntityJoin( classAlias, entityType, implicitJoin, parent );
// return;
// }
// Only join to the entity table if:
// 1) we were instructed to generate any needed joins (generateJoins==true)
// AND
// 2) EITHER:
// A) our parent represents a further dereference of this entity to anything
// other than the entity's id property
// OR
// B) this node is in any clause, other than the select clause (unless that
// select clause is part of a scalar query :/ )
DotNode parentAsDotNode = null;
String property = propertyName;
boolean joinIsNeeded = false;
if ( isDotNode( parent ) ) {
parentAsDotNode = ( DotNode ) parent;
property = parentAsDotNode.propertyName;
joinIsNeeded = generateJoin && !isReferenceToPrimaryKey( parentAsDotNode.propertyName, entityType );
}
else {
joinIsNeeded = generateJoin && ( !getWalker().isInSelect() || !getWalker().isShallowQuery() );
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -