/* * Generate plan for a UNION or UNION ALL node */ static Plan * generate_union_plan(SetOperationStmt *op, Query *parse, List *refnames_tlist) { List *planlist; List *tlist; Plan *plan; /* * If any of my children are identical UNION nodes (same op, all-flag, * and colTypes) then they can be merged into this node so that we * generate only one Append and Sort for the lot. Recurse to find * such nodes and compute their children's plans. */ planlist = nconc(recurse_union_children(op->larg, parse, op, refnames_tlist), recurse_union_children(op->rarg, parse, op, refnames_tlist)); /* * Generate tlist for Append plan node. * * The tlist for an Append plan isn't important as far as the Append is * concerned, but we must make it look real anyway for the benefit of * the next plan level up. */ tlist = generate_append_tlist(op->colTypes, false, planlist, refnames_tlist); /* * Append the child results together. */ plan = (Plan *) make_append(planlist, false, tlist); /* * For UNION ALL, we just need the Append plan. For UNION, need to * add Sort and Unique nodes to produce unique output. */ if (!op->all) { List *sortList; tlist = copyObject(tlist); sortList = addAllTargetsToSortList(NULL, NIL, tlist, false); plan = (Plan *) make_sort_from_sortclauses(parse, tlist, plan, sortList); plan = (Plan *) make_unique(tlist, plan, sortList); } return plan; }
/* * Generate plan for an INTERSECT, INTERSECT ALL, EXCEPT, or EXCEPT ALL node */ static Plan * generate_nonunion_plan(SetOperationStmt *op, Query *parse, List *refnames_tlist) { Plan *lplan, *rplan, *plan; List *tlist, *sortList, *planlist; SetOpCmd cmd; /* Recurse on children, ensuring their outputs are marked */ lplan = recurse_set_operations(op->larg, parse, op->colTypes, false, 0, refnames_tlist); rplan = recurse_set_operations(op->rarg, parse, op->colTypes, false, 1, refnames_tlist); planlist = makeList2(lplan, rplan); /* * Generate tlist for Append plan node. * * The tlist for an Append plan isn't important as far as the Append is * concerned, but we must make it look real anyway for the benefit of * the next plan level up. In fact, it has to be real enough that the * flag column is shown as a variable not a constant, else setrefs.c * will get confused. */ tlist = generate_append_tlist(op->colTypes, true, planlist, refnames_tlist); /* * Append the child results together. */ plan = (Plan *) make_append(planlist, false, tlist); /* * Sort the child results, then add a SetOp plan node to generate the * correct output. */ tlist = copyObject(tlist); sortList = addAllTargetsToSortList(NULL, NIL, tlist, false); plan = (Plan *) make_sort_from_sortclauses(parse, tlist, plan, sortList); switch (op->op) { case SETOP_INTERSECT: cmd = op->all ? SETOPCMD_INTERSECT_ALL : SETOPCMD_INTERSECT; break; case SETOP_EXCEPT: cmd = op->all ? SETOPCMD_EXCEPT_ALL : SETOPCMD_EXCEPT; break; default: elog(ERROR, "unrecognized set op: %d", (int) op->op); cmd = SETOPCMD_INTERSECT; /* keep compiler quiet */ break; } plan = (Plan *) make_setop(cmd, tlist, plan, sortList, length(op->colTypes) + 1); return plan; }
/* * Generate plan for a UNION or UNION ALL node */ static Plan * generate_union_plan(SetOperationStmt *op, PlannerInfo *root, double tuple_fraction, List *refnames_tlist, List **sortClauses) { List *planlist; List *tlist; Plan *plan; /* * If plain UNION, tell children to fetch all tuples. * * Note: in UNION ALL, we pass the top-level tuple_fraction unmodified to * each arm of the UNION ALL. One could make a case for reducing the * tuple fraction for later arms (discounting by the expected size of the * earlier arms' results) but it seems not worth the trouble. The normal * case where tuple_fraction isn't already zero is a LIMIT at top level, * and passing it down as-is is usually enough to get the desired result * of preferring fast-start plans. */ if (!op->all) tuple_fraction = 0.0; /* * If any of my children are identical UNION nodes (same op, all-flag, and * colTypes) then they can be merged into this node so that we generate * only one Append and Sort for the lot. Recurse to find such nodes and * compute their children's plans. */ planlist = list_concat(recurse_union_children(op->larg, root, tuple_fraction, op, refnames_tlist), recurse_union_children(op->rarg, root, tuple_fraction, op, refnames_tlist)); /* * Generate tlist for Append plan node. * * The tlist for an Append plan isn't important as far as the Append is * concerned, but we must make it look real anyway for the benefit of the * next plan level up. */ tlist = generate_append_tlist(op->colTypes, false, planlist, refnames_tlist); /* * Append the child results together. */ plan = (Plan *) make_append(planlist, false, tlist); /* * For UNION ALL, we just need the Append plan. For UNION, need to add * Sort and Unique nodes to produce unique output. */ if (!op->all) { List *sortList; sortList = addAllTargetsToSortList(NULL, NIL, tlist, false); if (sortList) { plan = (Plan *) make_sort_from_sortclauses(root, sortList, plan); plan = (Plan *) make_unique(plan, sortList); } *sortClauses = sortList; } else *sortClauses = NIL; return plan; }