]> granicus.if.org Git - postgresql/blobdiff - src/backend/optimizer/plan/createplan.c
Fix PARAM_EXEC assignment mechanism to be safe in the presence of WITH.
[postgresql] / src / backend / optimizer / plan / createplan.c
index d45ebfc461679c51e6bbeb2f360f9302c17540e1..030f420c90eb37946ee333250de54af61d9b82d7 100644 (file)
@@ -84,7 +84,8 @@ static HashJoin *create_hashjoin_plan(PlannerInfo *root, HashPath *best_path,
                                         Plan *outer_plan, Plan *inner_plan);
 static Node *replace_nestloop_params(PlannerInfo *root, Node *expr);
 static Node *replace_nestloop_params_mutator(Node *node, PlannerInfo *root);
-static void identify_nestloop_extparams(PlannerInfo *root, Plan *subplan);
+static void process_subquery_nestloop_params(PlannerInfo *root,
+                                                                List *subplan_params);
 static List *fix_indexqual_references(PlannerInfo *root, IndexPath *index_path);
 static List *fix_indexorderby_references(PlannerInfo *root, IndexPath *index_path);
 static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index, int indexcol);
@@ -188,6 +189,9 @@ create_plan(PlannerInfo *root, Path *best_path)
 {
        Plan       *plan;
 
+       /* plan_params should not be in use in current query level */
+       Assert(root->plan_params == NIL);
+
        /* Initialize this module's private workspace in PlannerInfo */
        root->curOuterRels = NULL;
        root->curOuterParams = NIL;
@@ -199,6 +203,12 @@ create_plan(PlannerInfo *root, Path *best_path)
        if (root->curOuterParams != NIL)
                elog(ERROR, "failed to assign all NestLoopParams to plan nodes");
 
+       /*
+        * Reset plan_params to ensure param IDs used for nestloop params are not
+        * re-used later
+        */
+       root->plan_params = NIL;
+
        return plan;
 }
 
@@ -298,8 +308,19 @@ create_scan_plan(PlannerInfo *root, Path *best_path)
                }
        }
        else
+       {
                tlist = build_relation_tlist(rel);
 
+               /*
+                * If it's a parameterized otherrel, there might be lateral references
+                * in the tlist, which need to be replaced with Params.  This cannot
+                * happen for regular baserels, though.  Note use_physical_tlist()
+                * always fails for otherrels, so we don't need to check this above.
+                */
+               if (rel->reloptkind != RELOPT_BASEREL && best_path->param_info)
+                       tlist = (List *) replace_nestloop_params(root, (Node *) tlist);
+       }
+
        /*
         * Extract the relevant restriction clauses from the parent relation. The
         * executor must apply all these restrictions during the scan, except for
@@ -1583,6 +1604,7 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
 {
        TidScan    *scan_plan;
        Index           scan_relid = best_path->path.parent->relid;
+       List       *tidquals = best_path->tidquals;
        List       *ortidquals;
 
        /* it should be a base rel... */
@@ -1595,11 +1617,20 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
        /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
        scan_clauses = extract_actual_clauses(scan_clauses, false);
 
+       /* Replace any outer-relation variables with nestloop params */
+       if (best_path->path.param_info)
+       {
+               tidquals = (List *)
+                       replace_nestloop_params(root, (Node *) tidquals);
+               scan_clauses = (List *)
+                       replace_nestloop_params(root, (Node *) scan_clauses);
+       }
+
        /*
         * Remove any clauses that are TID quals.  This is a bit tricky since the
         * tidquals list has implicit OR semantics.
         */
-       ortidquals = best_path->tidquals;
+       ortidquals = tidquals;
        if (list_length(ortidquals) > 1)
                ortidquals = list_make1(make_orclause(ortidquals));
        scan_clauses = list_difference(scan_clauses, ortidquals);
@@ -1607,7 +1638,7 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
        scan_plan = make_tidscan(tlist,
                                                         scan_clauses,
                                                         scan_relid,
-                                                        best_path->tidquals);
+                                                        tidquals);
 
        copy_path_costsize(&scan_plan->scan.plan, &best_path->path);
 
