Commit 49525c46 authored by Robert Haas's avatar Robert Haas

Rewrite recurse_union_children to iterate, rather than recurse.

Also, rename it to plan_union_chidren, so the old name wasn't
very descriptive.  This results in a small net reduction in code,
seems at least to me to be easier to understand, and saves
space on the process stack.

Patch by me, reviewed and tested by Ashutosh Bapat and Rajkumar
Raghuwanshi.

Discussion: http://postgr.es/m/CA+TgmoaLRAOqHmMZx=ESM3VDEPceg+-XXZsRXQ8GtFJO_zbMSw@mail.gmail.com
parent 71cce90e
......@@ -78,10 +78,10 @@ static Path *generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
List *refnames_tlist,
List **pTargetList,
double *pNumGroups);
static List *recurse_union_children(Node *setOp, PlannerInfo *root,
SetOperationStmt *top_union,
List *refnames_tlist,
List **tlist_list);
static List *plan_union_children(PlannerInfo *root,
SetOperationStmt *top_union,
List *refnames_tlist,
List **tlist_list);
static Path *make_union_unique(SetOperationStmt *op, Path *path, List *tlist,
PlannerInfo *root);
static bool choose_hashed_setop(PlannerInfo *root, List *groupClauses,
......@@ -545,8 +545,6 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
RelOptInfo *result_rel = fetch_upper_rel(root, UPPERREL_SETOP, NULL);
double save_fraction = root->tuple_fraction;
List *pathlist;
List *child_tlists1;
List *child_tlists2;
List *tlist_list;
List *tlist;
Path *path;
......@@ -571,13 +569,7 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
* only one Append and unique-ification for the lot. Recurse to find such
* nodes and compute their children's paths.
*/
pathlist = list_concat(recurse_union_children(op->larg, root,
op, refnames_tlist,
&child_tlists1),
recurse_union_children(op->rarg, root,
op, refnames_tlist,
&child_tlists2));
tlist_list = list_concat(child_tlists1, child_tlists2);
pathlist = plan_union_children(root, op, refnames_tlist, &tlist_list);
/*
* Generate tlist for Append plan node.
......@@ -797,56 +789,58 @@ generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
* generate_union_path will force a fresh sort if the top level is a UNION.
*/
static List *
recurse_union_children(Node *setOp, PlannerInfo *root,
SetOperationStmt *top_union,
List *refnames_tlist,
List **tlist_list)
plan_union_children(PlannerInfo *root,
SetOperationStmt *top_union,
List *refnames_tlist,
List **tlist_list)
{
List *result;
List *pending_rels = list_make1(top_union);
List *result = NIL;
List *child_tlist;
if (IsA(setOp, SetOperationStmt))
*tlist_list = NIL;
while (pending_rels != NIL)
{
SetOperationStmt *op = (SetOperationStmt *) setOp;
Node *setOp = linitial(pending_rels);
pending_rels = list_delete_first(pending_rels);
if (op->op == top_union->op &&
(op->all == top_union->all || op->all) &&
equal(op->colTypes, top_union->colTypes))
if (IsA(setOp, SetOperationStmt))
{
/* Same UNION, so fold children into parent's subpath list */
List *child_tlists1;
List *child_tlists2;
SetOperationStmt *op = (SetOperationStmt *) setOp;
result = list_concat(recurse_union_children(op->larg, root,
top_union,
refnames_tlist,
&child_tlists1),
recurse_union_children(op->rarg, root,
top_union,
refnames_tlist,
&child_tlists2));
*tlist_list = list_concat(child_tlists1, child_tlists2);
return result;
if (op->op == top_union->op &&
(op->all == top_union->all || op->all) &&
equal(op->colTypes, top_union->colTypes))
{
/* Same UNION, so fold children into parent */
pending_rels = lcons(op->rarg, pending_rels);
pending_rels = lcons(op->larg, pending_rels);
continue;
}
}
/*
* Not same, so plan this child separately.
*
* Note we disallow any resjunk columns in child results. This is
* necessary since the Append node that implements the union won't do
* any projection, and upper levels will get confused if some of our
* output tuples have junk and some don't. This case only arises when
* we have an EXCEPT or INTERSECT as child, else there won't be
* resjunk anyway.
*/
result = lappend(result, recurse_set_operations(setOp, root,
top_union->colTypes,
top_union->colCollations,
false, -1,
refnames_tlist,
&child_tlist,
NULL));
*tlist_list = lappend(*tlist_list, child_tlist);
}
/*
* Not same, so plan this child separately.
*
* Note we disallow any resjunk columns in child results. This is
* necessary since the Append node that implements the union won't do any
* projection, and upper levels will get confused if some of our output
* tuples have junk and some don't. This case only arises when we have an
* EXCEPT or INTERSECT as child, else there won't be resjunk anyway.
*/
result = list_make1(recurse_set_operations(setOp, root,
top_union->colTypes,
top_union->colCollations,
false, -1,
refnames_tlist,
&child_tlist,
NULL));
*tlist_list = list_make1(child_tlist);
return result;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment