Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,21 @@ class CXformApply2Join : public CXformExploration

COperator::EOperatorId op_id = pexprApply->Pop()->Eopid();

// An outer Apply introduced below a grouping operation for EXISTS or
// a quantified subquery can have a multi-row inner input. If
// decorrelation fails, it cannot be implemented as a scalar SubPlan:
// the grouping above it does not enforce scalar cardinality below it.
// Keep scalar correlated execution only when the inner input is
// proven to return at most one row. SubqueryUnnest also generates a
// correlated alternative directly from the original subquery.
if (COperator::EopLogicalLeftOuterApply == op_id &&
COperator::EopScalarSubquery ==
CLogicalApply::PopConvert(pexprApply->Pop())->EopidOriginSubq() &&
1 < (*pexprApply)[1]->DeriveMaxCard().Ull())
{
return false;
}

// consider only Inner/Outer/Left (Anti) Semi Apply here,
// correlated left anti semi apply (with ALL/NOT-IN semantics) can only be generated by SubqueryHandler
return COperator::EopLogicalInnerApply == op_id ||
Expand Down
64 changes: 58 additions & 6 deletions src/backend/optimizer/plan/orca.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
#include "optimizer/planner.h"
#include "optimizer/tlist.h"
#include "optimizer/transform.h"
#include "optimizer/walkers.h"
#include "parser/parse_collate.h"
#include "parser/parsetree.h"
#include "rewrite/rewriteManip.h"
Expand All @@ -52,6 +53,7 @@ extern PlannedStmt * GPOPTOptimizedPlan(Query *parse, bool *had_unexpected_failu
static Plan *remove_redundant_results(PlannerInfo *root, Plan *plan);
static Node *remove_redundant_results_mutator(Node *node, void *);
static bool can_replace_tlist(Plan *plan);
static bool preserves_subplans(List *old_tlist, List *new_tlist);
static Node *push_down_expr_mutator(Node *node, List *child_tlist);

/*
Expand Down Expand Up @@ -453,11 +455,12 @@ remove_redundant_results_mutator(Node *node, void *ctx)
!expression_returns_set((Node *) result_plan->plan.targetlist) &&
can_replace_tlist(child_plan))
{
List *tlist = result_plan->plan.targetlist;
List *tlist = copyObject(result_plan->plan.targetlist);
ListCell *lc;

child_plan = (Plan *)
remove_redundant_results_mutator((Node *) child_plan, ctx);
result_plan->plan.lefttree = child_plan;

foreach(lc, tlist)
{
Expand All @@ -467,6 +470,24 @@ remove_redundant_results_mutator(Node *node, void *ctx)
child_plan->targetlist);
}

/*
* The slice table has already been built. Dropping a SubPlan
* reference here can leave its Motion slices without an executable
* plan tree. Keep the Result unless all child SubPlans survive.
*/
if (!preserves_subplans(child_plan->targetlist, tlist))
{
/*
* The child was already processed above. Process the Result's
* target list here so that SubPlans retained by the Result are
* processed too, without descending into the child a second time.
*/
result_plan->plan.targetlist = (List *)
remove_redundant_results_mutator(
(Node *) result_plan->plan.targetlist, ctx);
return node;
Comment thread
Alena0704 marked this conversation as resolved.
Resolved
}

child_plan->targetlist = tlist;
child_plan->flow = result_plan->plan.flow;

Expand All @@ -480,6 +501,34 @@ remove_redundant_results_mutator(Node *node, void *ctx)
true);
}

/* Allow projection folding when it retains every referenced SubPlan. */
static bool
preserves_subplans(List *old_tlist, List *new_tlist)
{
List *old_subplans;
List *new_subplans;
ListCell *lc;
Bitmapset *remaining = NULL;
bool preserved;

if (!contain_subplans((Node *) old_tlist))
return true;

old_subplans = extract_nodes_expression((Node *) old_tlist, T_SubPlan, false);
new_subplans = new_tlist ?
extract_nodes_expression((Node *) new_tlist, T_SubPlan, false) : NIL;
foreach(lc, old_subplans)
remaining = bms_add_member(remaining, ((SubPlan *) lfirst(lc))->plan_id);
foreach(lc, new_subplans)
remaining = bms_del_member(remaining, ((SubPlan *) lfirst(lc))->plan_id);

preserved = bms_is_empty(remaining);
bms_free(remaining);
list_free(old_subplans);
list_free(new_subplans);
return preserved;
}

/*
* Can the target list of a Plan node safely be replaced?
*/
Expand Down Expand Up @@ -541,20 +590,23 @@ push_down_expr_mutator(Node *node, List *child_tlist)
{
TargetEntry *child_tle = (TargetEntry *)
list_nth(child_tlist, var->varattno - 1);
Expr *expr = copyObject(child_tle->expr);

/* Do not change the child if the proposed replacement is rejected. */
// The const expr pertatining to a column in a child result node
// has const.consttypmod set as default value.
// correct typmod can be found at var.vartypmod.
// const.consttypmod value needs to be fixed before replacing var with const.
if (IsA(child_tle->expr, Const))
if (IsA(expr, Const))
{
((Const *) child_tle->expr)->consttypmod = ((Var *) node)->vartypmod;
((Const *) expr)->consttypmod = var->vartypmod;
}
else if (IsA(child_tle->expr, Var))
else if (IsA(expr, Var))
{
((Var *) child_tle->expr)->vartypmod = ((Var *) node)->vartypmod;
((Var *) expr)->vartypmod = var->vartypmod;
}

return (Node *) child_tle->expr;
return (Node *) expr;
}
}
return expression_tree_mutator(node, push_down_expr_mutator, child_tlist);
Expand Down
Loading
Loading