@@ -1641,7 +1672,8 @@ create_subqueryscan_plan(PlannerInfo *root, Path *best_path,
        {
                scan_clauses = (List *)
                        replace_nestloop_params(root, (Node *) scan_clauses);
-               identify_nestloop_extparams(root, best_path->parent->subplan);
+               process_subquery_nestloop_params(root,
+                                                                                best_path->parent->subplan_params);
        }
 
        scan_plan = make_subqueryscan(tlist,
@@ -1823,6 +1855,13 @@ create_ctescan_plan(PlannerInfo *root, Path *best_path,
        /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
        scan_clauses = extract_actual_clauses(scan_clauses, false);
 
+       /* Replace any outer-relation variables with nestloop params */
+       if (best_path->param_info)
+       {
+               scan_clauses = (List *)
+                       replace_nestloop_params(root, (Node *) scan_clauses);
+       }
+
        scan_plan = make_ctescan(tlist, scan_clauses, scan_relid,
                                                         plan_id, cte_param_id);
 
@@ -1876,6 +1915,13 @@ create_worktablescan_plan(PlannerInfo *root, Path *best_path,
        /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
        scan_clauses = extract_actual_clauses(scan_clauses, false);
 
+       /* Replace any outer-relation variables with nestloop params */
+       if (best_path->param_info)
+       {
+               scan_clauses = (List *)
+                       replace_nestloop_params(root, (Node *) scan_clauses);
+       }
+
        scan_plan = make_worktablescan(tlist, scan_clauses, scan_relid,
                                                                   cteroot->wt_param_id);
 
@@ -2585,30 +2631,26 @@ replace_nestloop_params_mutator(Node *node, PlannerInfo *root)
 }
 
 /*
- * identify_nestloop_extparams
- *       Identify extParams of a parameterized subquery that need to be fed
+ * process_subquery_nestloop_params
+ *       Handle params of a parameterized subquery that need to be fed
  *       from an outer nestloop.
  *
+ * Currently, that would be *all* params that a subquery in FROM has demanded
+ * from the current query level, since they must be LATERAL references.
+ *
  * The subplan's references to the outer variables are already represented
  * as PARAM_EXEC Params, so we need not modify the subplan here.  What we
  * do need to do is add entries to root->curOuterParams to signal the parent
  * nestloop plan node that it must provide these values.
  */
 static void
-identify_nestloop_extparams(PlannerInfo *root, Plan *subplan)
+process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
 {
-       Bitmapset  *tmpset;
-       int                     paramid;
+       ListCell   *ppl;
 
-       /* Examine each extParam of the subquery's plan */
-       tmpset = bms_copy(subplan->extParam);
-       while ((paramid = bms_first_member(tmpset)) >= 0)
+       foreach(ppl, subplan_params)
        {
-               PlannerParamItem *pitem = list_nth(root->glob->paramlist, paramid);
-
-               /* Ignore anything coming from an upper query level */
-               if (pitem->abslevel != root->query_level)
-                       continue;
+               PlannerParamItem *pitem = (PlannerParamItem *) lfirst(ppl);
 
                if (IsA(pitem->item, Var))
                {
@@ -2616,14 +2658,14 @@ identify_nestloop_extparams(PlannerInfo *root, Plan *subplan)
                        NestLoopParam *nlp;
                        ListCell   *lc;
 
-                       /* If not from a nestloop outer rel, nothing to do */
+                       /* If not from a nestloop outer rel, complain */
                        if (!bms_is_member(var->varno, root->curOuterRels))
-                               continue;
+                               elog(ERROR, "non-LATERAL parameter required by subquery");
                        /* Is this param already listed in root->curOuterParams? */
                        foreach(lc, root->curOuterParams)
                        {
                                nlp = (NestLoopParam *) lfirst(lc);
-                               if (nlp->paramno == paramid)
+                               if (nlp->paramno == pitem->paramId)
                                {
                                        Assert(equal(var, nlp->paramval));
                                        /* Present, so nothing to do */
@@ -2634,7 +2676,7 @@ identify_nestloop_extparams(PlannerInfo *root, Plan *subplan)
                        {
                                /* No, so add it */
                                nlp = makeNode(NestLoopParam);
-                               nlp->paramno = paramid;
+                               nlp->paramno = pitem->paramId;
                                nlp->paramval = copyObject(var);
                                root->curOuterParams = lappend(root->curOuterParams, nlp);
                        }
@@ -2645,22 +2687,15 @@ identify_nestloop_extparams(PlannerInfo *root, Plan *subplan)
                        NestLoopParam *nlp;
                        ListCell   *lc;
 
-                       /*
-                        * If not from a nestloop outer rel, nothing to do.  We use
-                        * bms_overlap as a cheap/quick test to see if the PHV might be
-                        * evaluated in the outer rels, and then grab its PlaceHolderInfo
-                        * to tell for sure.
-                        */
-                       if (!bms_overlap(phv->phrels, root->curOuterRels))
-                               continue;
+                       /* If not from a nestloop outer rel, complain */
                        if (!bms_is_subset(find_placeholder_info(root, phv, false)->ph_eval_at,
                                                           root->curOuterRels))
-                               continue;
+                               elog(ERROR, "non-LATERAL parameter required by subquery");
                        /* Is this param already listed in root->curOuterParams? */
                        foreach(lc, root->curOuterParams)
                        {
                                nlp = (NestLoopParam *) lfirst(lc);
-                               if (nlp->paramno == paramid)
+                               if (nlp->paramno == pitem->paramId)
                                {
                                        Assert(equal(phv, nlp->paramval));
                                        /* Present, so nothing to do */
@@ -2671,13 +2706,14 @@ identify_nestloop_extparams(PlannerInfo *root, Plan *subplan)
                        {
                                /* No, so add it */
                                nlp = makeNode(NestLoopParam);
-                               nlp->paramno = paramid;
+                               nlp->paramno = pitem->paramId;
                                nlp->paramval = copyObject(phv);
                                root->curOuterParams = lappend(root->curOuterParams, nlp);
                        }
                }
+               else
+                       elog(ERROR, "unexpected type of subquery parameter");
        }
-       bms_free(tmpset);
 }
 
 /*