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);