aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRobert Haas <rhaas@postgresql.org>2018-03-19 11:54:56 -0400
committerRobert Haas <rhaas@postgresql.org>2018-03-19 11:54:56 -0400
commit49525c46309828b3024fe8040fa99c7dcc83933d (patch)
tree3ea53d1e00c5086c094309fa6e93851a88fef894
parent71cce90ee99098f52e65278b96662e32ca005771 (diff)
downloadpostgresql-49525c46309828b3024fe8040fa99c7dcc83933d.tar.gz
postgresql-49525c46309828b3024fe8040fa99c7dcc83933d.zip
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
-rw-r--r--src/backend/optimizer/prep/prepunion.c100
1 files changed, 47 insertions, 53 deletions
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index b586f941a86..f3873872891 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;
}