HHH-11538 - Skip generating joins for entity references used in equality and nullness predicates

This commit is contained in:
Christian Beikov 2017-03-03 13:39:20 +01:00 committed by Steve Ebersole
parent ce32b364b4
commit 17b8d2e294
10 changed files with 94 additions and 70 deletions

View File

@ -209,6 +209,8 @@ tokens
protected void resolve(AST node) throws SemanticException { }
protected void resolve(AST node, AST predicateNode) throws SemanticException { }
protected void resolveSelectExpression(AST dotNode) throws SemanticException { }
protected void processFunction(AST functionCall,boolean inSelect) throws SemanticException { }
@ -335,7 +337,7 @@ assignment
// For now, just use expr. Revisit after ejb3 solidifies this.
newValue
: expr | query
: expr [ null ] | query
;
// The query / subquery rule. Pops the current 'from node' context
@ -380,7 +382,7 @@ nullPrecedence
orderExpr
: { isOrderExpressionResultVariableRef( _t ) }? resultVariableRef
| expr
| expr [ null ]
;
resultVariableRef!
@ -392,7 +394,7 @@ resultVariableRef!
;
groupClause
: #(GROUP { handleClauseStart( GROUP ); } (expr)+ ( #(HAVING logicalExpr) )? ) {
: #(GROUP { handleClauseStart( GROUP ); } (expr [ null ])+ ( #(HAVING logicalExpr) )? ) {
handleClauseEnd();
}
;
@ -429,7 +431,7 @@ selectExpr
| count
| collectionFunction // elements() or indices()
| constant
| arithmeticExpr
| arithmeticExpr [ null ]
| logicalExpr
| parameter
| query
@ -448,7 +450,7 @@ constructor
;
aggregateExpr
: expr //p:propertyRef { resolve(#p); }
: expr [ null ] //p:propertyRef { resolve(#p); }
| collectionFunction
;
@ -572,36 +574,37 @@ logicalExpr
;
// TODO: Add any other comparison operators here.
// We pass through the comparisonExpr AST to the expressions so that joins can be avoided for EQ/IN/NULLNESS
comparisonExpr
:
( #(EQ exprOrSubquery exprOrSubquery)
| #(NE exprOrSubquery exprOrSubquery)
| #(LT exprOrSubquery exprOrSubquery)
| #(GT exprOrSubquery exprOrSubquery)
| #(LE exprOrSubquery exprOrSubquery)
| #(GE exprOrSubquery exprOrSubquery)
| #(LIKE exprOrSubquery expr ( #(ESCAPE expr) )? )
| #(NOT_LIKE exprOrSubquery expr ( #(ESCAPE expr) )? )
| #(BETWEEN exprOrSubquery exprOrSubquery exprOrSubquery)
| #(NOT_BETWEEN exprOrSubquery exprOrSubquery exprOrSubquery)
| #(IN exprOrSubquery inRhs )
| #(NOT_IN exprOrSubquery inRhs )
| #(IS_NULL exprOrSubquery)
| #(IS_NOT_NULL exprOrSubquery)
// | #(IS_TRUE expr)
// | #(IS_FALSE expr)
| #(EXISTS ( expr | collectionFunctionOrSubselect ) )
( #(EQ exprOrSubquery [ currentAST.root ] exprOrSubquery [ currentAST.root ])
| #(NE exprOrSubquery [ currentAST.root ] exprOrSubquery [ currentAST.root ])
| #(LT exprOrSubquery [ null ] exprOrSubquery [ null ])
| #(GT exprOrSubquery [ null ] exprOrSubquery [ null ])
| #(LE exprOrSubquery [ null ] exprOrSubquery [ null ])
| #(GE exprOrSubquery [ null ] exprOrSubquery [ null ])
| #(LIKE exprOrSubquery [ null ] expr [ null ] ( #(ESCAPE expr [ null ]) )? )
| #(NOT_LIKE exprOrSubquery [ null ] expr [ null ] ( #(ESCAPE expr [ null ]) )? )
| #(BETWEEN exprOrSubquery [ null ] exprOrSubquery [ null ] exprOrSubquery [ null ])
| #(NOT_BETWEEN exprOrSubquery [ null ] exprOrSubquery [ null ] exprOrSubquery [ null ])
| #(IN exprOrSubquery [ currentAST.root ] inRhs [ currentAST.root ] )
| #(NOT_IN exprOrSubquery [ currentAST.root ] inRhs [ currentAST.root ] )
| #(IS_NULL exprOrSubquery [ currentAST.root ])
| #(IS_NOT_NULL exprOrSubquery [ currentAST.root ])
// | #(IS_TRUE expr [ null ])
// | #(IS_FALSE expr [ null ])
| #(EXISTS ( expr [ null ] | collectionFunctionOrSubselect ) )
) {
prepareLogicOperator( #comparisonExpr );
}
;
inRhs
: #(IN_LIST ( collectionFunctionOrSubselect | ( (expr)* ) ) )
inRhs [ AST predicateNode ]
: #(IN_LIST ( collectionFunctionOrSubselect | ( (expr [ predicateNode ])* ) ) )
;
exprOrSubquery
: expr
exprOrSubquery [ AST predicateNode ]
: expr [ predicateNode ]
| query
| #(ANY collectionFunctionOrSubselect)
| #(ALL collectionFunctionOrSubselect)
@ -613,55 +616,55 @@ collectionFunctionOrSubselect
| query
;
expr
: ae:addrExpr [ true ] { resolve(#ae); } // Resolve the top level 'address expression'
| #( VECTOR_EXPR (expr)* )
expr [ AST predicateNode ]
: ae:addrExpr [ true ] { resolve(#ae, predicateNode); } // Resolve the top level 'address expression'
| #( VECTOR_EXPR (expr [ predicateNode ])* )
| constant
| arithmeticExpr
| arithmeticExpr [ predicateNode ]
| functionCall // Function call, not in the SELECT clause.
| parameter
| count // Count, not in the SELECT clause.
;
arithmeticExpr
: #(PLUS exprOrSubquery exprOrSubquery) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(MINUS exprOrSubquery exprOrSubquery) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(DIV exprOrSubquery exprOrSubquery) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(MOD exprOrSubquery exprOrSubquery) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(STAR exprOrSubquery exprOrSubquery) { prepareArithmeticOperator( #arithmeticExpr ); }
// | #(CONCAT expr (expr)+ ) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(UNARY_MINUS expr) { prepareArithmeticOperator( #arithmeticExpr ); }
| caseExpr
arithmeticExpr [ AST predicateNode ]
: #(PLUS exprOrSubquery [ null ] exprOrSubquery [ null ]) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(MINUS exprOrSubquery [ null ] exprOrSubquery [ null ]) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(DIV exprOrSubquery [ null ] exprOrSubquery [ null ]) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(MOD exprOrSubquery [ null ] exprOrSubquery [ null ]) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(STAR exprOrSubquery [ null ] exprOrSubquery [ null ]) { prepareArithmeticOperator( #arithmeticExpr ); }
// | #(CONCAT expr [ null ] (expr [ null ])+ ) { prepareArithmeticOperator( #arithmeticExpr ); }
| #(UNARY_MINUS expr [ null ]) { prepareArithmeticOperator( #arithmeticExpr ); }
| caseExpr [ predicateNode ]
;
caseExpr
: simpleCaseExpression
| searchedCaseExpression
caseExpr [ AST predicateNode ]
: simpleCaseExpression [ predicateNode ]
| searchedCaseExpression [ predicateNode ]
;
expressionOrSubQuery
: expr
expressionOrSubQuery [ AST predicateNode ]
: expr [ predicateNode ]
| query
;
simpleCaseExpression
: #(CASE2 {inCase=true;} expressionOrSubQuery (simpleCaseWhenClause)+ (elseClause)?) {inCase=false;}
simpleCaseExpression [ AST predicateNode ]
: #(CASE2 {inCase=true;} expressionOrSubQuery [ currentAST.root ] (simpleCaseWhenClause [ currentAST.root, predicateNode ])+ (elseClause [ predicateNode ])?) {inCase=false;}
;
simpleCaseWhenClause
: #(WHEN expressionOrSubQuery expressionOrSubQuery)
simpleCaseWhenClause [ AST predicateNode, AST superPredicateNode ]
: #(WHEN expressionOrSubQuery [ predicateNode ] expressionOrSubQuery [ superPredicateNode ])
;
elseClause
: #(ELSE expressionOrSubQuery)
elseClause [ AST predicateNode ]
: #(ELSE expressionOrSubQuery [ predicateNode ])
;
searchedCaseExpression
: #(CASE {inCase = true;} (searchedCaseWhenClause)+ (elseClause)?) {inCase = false;}
searchedCaseExpression [ AST predicateNode ]
: #(CASE {inCase = true;} (searchedCaseWhenClause [ predicateNode ])+ (elseClause [ predicateNode ])?) {inCase = false;}
;
searchedCaseWhenClause
: #(WHEN logicalExpr expressionOrSubQuery)
searchedCaseWhenClause [ AST predicateNode ]
: #(WHEN logicalExpr expressionOrSubQuery [ predicateNode ])
;
@ -675,11 +678,11 @@ collectionFunction
;
functionCall
: #(METHOD_CALL {inFunctionCall=true;} pathAsIdent ( #(EXPR_LIST (exprOrSubquery)* ) )? ) {
: #(METHOD_CALL {inFunctionCall=true;} pathAsIdent ( #(EXPR_LIST (exprOrSubquery [ null ])* ) )? ) {
processFunction( #functionCall, inSelect );
inFunctionCall=false;
}
| #(CAST {inFunctionCall=true;} exprOrSubquery pathAsIdent) {
| #(CAST {inFunctionCall=true;} exprOrSubquery [ null ] pathAsIdent) {
processCastFunction( #functionCall, inSelect );
inFunctionCall=false;
}
@ -715,7 +718,7 @@ addrExpr! [ boolean root ]
#addrExpr = #(#d, #lhs, #rhs);
#addrExpr = lookupProperty(#addrExpr,root,false);
}
| #(i:INDEX_OP lhs2:addrExprLhs rhs2:expr) {
| #(i:INDEX_OP lhs2:addrExprLhs rhs2:expr [ null ]) {
#addrExpr = #(#i, #lhs2, #rhs2);
processIndex(#addrExpr);
}
@ -794,7 +797,7 @@ mapComponentReference
;
mapPropertyExpression
: e:expr {
: e:expr [ null ] {
validateMapPropertyExpression( #e );
}
;

View File

@ -1023,6 +1023,11 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
@Override
protected void resolve(AST node) throws SemanticException {
resolve(node, null);
}
@Override
protected void resolve(AST node, AST predicateNode) throws SemanticException {
if ( node != null ) {
// This is called when it's time to fully resolve a path expression.
ResolvableNode r = (ResolvableNode) node;
@ -1030,7 +1035,7 @@ public class HqlSqlWalker extends HqlSqlBaseWalker implements ErrorReporter, Par
r.resolveInFunctionCall( false, true );
}
else {
r.resolve( false, true ); // Generate implicit joins, only if necessary.
r.resolve( false, true, null, null, predicateNode ); // Generate implicit joins, only if necessary.
}
}
}

View File

@ -45,7 +45,8 @@ public abstract class AbstractMapComponentNode extends FromReferenceNode impleme
boolean generateJoin,
boolean implicitJoin,
String classAlias,
AST parent) throws SemanticException {
AST parent,
AST parentPredicate) throws SemanticException {
if ( mapFromElement == null ) {
final FromReferenceNode mapReference = getMapReference();
mapReference.resolve( true, true );

View File

@ -194,7 +194,7 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec
dereferenceCollection( (CollectionType) propertyType, true, true, null, parent );
}
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent)
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent, AST parentPredicate)
throws SemanticException {
// If this dot has already been resolved, stop now.
if ( isResolved() ) {
@ -227,7 +227,7 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec
else if ( propertyType.isEntityType() ) {
// The property is another class..
checkLhsIsNotCollection();
dereferenceEntity( (EntityType) propertyType, implicitJoin, classAlias, generateJoin, parent );
dereferenceEntity( (EntityType) propertyType, implicitJoin, classAlias, generateJoin, parent, parentPredicate );
initText();
}
else if ( propertyType.isCollectionType() ) {
@ -361,7 +361,8 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec
boolean implicitJoin,
String classAlias,
boolean generateJoin,
AST parent) throws SemanticException {
AST parent,
AST parentPredicate) throws SemanticException {
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
@ -403,6 +404,10 @@ public class DotNode extends FromReferenceNode implements DisplayableNode, Selec
// this is the regression style determination which matches the logic of the classic translator
joinIsNeeded = generateJoin && ( !getWalker().isInSelect() || !getWalker().isShallowQuery() );
}
else if ( parentPredicate != null ) {
// Never generate a join when we compare entities directly
joinIsNeeded = generateJoin;
}
else {
joinIsNeeded = generateJoin || ( getWalker().isInSelect() || getWalker().isInFrom() );
}

View File

@ -109,6 +109,11 @@ public abstract class FromReferenceNode extends AbstractSelectExpression
resolve( generateJoin, implicitJoin, classAlias, null );
}
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent)
throws SemanticException {
resolve( generateJoin, implicitJoin, classAlias, parent, null );
}
public void prepareForDot(String propertyName) throws SemanticException {
}

View File

@ -102,7 +102,7 @@ public class IdentNode extends FromReferenceNode implements SelectExpression {
setText( text );
}
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent) {
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent, AST parentPredicate) {
if (!isResolved()) {
if ( getWalker().getCurrentFromClause().isFromElementAlias( getText() ) ) {
FromElement fromElement = getWalker().getCurrentFromClause().getFromElement( getText() );

View File

@ -65,7 +65,7 @@ public class IndexNode extends FromReferenceNode {
}
@Override
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent)
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent, AST parentPredicate)
throws SemanticException {
if ( isResolved() ) {
return;

View File

@ -65,11 +65,12 @@ public class MapEntryNode extends AbstractMapComponentNode implements Aggregated
boolean generateJoin,
boolean implicitJoin,
String classAlias,
AST parent) throws SemanticException {
AST parent,
AST parentPredicate) throws SemanticException {
if (parent != null) {
throw new SemanticException( expressionDescription() + " expression cannot be further de-referenced" );
}
super.resolve(generateJoin, implicitJoin, classAlias, parent);
super.resolve(generateJoin, implicitJoin, classAlias, parent, parentPredicate);
}
@Override

View File

@ -17,15 +17,19 @@ public interface ResolvableNode {
/**
* Does the work of resolving an identifier or a dot
*/
void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent, AST parentPredicate) throws SemanticException;
/**
* Does the work of resolving an identifier or a dot, but without a parent predicate node
*/
void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent) throws SemanticException;
/**
* Does the work of resolving an identifier or a dot, but without a parent node
* Does the work of resolving an identifier or a dot, but without a parent predicate node or parent node
*/
void resolve(boolean generateJoin, boolean implicitJoin, String classAlias) throws SemanticException;
/**
* Does the work of resolving an identifier or a dot, but without a parent node or alias
* Does the work of resolving an identifier or a dot, but without a parent predicate node or parent node or alias
*/
void resolve(boolean generateJoin, boolean implicitJoin) throws SemanticException;

View File

@ -24,7 +24,7 @@ public class SelectExpressionImpl extends FromReferenceNode implements SelectExp
setText( text );
}
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent) throws SemanticException {
public void resolve(boolean generateJoin, boolean implicitJoin, String classAlias, AST parent, AST parentPredicate) throws SemanticException {
// Generated select expressions are already resolved, nothing to do.
return;
}