diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2000-11-12 00:37:02 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2000-11-12 00:37:02 +0000 |
commit | 6543d81d659f4176c6530fb09eef83deede264a0 (patch) | |
tree | c1dd2a57ee5e640214978ae72e8e7b2f624f8972 /src/backend/optimizer/plan/createplan.c | |
parent | 609f9199af2411a52bb9731d8aa1f13885c439b5 (diff) | |
download | postgresql-6543d81d659f4176c6530fb09eef83deede264a0.tar.gz postgresql-6543d81d659f4176c6530fb09eef83deede264a0.zip |
Restructure handling of inheritance queries so that they work with outer
joins, and clean things up a good deal at the same time. Append plan node
no longer hacks on rangetable at runtime --- instead, all child tables are
given their own RT entries during planning. Concept of multiple target
tables pushed up into execMain, replacing bug-prone implementation within
nodeAppend. Planner now supports generating Append plans for inheritance
sets either at the top of the plan (the old way) or at the bottom. Expanding
at the bottom is appropriate for tables used as sources, since they may
appear inside an outer join; but we must still expand at the top when the
target of an UPDATE or DELETE is an inheritance set, because we actually need
a different targetlist and junkfilter for each target table in that case.
Fortunately a target table can't be inside an outer join... Bizarre mutual
recursion between union_planner and prepunion.c is gone --- in fact,
union_planner doesn't really have much to do with union queries anymore,
so I renamed it grouping_planner.
Diffstat (limited to 'src/backend/optimizer/plan/createplan.c')
-rw-r--r-- | src/backend/optimizer/plan/createplan.c | 392 |
1 files changed, 230 insertions, 162 deletions
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index a865da61b92..4069ed66e58 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.99 2000/10/26 21:36:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/createplan.c,v 1.100 2000/11/12 00:36:58 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -32,35 +32,38 @@ #include "utils/syscache.h" -static List *switch_outer(List *clauses); -static Scan *create_scan_node(Query *root, Path *best_path, List *tlist); -static Join *create_join_node(Query *root, JoinPath *best_path, List *tlist); -static SeqScan *create_seqscan_node(Path *best_path, List *tlist, +static Scan *create_scan_plan(Query *root, Path *best_path); +static Join *create_join_plan(Query *root, JoinPath *best_path); +static Append *create_append_plan(Query *root, AppendPath *best_path); +static SeqScan *create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses); -static IndexScan *create_indexscan_node(Query *root, IndexPath *best_path, +static IndexScan *create_indexscan_plan(Query *root, IndexPath *best_path, List *tlist, List *scan_clauses); -static TidScan *create_tidscan_node(TidPath *best_path, List *tlist, +static TidScan *create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses); -static SubqueryScan *create_subqueryscan_node(Path *best_path, +static SubqueryScan *create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses); -static NestLoop *create_nestloop_node(NestPath *best_path, List *tlist, +static NestLoop *create_nestloop_plan(NestPath *best_path, List *tlist, List *joinclauses, List *otherclauses, - Plan *outer_node, List *outer_tlist, - Plan *inner_node, List *inner_tlist); -static MergeJoin *create_mergejoin_node(MergePath *best_path, List *tlist, + Plan *outer_plan, List *outer_tlist, + Plan *inner_plan, List *inner_tlist); +static MergeJoin *create_mergejoin_plan(MergePath *best_path, List *tlist, List *joinclauses, List *otherclauses, - Plan *outer_node, List *outer_tlist, - Plan *inner_node, List *inner_tlist); -static HashJoin *create_hashjoin_node(HashPath *best_path, List *tlist, + Plan *outer_plan, List *outer_tlist, + Plan *inner_plan, List *inner_tlist); +static HashJoin *create_hashjoin_plan(HashPath *best_path, List *tlist, List *joinclauses, List *otherclauses, - Plan *outer_node, List *outer_tlist, - Plan *inner_node, List *inner_tlist); + Plan *outer_plan, List *outer_tlist, + Plan *inner_plan, List *inner_tlist); static List *fix_indxqual_references(List *indexquals, IndexPath *index_path); static List *fix_indxqual_sublist(List *indexqual, int baserelid, Oid relam, Form_pg_index index); static Node *fix_indxqual_operand(Node *node, int baserelid, Form_pg_index index, Oid *opclass); +static List *switch_outer(List *clauses); +static void copy_path_costsize(Plan *dest, Path *src); +static void copy_plan_costsize(Plan *dest, Plan *src); static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid); static IndexScan *make_indexscan(List *qptlist, List *qpqual, Index scanrelid, List *indxid, List *indxqual, @@ -83,7 +86,6 @@ static MergeJoin *make_mergejoin(List *tlist, List *mergeclauses, Plan *lefttree, Plan *righttree, JoinType jointype); -static void copy_path_costsize(Plan *dest, Path *src); /* * create_plan @@ -98,13 +100,12 @@ static void copy_path_costsize(Plan *dest, Path *src); * * best_path is the best access path * - * Returns the access plan. + * Returns a Plan tree. */ Plan * create_plan(Query *root, Path *best_path) { - List *tlist = best_path->parent->targetlist; - Plan *plan_node = (Plan *) NULL; + Plan *plan; switch (best_path->pathtype) { @@ -112,18 +113,22 @@ create_plan(Query *root, Path *best_path) case T_SeqScan: case T_TidScan: case T_SubqueryScan: - plan_node = (Plan *) create_scan_node(root, best_path, tlist); + plan = (Plan *) create_scan_plan(root, best_path); break; case T_HashJoin: case T_MergeJoin: case T_NestLoop: - plan_node = (Plan *) create_join_node(root, - (JoinPath *) best_path, - tlist); + plan = (Plan *) create_join_plan(root, + (JoinPath *) best_path); + break; + case T_Append: + plan = (Plan *) create_append_plan(root, + (AppendPath *) best_path); break; default: elog(ERROR, "create_plan: unknown pathtype %d", best_path->pathtype); + plan = NULL; /* keep compiler quiet */ break; } @@ -131,30 +136,29 @@ create_plan(Query *root, Path *best_path) /* sort clauses by cost/(1-selectivity) -- JMH 2/26/92 */ if (XfuncMode != XFUNC_OFF) { - set_qpqual((Plan) plan_node, - lisp_qsort(get_qpqual((Plan) plan_node), + set_qpqual((Plan) plan, + lisp_qsort(get_qpqual((Plan) plan), xfunc_clause_compare)); if (XfuncMode != XFUNC_NOR) /* sort the disjuncts within each clause by cost -- JMH 3/4/92 */ - xfunc_disjunct_sort(plan_node->qpqual); + xfunc_disjunct_sort(plan->qpqual); } #endif - return plan_node; + return plan; } /* - * create_scan_node - * Create a scan path for the parent relation of 'best_path'. + * create_scan_plan + * Create a scan plan for the parent relation of 'best_path'. * - * tlist is the targetlist for the base relation scanned by 'best_path' - * - * Returns the scan node. + * Returns a Plan node. */ static Scan * -create_scan_node(Query *root, Path *best_path, List *tlist) +create_scan_plan(Query *root, Path *best_path) { - Scan *node = NULL; + Scan *plan; + List *tlist = best_path->parent->targetlist; List *scan_clauses; /* @@ -166,65 +170,64 @@ create_scan_node(Query *root, Path *best_path, List *tlist) switch (best_path->pathtype) { case T_SeqScan: - node = (Scan *) create_seqscan_node(best_path, + plan = (Scan *) create_seqscan_plan(best_path, tlist, scan_clauses); break; case T_IndexScan: - node = (Scan *) create_indexscan_node(root, + plan = (Scan *) create_indexscan_plan(root, (IndexPath *) best_path, tlist, scan_clauses); break; case T_TidScan: - node = (Scan *) create_tidscan_node((TidPath *) best_path, + plan = (Scan *) create_tidscan_plan((TidPath *) best_path, tlist, scan_clauses); break; case T_SubqueryScan: - node = (Scan *) create_subqueryscan_node(best_path, + plan = (Scan *) create_subqueryscan_plan(best_path, tlist, scan_clauses); break; default: - elog(ERROR, "create_scan_node: unknown node type: %d", + elog(ERROR, "create_scan_plan: unknown node type: %d", best_path->pathtype); + plan = NULL; /* keep compiler quiet */ break; } - return node; + return plan; } /* - * create_join_node - * Create a join path for 'best_path' and(recursively) paths for its + * create_join_plan + * Create a join plan for 'best_path' and (recursively) plans for its * inner and outer paths. * - * 'tlist' is the targetlist for the join relation corresponding to - * 'best_path' - * - * Returns the join node. + * Returns a Plan node. */ static Join * -create_join_node(Query *root, JoinPath *best_path, List *tlist) +create_join_plan(Query *root, JoinPath *best_path) { - Plan *outer_node; + List *join_tlist = best_path->path.parent->targetlist; + Plan *outer_plan; List *outer_tlist; - Plan *inner_node; + Plan *inner_plan; List *inner_tlist; List *joinclauses; List *otherclauses; - Join *retval = NULL; + Join *plan; - outer_node = create_plan(root, best_path->outerjoinpath); - outer_tlist = outer_node->targetlist; + outer_plan = create_plan(root, best_path->outerjoinpath); + outer_tlist = outer_plan->targetlist; - inner_node = create_plan(root, best_path->innerjoinpath); - inner_tlist = inner_node->targetlist; + inner_plan = create_plan(root, best_path->innerjoinpath); + inner_tlist = inner_plan->targetlist; if (IS_OUTER_JOIN(best_path->jointype)) { @@ -241,38 +244,40 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist) switch (best_path->path.pathtype) { case T_MergeJoin: - retval = (Join *) create_mergejoin_node((MergePath *) best_path, - tlist, - joinclauses, - otherclauses, - outer_node, - outer_tlist, - inner_node, - inner_tlist); + plan = (Join *) create_mergejoin_plan((MergePath *) best_path, + join_tlist, + joinclauses, + otherclauses, + outer_plan, + outer_tlist, + inner_plan, + inner_tlist); break; case T_HashJoin: - retval = (Join *) create_hashjoin_node((HashPath *) best_path, - tlist, - joinclauses, - otherclauses, - outer_node, - outer_tlist, - inner_node, - inner_tlist); + plan = (Join *) create_hashjoin_plan((HashPath *) best_path, + join_tlist, + joinclauses, + otherclauses, + outer_plan, + outer_tlist, + inner_plan, + inner_tlist); break; case T_NestLoop: - retval = (Join *) create_nestloop_node((NestPath *) best_path, - tlist, - joinclauses, - otherclauses, - outer_node, - outer_tlist, - inner_node, - inner_tlist); + plan = (Join *) create_nestloop_plan((NestPath *) best_path, + join_tlist, + joinclauses, + otherclauses, + outer_plan, + outer_tlist, + inner_plan, + inner_tlist); break; default: - elog(ERROR, "create_join_node: unknown node type: %d", + elog(ERROR, "create_join_plan: unknown node type: %d", best_path->path.pathtype); + plan = NULL; /* keep compiler quiet */ + break; } #ifdef NOT_USED @@ -283,14 +288,42 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist) * JMH, 6/15/92 */ if (get_loc_restrictinfo(best_path) != NIL) - set_qpqual((Plan) retval, - nconc(get_qpqual((Plan) retval), + set_qpqual((Plan) plan, + nconc(get_qpqual((Plan) plan), get_actual_clauses(get_loc_restrictinfo(best_path)))); #endif - return retval; + return plan; } +/* + * create_append_plan + * Create an Append plan for 'best_path' and (recursively) plans + * for its subpaths. + * + * Returns a Plan node. + */ +static Append * +create_append_plan(Query *root, AppendPath *best_path) +{ + Append *plan; + List *tlist = best_path->path.parent->targetlist; + List *subplans = NIL; + List *subpaths; + + foreach(subpaths, best_path->subpaths) + { + Path *subpath = (Path *) lfirst(subpaths); + + subplans = lappend(subplans, create_plan(root, subpath)); + } + + plan = make_append(subplans, false, tlist); + + return plan; +} + + /***************************************************************************** * * BASE-RELATION SCAN METHODS @@ -299,14 +332,14 @@ create_join_node(Query *root, JoinPath *best_path, List *tlist) /* - * create_seqscan_node - * Returns a seqscan node for the base relation scanned by 'best_path' + * create_seqscan_plan + * Returns a seqscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */ static SeqScan * -create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses) +create_seqscan_plan(Path *best_path, List *tlist, List *scan_clauses) { - SeqScan *scan_node; + SeqScan *scan_plan; Index scan_relid; /* there should be exactly one base rel involved... */ @@ -315,18 +348,18 @@ create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses) scan_relid = (Index) lfirsti(best_path->parent->relids); - scan_node = make_seqscan(tlist, + scan_plan = make_seqscan(tlist, scan_clauses, scan_relid); - copy_path_costsize(&scan_node->plan, best_path); + copy_path_costsize(&scan_plan->plan, best_path); - return scan_node; + return scan_plan; } /* - * create_indexscan_node - * Returns a indexscan node for the base relation scanned by 'best_path' + * create_indexscan_plan + * Returns a indexscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. * * The indexqual of the path contains a sublist of implicitly-ANDed qual @@ -338,7 +371,7 @@ create_seqscan_node(Path *best_path, List *tlist, List *scan_clauses) * scan. */ static IndexScan * -create_indexscan_node(Query *root, +create_indexscan_plan(Query *root, IndexPath *best_path, List *tlist, List *scan_clauses) @@ -348,7 +381,7 @@ create_indexscan_node(Query *root, List *qpqual; List *fixed_indxqual; List *ixid; - IndexScan *scan_node; + IndexScan *scan_plan; bool lossy = false; /* there should be exactly one base rel involved... */ @@ -433,7 +466,7 @@ create_indexscan_node(Query *root, */ fixed_indxqual = fix_indxqual_references(indxqual, best_path); - scan_node = make_indexscan(tlist, + scan_plan = make_indexscan(tlist, qpqual, baserelid, best_path->indexid, @@ -441,22 +474,22 @@ create_indexscan_node(Query *root, indxqual, best_path->indexscandir); - copy_path_costsize(&scan_node->scan.plan, &best_path->path); + copy_path_costsize(&scan_plan->scan.plan, &best_path->path); /* use the indexscan-specific rows estimate, not the parent rel's */ - scan_node->scan.plan.plan_rows = best_path->rows; + scan_plan->scan.plan.plan_rows = best_path->rows; - return scan_node; + return scan_plan; } /* - * create_tidscan_node - * Returns a tidscan node for the base relation scanned by 'best_path' + * create_tidscan_plan + * Returns a tidscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */ static TidScan * -create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses) +create_tidscan_plan(TidPath *best_path, List *tlist, List *scan_clauses) { - TidScan *scan_node; + TidScan *scan_plan; Index scan_relid; /* there should be exactly one base rel involved... */ @@ -465,28 +498,28 @@ create_tidscan_node(TidPath *best_path, List *tlist, List *scan_clauses) scan_relid = (Index) lfirsti(best_path->path.parent->relids); - scan_node = make_tidscan(tlist, + scan_plan = make_tidscan(tlist, scan_clauses, scan_relid, best_path->tideval); if (best_path->unjoined_relids) - scan_node->needRescan = true; + scan_plan->needRescan = true; - copy_path_costsize(&scan_node->scan.plan, &best_path->path); + copy_path_costsize(&scan_plan->scan.plan, &best_path->path); - return scan_node; + return scan_plan; } /* - * create_subqueryscan_node - * Returns a subqueryscan node for the base relation scanned by 'best_path' + * create_subqueryscan_plan + * Returns a subqueryscan plan for the base relation scanned by 'best_path' * with restriction clauses 'scan_clauses' and targetlist 'tlist'. */ static SubqueryScan * -create_subqueryscan_node(Path *best_path, List *tlist, List *scan_clauses) +create_subqueryscan_plan(Path *best_path, List *tlist, List *scan_clauses) { - SubqueryScan *scan_node; + SubqueryScan *scan_plan; Index scan_relid; /* there should be exactly one base rel involved... */ @@ -496,14 +529,12 @@ create_subqueryscan_node(Path *best_path, List *tlist, List *scan_clauses) scan_relid = (Index) lfirsti(best_path->parent->relids); - scan_node = make_subqueryscan(tlist, + scan_plan = make_subqueryscan(tlist, scan_clauses, scan_relid, best_path->parent->subplan); - copy_path_costsize(&scan_node->scan.plan, best_path); - - return scan_node; + return scan_plan; } /***************************************************************************** @@ -528,18 +559,18 @@ create_subqueryscan_node(Path *best_path, List *tlist, List *scan_clauses) *****************************************************************************/ static NestLoop * -create_nestloop_node(NestPath *best_path, +create_nestloop_plan(NestPath *best_path, List *tlist, List *joinclauses, List *otherclauses, - Plan *outer_node, + Plan *outer_plan, List *outer_tlist, - Plan *inner_node, + Plan *inner_plan, List *inner_tlist) { - NestLoop *join_node; + NestLoop *join_plan; - if (IsA(inner_node, IndexScan)) + if (IsA(inner_plan, IndexScan)) { /* @@ -563,7 +594,7 @@ create_nestloop_node(NestPath *best_path, * and therefore has not itself done join_references renumbering * of the vars in its quals. */ - IndexScan *innerscan = (IndexScan *) inner_node; + IndexScan *innerscan = (IndexScan *) inner_plan; List *indxqualorig = innerscan->indxqualorig; /* No work needed if indxqual refers only to its own relation... */ @@ -591,23 +622,23 @@ create_nestloop_node(NestPath *best_path, NIL, innerrel); /* fix the inner qpqual too, if it has join clauses */ - if (NumRelids((Node *) inner_node->qual) > 1) - inner_node->qual = join_references(inner_node->qual, + if (NumRelids((Node *) inner_plan->qual) > 1) + inner_plan->qual = join_references(inner_plan->qual, outer_tlist, NIL, innerrel); } } - else if (IsA(inner_node, TidScan)) + else if (IsA(inner_plan, TidScan)) { - TidScan *innerscan = (TidScan *) inner_node; + TidScan *innerscan = (TidScan *) inner_plan; innerscan->tideval = join_references(innerscan->tideval, outer_tlist, inner_tlist, innerscan->scan.scanrelid); } - else if (IsA_Join(inner_node)) + else if (IsA_Join(inner_plan)) { /* @@ -617,8 +648,8 @@ create_nestloop_node(NestPath *best_path, * join --- how can we estimate whether this is a good thing to * do? */ - inner_node = (Plan *) make_material(inner_tlist, - inner_node); + inner_plan = (Plan *) make_material(inner_tlist, + inner_plan); } /* @@ -633,30 +664,30 @@ create_nestloop_node(NestPath *best_path, inner_tlist, (Index) 0); - join_node = make_nestloop(tlist, + join_plan = make_nestloop(tlist, joinclauses, otherclauses, - outer_node, - inner_node, + outer_plan, + inner_plan, best_path->jointype); - copy_path_costsize(&join_node->join.plan, &best_path->path); + copy_path_costsize(&join_plan->join.plan, &best_path->path); - return join_node; + return join_plan; } static MergeJoin * -create_mergejoin_node(MergePath *best_path, +create_mergejoin_plan(MergePath *best_path, List *tlist, List *joinclauses, List *otherclauses, - Plan *outer_node, + Plan *outer_plan, List *outer_tlist, - Plan *inner_node, + Plan *inner_plan, List *inner_tlist) { List *mergeclauses; - MergeJoin *join_node; + MergeJoin *join_plan; mergeclauses = get_actual_clauses(best_path->path_mergeclauses); @@ -692,15 +723,15 @@ create_mergejoin_node(MergePath *best_path, * necessary. The sort cost was already accounted for in the path. */ if (best_path->outersortkeys) - outer_node = (Plan *) + outer_plan = (Plan *) make_sort_from_pathkeys(outer_tlist, - outer_node, + outer_plan, best_path->outersortkeys); if (best_path->innersortkeys) - inner_node = (Plan *) + inner_plan = (Plan *) make_sort_from_pathkeys(inner_tlist, - inner_node, + inner_plan, best_path->innersortkeys); /* @@ -723,7 +754,7 @@ create_mergejoin_node(MergePath *best_path, * This check must agree with ExecMarkPos/ExecRestrPos in * executor/execAmi.c! */ - switch (nodeTag(inner_node)) + switch (nodeTag(inner_plan)) { case T_SeqScan: case T_IndexScan: @@ -734,40 +765,40 @@ create_mergejoin_node(MergePath *best_path, default: /* Ooops, need to materialize the inner plan */ - inner_node = (Plan *) make_material(inner_tlist, - inner_node); + inner_plan = (Plan *) make_material(inner_tlist, + inner_plan); break; } /* * Now we can build the mergejoin node. */ - join_node = make_mergejoin(tlist, + join_plan = make_mergejoin(tlist, joinclauses, otherclauses, mergeclauses, - outer_node, - inner_node, + outer_plan, + inner_plan, best_path->jpath.jointype); - copy_path_costsize(&join_node->join.plan, &best_path->jpath.path); + copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path); - return join_node; + return join_plan; } static HashJoin * -create_hashjoin_node(HashPath *best_path, +create_hashjoin_plan(HashPath *best_path, List *tlist, List *joinclauses, List *otherclauses, - Plan *outer_node, + Plan *outer_plan, List *outer_tlist, - Plan *inner_node, + Plan *inner_plan, List *inner_tlist) { List *hashclauses; - HashJoin *join_node; - Hash *hash_node; + HashJoin *join_plan; + Hash *hash_plan; Node *innerhashkey; /* @@ -811,18 +842,18 @@ create_hashjoin_node(HashPath *best_path, /* * Build the hash node and hash join node. */ - hash_node = make_hash(inner_tlist, innerhashkey, inner_node); - join_node = make_hashjoin(tlist, + hash_plan = make_hash(inner_tlist, innerhashkey, inner_plan); + join_plan = make_hashjoin(tlist, joinclauses, otherclauses, hashclauses, - outer_node, - (Plan *) hash_node, + outer_plan, + (Plan *) hash_plan, best_path->jpath.jointype); - copy_path_costsize(&join_node->join.plan, &best_path->jpath.path); + copy_path_costsize(&join_plan->join.plan, &best_path->jpath.path); - return join_node; + return join_plan; } @@ -1106,7 +1137,7 @@ copy_path_costsize(Plan *dest, Path *src) * but it helps produce more reasonable-looking EXPLAIN output. * (Some callers alter the info after copying it.) */ -void +static void copy_plan_costsize(Plan *dest, Plan *src) { if (src) @@ -1128,6 +1159,10 @@ copy_plan_costsize(Plan *dest, Plan *src) /***************************************************************************** * + * PLAN NODE BUILDING ROUTINES + * + * Some of these are exported because they are called to build plan nodes + * in contexts where we're not deriving the plan node from a path node. * *****************************************************************************/ @@ -1212,7 +1247,7 @@ make_subqueryscan(List *qptlist, SubqueryScan *node = makeNode(SubqueryScan); Plan *plan = &node->scan.plan; - /* cost should be inserted by caller */ + copy_plan_costsize(plan, subplan); plan->state = (EState *) NULL; plan->targetlist = qptlist; plan->qual = qpqual; @@ -1225,6 +1260,39 @@ make_subqueryscan(List *qptlist, return node; } +Append * +make_append(List *appendplans, bool isTarget, List *tlist) +{ + Append *node = makeNode(Append); + Plan *plan = &node->plan; + List *subnode; + + /* compute costs from subplan costs */ + plan->startup_cost = 0; + plan->total_cost = 0; + plan->plan_rows = 0; + plan->plan_width = 0; + foreach(subnode, appendplans) + { + Plan *subplan = (Plan *) lfirst(subnode); + + if (subnode == appendplans) /* first node? */ + plan->startup_cost = subplan->startup_cost; + plan->total_cost += subplan->total_cost; + plan->plan_rows += subplan->plan_rows; + if (plan->plan_width < subplan->plan_width) + plan->plan_width = subplan->plan_width; + } + plan->state = (EState *) NULL; + plan->targetlist = tlist; + plan->qual = NIL; + plan->lefttree = NULL; + plan->righttree = NULL; + node->appendplans = appendplans; + node->isTarget = isTarget; + + return node; +} static NestLoop * make_nestloop(List *tlist, |