Beispiel #1
0
/*
 * 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;
}
Beispiel #2
0
/*
 * Pull up children of a UNION node that are identically-propertied UNIONs.
 *
 * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
 * output rows will be lost anyway.
 */
static List *
recurse_union_children(Node *setOp, PlannerInfo *root,
					   double tuple_fraction,
					   SetOperationStmt *top_union,
					   List *refnames_tlist)
{
	List	   *child_sortclauses;

	if (IsA(setOp, SetOperationStmt))
	{
		SetOperationStmt *op = (SetOperationStmt *) setOp;

		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's subplan list */
			return list_concat(recurse_union_children(op->larg, root,
													  tuple_fraction,
													  top_union,
													  refnames_tlist),
							   recurse_union_children(op->rarg, root,
													  tuple_fraction,
													  top_union,
													  refnames_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.
	 */
	return list_make1(recurse_set_operations(setOp, root,
											 tuple_fraction,
											 top_union->colTypes, false,
											 -1, refnames_tlist,
											 &child_sortclauses));
}
Beispiel #3
0
/*
 * Pull up children of a UNION node that are identically-propertied UNIONs.
 *
 * NOTE: we can also pull a UNION ALL up into a UNION, since the distinct
 * output rows will be lost anyway.
 */
static List *
recurse_union_children(Node *setOp, Query *parse,
                       SetOperationStmt *top_union,
                       List *refnames_tlist)
{
    if (IsA(setOp, SetOperationStmt))
    {
        SetOperationStmt *op = (SetOperationStmt *) setOp;

        if (op->op == top_union->op &&
                (op->all == top_union->all || op->all) &&
                equalo(op->colTypes, top_union->colTypes))
        {
            /* Same UNION, so fold children into parent's subplan list */
            return nconc(recurse_union_children(op->larg, parse,
                                                top_union,
                                                refnames_tlist),
                         recurse_union_children(op->rarg, parse,
                                                top_union,
                                                refnames_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.
     */
    return makeList1(recurse_set_operations(setOp, parse,
                                            top_union->colTypes, false,
                                            -1, refnames_tlist));
}
Beispiel #4
0
/*
 * 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;
}