From 19a7ad8b89d9a1fc11c105343bde9e01df31a204 Mon Sep 17 00:00:00 2001 From: Robert Haas Date: Fri, 23 Feb 2018 12:13:46 -0500 Subject: [PATCH 3/5] 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. --- src/backend/optimizer/prep/prepunion.c | 100 ++++++++++++++++----------------- 1 file changed, 47 insertions(+), 53 deletions(-) diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index b586f941a8..f387387289 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -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; } -- 2.14.3 (Apple Git-98)