prototype_de_correlate_subqueries
Onder Kalaci 2018-05-18 09:55:18 +03:00
parent a16f0f0fe1
commit cdbd9e079f
1 changed files with 126 additions and 23 deletions

View File

@ -230,6 +230,8 @@ GenerateSubplansForSubqueriesAndCTEs(uint64 planId, Query *originalQuery,
static bool ShouldDeCorrelateSubqueries(Query *query, RecursivePlanningContext *context); static bool ShouldDeCorrelateSubqueries(Query *query, RecursivePlanningContext *context);
static void ExamineSublinks(Node *quals, RecursivePlanningContext *context); static void ExamineSublinks(Node *quals, RecursivePlanningContext *context);
static bool SublinkSafeToDeCorrelate(SubLink *sublink); static bool SublinkSafeToDeCorrelate(SubLink *sublink);
static Expr * ColumnMatchExpressionAtTopLevelConjunction(Node *node, Var *column);
static bool SimpleJoinExpression(Expr *clause);
/* /*
* RecursivelyPlanSubqueriesAndCTEs finds subqueries and CTEs that cannot be pushed down to * RecursivelyPlanSubqueriesAndCTEs finds subqueries and CTEs that cannot be pushed down to
@ -371,36 +373,46 @@ ExamineSublinks(Node *node, RecursivePlanningContext *context)
elog(INFO, "exists sublink found for de corrolation"); elog(INFO, "exists sublink found for de corrolation");
Query *subselect = (Query *) sublink->subselect; Query *subselect = (Query *) sublink->subselect;
List *varList = pull_vars_of_level(subselect->jointree->quals, 1); List *varList = pull_vars_of_level(subselect->jointree->quals, 1);
ListCell *varCell = NULL;
/* foreach(varCell, varList)
* What we actually need to do is to fetch the necessary {
* expression and operate on that. Var *v = (Var *) lfirst(varCell);
*/ Var *secondVar = NULL;
Expr *expr =
ColumnMatchExpressionAtTopLevelConjunction(
subselect->jointree->quals, v);
subselect->jointree->quals = NULL;
sublink->subLinkType = ANY_SUBLINK; subselect->jointree->quals = NULL;
/* sublink->operName = list_make1("="); */
Var *v = linitial(varList);
v->varlevelsup -= 1; sublink->subLinkType = ANY_SUBLINK;
Param *p = makeNode(Param);
p = makeNode(Param); v->varlevelsup -= 1;
p->paramkind = PARAM_EXEC; Param *p = makeNode(Param);
p->paramid = 10000;
p->paramtype = v->vartype;
p->paramtypmod = v->vartypmod;
p->paramcollid = v->varcollid;
p->location = v->location;
sublink->testexpr = (Node *) make_opclause(670, 16, false, (Expr *) v, p = makeNode(Param);
(Expr *) p, 0, 0); p->paramkind = PARAM_EXEC;
TargetEntry *tList = makeTargetEntry((Expr *) copyObject(v), 1, "col", p->paramid = 10000;
false); p->paramtype = v->vartype;
subselect->targetList = list_make1(tList); p->paramtypmod = v->vartypmod;
p->paramcollid = v->varcollid;
p->location = v->location;
RecursivelyPlanSubquery(subselect, context); if (equal(get_leftop(expr), v))
secondVar = (Var *) get_rightop(expr);
else
secondVar = (Var *) get_leftop(expr);
sublink->testexpr = (Node *) make_opclause(670, 16, false, (Expr *) v,
(Expr *) p, 0, 0);
TargetEntry *tList = makeTargetEntry((Expr *) copyObject(secondVar), 1, "col",
false);
subselect->targetList = list_make1(tList);
RecursivelyPlanSubquery(subselect, context);
}
} }
} }
} }
@ -457,6 +469,97 @@ ExamineSublinks(Node *node, RecursivePlanningContext *context)
} }
/*
* ColumnMatchExpressionAtTopLevelConjunction returns true if the query contains an exact
* match (equal) expression on the provided column. The function returns true only
* if the match expression has an AND relation with the rest of the expression tree.
*/
static Expr *
ColumnMatchExpressionAtTopLevelConjunction(Node *node, Var *column)
{
if (node == NULL)
{
return NULL;
}
if (IsA(node, OpExpr))
{
OpExpr *opExpr = (OpExpr *) node;
bool simpleExpression = SimpleJoinExpression((Expr *) opExpr);
bool columnInExpr = false;
if (!simpleExpression)
{
return NULL;
}
columnInExpr = OpExpressionContainsColumn(opExpr, column);
if (!columnInExpr)
{
return NULL;
}
return (Expr *) opExpr;
}
else if (IsA(node, BoolExpr))
{
BoolExpr *boolExpr = (BoolExpr *) node;
List *argumentList = boolExpr->args;
ListCell *argumentCell = NULL;
/* handling OR or NOT EXPRs seems hard for now */
if (boolExpr->boolop != AND_EXPR)
{
return NULL;
}
foreach(argumentCell, argumentList)
{
Node *argumentNode = (Node *) lfirst(argumentCell);
Expr *columnExpr =
ColumnMatchExpressionAtTopLevelConjunction(argumentNode, column);
if (columnExpr)
{
return columnExpr;
}
}
}
return NULL;
}
static bool
SimpleJoinExpression(Expr *clause)
{
Node *leftOperand = NULL;
Node *rightOperand = NULL;
Const *constantClause = NULL;
if (is_opclause(clause) && list_length(((OpExpr *) clause)->args) == 2)
{
leftOperand = get_leftop(clause);
rightOperand = get_rightop(clause);
}
else
{
return false; /* not a binary opclause */
}
/* strip coercions before doing check */
leftOperand = strip_implicit_coercions(leftOperand);
rightOperand = strip_implicit_coercions(rightOperand);
if (IsA(rightOperand, Var) && IsA(leftOperand, Var))
{
return true;
}
return false;
}
static bool static bool
SublinkSafeToDeCorrelate(SubLink *sublink) SublinkSafeToDeCorrelate(SubLink *sublink)
{ {