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,
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;
* 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.
* 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;
}