LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - paramassign.c (source / functions) Hit Total Coverage
Test: PostgreSQL 13devel Lines: 193 201 96.0 %
Date: 2019-09-19 23:07:04 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-2019, 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       61280 : 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      123972 :     for (levelsup = var->varlevelsup; levelsup > 0; levelsup--)
      74       62692 :         root = root->parent_root;
      75             : 
      76             :     /* If there's already a matching PlannerParamItem there, just use it */
      77       94208 :     foreach(ppl, root->plan_params)
      78             :     {
      79       41616 :         pitem = (PlannerParamItem *) lfirst(ppl);
      80       41616 :         if (IsA(pitem->item, Var))
      81             :         {
      82       41616 :             Var        *pvar = (Var *) pitem->item;
      83             : 
      84             :             /*
      85             :              * This comparison must match _equalVar(), except for ignoring
      86             :              * varlevelsup.  Note that _equalVar() ignores the location.
      87             :              */
      88       65322 :             if (pvar->varno == var->varno &&
      89       32394 :                 pvar->varattno == var->varattno &&
      90       17376 :                 pvar->vartype == var->vartype &&
      91       17376 :                 pvar->vartypmod == var->vartypmod &&
      92       17376 :                 pvar->varcollid == var->varcollid &&
      93       17376 :                 pvar->varnoold == var->varnoold &&
      94        8688 :                 pvar->varoattno == var->varoattno)
      95        8688 :                 return pitem->paramId;
      96             :         }
      97             :     }
      98             : 
      99             :     /* Nope, so make a new one */
     100       52592 :     var = copyObject(var);
     101       52592 :     var->varlevelsup = 0;
     102             : 
     103       52592 :     pitem = makeNode(PlannerParamItem);
     104       52592 :     pitem->item = (Node *) var;
     105       52592 :     pitem->paramId = list_length(root->glob->paramExecTypes);
     106       52592 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     107             :                                              var->vartype);
     108             : 
     109       52592 :     root->plan_params = lappend(root->plan_params, pitem);
     110             : 
     111       52592 :     return pitem->paramId;
     112             : }
     113             : 
     114             : /*
     115             :  * Generate a Param node to replace the given Var,
     116             :  * which is expected to have varlevelsup > 0 (ie, it is not local).
     117             :  * Record the need for the Var in the proper upper-level root->plan_params.
     118             :  */
     119             : Param *
     120       61280 : replace_outer_var(PlannerInfo *root, Var *var)
     121             : {
     122             :     Param      *retval;
     123             :     int         i;
     124             : 
     125             :     Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level);
     126             : 
     127             :     /* Find the Var in the appropriate plan_params, or add it if not present */
     128       61280 :     i = assign_param_for_var(root, var);
     129             : 
     130       61280 :     retval = makeNode(Param);
     131       61280 :     retval->paramkind = PARAM_EXEC;
     132       61280 :     retval->paramid = i;
     133       61280 :     retval->paramtype = var->vartype;
     134       61280 :     retval->paramtypmod = var->vartypmod;
     135       61280 :     retval->paramcollid = var->varcollid;
     136       61280 :     retval->location = var->location;
     137             : 
     138       61280 :     return retval;
     139             : }
     140             : 
     141             : /*
     142             :  * Select a PARAM_EXEC number to identify the given PlaceHolderVar as a
     143             :  * parameter for the current subquery.  (It might already have one.)
     144             :  * Record the need for the PHV in the proper upper-level root->plan_params.
     145             :  *
     146             :  * This is just like assign_param_for_var, except for PlaceHolderVars.
     147             :  */
     148             : static int
     149          20 : assign_param_for_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
     150             : {
     151             :     ListCell   *ppl;
     152             :     PlannerParamItem *pitem;
     153             :     Index       levelsup;
     154             : 
     155             :     /* Find the query level the PHV belongs to */
     156          40 :     for (levelsup = phv->phlevelsup; levelsup > 0; levelsup--)
     157          20 :         root = root->parent_root;
     158             : 
     159             :     /* If there's already a matching PlannerParamItem there, just use it */
     160          60 :     foreach(ppl, root->plan_params)
     161             :     {
     162          40 :         pitem = (PlannerParamItem *) lfirst(ppl);
     163          40 :         if (IsA(pitem->item, PlaceHolderVar))
     164             :         {
     165           0 :             PlaceHolderVar *pphv = (PlaceHolderVar *) pitem->item;
     166             : 
     167             :             /* We assume comparing the PHIDs is sufficient */
     168           0 :             if (pphv->phid == phv->phid)
     169           0 :                 return pitem->paramId;
     170             :         }
     171             :     }
     172             : 
     173             :     /* Nope, so make a new one */
     174          20 :     phv = copyObject(phv);
     175          20 :     IncrementVarSublevelsUp((Node *) phv, -((int) phv->phlevelsup), 0);
     176             :     Assert(phv->phlevelsup == 0);
     177             : 
     178          20 :     pitem = makeNode(PlannerParamItem);
     179          20 :     pitem->item = (Node *) phv;
     180          20 :     pitem->paramId = list_length(root->glob->paramExecTypes);
     181          40 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     182          20 :                                              exprType((Node *) phv->phexpr));
     183             : 
     184          20 :     root->plan_params = lappend(root->plan_params, pitem);
     185             : 
     186          20 :     return pitem->paramId;
     187             : }
     188             : 
     189             : /*
     190             :  * Generate a Param node to replace the given PlaceHolderVar,
     191             :  * which is expected to have phlevelsup > 0 (ie, it is not local).
     192             :  * Record the need for the PHV in the proper upper-level root->plan_params.
     193             :  *
     194             :  * This is just like replace_outer_var, except for PlaceHolderVars.
     195             :  */
     196             : Param *
     197          20 : replace_outer_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
     198             : {
     199             :     Param      *retval;
     200             :     int         i;
     201             : 
     202             :     Assert(phv->phlevelsup > 0 && phv->phlevelsup < root->query_level);
     203             : 
     204             :     /* Find the PHV in the appropriate plan_params, or add it if not present */
     205          20 :     i = assign_param_for_placeholdervar(root, phv);
     206             : 
     207          20 :     retval = makeNode(Param);
     208          20 :     retval->paramkind = PARAM_EXEC;
     209          20 :     retval->paramid = i;
     210          20 :     retval->paramtype = exprType((Node *) phv->phexpr);
     211          20 :     retval->paramtypmod = exprTypmod((Node *) phv->phexpr);
     212          20 :     retval->paramcollid = exprCollation((Node *) phv->phexpr);
     213          20 :     retval->location = -1;
     214             : 
     215          20 :     return retval;
     216             : }
     217             : 
     218             : /*
     219             :  * Generate a Param node to replace the given Aggref
     220             :  * which is expected to have agglevelsup > 0 (ie, it is not local).
     221             :  * Record the need for the Aggref in the proper upper-level root->plan_params.
     222             :  */
     223             : Param *
     224          32 : replace_outer_agg(PlannerInfo *root, Aggref *agg)
     225             : {
     226             :     Param      *retval;
     227             :     PlannerParamItem *pitem;
     228             :     Index       levelsup;
     229             : 
     230             :     Assert(agg->agglevelsup > 0 && agg->agglevelsup < root->query_level);
     231             : 
     232             :     /* Find the query level the Aggref belongs to */
     233          64 :     for (levelsup = agg->agglevelsup; levelsup > 0; levelsup--)
     234          32 :         root = root->parent_root;
     235             : 
     236             :     /*
     237             :      * It does not seem worthwhile to try to de-duplicate references to outer
     238             :      * aggs.  Just make a new slot every time.
     239             :      */
     240          32 :     agg = copyObject(agg);
     241          32 :     IncrementVarSublevelsUp((Node *) agg, -((int) agg->agglevelsup), 0);
     242             :     Assert(agg->agglevelsup == 0);
     243             : 
     244          32 :     pitem = makeNode(PlannerParamItem);
     245          32 :     pitem->item = (Node *) agg;
     246          32 :     pitem->paramId = list_length(root->glob->paramExecTypes);
     247          32 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     248             :                                              agg->aggtype);
     249             : 
     250          32 :     root->plan_params = lappend(root->plan_params, pitem);
     251             : 
     252          32 :     retval = makeNode(Param);
     253          32 :     retval->paramkind = PARAM_EXEC;
     254          32 :     retval->paramid = pitem->paramId;
     255          32 :     retval->paramtype = agg->aggtype;
     256          32 :     retval->paramtypmod = -1;
     257          32 :     retval->paramcollid = agg->aggcollid;
     258          32 :     retval->location = agg->location;
     259             : 
     260          32 :     return retval;
     261             : }
     262             : 
     263             : /*
     264             :  * Generate a Param node to replace the given GroupingFunc expression which is
     265             :  * expected to have agglevelsup > 0 (ie, it is not local).
     266             :  * Record the need for the GroupingFunc in the proper upper-level
     267             :  * root->plan_params.
     268             :  */
     269             : Param *
     270          16 : replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp)
     271             : {
     272             :     Param      *retval;
     273             :     PlannerParamItem *pitem;
     274             :     Index       levelsup;
     275          16 :     Oid         ptype = exprType((Node *) grp);
     276             : 
     277             :     Assert(grp->agglevelsup > 0 && grp->agglevelsup < root->query_level);
     278             : 
     279             :     /* Find the query level the GroupingFunc belongs to */
     280          36 :     for (levelsup = grp->agglevelsup; levelsup > 0; levelsup--)
     281          20 :         root = root->parent_root;
     282             : 
     283             :     /*
     284             :      * It does not seem worthwhile to try to de-duplicate references to outer
     285             :      * aggs.  Just make a new slot every time.
     286             :      */
     287          16 :     grp = copyObject(grp);
     288          16 :     IncrementVarSublevelsUp((Node *) grp, -((int) grp->agglevelsup), 0);
     289             :     Assert(grp->agglevelsup == 0);
     290             : 
     291          16 :     pitem = makeNode(PlannerParamItem);
     292          16 :     pitem->item = (Node *) grp;
     293          16 :     pitem->paramId = list_length(root->glob->paramExecTypes);
     294          16 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     295             :                                              ptype);
     296             : 
     297          16 :     root->plan_params = lappend(root->plan_params, pitem);
     298             : 
     299          16 :     retval = makeNode(Param);
     300          16 :     retval->paramkind = PARAM_EXEC;
     301          16 :     retval->paramid = pitem->paramId;
     302          16 :     retval->paramtype = ptype;
     303          16 :     retval->paramtypmod = -1;
     304          16 :     retval->paramcollid = InvalidOid;
     305          16 :     retval->location = grp->location;
     306             : 
     307          16 :     return retval;
     308             : }
     309             : 
     310             : /*
     311             :  * Generate a Param node to replace the given Var,
     312             :  * which is expected to come from some upper NestLoop plan node.
     313             :  * Record the need for the Var in root->curOuterParams.
     314             :  */
     315             : Param *
     316       37138 : replace_nestloop_param_var(PlannerInfo *root, Var *var)
     317             : {
     318             :     Param      *param;
     319             :     NestLoopParam *nlp;
     320             :     ListCell   *lc;
     321             : 
     322             :     /* Is this Var already listed in root->curOuterParams? */
     323       39648 :     foreach(lc, root->curOuterParams)
     324             :     {
     325       21226 :         nlp = (NestLoopParam *) lfirst(lc);
     326       21226 :         if (equal(var, nlp->paramval))
     327             :         {
     328             :             /* Yes, so just make a Param referencing this NLP's slot */
     329       18716 :             param = makeNode(Param);
     330       18716 :             param->paramkind = PARAM_EXEC;
     331       18716 :             param->paramid = nlp->paramno;
     332       18716 :             param->paramtype = var->vartype;
     333       18716 :             param->paramtypmod = var->vartypmod;
     334       18716 :             param->paramcollid = var->varcollid;
     335       18716 :             param->location = var->location;
     336       18716 :             return param;
     337             :         }
     338             :     }
     339             : 
     340             :     /* No, so assign a PARAM_EXEC slot for a new NLP */
     341       18422 :     param = generate_new_exec_param(root,
     342             :                                     var->vartype,
     343             :                                     var->vartypmod,
     344             :                                     var->varcollid);
     345       18422 :     param->location = var->location;
     346             : 
     347             :     /* Add it to the list of required NLPs */
     348       18422 :     nlp = makeNode(NestLoopParam);
     349       18422 :     nlp->paramno = param->paramid;
     350       18422 :     nlp->paramval = copyObject(var);
     351       18422 :     root->curOuterParams = lappend(root->curOuterParams, nlp);
     352             : 
     353             :     /* And return the replacement Param */
     354       18422 :     return param;
     355             : }
     356             : 
     357             : /*
     358             :  * Generate a Param node to replace the given PlaceHolderVar,
     359             :  * which is expected to come from some upper NestLoop plan node.
     360             :  * Record the need for the PHV in root->curOuterParams.
     361             :  *
     362             :  * This is just like replace_nestloop_param_var, except for PlaceHolderVars.
     363             :  */
     364             : Param *
     365         124 : replace_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
     366             : {
     367             :     Param      *param;
     368             :     NestLoopParam *nlp;
     369             :     ListCell   *lc;
     370             : 
     371             :     /* Is this PHV already listed in root->curOuterParams? */
     372         176 :     foreach(lc, root->curOuterParams)
     373             :     {
     374         104 :         nlp = (NestLoopParam *) lfirst(lc);
     375         104 :         if (equal(phv, nlp->paramval))
     376             :         {
     377             :             /* Yes, so just make a Param referencing this NLP's slot */
     378          52 :             param = makeNode(Param);
     379          52 :             param->paramkind = PARAM_EXEC;
     380          52 :             param->paramid = nlp->paramno;
     381          52 :             param->paramtype = exprType((Node *) phv->phexpr);
     382          52 :             param->paramtypmod = exprTypmod((Node *) phv->phexpr);
     383          52 :             param->paramcollid = exprCollation((Node *) phv->phexpr);
     384          52 :             param->location = -1;
     385          52 :             return param;
     386             :         }
     387             :     }
     388             : 
     389             :     /* No, so assign a PARAM_EXEC slot for a new NLP */
     390         216 :     param = generate_new_exec_param(root,
     391          72 :                                     exprType((Node *) phv->phexpr),
     392          72 :                                     exprTypmod((Node *) phv->phexpr),
     393          72 :                                     exprCollation((Node *) phv->phexpr));
     394             : 
     395             :     /* Add it to the list of required NLPs */
     396          72 :     nlp = makeNode(NestLoopParam);
     397          72 :     nlp->paramno = param->paramid;
     398          72 :     nlp->paramval = (Var *) copyObject(phv);
     399          72 :     root->curOuterParams = lappend(root->curOuterParams, nlp);
     400             : 
     401             :     /* And return the replacement Param */
     402          72 :     return param;
     403             : }
     404             : 
     405             : /*
     406             :  * process_subquery_nestloop_params
     407             :  *    Handle params of a parameterized subquery that need to be fed
     408             :  *    from an outer nestloop.
     409             :  *
     410             :  * Currently, that would be *all* params that a subquery in FROM has demanded
     411             :  * from the current query level, since they must be LATERAL references.
     412             :  *
     413             :  * subplan_params is a list of PlannerParamItems that we intend to pass to
     414             :  * a subquery-in-FROM.  (This was constructed in root->plan_params while
     415             :  * planning the subquery, but isn't there anymore when this is called.)
     416             :  *
     417             :  * The subplan's references to the outer variables are already represented
     418             :  * as PARAM_EXEC Params, since that conversion was done by the routines above
     419             :  * while planning the subquery.  So we need not modify the subplan or the
     420             :  * PlannerParamItems here.  What we do need to do is add entries to
     421             :  * root->curOuterParams to signal the parent nestloop plan node that it must
     422             :  * provide these values.  This differs from replace_nestloop_param_var in
     423             :  * that the PARAM_EXEC slots to use have already been determined.
     424             :  *
     425             :  * Note that we also use root->curOuterRels as an implicit parameter for
     426             :  * sanity checks.
     427             :  */
     428             : void
     429         192 : process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
     430             : {
     431             :     ListCell   *lc;
     432             : 
     433         440 :     foreach(lc, subplan_params)
     434             :     {
     435         248 :         PlannerParamItem *pitem = castNode(PlannerParamItem, lfirst(lc));
     436             : 
     437         248 :         if (IsA(pitem->item, Var))
     438             :         {
     439         236 :             Var        *var = (Var *) pitem->item;
     440             :             NestLoopParam *nlp;
     441             :             ListCell   *lc;
     442             : 
     443             :             /* If not from a nestloop outer rel, complain */
     444         236 :             if (!bms_is_member(var->varno, root->curOuterRels))
     445           0 :                 elog(ERROR, "non-LATERAL parameter required by subquery");
     446             : 
     447             :             /* Is this param already listed in root->curOuterParams? */
     448         360 :             foreach(lc, root->curOuterParams)
     449             :             {
     450         124 :                 nlp = (NestLoopParam *) lfirst(lc);
     451         124 :                 if (nlp->paramno == pitem->paramId)
     452             :                 {
     453             :                     Assert(equal(var, nlp->paramval));
     454             :                     /* Present, so nothing to do */
     455           0 :                     break;
     456             :                 }
     457             :             }
     458         236 :             if (lc == NULL)
     459             :             {
     460             :                 /* No, so add it */
     461         236 :                 nlp = makeNode(NestLoopParam);
     462         236 :                 nlp->paramno = pitem->paramId;
     463         236 :                 nlp->paramval = copyObject(var);
     464         236 :                 root->curOuterParams = lappend(root->curOuterParams, nlp);
     465             :             }
     466             :         }
     467          12 :         else if (IsA(pitem->item, PlaceHolderVar))
     468             :         {
     469          12 :             PlaceHolderVar *phv = (PlaceHolderVar *) pitem->item;
     470             :             NestLoopParam *nlp;
     471             :             ListCell   *lc;
     472             : 
     473             :             /* If not from a nestloop outer rel, complain */
     474          12 :             if (!bms_is_subset(find_placeholder_info(root, phv, false)->ph_eval_at,
     475          12 :                                root->curOuterRels))
     476           0 :                 elog(ERROR, "non-LATERAL parameter required by subquery");
     477             : 
     478             :             /* Is this param already listed in root->curOuterParams? */
     479          52 :             foreach(lc, root->curOuterParams)
     480             :             {
     481          40 :                 nlp = (NestLoopParam *) lfirst(lc);
     482          40 :                 if (nlp->paramno == pitem->paramId)
     483             :                 {
     484             :                     Assert(equal(phv, nlp->paramval));
     485             :                     /* Present, so nothing to do */
     486           0 :                     break;
     487             :                 }
     488             :             }
     489          12 :             if (lc == NULL)
     490             :             {
     491             :                 /* No, so add it */
     492          12 :                 nlp = makeNode(NestLoopParam);
     493          12 :                 nlp->paramno = pitem->paramId;
     494          12 :                 nlp->paramval = (Var *) copyObject(phv);
     495          12 :                 root->curOuterParams = lappend(root->curOuterParams, nlp);
     496             :             }
     497             :         }
     498             :         else
     499           0 :             elog(ERROR, "unexpected type of subquery parameter");
     500             :     }
     501         192 : }
     502             : 
     503             : /*
     504             :  * Identify any NestLoopParams that should be supplied by a NestLoop plan
     505             :  * node with the specified lefthand rels.  Remove them from the active
     506             :  * root->curOuterParams list and return them as the result list.
     507             :  */
     508             : List *
     509       30644 : identify_current_nestloop_params(PlannerInfo *root, Relids leftrelids)
     510             : {
     511             :     List       *result;
     512             :     ListCell   *cell;
     513             : 
     514       30644 :     result = NIL;
     515       49798 :     foreach(cell, root->curOuterParams)
     516             :     {
     517       19154 :         NestLoopParam *nlp = (NestLoopParam *) lfirst(cell);
     518             : 
     519             :         /*
     520             :          * We are looking for Vars and PHVs that can be supplied by the
     521             :          * lefthand rels.  The "bms_overlap" test is just an optimization to
     522             :          * allow skipping find_placeholder_info() if the PHV couldn't match.
     523             :          */
     524       38224 :         if (IsA(nlp->paramval, Var) &&
     525       19070 :             bms_is_member(nlp->paramval->varno, leftrelids))
     526             :         {
     527       18658 :             root->curOuterParams = foreach_delete_current(root->curOuterParams,
     528             :                                                           cell);
     529       18658 :             result = lappend(result, nlp);
     530             :         }
     531         580 :         else if (IsA(nlp->paramval, PlaceHolderVar) &&
     532          84 :                  bms_overlap(((PlaceHolderVar *) nlp->paramval)->phrels,
     533          84 :                              leftrelids) &&
     534         168 :                  bms_is_subset(find_placeholder_info(root,
     535          84 :                                                      (PlaceHolderVar *) nlp->paramval,
     536          84 :                                                      false)->ph_eval_at,
     537             :                                leftrelids))
     538             :         {
     539          84 :             root->curOuterParams = foreach_delete_current(root->curOuterParams,
     540             :                                                           cell);
     541          84 :             result = lappend(result, nlp);
     542             :         }
     543             :     }
     544       30644 :     return result;
     545             : }
     546             : 
     547             : /*
     548             :  * Generate a new Param node that will not conflict with any other.
     549             :  *
     550             :  * This is used to create Params representing subplan outputs or
     551             :  * NestLoop parameters.
     552             :  *
     553             :  * We don't need to build a PlannerParamItem for such a Param, but we do
     554             :  * need to make sure we record the type in paramExecTypes (otherwise,
     555             :  * there won't be a slot allocated for it).
     556             :  */
     557             : Param *
     558       29464 : generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod,
     559             :                         Oid paramcollation)
     560             : {
     561             :     Param      *retval;
     562             : 
     563       29464 :     retval = makeNode(Param);
     564       29464 :     retval->paramkind = PARAM_EXEC;
     565       29464 :     retval->paramid = list_length(root->glob->paramExecTypes);
     566       29464 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     567             :                                              paramtype);
     568       29464 :     retval->paramtype = paramtype;
     569       29464 :     retval->paramtypmod = paramtypmod;
     570       29464 :     retval->paramcollid = paramcollation;
     571       29464 :     retval->location = -1;
     572             : 
     573       29464 :     return retval;
     574             : }
     575             : 
     576             : /*
     577             :  * Assign a (nonnegative) PARAM_EXEC ID for a special parameter (one that
     578             :  * is not actually used to carry a value at runtime).  Such parameters are
     579             :  * used for special runtime signaling purposes, such as connecting a
     580             :  * recursive union node to its worktable scan node or forcing plan
     581             :  * re-evaluation within the EvalPlanQual mechanism.  No actual Param node
     582             :  * exists with this ID, however.
     583             :  */
     584             : int
     585       80290 : assign_special_exec_param(PlannerInfo *root)
     586             : {
     587       80290 :     int         paramId = list_length(root->glob->paramExecTypes);
     588             : 
     589       80290 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     590             :                                              InvalidOid);
     591       80290 :     return paramId;
     592             : }

Generated by: LCOV version 1.13