Methods Summary |
---|
private void | checkForCorrelatedSubquery(java.lang.String methodName)
if ( isCorrelatedSubselect() ) {
if ( log.isDebugEnabled() ) {
log.debug( methodName + "() : correlated subquery" );
}
}
|
private void | checkLhsIsNotCollection()
if ( getLhs().getDataType() != null && getLhs().getDataType().isCollectionType() ) {
throw ILLEGAL_COLL_DEREF_EXCP_BUILDER.buildIllegalCollectionDereferenceException( propertyName, getLhs() );
}
|
private boolean | checkSubclassOrSuperclassPropertyReference(FromReferenceNode lhs, java.lang.String propertyName)
if ( lhs != null && !( lhs instanceof IndexNode ) ) {
final FromElement source = lhs.getFromElement();
if ( source != null ) {
source.handlePropertyBeingDereferenced( lhs.getDataType(), propertyName );
}
}
return false;
|
private void | dereferenceCollection(org.hibernate.type.CollectionType collectionType, boolean implicitJoin, boolean indexed, java.lang.String classAlias, antlr.collections.AST parent)
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 | dereferenceComponent(antlr.collections.AST parent)
dereferenceType = DEREF_COMPONENT;
setPropertyNameAndPath( parent );
|
private void | dereferenceEntity(org.hibernate.type.EntityType entityType, boolean implicitJoin, java.lang.String classAlias, boolean generateJoin, antlr.collections.AST parent)
checkForCorrelatedSubquery( "dereferenceEntity" );
// three general cases we check here as to whether to render a physical SQL join:
// 1) is our parent a DotNode as well? If so, our property reference is
// being further de-referenced...
// 2) is this a DML statement
// 3) we were asked to generate any needed joins (generateJoins==true) *OR*
// we are currently processing a select or from clause
// (an additional check is the REGRESSION_STYLE_JOIN_SUPPRESSION check solely intended for the test suite)
//
// The REGRESSION_STYLE_JOIN_SUPPRESSION is an additional check
// intended solely for use within the test suite. This forces the
// implicit join resolution to behave more like the classic parser.
// The underlying issue is that classic translator is simply wrong
// about its decisions on whether or not to render an implicit join
// into a physical SQL join in a lot of cases. The piece it generally
// tends to miss is that INNER joins effect the results by further
// restricting the data set! A particular manifestation of this is
// the fact that the classic translator will skip the physical join
// for ToOne implicit joins *if the query is shallow*; the result
// being that Query.list() and Query.iterate() could return
// different number of results!
DotNode parentAsDotNode = null;
String property = propertyName;
final boolean joinIsNeeded;
if ( isDotNode( parent ) ) {
// our parent is another dot node, meaning we are being further dereferenced.
// thus we need to generate a join unless the parent refers to the associated
// entity's PK (because 'our' table would know the FK).
parentAsDotNode = ( DotNode ) parent;
property = parentAsDotNode.propertyName;
joinIsNeeded = generateJoin && !isReferenceToPrimaryKey( parentAsDotNode.propertyName, entityType );
}
else if ( ! getWalker().isSelectStatement() ) {
joinIsNeeded = false;
}
else if ( REGRESSION_STYLE_JOIN_SUPPRESSION ) {
// this is the regression style determination which matches the logic of the classic translator
joinIsNeeded = generateJoin && ( !getWalker().isInSelect() || !getWalker().isShallowQuery() );
}
else {
joinIsNeeded = generateJoin || ( getWalker().isInSelect() || getWalker().isInFrom() );
}
if ( joinIsNeeded ) {
dereferenceEntityJoin( classAlias, entityType, implicitJoin, parent );
}
else {
dereferenceEntityIdentifier( property, parentAsDotNode );
}
|
private void | dereferenceEntityIdentifier(java.lang.String propertyName, org.hibernate.hql.ast.tree.DotNode dotParent)
// special shortcut for id properties, skip the join!
// this must only occur at the _end_ of a path expression
if ( log.isDebugEnabled() ) {
log.debug( "dereferenceShortcut() : property " +
propertyName + " in " + getFromElement().getClassName() +
" does not require a join." );
}
initText();
setPropertyNameAndPath( dotParent ); // Set the unresolved path in this node and the parent.
// Set the text for the parent.
if ( dotParent != null ) {
dotParent.dereferenceType = DEREF_IDENTIFIER;
dotParent.setText( getText() );
dotParent.columns = getColumns();
}
|
private void | dereferenceEntityJoin(java.lang.String classAlias, org.hibernate.type.EntityType propertyType, boolean impliedJoin, antlr.collections.AST parent)
dereferenceType = DEREF_ENTITY;
if ( log.isDebugEnabled() ) {
log.debug( "dereferenceEntityJoin() : generating join for " + propertyName + " in "
+ getFromElement().getClassName() + " "
+ ( ( classAlias == null ) ? "{no alias}" : "(" + classAlias + ")" )
+ " parent = " + ASTUtil.getDebugString( parent )
);
}
// Create a new FROM node for the referenced class.
String associatedEntityName = propertyType.getAssociatedEntityName();
String tableAlias = getAliasGenerator().createName( associatedEntityName );
String[] joinColumns = getColumns();
String joinPath = getPath();
if ( impliedJoin && getWalker().isInFrom() ) {
joinType = getWalker().getImpliedJoinType();
}
FromClause currentFromClause = getWalker().getCurrentFromClause();
FromElement elem = currentFromClause.findJoinByPath( joinPath );
///////////////////////////////////////////////////////////////////////////////
//
// This is the piece which recognizes the condition where an implicit join path
// resolved earlier in a correlated subquery is now being referenced in the
// outer query. For 3.0final, we just let this generate a second join (which
// is exactly how the old parser handles this). Eventually we need to add this
// logic back in and complete the logic in FromClause.promoteJoin; however,
// FromClause.promoteJoin has its own difficulties (see the comments in
// FromClause.promoteJoin).
//
// if ( elem == null ) {
// // see if this joinPath has been used in a "child" FromClause, and if so
// // promote that element to the outer query
// FromClause currentNodeOwner = getFromElement().getFromClause();
// FromClause currentJoinOwner = currentNodeOwner.locateChildFromClauseWithJoinByPath( joinPath );
// if ( currentJoinOwner != null && currentNodeOwner != currentJoinOwner ) {
// elem = currentJoinOwner.findJoinByPathLocal( joinPath );
// if ( elem != null ) {
// currentFromClause.promoteJoin( elem );
// // EARLY EXIT!!!
// return;
// }
// }
// }
//
///////////////////////////////////////////////////////////////////////////////
if ( elem == null ) {
// If this is an implied join in a from element, then use the impled join type which is part of the
// tree parser's state (set by the gramamar actions).
JoinSequence joinSequence = getSessionFactoryHelper()
.createJoinSequence( impliedJoin, propertyType, tableAlias, joinType, joinColumns );
FromElementFactory factory = new FromElementFactory(
currentFromClause,
getLhs().getFromElement(),
joinPath,
classAlias,
joinColumns,
impliedJoin
);
elem = factory.createEntityJoin(
associatedEntityName,
tableAlias,
joinSequence,
fetch,
getWalker().isInFrom(),
propertyType
);
}
else {
currentFromClause.addDuplicateAlias(classAlias, elem);
}
setImpliedJoin( elem );
getWalker().addQuerySpaces( elem.getEntityPersister().getQuerySpaces() );
setFromElement( elem ); // This 'dot' expression now refers to the resulting from element.
|
private java.lang.String[] | getColumns()
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 org.hibernate.type.Type | getDataType()
if ( super.getDataType() == null ) {
FromElement fromElement = getLhs().getFromElement();
if ( fromElement == null ) {
return null;
}
// If the lhs is a collection, use CollectionPropertyMapping
Type propertyType = fromElement.getPropertyType( propertyName, propertyPath );
if ( log.isDebugEnabled() ) {
log.debug( "getDataType() : " + propertyPath + " -> " + propertyType );
}
super.setDataType( propertyType );
}
return super.getDataType();
|
public java.lang.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();
|
public FromElement | getImpliedJoin()
return impliedJoin;
|
public FromReferenceNode | getLhs()
FromReferenceNode lhs = ( ( FromReferenceNode ) getFirstChild() );
if ( lhs == null ) {
throw new IllegalStateException( "DOT node with no left-hand-side!" );
}
return lhs;
|
public java.lang.String | getPath()Returns the full path of the node.
if ( path == null ) {
FromReferenceNode lhs = getLhs();
if ( lhs == null ) {
path = getText();
}
else {
SqlNode rhs = ( SqlNode ) lhs.getNextSibling();
path = lhs.getPath() + "." + rhs.getOriginalText();
}
}
return path;
|
public java.lang.String | getPropertyPath()
return propertyPath;
|
private void | initText()
String[] cols = getColumns();
String text = StringHelper.join( ", ", cols );
if ( cols.length > 1 && getWalker().isComparativeExpressionClause() ) {
text = "(" + text + ")";
}
setText( text );
|
private boolean | isCorrelatedSubselect()
return getWalker().isSubQuery() &&
getFromElement().getFromClause() != getWalker().getCurrentFromClause();
|
private boolean | isDotNode(antlr.collections.AST n)
return n != null && n.getType() == SqlTokenTypes.DOT;
|
private boolean | isReferenceToPrimaryKey(java.lang.String propertyName, org.hibernate.type.EntityType owningType)Is the given property name a reference to the primary key of the associated
entity construed by the given entity type?
For example, consider a fragment like order.customer.id
(where order is a from-element alias). Here, we'd have:
propertyName = "id" AND
owningType = ManyToOneType(Customer)
and are being asked to determine whether "customer.id" is a reference
to customer's PK...
EntityPersister persister = getSessionFactoryHelper()
.getFactory()
.getEntityPersister( owningType.getAssociatedEntityName() );
if ( persister.getEntityMetamodel().hasNonIdentifierPropertyNamedId() ) {
// only the identifier property field name can be a reference to the associated entity's PK...
return propertyName.equals( persister.getIdentifierPropertyName() ) && owningType.isReferenceToPrimaryKey();
}
else {
// here, we have two possibilities:
// 1) the property-name matches the explicitly identifier property name
// 2) the property-name matches the implicit 'id' property name
if ( EntityPersister.ENTITY_ID.equals( propertyName ) ) {
// the referenced node text is the special 'id'
return owningType.isReferenceToPrimaryKey();
}
else {
String keyPropertyName = getSessionFactoryHelper().getIdentifierOrUniqueKeyPropertyName( owningType );
return keyPropertyName != null && keyPropertyName.equals( propertyName ) && owningType.isReferenceToPrimaryKey();
}
}
|
private org.hibernate.type.Type | prepareLhs()
FromReferenceNode lhs = getLhs();
lhs.prepareForDot( propertyName );
return getDataType();
|
public void | resolve(boolean generateJoin, boolean implicitJoin, java.lang.String classAlias, antlr.collections.AST parent)
// 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;
}
if ( propertyType.isComponentType() ) {
// The property is a component...
checkLhsIsNotCollection();
dereferenceComponent( parent );
initText();
}
else if ( propertyType.isEntityType() ) {
// The property is another class..
checkLhsIsNotCollection();
dereferenceEntity( ( EntityType ) propertyType, implicitJoin, classAlias, generateJoin, parent );
initText();
}
else if ( propertyType.isCollectionType() ) {
// The property is a collection...
checkLhsIsNotCollection();
dereferenceCollection( ( CollectionType ) propertyType, implicitJoin, false, classAlias, parent );
}
else {
// Otherwise, this is a primitive type.
if ( ! CollectionProperties.isAnyCollectionProperty( propertyName ) ) {
checkLhsIsNotCollection();
}
dereferenceType = DEREF_PRIMITIVE;
initText();
}
setResolved();
|
public void | resolveFirstChild()Resolves the left hand side of the DOT.
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.
checkSubclassOrSuperclassPropertyReference( lhs, propName );
|
public void | resolveInFunctionCall(boolean generateJoin, boolean implicitJoin)
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(antlr.collections.AST parent)
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 | resolveSelectExpression()Special method to resolve expressions in the SELECT list.
if ( getWalker().isShallowQuery() || getWalker().getCurrentFromClause().isSubQuery() ) {
resolve(false, true);
}
else {
resolve(true, false);
Type type = getDataType();
if ( type.isEntityType() ) {
FromElement fromElement = getFromElement();
fromElement.setIncludeSubclasses( true ); // Tell the destination fromElement to 'includeSubclasses'.
if ( useThetaStyleImplicitJoins ) {
fromElement.getJoinSequence().setUseThetaStyle( true ); // Use theta style (for regression)
// Move the node up, after the origin node.
FromElement origin = fromElement.getOrigin();
if ( origin != null ) {
ASTUtil.makeSiblingOfParent( origin, fromElement );
}
}
}
}
FromReferenceNode lhs = getLhs();
while ( lhs != null ) {
checkSubclassOrSuperclassPropertyReference( lhs, lhs.getNextSibling().getText() );
lhs = ( FromReferenceNode ) lhs.getFirstChild();
}
|
public void | setFetch(boolean fetch)
this.fetch = fetch;
|
private void | setImpliedJoin(FromElement elem)
this.impliedJoin = elem;
if ( getFirstChild().getType() == SqlTokenTypes.DOT ) {
DotNode dotLhs = ( DotNode ) getFirstChild();
if ( dotLhs.getImpliedJoin() != null ) {
this.impliedJoin = dotLhs.getImpliedJoin();
}
}
|
public void | setJoinType(int joinType)Sets the join type for this '.' node structure.
this.joinType = joinType;
|
private void | setPropertyNameAndPath(antlr.collections.AST parent)
if ( isDotNode( parent ) ) {
DotNode dotNode = ( DotNode ) parent;
AST lhs = dotNode.getFirstChild();
AST rhs = lhs.getNextSibling();
propertyName = rhs.getText();
propertyPath = propertyPath + "." + propertyName; // Append the new property name onto the unresolved path.
dotNode.propertyPath = propertyPath;
if ( log.isDebugEnabled() ) {
log.debug( "Unresolved property path is now '" + dotNode.propertyPath + "'" );
}
}
else {
if ( log.isDebugEnabled() ) {
log.debug( "terminal propertyPath = [" + propertyPath + "]" );
}
}
|
public void | setPropertyPath(java.lang.String propertyPath)
this.propertyPath = propertyPath;
|
public void | setResolvedConstant(java.lang.String text)
path = text;
dereferenceType = DEREF_JAVA_CONSTANT;
setResolved(); // Don't resolve the node again.
|
public void | setScalarColumnText(int i)
String[] sqlColumns = getColumns();
ColumnHelper.generateScalarColumns( this, sqlColumns, i );
|