From b3aaf9081a1a95c245fd605dcf02c91b3a5c3a29 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Sat, 3 Sep 2011 15:35:12 -0400 Subject: [PATCH] Rearrange planner to save the whole PlannerInfo (subroot) for a subquery. Formerly, set_subquery_pathlist and other creators of plans for subqueries saved only the rangetable and rowMarks lists from the lower-level PlannerInfo. But there's no reason not to remember the whole PlannerInfo, and indeed this turns out to simplify matters in a number of places. The immediate reason for doing this was so that the subroot will still be accessible when we're trying to extract column statistics out of an already-planned subquery. But now that I've done it, it seems like a good code-beautification effort in its own right. I also chose to get rid of the transient subrtable and subrowmark fields in SubqueryScan nodes, in favor of having setrefs.c look up the subquery's RelOptInfo. That required changing all the APIs in setrefs.c to pass PlannerInfo not PlannerGlobal, which was a large but quite mechanical transformation. One side-effect not foreseen at the beginning is that this finally broke inheritance_planner's assumption that replanning the same subquery RTE N times would necessarily give interchangeable results each time. That assumption was always pretty risky, but now we really have to make a separate RTE for each instance so that there's a place to carry the separate subroots. --- src/backend/executor/nodeSubqueryscan.c | 7 +- src/backend/nodes/copyfuncs.c | 2 - src/backend/nodes/outfuncs.c | 8 +- src/backend/optimizer/path/allpaths.c | 5 +- src/backend/optimizer/path/costsize.c | 4 +- src/backend/optimizer/plan/createplan.c | 10 +- src/backend/optimizer/plan/planmain.c | 20 +- src/backend/optimizer/plan/planner.c | 198 ++++++++++++----- src/backend/optimizer/plan/setrefs.c | 278 ++++++++++++------------ src/backend/optimizer/plan/subselect.c | 34 +-- src/backend/optimizer/prep/prepunion.c | 30 ++- src/backend/optimizer/util/clauses.c | 17 +- src/backend/optimizer/util/relnode.c | 35 ++- src/backend/rewrite/rewriteManip.c | 16 ++ src/include/nodes/plannodes.h | 6 - src/include/nodes/relation.h | 12 +- src/include/optimizer/cost.h | 3 +- src/include/optimizer/pathnode.h | 1 + src/include/optimizer/planmain.h | 12 +- 19 files changed, 394 insertions(+), 304 deletions(-) diff --git a/src/backend/executor/nodeSubqueryscan.c b/src/backend/executor/nodeSubqueryscan.c index 04cdab9fa1..7e4d5de38b 100644 --- a/src/backend/executor/nodeSubqueryscan.c +++ b/src/backend/executor/nodeSubqueryscan.c @@ -99,14 +99,9 @@ ExecInitSubqueryScan(SubqueryScan *node, EState *estate, int eflags) /* check for unsupported flags */ Assert(!(eflags & EXEC_FLAG_MARK)); - /* - * SubqueryScan should not have any "normal" children. Also, if planner - * left anything in subrtable/subrowmark, it's fishy. - */ + /* SubqueryScan should not have any "normal" children */ Assert(outerPlan(node) == NULL); Assert(innerPlan(node) == NULL); - Assert(node->subrtable == NIL); - Assert(node->subrowmark == NIL); /* * create state structure diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index afc1c61876..661a5162e6 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -456,8 +456,6 @@ _copySubqueryScan(SubqueryScan *from) * copy remainder of node */ COPY_NODE_FIELD(subplan); - COPY_NODE_FIELD(subrtable); - COPY_NODE_FIELD(subrowmark); return newnode; } diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 93ab08a7d7..88cde3956c 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -489,8 +489,6 @@ _outSubqueryScan(StringInfo str, SubqueryScan *node) _outScanInfo(str, (Scan *) node); WRITE_NODE_FIELD(subplan); - WRITE_NODE_FIELD(subrtable); - WRITE_NODE_FIELD(subrowmark); } static void @@ -1656,8 +1654,7 @@ _outPlannerGlobal(StringInfo str, PlannerGlobal *node) /* NB: this isn't a complete set of fields */ WRITE_NODE_FIELD(paramlist); WRITE_NODE_FIELD(subplans); - WRITE_NODE_FIELD(subrtables); - WRITE_NODE_FIELD(subrowmarks); + WRITE_NODE_FIELD(subroots); WRITE_BITMAPSET_FIELD(rewindPlanIDs); WRITE_NODE_FIELD(finalrtable); WRITE_NODE_FIELD(finalrowmarks); @@ -1734,8 +1731,7 @@ _outRelOptInfo(StringInfo str, RelOptInfo *node) WRITE_UINT_FIELD(pages); WRITE_FLOAT_FIELD(tuples, "%.0f"); WRITE_NODE_FIELD(subplan); - WRITE_NODE_FIELD(subrtable); - WRITE_NODE_FIELD(subrowmark); + WRITE_NODE_FIELD(subroot); WRITE_NODE_FIELD(baserestrictinfo); WRITE_NODE_FIELD(joininfo); WRITE_BOOL_FIELD(has_eclass_joins); diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index a14b809a14..b421481828 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -791,11 +791,10 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, root, false, tuple_fraction, &subroot); - rel->subrtable = subroot->parse->rtable; - rel->subrowmark = subroot->rowMarks; + rel->subroot = subroot; /* Mark rel with estimated output rows, width, etc */ - set_subquery_size_estimates(root, rel, subroot); + set_subquery_size_estimates(root, rel); /* Convert subquery pathkeys to outer representation */ pathkeys = convert_subquery_pathkeys(root, rel, subroot->query_pathkeys); diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c index c853bd8dcb..7812a8628f 100644 --- a/src/backend/optimizer/path/costsize.c +++ b/src/backend/optimizer/path/costsize.c @@ -3221,9 +3221,9 @@ set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel, * We set the same fields as set_baserel_size_estimates. */ void -set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel, - PlannerInfo *subroot) +set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel) { + PlannerInfo *subroot = rel->subroot; RangeTblEntry *rte; ListCell *lc; diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index a3a82ec123..b674afe426 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -1557,9 +1557,7 @@ create_subqueryscan_plan(PlannerInfo *root, Path *best_path, scan_plan = make_subqueryscan(tlist, scan_clauses, scan_relid, - best_path->parent->subplan, - best_path->parent->subrtable, - best_path->parent->subrowmark); + best_path->parent->subplan); copy_path_costsize(&scan_plan->scan.plan, best_path); @@ -2931,9 +2929,7 @@ SubqueryScan * make_subqueryscan(List *qptlist, List *qpqual, Index scanrelid, - Plan *subplan, - List *subrtable, - List *subrowmark) + Plan *subplan) { SubqueryScan *node = makeNode(SubqueryScan); Plan *plan = &node->scan.plan; @@ -2952,8 +2948,6 @@ make_subqueryscan(List *qptlist, plan->righttree = NULL; node->scan.scanrelid = scanrelid; node->subplan = subplan; - node->subrtable = subrtable; - node->subrowmark = subrowmark; return node; } diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index ff39d5754d..55311058e5 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -98,7 +98,6 @@ query_planner(PlannerInfo *root, List *tlist, Path *cheapestpath; Path *sortedpath; Index rti; - ListCell *lc; double total_pages; /* Make tuple_fraction, limit_tuples accessible to lower-level routines */ @@ -128,15 +127,11 @@ query_planner(PlannerInfo *root, List *tlist, } /* - * Init planner lists to empty, and set up the array to hold RelOptInfos - * for "simple" rels. + * Init planner lists to empty. * * NOTE: append_rel_list was set up by subquery_planner, so do not touch * here; eq_classes and minmax_aggs may contain data already, too. */ - root->simple_rel_array_size = list_length(parse->rtable) + 1; - root->simple_rel_array = (RelOptInfo **) - palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *)); root->join_rel_list = NIL; root->join_rel_hash = NULL; root->join_rel_level = NULL; @@ -151,17 +146,10 @@ query_planner(PlannerInfo *root, List *tlist, /* * Make a flattened version of the rangetable for faster access (this is - * OK because the rangetable won't change any more). + * OK because the rangetable won't change any more), and set up an + * empty array for indexing base relations. */ - root->simple_rte_array = (RangeTblEntry **) - palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *)); - rti = 1; - foreach(lc, parse->rtable) - { - RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); - - root->simple_rte_array[rti++] = rte; - } + setup_simple_rel_arrays(root); /* * Construct RelOptInfo nodes for all base relations in query, and diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 484d44108e..64b5eb4d9c 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -21,6 +21,9 @@ #include "executor/nodeAgg.h" #include "miscadmin.h" #include "nodes/makefuncs.h" +#ifdef OPTIMIZER_DEBUG +#include "nodes/print.h" +#endif #include "optimizer/clauses.h" #include "optimizer/cost.h" #include "optimizer/pathnode.h" @@ -31,11 +34,9 @@ #include "optimizer/prep.h" #include "optimizer/subselect.h" #include "optimizer/tlist.h" -#ifdef OPTIMIZER_DEBUG -#include "nodes/print.h" -#endif #include "parser/analyze.h" #include "parser/parsetree.h" +#include "rewrite/rewriteManip.h" #include "utils/rel.h" @@ -135,8 +136,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) PlannerInfo *root; Plan *top_plan; ListCell *lp, - *lrt, - *lrm; + *lr; /* Cursor options may come from caller or from DECLARE CURSOR stmt */ if (parse->utilityStmt && @@ -154,8 +154,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) glob->boundParams = boundParams; glob->paramlist = NIL; glob->subplans = NIL; - glob->subrtables = NIL; - glob->subrowmarks = NIL; + glob->subroots = NIL; glob->rewindPlanIDs = NULL; glob->finalrtable = NIL; glob->finalrowmarks = NIL; @@ -212,24 +211,15 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) Assert(glob->finalrtable == NIL); Assert(glob->finalrowmarks == NIL); Assert(glob->resultRelations == NIL); - top_plan = set_plan_references(glob, top_plan, - root->parse->rtable, - root->rowMarks); + top_plan = set_plan_references(root, top_plan); /* ... and the subplans (both regular subplans and initplans) */ - Assert(list_length(glob->subplans) == list_length(glob->subrtables)); - Assert(list_length(glob->subplans) == list_length(glob->subrowmarks)); - lrt = list_head(glob->subrtables); - lrm = list_head(glob->subrowmarks); - foreach(lp, glob->subplans) + Assert(list_length(glob->subplans) == list_length(glob->subroots)); + forboth(lp, glob->subplans, lr, glob->subroots) { Plan *subplan = (Plan *) lfirst(lp); - List *subrtable = (List *) lfirst(lrt); - List *subrowmark = (List *) lfirst(lrm); + PlannerInfo *subroot = (PlannerInfo *) lfirst(lr); - lfirst(lp) = set_plan_references(glob, subplan, - subrtable, subrowmark); - lrt = lnext(lrt); - lrm = lnext(lrm); + lfirst(lp) = set_plan_references(subroot, subplan); } /* build the PlannedStmt result */ @@ -550,7 +540,7 @@ subquery_planner(PlannerGlobal *glob, Query *parse, List *rlist; Assert(parse->resultRelation); - rlist = set_returning_clause_references(root->glob, + rlist = set_returning_clause_references(root, parse->returningList, plan, parse->resultRelation); @@ -735,55 +725,164 @@ inheritance_planner(PlannerInfo *root) { Query *parse = root->parse; int parentRTindex = parse->resultRelation; + List *final_rtable = NIL; + int save_rel_array_size = 0; + RelOptInfo **save_rel_array = NULL; List *subplans = NIL; List *resultRelations = NIL; List *returningLists = NIL; - List *rtable = NIL; List *rowMarks; - List *tlist; - PlannerInfo subroot; - ListCell *l; + ListCell *lc; - foreach(l, root->append_rel_list) + /* + * We generate a modified instance of the original Query for each target + * relation, plan that, and put all the plans into a list that will be + * controlled by a single ModifyTable node. All the instances share the + * same rangetable, but each instance must have its own set of subquery + * RTEs within the finished rangetable because (1) they are likely to get + * scribbled on during planning, and (2) it's not inconceivable that + * subqueries could get planned differently in different cases. We need + * not create duplicate copies of other RTE kinds, in particular not the + * target relations, because they don't have either of those issues. Not + * having to duplicate the target relations is important because doing so + * (1) would result in a rangetable of length O(N^2) for N targets, with + * at least O(N^3) work expended here; and (2) would greatly complicate + * management of the rowMarks list. + */ + foreach(lc, root->append_rel_list) { - AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l); + AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(lc); + PlannerInfo subroot; Plan *subplan; + Index rti; /* append_rel_list contains all append rels; ignore others */ if (appinfo->parent_relid != parentRTindex) continue; /* - * Generate modified query with this rel as target. + * We need a working copy of the PlannerInfo so that we can control + * propagation of information back to the main copy. */ memcpy(&subroot, root, sizeof(PlannerInfo)); + + /* + * Generate modified query with this rel as target. We first apply + * adjust_appendrel_attrs, which copies the Query and changes + * references to the parent RTE to refer to the current child RTE, + * then fool around with subquery RTEs. + */ subroot.parse = (Query *) adjust_appendrel_attrs((Node *) parse, appinfo); - subroot.init_plans = NIL; - subroot.hasInheritedTarget = true; + + /* + * The rowMarks list might contain references to subquery RTEs, so + * make a copy that we can apply ChangeVarNodes to. (Fortunately, + * the executor doesn't need to see the modified copies --- we can + * just pass it the original rowMarks list.) + */ + subroot.rowMarks = (List *) copyObject(root->rowMarks); + + /* + * Add placeholders to the child Query's rangetable list to fill the + * RT indexes already reserved for subqueries in previous children. + * These won't be referenced, so there's no need to make them very + * valid-looking. + */ + while (list_length(subroot.parse->rtable) < list_length(final_rtable)) + subroot.parse->rtable = lappend(subroot.parse->rtable, + makeNode(RangeTblEntry)); + + /* + * If this isn't the first child Query, generate duplicates of all + * subquery RTEs, and adjust Var numbering to reference the duplicates. + * To simplify the loop logic, we scan the original rtable not the + * copy just made by adjust_appendrel_attrs; that should be OK since + * subquery RTEs couldn't contain any references to the target rel. + */ + if (final_rtable != NIL) + { + ListCell *lr; + + rti = 1; + foreach(lr, parse->rtable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(lr); + + if (rte->rtekind == RTE_SUBQUERY) + { + Index newrti; + + /* + * The RTE can't contain any references to its own RT + * index, so we can save a few cycles by applying + * ChangeVarNodes before we append the RTE to the + * rangetable. + */ + newrti = list_length(subroot.parse->rtable) + 1; + ChangeVarNodes((Node *) subroot.parse, rti, newrti, 0); + ChangeVarNodes((Node *) subroot.rowMarks, rti, newrti, 0); + rte = copyObject(rte); + subroot.parse->rtable = lappend(subroot.parse->rtable, + rte); + } + rti++; + } + } + /* We needn't modify the child's append_rel_list */ /* There shouldn't be any OJ info to translate, as yet */ Assert(subroot.join_info_list == NIL); /* and we haven't created PlaceHolderInfos, either */ Assert(subroot.placeholder_list == NIL); + /* build a separate list of initplans for each child */ + subroot.init_plans = NIL; + /* hack to mark target relation as an inheritance partition */ + subroot.hasInheritedTarget = true; /* Generate plan */ subplan = grouping_planner(&subroot, 0.0 /* retrieve all tuples */ ); /* * If this child rel was excluded by constraint exclusion, exclude it - * from the plan. + * from the result plan. */ if (is_dummy_plan(subplan)) continue; - /* Save rtable from first rel for use below */ - if (subplans == NIL) - rtable = subroot.parse->rtable; - subplans = lappend(subplans, subplan); + /* + * If this is the first non-excluded child, its post-planning rtable + * becomes the initial contents of final_rtable; otherwise, append + * just its modified subquery RTEs to final_rtable. + */ + if (final_rtable == NIL) + final_rtable = subroot.parse->rtable; + else + final_rtable = list_concat(final_rtable, + list_copy_tail(subroot.parse->rtable, + list_length(final_rtable))); + + /* + * We need to collect all the RelOptInfos from all child plans into + * the main PlannerInfo, since setrefs.c will need them. We use the + * last child's simple_rel_array (previous ones are too short), so we + * have to propagate forward the RelOptInfos that were already built + * in previous children. + */ + Assert(subroot.simple_rel_array_size >= save_rel_array_size); + for (rti = 1; rti < save_rel_array_size; rti++) + { + RelOptInfo *brel = save_rel_array[rti]; + + if (brel) + subroot.simple_rel_array[rti] = brel; + } + save_rel_array_size = subroot.simple_rel_array_size; + save_rel_array = subroot.simple_rel_array; + /* Make sure any initplans from this rel get into the outer list */ root->init_plans = list_concat(root->init_plans, subroot.init_plans); @@ -795,7 +894,7 @@ inheritance_planner(PlannerInfo *root) { List *rlist; - rlist = set_returning_clause_references(root->glob, + rlist = set_returning_clause_references(&subroot, subroot.parse->returningList, subplan, appinfo->child_relid); @@ -813,6 +912,8 @@ inheritance_planner(PlannerInfo *root) if (subplans == NIL) { /* although dummy, it must have a valid tlist for executor */ + List *tlist; + tlist = preprocess_targetlist(root, parse->targetList); return (Plan *) make_result(root, tlist, @@ -822,17 +923,11 @@ inheritance_planner(PlannerInfo *root) } /* - * Planning might have modified the rangetable, due to changes of the - * Query structures inside subquery RTEs. We have to ensure that this - * gets propagated back to the master copy. But can't do this until we - * are done planning, because all the calls to grouping_planner need - * virgin sub-Queries to work from. (We are effectively assuming that - * sub-Queries will get planned identically each time, or at least that - * the impacts on their rangetables will be the same each time.) - * - * XXX should clean this up someday + * Put back the final adjusted rtable into the master copy of the Query. */ - parse->rtable = rtable; + parse->rtable = final_rtable; + root->simple_rel_array_size = save_rel_array_size; + root->simple_rel_array = save_rel_array; /* * If there was a FOR UPDATE/SHARE clause, the LockRows node will have @@ -3149,13 +3244,8 @@ plan_cluster_use_sort(Oid tableOid, Oid indexOid) rte->inFromCl = true; query->rtable = list_make1(rte); - /* ... and insert it into PlannerInfo */ - root->simple_rel_array_size = 2; - root->simple_rel_array = (RelOptInfo **) - palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *)); - root->simple_rte_array = (RangeTblEntry **) - palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *)); - root->simple_rte_array[1] = rte; + /* Set up RTE/RelOptInfo arrays */ + setup_simple_rel_arrays(root); /* Build RelOptInfo */ rel = build_simple_rel(root, 1, RELOPT_BASEREL); diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index 8508d25316..d60163379b 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -20,6 +20,7 @@ #include "catalog/pg_type.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" +#include "optimizer/pathnode.h" #include "optimizer/planmain.h" #include "optimizer/tlist.h" #include "utils/lsyscache.h" @@ -45,13 +46,13 @@ typedef struct typedef struct { - PlannerGlobal *glob; + PlannerInfo *root; int rtoffset; } fix_scan_expr_context; typedef struct { - PlannerGlobal *glob; + PlannerInfo *root; indexed_tlist *outer_itlist; indexed_tlist *inner_itlist; Index acceptable_rel; @@ -60,7 +61,7 @@ typedef struct typedef struct { - PlannerGlobal *glob; + PlannerInfo *root; indexed_tlist *subplan_itlist; int rtoffset; } fix_upper_expr_context; @@ -76,19 +77,19 @@ typedef struct (((con)->consttype == REGCLASSOID || (con)->consttype == OIDOID) && \ !(con)->constisnull) -#define fix_scan_list(glob, lst, rtoffset) \ - ((List *) fix_scan_expr(glob, (Node *) (lst), rtoffset)) +#define fix_scan_list(root, lst, rtoffset) \ + ((List *) fix_scan_expr(root, (Node *) (lst), rtoffset)) -static Plan *set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset); -static Plan *set_subqueryscan_references(PlannerGlobal *glob, +static Plan *set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset); +static Plan *set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset); static bool trivial_subqueryscan(SubqueryScan *plan); -static Node *fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset); +static Node *fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset); static Node *fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context); static bool fix_scan_expr_walker(Node *node, fix_scan_expr_context *context); -static void set_join_references(PlannerGlobal *glob, Join *join, int rtoffset); -static void set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset); +static void set_join_references(PlannerInfo *root, Join *join, int rtoffset); +static void set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset); static void set_dummy_tlist_references(Plan *plan, int rtoffset); static indexed_tlist *build_tlist_index(List *tlist); static Var *search_indexed_tlist_for_var(Var *var, @@ -102,14 +103,14 @@ static Var *search_indexed_tlist_for_sortgroupref(Node *node, Index sortgroupref, indexed_tlist *itlist, Index newvarno); -static List *fix_join_expr(PlannerGlobal *glob, +static List *fix_join_expr(PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, Index acceptable_rel, int rtoffset); static Node *fix_join_expr_mutator(Node *node, fix_join_expr_context *context); -static Node *fix_upper_expr(PlannerGlobal *glob, +static Node *fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int rtoffset); @@ -117,7 +118,7 @@ static Node *fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context); static bool fix_opfuncids_walker(Node *node, void *context); static bool extract_query_dependencies_walker(Node *node, - PlannerGlobal *context); + PlannerInfo *context); /***************************************************************************** @@ -163,20 +164,14 @@ static bool extract_query_dependencies_walker(Node *node, * * set_plan_references recursively traverses the whole plan tree. * - * Inputs: - * glob: global data for planner run - * plan: the topmost node of the plan - * rtable: the rangetable for the current subquery - * rowmarks: the PlanRowMark list for the current subquery - * * The return value is normally the same Plan node passed in, but can be * different when the passed-in Plan is a SubqueryScan we decide isn't needed. * - * The flattened rangetable entries are appended to glob->finalrtable. - * Also, rowmarks entries are appended to glob->finalrowmarks, and the - * RT indexes of ModifyTable result relations to glob->resultRelations. - * Plan dependencies are appended to glob->relationOids (for relations) - * and glob->invalItems (for everything else). + * The flattened rangetable entries are appended to root->glob->finalrtable. + * Also, rowmarks entries are appended to root->glob->finalrowmarks, and the + * RT indexes of ModifyTable result relations to root->glob->resultRelations. + * Plan dependencies are appended to root->glob->relationOids (for relations) + * and root->glob->invalItems (for everything else). * * Notice that we modify Plan nodes in-place, but use expression_tree_mutator * to process targetlist and qual expressions. We can assume that the Plan @@ -184,9 +179,9 @@ static bool extract_query_dependencies_walker(Node *node, * it's not so safe to assume that for expression tree nodes. */ Plan * -set_plan_references(PlannerGlobal *glob, Plan *plan, - List *rtable, List *rowmarks) +set_plan_references(PlannerInfo *root, Plan *plan) { + PlannerGlobal *glob = root->glob; int rtoffset = list_length(glob->finalrtable); ListCell *lc; @@ -198,7 +193,7 @@ set_plan_references(PlannerGlobal *glob, Plan *plan, * which are needed for executor-startup permissions checking and for * trigger event checking. */ - foreach(lc, rtable) + foreach(lc, root->parse->rtable) { RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); RangeTblEntry *newrte; @@ -242,7 +237,7 @@ set_plan_references(PlannerGlobal *glob, Plan *plan, /* * Adjust RT indexes of PlanRowMarks and add to final rowmarks list */ - foreach(lc, rowmarks) + foreach(lc, root->rowMarks) { PlanRowMark *rc = (PlanRowMark *) lfirst(lc); PlanRowMark *newrc; @@ -261,14 +256,14 @@ set_plan_references(PlannerGlobal *glob, Plan *plan, } /* Now fix the Plan tree */ - return set_plan_refs(glob, plan, rtoffset); + return set_plan_refs(root, plan, rtoffset); } /* * set_plan_refs: recurse through the Plan nodes of a single subquery level */ static Plan * -set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) +set_plan_refs(PlannerInfo *root, Plan *plan, int rtoffset) { ListCell *l; @@ -286,9 +281,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) splan->scanrelid += rtoffset; splan->plan.targetlist = - fix_scan_list(glob, splan->plan.targetlist, rtoffset); + fix_scan_list(root, splan->plan.targetlist, rtoffset); splan->plan.qual = - fix_scan_list(glob, splan->plan.qual, rtoffset); + fix_scan_list(root, splan->plan.qual, rtoffset); } break; case T_IndexScan: @@ -297,17 +292,17 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) splan->scan.scanrelid += rtoffset; splan->scan.plan.targetlist = - fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset); + fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); splan->scan.plan.qual = - fix_scan_list(glob, splan->scan.plan.qual, rtoffset); + fix_scan_list(root, splan->scan.plan.qual, rtoffset); splan->indexqual = - fix_scan_list(glob, splan->indexqual, rtoffset); + fix_scan_list(root, splan->indexqual, rtoffset); splan->indexqualorig = - fix_scan_list(glob, splan->indexqualorig, rtoffset); + fix_scan_list(root, splan->indexqualorig, rtoffset); splan->indexorderby = - fix_scan_list(glob, splan->indexorderby, rtoffset); + fix_scan_list(root, splan->indexorderby, rtoffset); splan->indexorderbyorig = - fix_scan_list(glob, splan->indexorderbyorig, rtoffset); + fix_scan_list(root, splan->indexorderbyorig, rtoffset); } break; case T_BitmapIndexScan: @@ -319,9 +314,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) Assert(splan->scan.plan.targetlist == NIL); Assert(splan->scan.plan.qual == NIL); splan->indexqual = - fix_scan_list(glob, splan->indexqual, rtoffset); + fix_scan_list(root, splan->indexqual, rtoffset); splan->indexqualorig = - fix_scan_list(glob, splan->indexqualorig, rtoffset); + fix_scan_list(root, splan->indexqualorig, rtoffset); } break; case T_BitmapHeapScan: @@ -330,11 +325,11 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) splan->scan.scanrelid += rtoffset; splan->scan.plan.targetlist = - fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset); + fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); splan->scan.plan.qual = - fix_scan_list(glob, splan->scan.plan.qual, rtoffset); + fix_scan_list(root, splan->scan.plan.qual, rtoffset); splan->bitmapqualorig = - fix_scan_list(glob, splan->bitmapqualorig, rtoffset); + fix_scan_list(root, splan->bitmapqualorig, rtoffset); } break; case T_TidScan: @@ -343,16 +338,16 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) splan->scan.scanrelid += rtoffset; splan->scan.plan.targetlist = - fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset); + fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); splan->scan.plan.qual = - fix_scan_list(glob, splan->scan.plan.qual, rtoffset); + fix_scan_list(root, splan->scan.plan.qual, rtoffset); splan->tidquals = - fix_scan_list(glob, splan->tidquals, rtoffset); + fix_scan_list(root, splan->tidquals, rtoffset); } break; case T_SubqueryScan: /* Needs special treatment, see comments below */ - return set_subqueryscan_references(glob, + return set_subqueryscan_references(root, (SubqueryScan *) plan, rtoffset); case T_FunctionScan: @@ -361,11 +356,11 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) splan->scan.scanrelid += rtoffset; splan->scan.plan.targetlist = - fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset); + fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); splan->scan.plan.qual = - fix_scan_list(glob, splan->scan.plan.qual, rtoffset); + fix_scan_list(root, splan->scan.plan.qual, rtoffset); splan->funcexpr = - fix_scan_expr(glob, splan->funcexpr, rtoffset); + fix_scan_expr(root, splan->funcexpr, rtoffset); } break; case T_ValuesScan: @@ -374,11 +369,11 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) splan->scan.scanrelid += rtoffset; splan->scan.plan.targetlist = - fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset); + fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); splan->scan.plan.qual = - fix_scan_list(glob, splan->scan.plan.qual, rtoffset); + fix_scan_list(root, splan->scan.plan.qual, rtoffset); splan->values_lists = - fix_scan_list(glob, splan->values_lists, rtoffset); + fix_scan_list(root, splan->values_lists, rtoffset); } break; case T_CteScan: @@ -387,9 +382,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) splan->scan.scanrelid += rtoffset; splan->scan.plan.targetlist = - fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset); + fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); splan->scan.plan.qual = - fix_scan_list(glob, splan->scan.plan.qual, rtoffset); + fix_scan_list(root, splan->scan.plan.qual, rtoffset); } break; case T_WorkTableScan: @@ -398,9 +393,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) splan->scan.scanrelid += rtoffset; splan->scan.plan.targetlist = - fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset); + fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); splan->scan.plan.qual = - fix_scan_list(glob, splan->scan.plan.qual, rtoffset); + fix_scan_list(root, splan->scan.plan.qual, rtoffset); } break; case T_ForeignScan: @@ -409,16 +404,16 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) splan->scan.scanrelid += rtoffset; splan->scan.plan.targetlist = - fix_scan_list(glob, splan->scan.plan.targetlist, rtoffset); + fix_scan_list(root, splan->scan.plan.targetlist, rtoffset); splan->scan.plan.qual = - fix_scan_list(glob, splan->scan.plan.qual, rtoffset); + fix_scan_list(root, splan->scan.plan.qual, rtoffset); } break; case T_NestLoop: case T_MergeJoin: case T_HashJoin: - set_join_references(glob, (Join *) plan, rtoffset); + set_join_references(root, (Join *) plan, rtoffset); break; case T_Hash: @@ -477,20 +472,20 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) Assert(splan->plan.qual == NIL); splan->limitOffset = - fix_scan_expr(glob, splan->limitOffset, rtoffset); + fix_scan_expr(root, splan->limitOffset, rtoffset); splan->limitCount = - fix_scan_expr(glob, splan->limitCount, rtoffset); + fix_scan_expr(root, splan->limitCount, rtoffset); } break; case T_Agg: case T_Group: - set_upper_references(glob, plan, rtoffset); + set_upper_references(root, plan, rtoffset); break; case T_WindowAgg: { WindowAgg *wplan = (WindowAgg *) plan; - set_upper_references(glob, plan, rtoffset); + set_upper_references(root, plan, rtoffset); /* * Like Limit node limit/offset expressions, WindowAgg has @@ -498,9 +493,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) * variable refs, so fix_scan_expr works for them. */ wplan->startOffset = - fix_scan_expr(glob, wplan->startOffset, rtoffset); + fix_scan_expr(root, wplan->startOffset, rtoffset); wplan->endOffset = - fix_scan_expr(glob, wplan->endOffset, rtoffset); + fix_scan_expr(root, wplan->endOffset, rtoffset); } break; case T_Result: @@ -512,17 +507,17 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) * like a scan node than an upper node. */ if (splan->plan.lefttree != NULL) - set_upper_references(glob, plan, rtoffset); + set_upper_references(root, plan, rtoffset); else { splan->plan.targetlist = - fix_scan_list(glob, splan->plan.targetlist, rtoffset); + fix_scan_list(root, splan->plan.targetlist, rtoffset); splan->plan.qual = - fix_scan_list(glob, splan->plan.qual, rtoffset); + fix_scan_list(root, splan->plan.qual, rtoffset); } /* resconstantqual can't contain any subplan variable refs */ splan->resconstantqual = - fix_scan_expr(glob, splan->resconstantqual, rtoffset); + fix_scan_expr(root, splan->resconstantqual, rtoffset); } break; case T_ModifyTable: @@ -549,7 +544,7 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) } foreach(l, splan->plans) { - lfirst(l) = set_plan_refs(glob, + lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); } @@ -560,9 +555,9 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) * resultRelIndex to reflect their starting position in the * global list. */ - splan->resultRelIndex = list_length(glob->resultRelations); - glob->resultRelations = - list_concat(glob->resultRelations, + splan->resultRelIndex = list_length(root->glob->resultRelations); + root->glob->resultRelations = + list_concat(root->glob->resultRelations, list_copy(splan->resultRelations)); } break; @@ -578,7 +573,7 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) Assert(splan->plan.qual == NIL); foreach(l, splan->appendplans) { - lfirst(l) = set_plan_refs(glob, + lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); } @@ -596,7 +591,7 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) Assert(splan->plan.qual == NIL); foreach(l, splan->mergeplans) { - lfirst(l) = set_plan_refs(glob, + lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); } @@ -616,7 +611,7 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) Assert(splan->plan.qual == NIL); foreach(l, splan->bitmapplans) { - lfirst(l) = set_plan_refs(glob, + lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); } @@ -631,7 +626,7 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) Assert(splan->plan.qual == NIL); foreach(l, splan->bitmapplans) { - lfirst(l) = set_plan_refs(glob, + lfirst(l) = set_plan_refs(root, (Plan *) lfirst(l), rtoffset); } @@ -651,8 +646,8 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) * reference-adjustments bottom-up, then we would fail to match this * plan's var nodes against the already-modified nodes of the children. */ - plan->lefttree = set_plan_refs(glob, plan->lefttree, rtoffset); - plan->righttree = set_plan_refs(glob, plan->righttree, rtoffset); + plan->lefttree = set_plan_refs(root, plan->lefttree, rtoffset); + plan->righttree = set_plan_refs(root, plan->righttree, rtoffset); return plan; } @@ -665,19 +660,19 @@ set_plan_refs(PlannerGlobal *glob, Plan *plan, int rtoffset) * to do the normal processing on it. */ static Plan * -set_subqueryscan_references(PlannerGlobal *glob, +set_subqueryscan_references(PlannerInfo *root, SubqueryScan *plan, int rtoffset) { + RelOptInfo *rel; Plan *result; - /* First, recursively process the subplan */ - plan->subplan = set_plan_references(glob, plan->subplan, - plan->subrtable, plan->subrowmark); + /* Need to look up the subquery's RelOptInfo, since we need its subroot */ + rel = find_base_rel(root, plan->scan.scanrelid); + Assert(rel->subplan == plan->subplan); - /* subrtable/subrowmark are no longer needed in the plan tree */ - plan->subrtable = NIL; - plan->subrowmark = NIL; + /* Recursively process the subplan */ + plan->subplan = set_plan_references(rel->subroot, plan->subplan); if (trivial_subqueryscan(plan)) { @@ -720,9 +715,9 @@ set_subqueryscan_references(PlannerGlobal *glob, */ plan->scan.scanrelid += rtoffset; plan->scan.plan.targetlist = - fix_scan_list(glob, plan->scan.plan.targetlist, rtoffset); + fix_scan_list(root, plan->scan.plan.targetlist, rtoffset); plan->scan.plan.qual = - fix_scan_list(glob, plan->scan.plan.qual, rtoffset); + fix_scan_list(root, plan->scan.plan.qual, rtoffset); result = (Plan *) plan; } @@ -810,59 +805,59 @@ copyVar(Var *var) * * This is code that is common to all variants of expression-fixing. * We must look up operator opcode info for OpExpr and related nodes, - * add OIDs from regclass Const nodes into glob->relationOids, - * and add catalog TIDs for user-defined functions into glob->invalItems. + * add OIDs from regclass Const nodes into root->glob->relationOids, and + * add catalog TIDs for user-defined functions into root->glob->invalItems. * * We assume it's okay to update opcode info in-place. So this could possibly * scribble on the planner's input data structures, but it's OK. */ static void -fix_expr_common(PlannerGlobal *glob, Node *node) +fix_expr_common(PlannerInfo *root, Node *node) { /* We assume callers won't call us on a NULL pointer */ if (IsA(node, Aggref)) { - record_plan_function_dependency(glob, + record_plan_function_dependency(root, ((Aggref *) node)->aggfnoid); } else if (IsA(node, WindowFunc)) { - record_plan_function_dependency(glob, + record_plan_function_dependency(root, ((WindowFunc *) node)->winfnoid); } else if (IsA(node, FuncExpr)) { - record_plan_function_dependency(glob, + record_plan_function_dependency(root, ((FuncExpr *) node)->funcid); } else if (IsA(node, OpExpr)) { set_opfuncid((OpExpr *) node); - record_plan_function_dependency(glob, + record_plan_function_dependency(root, ((OpExpr *) node)->opfuncid); } else if (IsA(node, DistinctExpr)) { set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ - record_plan_function_dependency(glob, + record_plan_function_dependency(root, ((DistinctExpr *) node)->opfuncid); } else if (IsA(node, NullIfExpr)) { set_opfuncid((OpExpr *) node); /* rely on struct equivalence */ - record_plan_function_dependency(glob, + record_plan_function_dependency(root, ((NullIfExpr *) node)->opfuncid); } else if (IsA(node, ScalarArrayOpExpr)) { set_sa_opfuncid((ScalarArrayOpExpr *) node); - record_plan_function_dependency(glob, + record_plan_function_dependency(root, ((ScalarArrayOpExpr *) node)->opfuncid); } else if (IsA(node, ArrayCoerceExpr)) { if (OidIsValid(((ArrayCoerceExpr *) node)->elemfuncid)) - record_plan_function_dependency(glob, + record_plan_function_dependency(root, ((ArrayCoerceExpr *) node)->elemfuncid); } else if (IsA(node, Const)) @@ -871,8 +866,8 @@ fix_expr_common(PlannerGlobal *glob, Node *node) /* Check for regclass reference */ if (ISREGCLASSCONST(con)) - glob->relationOids = - lappend_oid(glob->relationOids, + root->glob->relationOids = + lappend_oid(root->glob->relationOids, DatumGetObjectId(con->constvalue)); } } @@ -883,17 +878,17 @@ fix_expr_common(PlannerGlobal *glob, Node *node) * * This consists of incrementing all Vars' varnos by rtoffset, * looking up operator opcode info for OpExpr and related nodes, - * and adding OIDs from regclass Const nodes into glob->relationOids. + * and adding OIDs from regclass Const nodes into root->glob->relationOids. */ static Node * -fix_scan_expr(PlannerGlobal *glob, Node *node, int rtoffset) +fix_scan_expr(PlannerInfo *root, Node *node, int rtoffset) { fix_scan_expr_context context; - context.glob = glob; + context.root = root; context.rtoffset = rtoffset; - if (rtoffset != 0 || glob->lastPHId != 0) + if (rtoffset != 0 || root->glob->lastPHId != 0) { return fix_scan_expr_mutator(node, &context); } @@ -949,7 +944,7 @@ fix_scan_expr_mutator(Node *node, fix_scan_expr_context *context) return fix_scan_expr_mutator((Node *) phv->phexpr, context); } - fix_expr_common(context->glob, node); + fix_expr_common(context->root, node); return expression_tree_mutator(node, fix_scan_expr_mutator, (void *) context); } @@ -960,7 +955,7 @@ fix_scan_expr_walker(Node *node, fix_scan_expr_context *context) if (node == NULL) return false; Assert(!IsA(node, PlaceHolderVar)); - fix_expr_common(context->glob, node); + fix_expr_common(context->root, node); return expression_tree_walker(node, fix_scan_expr_walker, (void *) context); } @@ -971,10 +966,10 @@ fix_scan_expr_walker(Node *node, fix_scan_expr_context *context) * subplans, by setting the varnos to OUTER or INNER and setting attno * values to the result domain number of either the corresponding outer * or inner join tuple item. Also perform opcode lookup for these - * expressions. and add regclass OIDs to glob->relationOids. + * expressions. and add regclass OIDs to root->glob->relationOids. */ static void -set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) +set_join_references(PlannerInfo *root, Join *join, int rtoffset) { Plan *outer_plan = join->plan.lefttree; Plan *inner_plan = join->plan.righttree; @@ -985,19 +980,19 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) inner_itlist = build_tlist_index(inner_plan->targetlist); /* All join plans have tlist, qual, and joinqual */ - join->plan.targetlist = fix_join_expr(glob, + join->plan.targetlist = fix_join_expr(root, join->plan.targetlist, outer_itlist, inner_itlist, (Index) 0, rtoffset); - join->plan.qual = fix_join_expr(glob, + join->plan.qual = fix_join_expr(root, join->plan.qual, outer_itlist, inner_itlist, (Index) 0, rtoffset); - join->joinqual = fix_join_expr(glob, + join->joinqual = fix_join_expr(root, join->joinqual, outer_itlist, inner_itlist, @@ -1014,7 +1009,7 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) { NestLoopParam *nlp = (NestLoopParam *) lfirst(lc); - nlp->paramval = (Var *) fix_upper_expr(glob, + nlp->paramval = (Var *) fix_upper_expr(root, (Node *) nlp->paramval, outer_itlist, rtoffset); @@ -1024,7 +1019,7 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) { MergeJoin *mj = (MergeJoin *) join; - mj->mergeclauses = fix_join_expr(glob, + mj->mergeclauses = fix_join_expr(root, mj->mergeclauses, outer_itlist, inner_itlist, @@ -1035,7 +1030,7 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) { HashJoin *hj = (HashJoin *) join; - hj->hashclauses = fix_join_expr(glob, + hj->hashclauses = fix_join_expr(root, hj->hashclauses, outer_itlist, inner_itlist, @@ -1052,7 +1047,7 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) * Update the targetlist and quals of an upper-level plan node * to refer to the tuples returned by its lefttree subplan. * Also perform opcode lookup for these expressions, and - * add regclass OIDs to glob->relationOids. + * add regclass OIDs to root->glob->relationOids. * * This is used for single-input plan types like Agg, Group, Result. * @@ -1066,7 +1061,7 @@ set_join_references(PlannerGlobal *glob, Join *join, int rtoffset) * the expression. */ static void -set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset) +set_upper_references(PlannerInfo *root, Plan *plan, int rtoffset) { Plan *subplan = plan->lefttree; indexed_tlist *subplan_itlist; @@ -1090,13 +1085,13 @@ set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset) subplan_itlist, OUTER); if (!newexpr) - newexpr = fix_upper_expr(glob, + newexpr = fix_upper_expr(root, (Node *) tle->expr, subplan_itlist, rtoffset); } else - newexpr = fix_upper_expr(glob, + newexpr = fix_upper_expr(root, (Node *) tle->expr, subplan_itlist, rtoffset); @@ -1107,7 +1102,7 @@ set_upper_references(PlannerGlobal *glob, Plan *plan, int rtoffset) plan->targetlist = output_targetlist; plan->qual = (List *) - fix_upper_expr(glob, + fix_upper_expr(root, (Node *) plan->qual, subplan_itlist, rtoffset); @@ -1385,7 +1380,7 @@ search_indexed_tlist_for_sortgroupref(Node *node, * changing the varno/varattno values of variables in the clauses * to reference target list values from the outer and inner join * relation target lists. Also perform opcode lookup and add - * regclass OIDs to glob->relationOids. + * regclass OIDs to root->glob->relationOids. * * This is used in two different scenarios: a normal join clause, where * all the Vars in the clause *must* be replaced by OUTER or INNER references; @@ -1409,7 +1404,7 @@ search_indexed_tlist_for_sortgroupref(Node *node, * not modified. */ static List * -fix_join_expr(PlannerGlobal *glob, +fix_join_expr(PlannerInfo *root, List *clauses, indexed_tlist *outer_itlist, indexed_tlist *inner_itlist, @@ -1418,7 +1413,7 @@ fix_join_expr(PlannerGlobal *glob, { fix_join_expr_context context; - context.glob = glob; + context.root = root; context.outer_itlist = outer_itlist; context.inner_itlist = inner_itlist; context.acceptable_rel = acceptable_rel; @@ -1508,7 +1503,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) if (newvar) return (Node *) newvar; } - fix_expr_common(context->glob, node); + fix_expr_common(context->root, node); return expression_tree_mutator(node, fix_join_expr_mutator, (void *) context); @@ -1518,7 +1513,7 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) * fix_upper_expr * Modifies an expression tree so that all Var nodes reference outputs * of a subplan. Also performs opcode lookup, and adds regclass OIDs to - * glob->relationOids. + * root->glob->relationOids. * * This is used to fix up target and qual expressions of non-join upper-level * plan nodes. @@ -1542,14 +1537,14 @@ fix_join_expr_mutator(Node *node, fix_join_expr_context *context) * The original tree is not modified. */ static Node * -fix_upper_expr(PlannerGlobal *glob, +fix_upper_expr(PlannerInfo *root, Node *node, indexed_tlist *subplan_itlist, int rtoffset) { fix_upper_expr_context context; - context.glob = glob; + context.root = root; context.subplan_itlist = subplan_itlist; context.rtoffset = rtoffset; return fix_upper_expr_mutator(node, &context); @@ -1599,7 +1594,7 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) if (newvar) return (Node *) newvar; } - fix_expr_common(context->glob, node); + fix_expr_common(context->root, node); return expression_tree_mutator(node, fix_upper_expr_mutator, (void *) context); @@ -1618,7 +1613,7 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) * original varno, but Vars for other rels will have varno OUTER. * * We also must perform opcode lookup and add regclass OIDs to - * glob->relationOids. + * root->glob->relationOids. * * 'rlist': the RETURNING targetlist to be fixed * 'topplan': the top subplan node that will be just below the ModifyTable @@ -1629,7 +1624,7 @@ fix_upper_expr_mutator(Node *node, fix_upper_expr_context *context) * they are not coming from a subplan. */ List * -set_returning_clause_references(PlannerGlobal *glob, +set_returning_clause_references(PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation) @@ -1652,7 +1647,7 @@ set_returning_clause_references(PlannerGlobal *glob, */ itlist = build_tlist_index_other_vars(topplan->targetlist, resultRelation); - rlist = fix_join_expr(glob, + rlist = fix_join_expr(root, rlist, itlist, NULL, @@ -1738,7 +1733,7 @@ set_sa_opfuncid(ScalarArrayOpExpr *opexpr) * dependency on a function that it's removed from the plan tree. */ void -record_plan_function_dependency(PlannerGlobal *glob, Oid funcid) +record_plan_function_dependency(PlannerInfo *root, Oid funcid) { /* * For performance reasons, we don't bother to track built-in functions; @@ -1764,7 +1759,7 @@ record_plan_function_dependency(PlannerGlobal *glob, Oid funcid) DatumGetUInt32(DirectFunctionCall1(hashoid, ObjectIdGetDatum(funcid))); - glob->invalItems = lappend(glob->invalItems, inval_item); + root->glob->invalItems = lappend(root->glob->invalItems, inval_item); } } @@ -1783,21 +1778,26 @@ extract_query_dependencies(Node *query, List **invalItems) { PlannerGlobal glob; + PlannerInfo root; - /* Make up a dummy PlannerGlobal so we can use this module's machinery */ + /* Make up dummy planner state so we can use this module's machinery */ MemSet(&glob, 0, sizeof(glob)); glob.type = T_PlannerGlobal; glob.relationOids = NIL; glob.invalItems = NIL; - (void) extract_query_dependencies_walker(query, &glob); + MemSet(&root, 0, sizeof(root)); + root.type = T_PlannerInfo; + root.glob = &glob; + + (void) extract_query_dependencies_walker(query, &root); *relationOids = glob.relationOids; *invalItems = glob.invalItems; } static bool -extract_query_dependencies_walker(Node *node, PlannerGlobal *context) +extract_query_dependencies_walker(Node *node, PlannerInfo *context) { if (node == NULL) return false; @@ -1828,8 +1828,8 @@ extract_query_dependencies_walker(Node *node, PlannerGlobal *context) RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); if (rte->rtekind == RTE_RELATION) - context->relationOids = lappend_oid(context->relationOids, - rte->relid); + context->glob->relationOids = + lappend_oid(context->glob->relationOids, rte->relid); } /* And recurse into the query's subexpressions */ diff --git a/src/backend/optimizer/plan/subselect.c b/src/backend/optimizer/plan/subselect.c index 4d4e6bf78e..2e308c625a 100644 --- a/src/backend/optimizer/plan/subselect.c +++ b/src/backend/optimizer/plan/subselect.c @@ -52,8 +52,7 @@ typedef struct finalize_primnode_context } finalize_primnode_context; -static Node *build_subplan(PlannerInfo *root, Plan *plan, - List *rtable, List *rowmarks, +static Node *build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot, SubLinkType subLinkType, Node *testexpr, bool adjust_testexpr, bool unknownEqFalse); static List *generate_subquery_params(PlannerInfo *root, List *tlist, @@ -389,8 +388,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery, SubLinkType subLinkType, &subroot); /* And convert to SubPlan or InitPlan format. */ - result = build_subplan(root, plan, - subroot->parse->rtable, subroot->rowMarks, + result = build_subplan(root, plan, subroot, subLinkType, testexpr, true, isTopQual); /* @@ -430,9 +428,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery, SubLinkType subLinkType, AlternativeSubPlan *asplan; /* OK, convert to SubPlan format. */ - hashplan = (SubPlan *) build_subplan(root, plan, - subroot->parse->rtable, - subroot->rowMarks, + hashplan = (SubPlan *) build_subplan(root, plan, subroot, ANY_SUBLINK, newtestexpr, false, true); /* Check we got what we expected */ @@ -460,7 +456,7 @@ make_subplan(PlannerInfo *root, Query *orig_subquery, SubLinkType subLinkType, * as explained in the comments for make_subplan. */ static Node * -build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks, +build_subplan(PlannerInfo *root, Plan *plan, PlannerInfo *subroot, SubLinkType subLinkType, Node *testexpr, bool adjust_testexpr, bool unknownEqFalse) { @@ -644,11 +640,10 @@ build_subplan(PlannerInfo *root, Plan *plan, List *rtable, List *rowmarks, } /* - * Add the subplan and its rtable to the global lists. + * Add the subplan and its PlannerInfo to the global lists. */ root->glob->subplans = lappend(root->glob->subplans, plan); - root->glob->subrtables = lappend(root->glob->subrtables, rtable); - root->glob->subrowmarks = lappend(root->glob->subrowmarks, rowmarks); + root->glob->subroots = lappend(root->glob->subroots, subroot); splan->plan_id = list_length(root->glob->subplans); if (isInitPlan) @@ -1018,13 +1013,10 @@ SS_process_ctes(PlannerInfo *root) splan->setParam = list_make1_int(prm->paramid); /* - * Add the subplan and its rtable to the global lists. + * Add the subplan and its PlannerInfo to the global lists. */ root->glob->subplans = lappend(root->glob->subplans, plan); - root->glob->subrtables = lappend(root->glob->subrtables, - subroot->parse->rtable); - root->glob->subrowmarks = lappend(root->glob->subrowmarks, - subroot->rowMarks); + root->glob->subroots = lappend(root->glob->subroots, subroot); splan->plan_id = list_length(root->glob->subplans); root->init_plans = lappend(root->init_plans, splan); @@ -2406,14 +2398,10 @@ SS_make_initplan_from_plan(PlannerInfo *root, Plan *plan, SS_finalize_plan(root, plan, false); /* - * Add the subplan and its rtable to the global lists. + * Add the subplan and its PlannerInfo to the global lists. */ - root->glob->subplans = lappend(root->glob->subplans, - plan); - root->glob->subrtables = lappend(root->glob->subrtables, - root->parse->rtable); - root->glob->subrowmarks = lappend(root->glob->subrowmarks, - root->rowMarks); + root->glob->subplans = lappend(root->glob->subplans, plan); + root->glob->subroots = lappend(root->glob->subroots, root); /* * Create a SubPlan node and add it to the outer list of InitPlans. Note diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 31b101b7a1..b6ab0f53f5 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -130,6 +130,7 @@ plan_set_operations(PlannerInfo *root, double tuple_fraction, Query *parse = root->parse; SetOperationStmt *topop = (SetOperationStmt *) parse->setOperations; Node *node; + RangeTblEntry *leftmostRTE; Query *leftmostQuery; Assert(topop && IsA(topop, SetOperationStmt)); @@ -142,6 +143,13 @@ plan_set_operations(PlannerInfo *root, double tuple_fraction, Assert(parse->windowClause == NIL); Assert(parse->distinctClause == NIL); + /* + * We'll need to build RelOptInfos for each of the leaf subqueries, + * which are RTE_SUBQUERY rangetable entries in this Query. Prepare the + * index arrays for that. + */ + setup_simple_rel_arrays(root); + /* * Find the leftmost component Query. We need to use its column names for * all generated tlists (else SELECT INTO won't work right). @@ -150,8 +158,8 @@ plan_set_operations(PlannerInfo *root, double tuple_fraction, while (node && IsA(node, SetOperationStmt)) node = ((SetOperationStmt *) node)->larg; Assert(node && IsA(node, RangeTblRef)); - leftmostQuery = rt_fetch(((RangeTblRef *) node)->rtindex, - parse->rtable)->subquery; + leftmostRTE = root->simple_rte_array[((RangeTblRef *) node)->rtindex]; + leftmostQuery = leftmostRTE->subquery; Assert(leftmostQuery != NULL); /* @@ -206,14 +214,22 @@ recurse_set_operations(Node *setOp, PlannerInfo *root, if (IsA(setOp, RangeTblRef)) { RangeTblRef *rtr = (RangeTblRef *) setOp; - RangeTblEntry *rte = rt_fetch(rtr->rtindex, root->parse->rtable); + RangeTblEntry *rte = root->simple_rte_array[rtr->rtindex]; Query *subquery = rte->subquery; + RelOptInfo *rel; PlannerInfo *subroot; Plan *subplan, *plan; Assert(subquery != NULL); + /* + * We need to build a RelOptInfo for each leaf subquery. This isn't + * used for anything here, but it carries the subroot data structures + * forward to setrefs.c processing. + */ + rel = build_simple_rel(root, rtr->rtindex, RELOPT_BASEREL); + /* * Generate plan for primitive subquery */ @@ -222,6 +238,10 @@ recurse_set_operations(Node *setOp, PlannerInfo *root, false, tuple_fraction, &subroot); + /* Save subroot and subplan in RelOptInfo for setrefs.c */ + rel->subplan = subplan; + rel->subroot = subroot; + /* * Estimate number of groups if caller wants it. If the subquery used * grouping or aggregation, its output is probably mostly unique @@ -250,9 +270,7 @@ recurse_set_operations(Node *setOp, PlannerInfo *root, refnames_tlist), NIL, rtr->rtindex, - subplan, - subroot->parse->rtable, - subroot->rowMarks); + subplan); /* * We don't bother to determine the subquery's output ordering since diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index efa986e521..baa90fa9b2 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -57,7 +57,7 @@ typedef struct typedef struct { ParamListInfo boundParams; - PlannerGlobal *glob; + PlannerInfo *root; List *active_fns; Node *case_val; bool estimate; @@ -2058,15 +2058,10 @@ eval_const_expressions(PlannerInfo *root, Node *node) eval_const_expressions_context context; if (root) - { context.boundParams = root->glob->boundParams; /* bound Params */ - context.glob = root->glob; /* for inlined-function dependencies */ - } else - { context.boundParams = NULL; - context.glob = NULL; - } + context.root = root; /* for inlined-function dependencies */ context.active_fns = NIL; /* nothing being recursively simplified */ context.case_val = NULL; /* no CASE being examined */ context.estimate = false; /* safe transformations only */ @@ -2097,7 +2092,7 @@ estimate_expression_value(PlannerInfo *root, Node *node) context.boundParams = root->glob->boundParams; /* bound Params */ /* we do not need to mark the plan as depending on inlined functions */ - context.glob = NULL; + context.root = NULL; context.active_fns = NIL; /* nothing being recursively simplified */ context.case_val = NULL; /* no CASE being examined */ context.estimate = true; /* unsafe transformations OK */ @@ -4123,8 +4118,8 @@ inline_function(Oid funcid, Oid result_type, Oid result_collid, * Since there is now no trace of the function in the plan tree, we must * explicitly record the plan's dependency on the function. */ - if (context->glob) - record_plan_function_dependency(context->glob, funcid); + if (context->root) + record_plan_function_dependency(context->root, funcid); /* * Recursively try to simplify the modified expression. Here we must add @@ -4559,7 +4554,7 @@ inline_set_returning_function(PlannerInfo *root, RangeTblEntry *rte) * Since there is now no trace of the function in the plan tree, we must * explicitly record the plan's dependency on the function. */ - record_plan_function_dependency(root->glob, func_oid); + record_plan_function_dependency(root, func_oid); return querytree; diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c index b59eb090aa..1df727d9fc 100644 --- a/src/backend/optimizer/util/relnode.c +++ b/src/backend/optimizer/util/relnode.c @@ -45,6 +45,35 @@ static List *subbuild_joinrel_joinlist(RelOptInfo *joinrel, List *new_joininfo); +/* + * setup_simple_rel_arrays + * Prepare the arrays we use for quickly accessing base relations. + */ +void +setup_simple_rel_arrays(PlannerInfo *root) +{ + Index rti; + ListCell *lc; + + /* Arrays are accessed using RT indexes (1..N) */ + root->simple_rel_array_size = list_length(root->parse->rtable) + 1; + + /* simple_rel_array is initialized to all NULLs */ + root->simple_rel_array = (RelOptInfo **) + palloc0(root->simple_rel_array_size * sizeof(RelOptInfo *)); + + /* simple_rte_array is an array equivalent of the rtable list */ + root->simple_rte_array = (RangeTblEntry **) + palloc0(root->simple_rel_array_size * sizeof(RangeTblEntry *)); + rti = 1; + foreach(lc, root->parse->rtable) + { + RangeTblEntry *rte = (RangeTblEntry *) lfirst(lc); + + root->simple_rte_array[rti++] = rte; + } +} + /* * build_simple_rel * Construct a new RelOptInfo for a base relation or 'other' relation. @@ -81,8 +110,7 @@ build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind) rel->pages = 0; rel->tuples = 0; rel->subplan = NULL; - rel->subrtable = NIL; - rel->subrowmark = NIL; + rel->subroot = NULL; rel->baserestrictinfo = NIL; rel->baserestrictcost.startup = 0; rel->baserestrictcost.per_tuple = 0; @@ -335,8 +363,7 @@ build_join_rel(PlannerInfo *root, joinrel->pages = 0; joinrel->tuples = 0; joinrel->subplan = NULL; - joinrel->subrtable = NIL; - joinrel->subrowmark = NIL; + joinrel->subroot = NULL; joinrel->baserestrictinfo = NIL; joinrel->baserestrictcost.startup = 0; joinrel->baserestrictcost.per_tuple = 0; diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index d3985b2093..5bd916862a 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -16,6 +16,7 @@ #include "catalog/pg_type.h" #include "nodes/makefuncs.h" #include "nodes/nodeFuncs.h" +#include "nodes/plannodes.h" #include "optimizer/clauses.h" #include "parser/parse_coerce.h" #include "parser/parse_relation.h" @@ -375,6 +376,7 @@ OffsetVarNodes_walker(Node *node, OffsetVarNodes_context *context) /* fall through to examine children */ } /* Shouldn't need to handle other planner auxiliary nodes here */ + Assert(!IsA(node, PlanRowMark)); Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, PlaceHolderInfo)); Assert(!IsA(node, MinMaxAggInfo)); @@ -529,6 +531,19 @@ ChangeVarNodes_walker(Node *node, ChangeVarNodes_context *context) } /* fall through to examine children */ } + if (IsA(node, PlanRowMark)) + { + PlanRowMark *rowmark = (PlanRowMark *) node; + + if (context->sublevels_up == 0) + { + if (rowmark->rti == context->rt_index) + rowmark->rti = context->new_index; + if (rowmark->prti == context->rt_index) + rowmark->prti = context->new_index; + } + return false; + } if (IsA(node, AppendRelInfo)) { AppendRelInfo *appinfo = (AppendRelInfo *) node; @@ -810,6 +825,7 @@ rangeTableEntry_used_walker(Node *node, } /* Shouldn't need to handle planner auxiliary nodes here */ Assert(!IsA(node, PlaceHolderVar)); + Assert(!IsA(node, PlanRowMark)); Assert(!IsA(node, SpecialJoinInfo)); Assert(!IsA(node, AppendRelInfo)); Assert(!IsA(node, PlaceHolderInfo)); diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 852ef77530..535eca77a7 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -380,18 +380,12 @@ typedef struct TidScan * the generic lefttree field as you might expect. This is because we do * not want plan-tree-traversal routines to recurse into the subplan without * knowing that they are changing Query contexts. - * - * Note: subrtable is used just to carry the subquery rangetable from - * createplan.c to setrefs.c; it should always be NIL by the time the - * executor sees the plan. Similarly for subrowmark. * ---------------- */ typedef struct SubqueryScan { Scan scan; Plan *subplan; - List *subrtable; /* temporary workspace for planner */ - List *subrowmark; /* temporary workspace for planner */ } SubqueryScan; /* ---------------- diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 722567df5c..ecbbc1cd39 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -79,9 +79,7 @@ typedef struct PlannerGlobal List *subplans; /* Plans for SubPlan nodes */ - List *subrtables; /* Rangetables for SubPlan nodes */ - - List *subrowmarks; /* PlanRowMarks for SubPlan nodes */ + List *subroots; /* PlannerInfos for SubPlan nodes */ Bitmapset *rewindPlanIDs; /* indices of subplans that require REWIND */ @@ -322,10 +320,9 @@ typedef struct PlannerInfo * pages - number of disk pages in relation (zero if not a table) * tuples - number of tuples in relation (not considering restrictions) * subplan - plan for subquery (NULL if it's not a subquery) - * subrtable - rangetable for subquery (NIL if it's not a subquery) - * subrowmark - rowmarks for subquery (NIL if it's not a subquery) + * subroot - PlannerInfo for subquery (NULL if it's not a subquery) * - * Note: for a subquery, tuples and subplan are not set immediately + * Note: for a subquery, tuples, subplan, subroot are not set immediately * upon creation of the RelOptInfo object; they are filled in when * set_base_rel_pathlist processes the object. * @@ -408,8 +405,7 @@ typedef struct RelOptInfo BlockNumber pages; double tuples; struct Plan *subplan; /* if subquery */ - List *subrtable; /* if subquery */ - List *subrowmark; /* if subquery */ + PlannerInfo *subroot; /* if subquery */ /* used by various scans and joins: */ List *baserestrictinfo; /* RestrictInfo structures (if base diff --git a/src/include/optimizer/cost.h b/src/include/optimizer/cost.h index 2763863af2..604df335d2 100644 --- a/src/include/optimizer/cost.h +++ b/src/include/optimizer/cost.h @@ -121,8 +121,7 @@ extern void set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel, RelOptInfo *inner_rel, SpecialJoinInfo *sjinfo, List *restrictlist); -extern void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel, - PlannerInfo *subroot); +extern void set_subquery_size_estimates(PlannerInfo *root, RelOptInfo *rel); extern void set_function_size_estimates(PlannerInfo *root, RelOptInfo *rel); extern void set_values_size_estimates(PlannerInfo *root, RelOptInfo *rel); extern void set_cte_size_estimates(PlannerInfo *root, RelOptInfo *rel, diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h index 1da2131b09..ee02732fe1 100644 --- a/src/include/optimizer/pathnode.h +++ b/src/include/optimizer/pathnode.h @@ -96,6 +96,7 @@ extern HashPath *create_hashjoin_path(PlannerInfo *root, /* * prototypes for relnode.c */ +extern void setup_simple_rel_arrays(PlannerInfo *root); extern RelOptInfo *build_simple_rel(PlannerInfo *root, int relid, RelOptKind reloptkind); extern RelOptInfo *find_base_rel(PlannerInfo *root, int relid); diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index 69ba6b6923..3b4bcdff74 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -41,8 +41,7 @@ extern Plan *optimize_minmax_aggregates(PlannerInfo *root, List *tlist, */ extern Plan *create_plan(PlannerInfo *root, Path *best_path); extern SubqueryScan *make_subqueryscan(List *qptlist, List *qpqual, - Index scanrelid, Plan *subplan, - List *subrtable, List *subrowmark); + Index scanrelid, Plan *subplan); extern Append *make_append(List *appendplans, List *tlist); extern RecursiveUnion *make_recursive_union(List *tlist, Plan *lefttree, Plan *righttree, int wtParam, @@ -118,18 +117,15 @@ extern List *remove_useless_joins(PlannerInfo *root, List *joinlist); /* * prototypes for plan/setrefs.c */ -extern Plan *set_plan_references(PlannerGlobal *glob, - Plan *plan, - List *rtable, - List *rowmarks); -extern List *set_returning_clause_references(PlannerGlobal *glob, +extern Plan *set_plan_references(PlannerInfo *root, Plan *plan); +extern List *set_returning_clause_references(PlannerInfo *root, List *rlist, Plan *topplan, Index resultRelation); extern void fix_opfuncids(Node *node); extern void set_opfuncid(OpExpr *opexpr); extern void set_sa_opfuncid(ScalarArrayOpExpr *opexpr); -extern void record_plan_function_dependency(PlannerGlobal *glob, Oid funcid); +extern void record_plan_function_dependency(PlannerInfo *root, Oid funcid); extern void extract_query_dependencies(Node *query, List **relationOids, List **invalItems);