LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - paramassign.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13beta1 Lines: 191 199 96.0 %
Date: 2020-06-03 09:06:53 Functions: 12 12 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * paramassign.c
       4             :  *      Functions for assigning PARAM_EXEC slots during planning.
       5             :  *
       6             :  * This module is responsible for managing three planner data structures:
       7             :  *
       8             :  * root->glob->paramExecTypes: records actual assignments of PARAM_EXEC slots.
       9             :  * The i'th list element holds the data type OID of the i'th parameter slot.
      10             :  * (Elements can be InvalidOid if they represent slots that are needed for
      11             :  * chgParam signaling, but will never hold a value at runtime.)  This list is
      12             :  * global to the whole plan since the executor has only one PARAM_EXEC array.
      13             :  * Assignments are permanent for the plan: we never remove entries once added.
      14             :  *
      15             :  * root->plan_params: a list of PlannerParamItem nodes, recording Vars and
      16             :  * PlaceHolderVars that the root's query level needs to supply to lower-level
      17             :  * subqueries, along with the PARAM_EXEC number to use for each such value.
      18             :  * Elements are added to this list while planning a subquery, and the list
      19             :  * is reset to empty after completion of each subquery.
      20             :  *
      21             :  * root->curOuterParams: a list of NestLoopParam nodes, recording Vars and
      22             :  * PlaceHolderVars that some outer level of nestloop needs to pass down to
      23             :  * a lower-level plan node in its righthand side.  Elements are added to this
      24             :  * list as createplan.c creates lower Plan nodes that need such Params, and
      25             :  * are removed when it creates a NestLoop Plan node that will supply those
      26             :  * values.
      27             :  *
      28             :  * The latter two data structures are used to prevent creating multiple
      29             :  * PARAM_EXEC slots (each requiring work to fill) when the same upper
      30             :  * SubPlan or NestLoop supplies a value that is referenced in more than
      31             :  * one place in its child plan nodes.  However, when the same Var has to
      32             :  * be supplied to different subplan trees by different SubPlan or NestLoop
      33             :  * parent nodes, we don't recognize any commonality; a fresh plan_params or
      34             :  * curOuterParams entry will be made (since the old one has been removed
      35             :  * when we finished processing the earlier SubPlan or NestLoop) and a fresh
      36             :  * PARAM_EXEC number will be assigned.  At one time we tried to avoid
      37             :  * allocating duplicate PARAM_EXEC numbers in such cases, but it's harder
      38             :  * than it seems to avoid bugs due to overlapping Param lifetimes, so we
      39             :  * don't risk that anymore.  Minimizing the number of PARAM_EXEC slots
      40             :  * doesn't really save much executor work anyway.
      41             :  *
      42             :  *
      43             :  * Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
      44             :  * Portions Copyright (c) 1994, Regents of the University of California
      45             :  *
      46             :  * IDENTIFICATION
      47             :  *    src/backend/optimizer/util/paramassign.c
      48             :  *
      49             :  *-------------------------------------------------------------------------
      50             :  */
      51             : #include "postgres.h"
      52             : 
      53             : #include "nodes/nodeFuncs.h"
      54             : #include "nodes/plannodes.h"
      55             : #include "optimizer/paramassign.h"
      56             : #include "optimizer/placeholder.h"
      57             : #include "rewrite/rewriteManip.h"
      58             : 
      59             : 
      60             : /*
      61             :  * Select a PARAM_EXEC number to identify the given Var as a parameter for
      62             :  * the current subquery.  (It might already have one.)
      63             :  * Record the need for the Var in the proper upper-level root->plan_params.
      64             :  */
      65             : static int
      66       64996 : assign_param_for_var(PlannerInfo *root, Var *var)
      67             : {
      68             :     ListCell   *ppl;
      69             :     PlannerParamItem *pitem;
      70             :     Index       levelsup;
      71             : 
      72             :     /* Find the query level the Var belongs to */
      73      131536 :     for (levelsup = var->varlevelsup; levelsup > 0; levelsup--)
      74       66540 :         root = root->parent_root;
      75             : 
      76             :     /* If there's already a matching PlannerParamItem there, just use it */
      77       99484 :     foreach(ppl, root->plan_params)
      78             :     {
      79       43608 :         pitem = (PlannerParamItem *) lfirst(ppl);
      80       43608 :         if (IsA(pitem->item, Var))
      81             :         {
      82       43608 :             Var        *pvar = (Var *) pitem->item;
      83             : 
      84             :             /*
      85             :              * This comparison must match _equalVar(), except for ignoring
      86             :              * varlevelsup.  Note that _equalVar() ignores varnosyn,
      87             :              * varattnosyn, and location, so this does too.
      88             :              */
      89       43608 :             if (pvar->varno == var->varno &&
      90       25390 :                 pvar->varattno == var->varattno &&
      91        9120 :                 pvar->vartype == var->vartype &&
      92        9120 :                 pvar->vartypmod == var->vartypmod &&
      93        9120 :                 pvar->varcollid == var->varcollid)
      94        9120 :                 return pitem->paramId;
      95             :         }
      96             :     }
      97             : 
      98             :     /* Nope, so make a new one */
      99       55876 :     var = copyObject(var);
     100       55876 :     var->varlevelsup = 0;
     101             : 
     102       55876 :     pitem = makeNode(PlannerParamItem);
     103       55876 :     pitem->item = (Node *) var;
     104       55876 :     pitem->paramId = list_length(root->glob->paramExecTypes);
     105       55876 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     106             :                                              var->vartype);
     107             : 
     108       55876 :     root->plan_params = lappend(root->plan_params, pitem);
     109             : 
     110       55876 :     return pitem->paramId;
     111             : }
     112             : 
     113             : /*
     114             :  * Generate a Param node to replace the given Var,
     115             :  * which is expected to have varlevelsup > 0 (ie, it is not local).
     116             :  * Record the need for the Var in the proper upper-level root->plan_params.
     117             :  */
     118             : Param *
     119       64996 : replace_outer_var(PlannerInfo *root, Var *var)
     120             : {
     121             :     Param      *retval;
     122             :     int         i;
     123             : 
     124             :     Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level);
     125             : 
     126             :     /* Find the Var in the appropriate plan_params, or add it if not present */
     127       64996 :     i = assign_param_for_var(root, var);
     128             : 
     129       64996 :     retval = makeNode(Param);
     130       64996 :     retval->paramkind = PARAM_EXEC;
     131       64996 :     retval->paramid = i;
     132       64996 :     retval->paramtype = var->vartype;
     133       64996 :     retval->paramtypmod = var->vartypmod;
     134       64996 :     retval->paramcollid = var->varcollid;
     135       64996 :     retval->location = var->location;
     136             : 
     137       64996 :     return retval;
     138             : }
     139             : 
     140             : /*
     141             :  * Select a PARAM_EXEC number to identify the given PlaceHolderVar as a
     142             :  * parameter for the current subquery.  (It might already have one.)
     143             :  * Record the need for the PHV in the proper upper-level root->plan_params.
     144             :  *
     145             :  * This is just like assign_param_for_var, except for PlaceHolderVars.
     146             :  */
     147             : static int
     148          28 : assign_param_for_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
     149             : {
     150             :     ListCell   *ppl;
     151             :     PlannerParamItem *pitem;
     152             :     Index       levelsup;
     153             : 
     154             :     /* Find the query level the PHV belongs to */
     155          56 :     for (levelsup = phv->phlevelsup; levelsup > 0; levelsup--)
     156          28 :         root = root->parent_root;
     157             : 
     158             :     /* If there's already a matching PlannerParamItem there, just use it */
     159          68 :     foreach(ppl, root->plan_params)
     160             :     {
     161          40 :         pitem = (PlannerParamItem *) lfirst(ppl);
     162          40 :         if (IsA(pitem->item, PlaceHolderVar))
     163             :         {
     164           0 :             PlaceHolderVar *pphv = (PlaceHolderVar *) pitem->item;
     165             : 
     166             :             /* We assume comparing the PHIDs is sufficient */
     167           0 :             if (pphv->phid == phv->phid)
     168           0 :                 return pitem->paramId;
     169             :         }
     170             :     }
     171             : 
     172             :     /* Nope, so make a new one */
     173          28 :     phv = copyObject(phv);
     174          28 :     IncrementVarSublevelsUp((Node *) phv, -((int) phv->phlevelsup), 0);
     175             :     Assert(phv->phlevelsup == 0);
     176             : 
     177          28 :     pitem = makeNode(PlannerParamItem);
     178          28 :     pitem->item = (Node *) phv;
     179          28 :     pitem->paramId = list_length(root->glob->paramExecTypes);
     180          28 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     181          28 :                                              exprType((Node *) phv->phexpr));
     182             : 
     183          28 :     root->plan_params = lappend(root->plan_params, pitem);
     184             : 
     185          28 :     return pitem->paramId;
     186             : }
     187             : 
     188             : /*
     189             :  * Generate a Param node to replace the given PlaceHolderVar,
     190             :  * which is expected to have phlevelsup > 0 (ie, it is not local).
     191             :  * Record the need for the PHV in the proper upper-level root->plan_params.
     192             :  *
     193             :  * This is just like replace_outer_var, except for PlaceHolderVars.
     194             :  */
     195             : Param *
     196          28 : replace_outer_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
     197             : {
     198             :     Param      *retval;
     199             :     int         i;
     200             : 
     201             :     Assert(phv->phlevelsup > 0 && phv->phlevelsup < root->query_level);
     202             : 
     203             :     /* Find the PHV in the appropriate plan_params, or add it if not present */
     204          28 :     i = assign_param_for_placeholdervar(root, phv);
     205             : 
     206          28 :     retval = makeNode(Param);
     207          28 :     retval->paramkind = PARAM_EXEC;
     208          28 :     retval->paramid = i;
     209          28 :     retval->paramtype = exprType((Node *) phv->phexpr);
     210          28 :     retval->paramtypmod = exprTypmod((Node *) phv->phexpr);
     211          28 :     retval->paramcollid = exprCollation((Node *) phv->phexpr);
     212          28 :     retval->location = -1;
     213             : 
     214          28 :     return retval;
     215             : }
     216             : 
     217             : /*
     218             :  * Generate a Param node to replace the given Aggref
     219             :  * which is expected to have agglevelsup > 0 (ie, it is not local).
     220             :  * Record the need for the Aggref in the proper upper-level root->plan_params.
     221             :  */
     222             : Param *
     223          32 : replace_outer_agg(PlannerInfo *root, Aggref *agg)
     224             : {
     225             :     Param      *retval;
     226             :     PlannerParamItem *pitem;
     227             :     Index       levelsup;
     228             : 
     229             :     Assert(agg->agglevelsup > 0 && agg->agglevelsup < root->query_level);
     230             : 
     231             :     /* Find the query level the Aggref belongs to */
     232          64 :     for (levelsup = agg->agglevelsup; levelsup > 0; levelsup--)
     233          32 :         root = root->parent_root;
     234             : 
     235             :     /*
     236             :      * It does not seem worthwhile to try to de-duplicate references to outer
     237             :      * aggs.  Just make a new slot every time.
     238             :      */
     239          32 :     agg = copyObject(agg);
     240          32 :     IncrementVarSublevelsUp((Node *) agg, -((int) agg->agglevelsup), 0);
     241             :     Assert(agg->agglevelsup == 0);
     242             : 
     243          32 :     pitem = makeNode(PlannerParamItem);
     244          32 :     pitem->item = (Node *) agg;
     245          32 :     pitem->paramId = list_length(root->glob->paramExecTypes);
     246          32 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     247             :                                              agg->aggtype);
     248             : 
     249          32 :     root->plan_params = lappend(root->plan_params, pitem);
     250             : 
     251          32 :     retval = makeNode(Param);
     252          32 :     retval->paramkind = PARAM_EXEC;
     253          32 :     retval->paramid = pitem->paramId;
     254          32 :     retval->paramtype = agg->aggtype;
     255          32 :     retval->paramtypmod = -1;
     256          32 :     retval->paramcollid = agg->aggcollid;
     257          32 :     retval->location = agg->location;
     258             : 
     259          32 :     return retval;
     260             : }
     261             : 
     262             : /*
     263             :  * Generate a Param node to replace the given GroupingFunc expression which is
     264             :  * expected to have agglevelsup > 0 (ie, it is not local).
     265             :  * Record the need for the GroupingFunc in the proper upper-level
     266             :  * root->plan_params.
     267             :  */
     268             : Param *
     269          16 : replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp)
     270             : {
     271             :     Param      *retval;
     272             :     PlannerParamItem *pitem;
     273             :     Index       levelsup;
     274          16 :     Oid         ptype = exprType((Node *) grp);
     275             : 
     276             :     Assert(grp->agglevelsup > 0 && grp->agglevelsup < root->query_level);
     277             : 
     278             :     /* Find the query level the GroupingFunc belongs to */
     279          36 :     for (levelsup = grp->agglevelsup; levelsup > 0; levelsup--)
     280          20 :         root = root->parent_root;
     281             : 
     282             :     /*
     283             :      * It does not seem worthwhile to try to de-duplicate references to outer
     284             :      * aggs.  Just make a new slot every time.
     285             :      */
     286          16 :     grp = copyObject(grp);
     287          16 :     IncrementVarSublevelsUp((Node *) grp, -((int) grp->agglevelsup), 0);
     288             :     Assert(grp->agglevelsup == 0);
     289             : 
     290          16 :     pitem = makeNode(PlannerParamItem);
     291          16 :     pitem->item = (Node *) grp;
     292          16 :     pitem->paramId = list_length(root->glob->paramExecTypes);
     293          16 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     294             :                                              ptype);
     295             : 
     296          16 :     root->plan_params = lappend(root->plan_params, pitem);
     297             : 
     298          16 :     retval = makeNode(Param);
     299          16 :     retval->paramkind = PARAM_EXEC;
     300          16 :     retval->paramid = pitem->paramId;
     301          16 :     retval->paramtype = ptype;
     302          16 :     retval->paramtypmod = -1;
     303          16 :     retval->paramcollid = InvalidOid;
     304          16 :     retval->location = grp->location;
     305             : 
     306          16 :     return retval;
     307             : }
     308             : 
     309             : /*
     310             :  * Generate a Param node to replace the given Var,
     311             :  * which is expected to come from some upper NestLoop plan node.
     312             :  * Record the need for the Var in root->curOuterParams.
     313             :  */
     314             : Param *
     315       39470 : replace_nestloop_param_var(PlannerInfo *root, Var *var)
     316             : {
     317             :     Param      *param;
     318             :     NestLoopParam *nlp;
     319             :     ListCell   *lc;
     320             : 
     321             :     /* Is this Var already listed in root->curOuterParams? */
     322       42014 :     foreach(lc, root->curOuterParams)
     323             :     {
     324       22466 :         nlp = (NestLoopParam *) lfirst(lc);
     325       22466 :         if (equal(var, nlp->paramval))
     326             :         {
     327             :             /* Yes, so just make a Param referencing this NLP's slot */
     328       19922 :             param = makeNode(Param);
     329       19922 :             param->paramkind = PARAM_EXEC;
     330       19922 :             param->paramid = nlp->paramno;
     331       19922 :             param->paramtype = var->vartype;
     332       19922 :             param->paramtypmod = var->vartypmod;
     333       19922 :             param->paramcollid = var->varcollid;
     334       19922 :             param->location = var->location;
     335       19922 :             return param;
     336             :         }
     337             :     }
     338             : 
     339             :     /* No, so assign a PARAM_EXEC slot for a new NLP */
     340       19548 :     param = generate_new_exec_param(root,
     341             :                                     var->vartype,
     342             :                                     var->vartypmod,
     343             :                                     var->varcollid);
     344       19548 :     param->location = var->location;
     345             : 
     346             :     /* Add it to the list of required NLPs */
     347       19548 :     nlp = makeNode(NestLoopParam);
     348       19548 :     nlp->paramno = param->paramid;
     349       19548 :     nlp->paramval = copyObject(var);
     350       19548 :     root->curOuterParams = lappend(root->curOuterParams, nlp);
     351             : 
     352             :     /* And return the replacement Param */
     353       19548 :     return param;
     354             : }
     355             : 
     356             : /*
     357             :  * Generate a Param node to replace the given PlaceHolderVar,
     358             :  * which is expected to come from some upper NestLoop plan node.
     359             :  * Record the need for the PHV in root->curOuterParams.
     360             :  *
     361             :  * This is just like replace_nestloop_param_var, except for PlaceHolderVars.
     362             :  */
     363             : Param *
     364         124 : replace_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
     365             : {
     366             :     Param      *param;
     367             :     NestLoopParam *nlp;
     368             :     ListCell   *lc;
     369             : 
     370             :     /* Is this PHV already listed in root->curOuterParams? */
     371         176 :     foreach(lc, root->curOuterParams)
     372             :     {
     373         104 :         nlp = (NestLoopParam *) lfirst(lc);
     374         104 :         if (equal(phv, nlp->paramval))
     375             :         {
     376             :             /* Yes, so just make a Param referencing this NLP's slot */
     377          52 :             param = makeNode(Param);
     378          52 :             param->paramkind = PARAM_EXEC;
     379          52 :             param->paramid = nlp->paramno;
     380          52 :             param->paramtype = exprType((Node *) phv->phexpr);
     381          52 :             param->paramtypmod = exprTypmod((Node *) phv->phexpr);
     382          52 :             param->paramcollid = exprCollation((Node *) phv->phexpr);
     383          52 :             param->location = -1;
     384          52 :             return param;
     385             :         }
     386             :     }
     387             : 
     388             :     /* No, so assign a PARAM_EXEC slot for a new NLP */
     389          72 :     param = generate_new_exec_param(root,
     390          72 :                                     exprType((Node *) phv->phexpr),
     391          72 :                                     exprTypmod((Node *) phv->phexpr),
     392          72 :                                     exprCollation((Node *) phv->phexpr));
     393             : 
     394             :     /* Add it to the list of required NLPs */
     395          72 :     nlp = makeNode(NestLoopParam);
     396          72 :     nlp->paramno = param->paramid;
     397          72 :     nlp->paramval = (Var *) copyObject(phv);
     398          72 :     root->curOuterParams = lappend(root->curOuterParams, nlp);
     399             : 
     400             :     /* And return the replacement Param */
     401          72 :     return param;
     402             : }
     403             : 
     404             : /*
     405             :  * process_subquery_nestloop_params
     406             :  *    Handle params of a parameterized subquery that need to be fed
     407             :  *    from an outer nestloop.
     408             :  *
     409             :  * Currently, that would be *all* params that a subquery in FROM has demanded
     410             :  * from the current query level, since they must be LATERAL references.
     411             :  *
     412             :  * subplan_params is a list of PlannerParamItems that we intend to pass to
     413             :  * a subquery-in-FROM.  (This was constructed in root->plan_params while
     414             :  * planning the subquery, but isn't there anymore when this is called.)
     415             :  *
     416             :  * The subplan's references to the outer variables are already represented
     417             :  * as PARAM_EXEC Params, since that conversion was done by the routines above
     418             :  * while planning the subquery.  So we need not modify the subplan or the
     419             :  * PlannerParamItems here.  What we do need to do is add entries to
     420             :  * root->curOuterParams to signal the parent nestloop plan node that it must
     421             :  * provide these values.  This differs from replace_nestloop_param_var in
     422             :  * that the PARAM_EXEC slots to use have already been determined.
     423             :  *
     424             :  * Note that we also use root->curOuterRels as an implicit parameter for
     425             :  * sanity checks.
     426             :  */
     427             : void
     428         232 : process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
     429             : {
     430             :     ListCell   *lc;
     431             : 
     432         536 :     foreach(lc, subplan_params)
     433             :     {
     434         304 :         PlannerParamItem *pitem = castNode(PlannerParamItem, lfirst(lc));
     435             : 
     436         304 :         if (IsA(pitem->item, Var))
     437             :         {
     438         284 :             Var        *var = (Var *) pitem->item;
     439             :             NestLoopParam *nlp;
     440             :             ListCell   *lc;
     441             : 
     442             :             /* If not from a nestloop outer rel, complain */
     443         284 :             if (!bms_is_member(var->varno, root->curOuterRels))
     444           0 :                 elog(ERROR, "non-LATERAL parameter required by subquery");
     445             : 
     446             :             /* Is this param already listed in root->curOuterParams? */
     447         424 :             foreach(lc, root->curOuterParams)
     448             :             {
     449         140 :                 nlp = (NestLoopParam *) lfirst(lc);
     450         140 :                 if (nlp->paramno == pitem->paramId)
     451             :                 {
     452             :                     Assert(equal(var, nlp->paramval));
     453             :                     /* Present, so nothing to do */
     454           0 :                     break;
     455             :                 }
     456             :             }
     457         284 :             if (lc == NULL)
     458             :             {
     459             :                 /* No, so add it */
     460         284 :                 nlp = makeNode(NestLoopParam);
     461         284 :                 nlp->paramno = pitem->paramId;
     462         284 :                 nlp->paramval = copyObject(var);
     463         284 :                 root->curOuterParams = lappend(root->curOuterParams, nlp);
     464             :             }
     465             :         }
     466          20 :         else if (IsA(pitem->item, PlaceHolderVar))
     467             :         {
     468          20 :             PlaceHolderVar *phv = (PlaceHolderVar *) pitem->item;
     469             :             NestLoopParam *nlp;
     470             :             ListCell   *lc;
     471             : 
     472             :             /* If not from a nestloop outer rel, complain */
     473          20 :             if (!bms_is_subset(find_placeholder_info(root, phv, false)->ph_eval_at,
     474          20 :                                root->curOuterRels))
     475           0 :                 elog(ERROR, "non-LATERAL parameter required by subquery");
     476             : 
     477             :             /* Is this param already listed in root->curOuterParams? */
     478          60 :             foreach(lc, root->curOuterParams)
     479             :             {
     480          40 :                 nlp = (NestLoopParam *) lfirst(lc);
     481          40 :                 if (nlp->paramno == pitem->paramId)
     482             :                 {
     483             :                     Assert(equal(phv, nlp->paramval));
     484             :                     /* Present, so nothing to do */
     485           0 :                     break;
     486             :                 }
     487             :             }
     488          20 :             if (lc == NULL)
     489             :             {
     490             :                 /* No, so add it */
     491          20 :                 nlp = makeNode(NestLoopParam);
     492          20 :                 nlp->paramno = pitem->paramId;
     493          20 :                 nlp->paramval = (Var *) copyObject(phv);
     494          20 :                 root->curOuterParams = lappend(root->curOuterParams, nlp);
     495             :             }
     496             :         }
     497             :         else
     498           0 :             elog(ERROR, "unexpected type of subquery parameter");
     499             :     }
     500         232 : }
     501             : 
     502             : /*
     503             :  * Identify any NestLoopParams that should be supplied by a NestLoop plan
     504             :  * node with the specified lefthand rels.  Remove them from the active
     505             :  * root->curOuterParams list and return them as the result list.
     506             :  */
     507             : List *
     508       33406 : identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids)
     509             : {
     510             :     List       *result;
     511             :     ListCell   *cell;
     512             : 
     513       33406 :     result = NIL;
     514       53734 :     foreach(cell, root->curOuterParams)
     515             :     {
     516       20328 :         NestLoopParam *nlp = (NestLoopParam *) lfirst(cell);
     517             : 
     518             :         /*
     519             :          * We are looking for Vars and PHVs that can be supplied by the
     520             :          * lefthand rels.  The "bms_overlap" test is just an optimization to
     521             :          * allow skipping find_placeholder_info() if the PHV couldn't match.
     522             :          */
     523       40564 :         if (IsA(nlp->paramval, Var) &&
     524       20236 :             bms_is_member(nlp->paramval->varno, leftrelids))
     525             :         {
     526       19832 :             root->curOuterParams = foreach_delete_current(root->curOuterParams,
     527             :                                                           cell);
     528       19832 :             result = lappend(result, nlp);
     529             :         }
     530         588 :         else if (IsA(nlp->paramval, PlaceHolderVar) &&
     531          92 :                  bms_overlap(((PlaceHolderVar *) nlp->paramval)->phrels,
     532          92 :                              leftrelids) &&
     533         184 :                  bms_is_subset(find_placeholder_info(root,
     534          92 :                                                      (PlaceHolderVar *) nlp->paramval,
     535          92 :                                                      false)->ph_eval_at,
     536             :                                leftrelids))
     537             :         {
     538          92 :             root->curOuterParams = foreach_delete_current(root->curOuterParams,
     539             :                                                           cell);
     540          92 :             result = lappend(result, nlp);
     541             :         }
     542             :     }
     543       33406 :     return result;
     544             : }
     545             : 
     546             : /*
     547             :  * Generate a new Param node that will not conflict with any other.
     548             :  *
     549             :  * This is used to create Params representing subplan outputs or
     550             :  * NestLoop parameters.
     551             :  *
     552             :  * We don't need to build a PlannerParamItem for such a Param, but we do
     553             :  * need to make sure we record the type in paramExecTypes (otherwise,
     554             :  * there won't be a slot allocated for it).
     555             :  */
     556             : Param *
     557       31274 : generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod,
     558             :                         Oid paramcollation)
     559             : {
     560             :     Param      *retval;
     561             : 
     562       31274 :     retval = makeNode(Param);
     563       31274 :     retval->paramkind = PARAM_EXEC;
     564       31274 :     retval->paramid = list_length(root->glob->paramExecTypes);
     565       31274 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     566             :                                              paramtype);
     567       31274 :     retval->paramtype = paramtype;
     568       31274 :     retval->paramtypmod = paramtypmod;
     569       31274 :     retval->paramcollid = paramcollation;
     570       31274 :     retval->location = -1;
     571             : 
     572       31274 :     return retval;
     573             : }
     574             : 
     575             : /*
     576             :  * Assign a (nonnegative) PARAM_EXEC ID for a special parameter (one that
     577             :  * is not actually used to carry a value at runtime).  Such parameters are
     578             :  * used for special runtime signaling purposes, such as connecting a
     579             :  * recursive union node to its worktable scan node or forcing plan
     580             :  * re-evaluation within the EvalPlanQual mechanism.  No actual Param node
     581             :  * exists with this ID, however.
     582             :  */
     583             : int
     584       80208 : assign_special_exec_param(PlannerInfo *root)
     585             : {
     586       80208 :     int         paramId = list_length(root->glob->paramExecTypes);
     587             : 
     588       80208 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     589             :                                              InvalidOid);
     590       80208 :     return paramId;
     591             : }

Generated by: LCOV version 1.13