LCOV - code coverage report
Current view: top level - src/backend/optimizer/util - paramassign.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 96.5 % 342 330
Test Date: 2026-01-26 10:56:24 Functions: 100.0 % 14 14
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 69.4 % 170 118

             Branch data     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-2026, 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                 :        6995 : assign_param_for_var(PlannerInfo *root, Var *var)
      67                 :             : {
      68                 :        6995 :         ListCell   *ppl;
      69                 :        6995 :         PlannerParamItem *pitem;
      70                 :        6995 :         Index           levelsup;
      71                 :             : 
      72                 :             :         /* Find the query level the Var belongs to */
      73         [ +  + ]:       14040 :         for (levelsup = var->varlevelsup; levelsup > 0; levelsup--)
      74                 :        7045 :                 root = root->parent_root;
      75                 :             : 
      76                 :             :         /* If there's already a matching PlannerParamItem there, just use it */
      77   [ +  +  +  +  :       11974 :         foreach(ppl, root->plan_params)
             +  +  +  + ]
      78                 :             :         {
      79                 :        4979 :                 pitem = (PlannerParamItem *) lfirst(ppl);
      80         [ -  + ]:        4979 :                 if (IsA(pitem->item, Var))
      81                 :             :                 {
      82                 :        4979 :                         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         [ +  + ]:        4979 :                         if (pvar->varno == var->varno &&
      90         [ +  + ]:        4787 :                                 pvar->varattno == var->varattno &&
      91         [ +  - ]:        1182 :                                 pvar->vartype == var->vartype &&
      92         [ +  - ]:        1182 :                                 pvar->vartypmod == var->vartypmod &&
      93         [ +  - ]:        1182 :                                 pvar->varcollid == var->varcollid &&
      94   [ +  +  -  + ]:        1182 :                                 pvar->varreturningtype == var->varreturningtype &&
      95                 :        1179 :                                 bms_equal(pvar->varnullingrels, var->varnullingrels))
      96                 :        1179 :                                 return pitem->paramId;
      97         [ +  + ]:        4979 :                 }
      98                 :        3800 :         }
      99                 :             : 
     100                 :             :         /* Nope, so make a new one */
     101                 :        5816 :         var = copyObject(var);
     102                 :        5816 :         var->varlevelsup = 0;
     103                 :             : 
     104                 :        5816 :         pitem = makeNode(PlannerParamItem);
     105                 :        5816 :         pitem->item = (Node *) var;
     106                 :        5816 :         pitem->paramId = list_length(root->glob->paramExecTypes);
     107                 :       11632 :         root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     108                 :        5816 :                                                                                          var->vartype);
     109                 :             : 
     110                 :        5816 :         root->plan_params = lappend(root->plan_params, pitem);
     111                 :             : 
     112                 :        5816 :         return pitem->paramId;
     113                 :        6995 : }
     114                 :             : 
     115                 :             : /*
     116                 :             :  * Generate a Param node to replace the given Var,
     117                 :             :  * which is expected to have varlevelsup > 0 (ie, it is not local).
     118                 :             :  * Record the need for the Var in the proper upper-level root->plan_params.
     119                 :             :  */
     120                 :             : Param *
     121                 :        6995 : replace_outer_var(PlannerInfo *root, Var *var)
     122                 :             : {
     123                 :        6995 :         Param      *retval;
     124                 :        6995 :         int                     i;
     125                 :             : 
     126         [ +  - ]:        6995 :         Assert(var->varlevelsup > 0 && var->varlevelsup < root->query_level);
     127                 :             : 
     128                 :             :         /* Find the Var in the appropriate plan_params, or add it if not present */
     129                 :        6995 :         i = assign_param_for_var(root, var);
     130                 :             : 
     131                 :        6995 :         retval = makeNode(Param);
     132                 :        6995 :         retval->paramkind = PARAM_EXEC;
     133                 :        6995 :         retval->paramid = i;
     134                 :        6995 :         retval->paramtype = var->vartype;
     135                 :        6995 :         retval->paramtypmod = var->vartypmod;
     136                 :        6995 :         retval->paramcollid = var->varcollid;
     137                 :        6995 :         retval->location = var->location;
     138                 :             : 
     139                 :       13990 :         return retval;
     140                 :        6995 : }
     141                 :             : 
     142                 :             : /*
     143                 :             :  * Select a PARAM_EXEC number to identify the given PlaceHolderVar as a
     144                 :             :  * parameter for the current subquery.  (It might already have one.)
     145                 :             :  * Record the need for the PHV in the proper upper-level root->plan_params.
     146                 :             :  *
     147                 :             :  * This is just like assign_param_for_var, except for PlaceHolderVars.
     148                 :             :  */
     149                 :             : static int
     150                 :          10 : assign_param_for_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
     151                 :             : {
     152                 :          10 :         ListCell   *ppl;
     153                 :          10 :         PlannerParamItem *pitem;
     154                 :          10 :         Index           levelsup;
     155                 :             : 
     156                 :             :         /* Find the query level the PHV belongs to */
     157         [ +  + ]:          20 :         for (levelsup = phv->phlevelsup; levelsup > 0; levelsup--)
     158                 :          10 :                 root = root->parent_root;
     159                 :             : 
     160                 :             :         /* If there's already a matching PlannerParamItem there, just use it */
     161   [ +  +  +  +  :          22 :         foreach(ppl, root->plan_params)
             +  +  -  + ]
     162                 :             :         {
     163                 :          12 :                 pitem = (PlannerParamItem *) lfirst(ppl);
     164         [ +  - ]:          12 :                 if (IsA(pitem->item, PlaceHolderVar))
     165                 :             :                 {
     166                 :           0 :                         PlaceHolderVar *pphv = (PlaceHolderVar *) pitem->item;
     167                 :             : 
     168                 :             :                         /* We assume comparing the PHIDs is sufficient */
     169         [ #  # ]:           0 :                         if (pphv->phid == phv->phid)
     170                 :           0 :                                 return pitem->paramId;
     171         [ #  # ]:           0 :                 }
     172                 :          12 :         }
     173                 :             : 
     174                 :             :         /* Nope, so make a new one */
     175                 :          10 :         phv = copyObject(phv);
     176                 :          10 :         IncrementVarSublevelsUp((Node *) phv, -((int) phv->phlevelsup), 0);
     177         [ +  - ]:          10 :         Assert(phv->phlevelsup == 0);
     178                 :             : 
     179                 :          10 :         pitem = makeNode(PlannerParamItem);
     180                 :          10 :         pitem->item = (Node *) phv;
     181                 :          10 :         pitem->paramId = list_length(root->glob->paramExecTypes);
     182                 :          20 :         root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     183                 :          10 :                                                                                          exprType((Node *) phv->phexpr));
     184                 :             : 
     185                 :          10 :         root->plan_params = lappend(root->plan_params, pitem);
     186                 :             : 
     187                 :          10 :         return pitem->paramId;
     188                 :          10 : }
     189                 :             : 
     190                 :             : /*
     191                 :             :  * Generate a Param node to replace the given PlaceHolderVar,
     192                 :             :  * which is expected to have phlevelsup > 0 (ie, it is not local).
     193                 :             :  * Record the need for the PHV in the proper upper-level root->plan_params.
     194                 :             :  *
     195                 :             :  * This is just like replace_outer_var, except for PlaceHolderVars.
     196                 :             :  */
     197                 :             : Param *
     198                 :          10 : replace_outer_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
     199                 :             : {
     200                 :          10 :         Param      *retval;
     201                 :          10 :         int                     i;
     202                 :             : 
     203         [ +  - ]:          10 :         Assert(phv->phlevelsup > 0 && phv->phlevelsup < root->query_level);
     204                 :             : 
     205                 :             :         /* Find the PHV in the appropriate plan_params, or add it if not present */
     206                 :          10 :         i = assign_param_for_placeholdervar(root, phv);
     207                 :             : 
     208                 :          10 :         retval = makeNode(Param);
     209                 :          10 :         retval->paramkind = PARAM_EXEC;
     210                 :          10 :         retval->paramid = i;
     211                 :          10 :         retval->paramtype = exprType((Node *) phv->phexpr);
     212                 :          10 :         retval->paramtypmod = exprTypmod((Node *) phv->phexpr);
     213                 :          10 :         retval->paramcollid = exprCollation((Node *) phv->phexpr);
     214                 :          10 :         retval->location = -1;
     215                 :             : 
     216                 :          20 :         return retval;
     217                 :          10 : }
     218                 :             : 
     219                 :             : /*
     220                 :             :  * Generate a Param node to replace the given Aggref
     221                 :             :  * which is expected to have agglevelsup > 0 (ie, it is not local).
     222                 :             :  * Record the need for the Aggref in the proper upper-level root->plan_params.
     223                 :             :  */
     224                 :             : Param *
     225                 :           9 : replace_outer_agg(PlannerInfo *root, Aggref *agg)
     226                 :             : {
     227                 :           9 :         Param      *retval;
     228                 :           9 :         PlannerParamItem *pitem;
     229                 :           9 :         Index           levelsup;
     230                 :             : 
     231         [ +  - ]:           9 :         Assert(agg->agglevelsup > 0 && agg->agglevelsup < root->query_level);
     232                 :             : 
     233                 :             :         /* Find the query level the Aggref belongs to */
     234         [ +  + ]:          18 :         for (levelsup = agg->agglevelsup; levelsup > 0; levelsup--)
     235                 :           9 :                 root = root->parent_root;
     236                 :             : 
     237                 :             :         /*
     238                 :             :          * It does not seem worthwhile to try to de-duplicate references to outer
     239                 :             :          * aggs.  Just make a new slot every time.
     240                 :             :          */
     241                 :           9 :         agg = copyObject(agg);
     242                 :           9 :         IncrementVarSublevelsUp((Node *) agg, -((int) agg->agglevelsup), 0);
     243         [ +  - ]:           9 :         Assert(agg->agglevelsup == 0);
     244                 :             : 
     245                 :           9 :         pitem = makeNode(PlannerParamItem);
     246                 :           9 :         pitem->item = (Node *) agg;
     247                 :           9 :         pitem->paramId = list_length(root->glob->paramExecTypes);
     248                 :          18 :         root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     249                 :           9 :                                                                                          agg->aggtype);
     250                 :             : 
     251                 :           9 :         root->plan_params = lappend(root->plan_params, pitem);
     252                 :             : 
     253                 :           9 :         retval = makeNode(Param);
     254                 :           9 :         retval->paramkind = PARAM_EXEC;
     255                 :           9 :         retval->paramid = pitem->paramId;
     256                 :           9 :         retval->paramtype = agg->aggtype;
     257                 :           9 :         retval->paramtypmod = -1;
     258                 :           9 :         retval->paramcollid = agg->aggcollid;
     259                 :           9 :         retval->location = agg->location;
     260                 :             : 
     261                 :          18 :         return retval;
     262                 :           9 : }
     263                 :             : 
     264                 :             : /*
     265                 :             :  * Generate a Param node to replace the given GroupingFunc expression which is
     266                 :             :  * expected to have agglevelsup > 0 (ie, it is not local).
     267                 :             :  * Record the need for the GroupingFunc in the proper upper-level
     268                 :             :  * root->plan_params.
     269                 :             :  */
     270                 :             : Param *
     271                 :          10 : replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp)
     272                 :             : {
     273                 :          10 :         Param      *retval;
     274                 :          10 :         PlannerParamItem *pitem;
     275                 :          10 :         Index           levelsup;
     276                 :          10 :         Oid                     ptype = exprType((Node *) grp);
     277                 :             : 
     278         [ +  - ]:          10 :         Assert(grp->agglevelsup > 0 && grp->agglevelsup < root->query_level);
     279                 :             : 
     280                 :             :         /* Find the query level the GroupingFunc belongs to */
     281         [ +  + ]:          21 :         for (levelsup = grp->agglevelsup; levelsup > 0; levelsup--)
     282                 :          11 :                 root = root->parent_root;
     283                 :             : 
     284                 :             :         /*
     285                 :             :          * It does not seem worthwhile to try to de-duplicate references to outer
     286                 :             :          * aggs.  Just make a new slot every time.
     287                 :             :          */
     288                 :          10 :         grp = copyObject(grp);
     289                 :          10 :         IncrementVarSublevelsUp((Node *) grp, -((int) grp->agglevelsup), 0);
     290         [ +  - ]:          10 :         Assert(grp->agglevelsup == 0);
     291                 :             : 
     292                 :          10 :         pitem = makeNode(PlannerParamItem);
     293                 :          10 :         pitem->item = (Node *) grp;
     294                 :          10 :         pitem->paramId = list_length(root->glob->paramExecTypes);
     295                 :          20 :         root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     296                 :          10 :                                                                                          ptype);
     297                 :             : 
     298                 :          10 :         root->plan_params = lappend(root->plan_params, pitem);
     299                 :             : 
     300                 :          10 :         retval = makeNode(Param);
     301                 :          10 :         retval->paramkind = PARAM_EXEC;
     302                 :          10 :         retval->paramid = pitem->paramId;
     303                 :          10 :         retval->paramtype = ptype;
     304                 :          10 :         retval->paramtypmod = -1;
     305                 :          10 :         retval->paramcollid = InvalidOid;
     306                 :          10 :         retval->location = grp->location;
     307                 :             : 
     308                 :          20 :         return retval;
     309                 :          10 : }
     310                 :             : 
     311                 :             : /*
     312                 :             :  * Generate a Param node to replace the given MergeSupportFunc expression
     313                 :             :  * which is expected to be in the RETURNING list of an upper-level MERGE
     314                 :             :  * query.  Record the need for the MergeSupportFunc in the proper upper-level
     315                 :             :  * root->plan_params.
     316                 :             :  */
     317                 :             : Param *
     318                 :           1 : replace_outer_merge_support(PlannerInfo *root, MergeSupportFunc *msf)
     319                 :             : {
     320                 :           1 :         Param      *retval;
     321                 :           1 :         PlannerParamItem *pitem;
     322                 :           1 :         Oid                     ptype = exprType((Node *) msf);
     323                 :             : 
     324         [ +  - ]:           1 :         Assert(root->parse->commandType != CMD_MERGE);
     325                 :             : 
     326                 :             :         /*
     327                 :             :          * The parser should have ensured that the MergeSupportFunc is in the
     328                 :             :          * RETURNING list of an upper-level MERGE query, so find that query.
     329                 :             :          */
     330                 :           1 :         do
     331                 :             :         {
     332                 :           1 :                 root = root->parent_root;
     333         [ +  - ]:           1 :                 if (root == NULL)
     334   [ #  #  #  # ]:           0 :                         elog(ERROR, "MergeSupportFunc found outside MERGE");
     335         [ -  + ]:           1 :         } while (root->parse->commandType != CMD_MERGE);
     336                 :             : 
     337                 :             :         /*
     338                 :             :          * It does not seem worthwhile to try to de-duplicate references to outer
     339                 :             :          * MergeSupportFunc expressions.  Just make a new slot every time.
     340                 :             :          */
     341                 :           1 :         msf = copyObject(msf);
     342                 :             : 
     343                 :           1 :         pitem = makeNode(PlannerParamItem);
     344                 :           1 :         pitem->item = (Node *) msf;
     345                 :           1 :         pitem->paramId = list_length(root->glob->paramExecTypes);
     346                 :           2 :         root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     347                 :           1 :                                                                                          ptype);
     348                 :             : 
     349                 :           1 :         root->plan_params = lappend(root->plan_params, pitem);
     350                 :             : 
     351                 :           1 :         retval = makeNode(Param);
     352                 :           1 :         retval->paramkind = PARAM_EXEC;
     353                 :           1 :         retval->paramid = pitem->paramId;
     354                 :           1 :         retval->paramtype = ptype;
     355                 :           1 :         retval->paramtypmod = -1;
     356                 :           1 :         retval->paramcollid = InvalidOid;
     357                 :           1 :         retval->location = msf->location;
     358                 :             : 
     359                 :           2 :         return retval;
     360                 :           1 : }
     361                 :             : 
     362                 :             : /*
     363                 :             :  * Generate a Param node to replace the given ReturningExpr expression which
     364                 :             :  * is expected to have retlevelsup > 0 (ie, it is not local).  Record the need
     365                 :             :  * for the ReturningExpr in the proper upper-level root->plan_params.
     366                 :             :  */
     367                 :             : Param *
     368                 :           3 : replace_outer_returning(PlannerInfo *root, ReturningExpr *rexpr)
     369                 :             : {
     370                 :           3 :         Param      *retval;
     371                 :           3 :         PlannerParamItem *pitem;
     372                 :           3 :         Index           levelsup;
     373                 :           3 :         Oid                     ptype = exprType((Node *) rexpr->retexpr);
     374                 :             : 
     375         [ +  - ]:           3 :         Assert(rexpr->retlevelsup > 0 && rexpr->retlevelsup < root->query_level);
     376                 :             : 
     377                 :             :         /* Find the query level the ReturningExpr belongs to */
     378         [ +  + ]:           7 :         for (levelsup = rexpr->retlevelsup; levelsup > 0; levelsup--)
     379                 :           4 :                 root = root->parent_root;
     380                 :             : 
     381                 :             :         /*
     382                 :             :          * It does not seem worthwhile to try to de-duplicate references to outer
     383                 :             :          * ReturningExprs.  Just make a new slot every time.
     384                 :             :          */
     385                 :           3 :         rexpr = copyObject(rexpr);
     386                 :           3 :         IncrementVarSublevelsUp((Node *) rexpr, -((int) rexpr->retlevelsup), 0);
     387         [ +  - ]:           3 :         Assert(rexpr->retlevelsup == 0);
     388                 :             : 
     389                 :           3 :         pitem = makeNode(PlannerParamItem);
     390                 :           3 :         pitem->item = (Node *) rexpr;
     391                 :           3 :         pitem->paramId = list_length(root->glob->paramExecTypes);
     392                 :           6 :         root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     393                 :           3 :                                                                                          ptype);
     394                 :             : 
     395                 :           3 :         root->plan_params = lappend(root->plan_params, pitem);
     396                 :             : 
     397                 :           3 :         retval = makeNode(Param);
     398                 :           3 :         retval->paramkind = PARAM_EXEC;
     399                 :           3 :         retval->paramid = pitem->paramId;
     400                 :           3 :         retval->paramtype = ptype;
     401                 :           3 :         retval->paramtypmod = exprTypmod((Node *) rexpr->retexpr);
     402                 :           3 :         retval->paramcollid = exprCollation((Node *) rexpr->retexpr);
     403                 :           3 :         retval->location = exprLocation((Node *) rexpr->retexpr);
     404                 :             : 
     405                 :           6 :         return retval;
     406                 :           3 : }
     407                 :             : 
     408                 :             : /*
     409                 :             :  * Generate a Param node to replace the given Var,
     410                 :             :  * which is expected to come from some upper NestLoop plan node.
     411                 :             :  * Record the need for the Var in root->curOuterParams.
     412                 :             :  */
     413                 :             : Param *
     414                 :        8594 : replace_nestloop_param_var(PlannerInfo *root, Var *var)
     415                 :             : {
     416                 :        8594 :         Param      *param;
     417                 :        8594 :         NestLoopParam *nlp;
     418                 :        8594 :         ListCell   *lc;
     419                 :             : 
     420                 :             :         /* Is this Var already listed in root->curOuterParams? */
     421   [ +  +  +  +  :       14015 :         foreach(lc, root->curOuterParams)
             +  +  +  + ]
     422                 :             :         {
     423                 :        5421 :                 nlp = (NestLoopParam *) lfirst(lc);
     424         [ +  + ]:        5421 :                 if (equal(var, nlp->paramval))
     425                 :             :                 {
     426                 :             :                         /* Yes, so just make a Param referencing this NLP's slot */
     427                 :        4499 :                         param = makeNode(Param);
     428                 :        4499 :                         param->paramkind = PARAM_EXEC;
     429                 :        4499 :                         param->paramid = nlp->paramno;
     430                 :        4499 :                         param->paramtype = var->vartype;
     431                 :        4499 :                         param->paramtypmod = var->vartypmod;
     432                 :        4499 :                         param->paramcollid = var->varcollid;
     433                 :        4499 :                         param->location = var->location;
     434                 :        4499 :                         return param;
     435                 :             :                 }
     436                 :         922 :         }
     437                 :             : 
     438                 :             :         /* No, so assign a PARAM_EXEC slot for a new NLP */
     439                 :        8190 :         param = generate_new_exec_param(root,
     440                 :        4095 :                                                                         var->vartype,
     441                 :        4095 :                                                                         var->vartypmod,
     442                 :        4095 :                                                                         var->varcollid);
     443                 :        4095 :         param->location = var->location;
     444                 :             : 
     445                 :             :         /* Add it to the list of required NLPs */
     446                 :        4095 :         nlp = makeNode(NestLoopParam);
     447                 :        4095 :         nlp->paramno = param->paramid;
     448                 :        4095 :         nlp->paramval = copyObject(var);
     449                 :        4095 :         root->curOuterParams = lappend(root->curOuterParams, nlp);
     450                 :             : 
     451                 :             :         /* And return the replacement Param */
     452                 :        4095 :         return param;
     453                 :        8594 : }
     454                 :             : 
     455                 :             : /*
     456                 :             :  * Generate a Param node to replace the given PlaceHolderVar,
     457                 :             :  * which is expected to come from some upper NestLoop plan node.
     458                 :             :  * Record the need for the PHV in root->curOuterParams.
     459                 :             :  *
     460                 :             :  * This is just like replace_nestloop_param_var, except for PlaceHolderVars.
     461                 :             :  */
     462                 :             : Param *
     463                 :          54 : replace_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
     464                 :             : {
     465                 :          54 :         Param      *param;
     466                 :          54 :         NestLoopParam *nlp;
     467                 :          54 :         ListCell   *lc;
     468                 :             : 
     469                 :             :         /* Is this PHV already listed in root->curOuterParams? */
     470   [ +  +  +  +  :          91 :         foreach(lc, root->curOuterParams)
             +  +  +  + ]
     471                 :             :         {
     472                 :          37 :                 nlp = (NestLoopParam *) lfirst(lc);
     473         [ +  + ]:          37 :                 if (equal(phv, nlp->paramval))
     474                 :             :                 {
     475                 :             :                         /* Yes, so just make a Param referencing this NLP's slot */
     476                 :          20 :                         param = makeNode(Param);
     477                 :          20 :                         param->paramkind = PARAM_EXEC;
     478                 :          20 :                         param->paramid = nlp->paramno;
     479                 :          20 :                         param->paramtype = exprType((Node *) phv->phexpr);
     480                 :          20 :                         param->paramtypmod = exprTypmod((Node *) phv->phexpr);
     481                 :          20 :                         param->paramcollid = exprCollation((Node *) phv->phexpr);
     482                 :          20 :                         param->location = -1;
     483                 :          20 :                         return param;
     484                 :             :                 }
     485                 :          17 :         }
     486                 :             : 
     487                 :             :         /* No, so assign a PARAM_EXEC slot for a new NLP */
     488                 :          68 :         param = generate_new_exec_param(root,
     489                 :          34 :                                                                         exprType((Node *) phv->phexpr),
     490                 :          34 :                                                                         exprTypmod((Node *) phv->phexpr),
     491                 :          34 :                                                                         exprCollation((Node *) phv->phexpr));
     492                 :             : 
     493                 :             :         /* Add it to the list of required NLPs */
     494                 :          34 :         nlp = makeNode(NestLoopParam);
     495                 :          34 :         nlp->paramno = param->paramid;
     496                 :          34 :         nlp->paramval = (Var *) copyObject(phv);
     497                 :          34 :         root->curOuterParams = lappend(root->curOuterParams, nlp);
     498                 :             : 
     499                 :             :         /* And return the replacement Param */
     500                 :          34 :         return param;
     501                 :          54 : }
     502                 :             : 
     503                 :             : /*
     504                 :             :  * process_subquery_nestloop_params
     505                 :             :  *        Handle params of a parameterized subquery that need to be fed
     506                 :             :  *        from an outer nestloop.
     507                 :             :  *
     508                 :             :  * Currently, that would be *all* params that a subquery in FROM has demanded
     509                 :             :  * from the current query level, since they must be LATERAL references.
     510                 :             :  *
     511                 :             :  * subplan_params is a list of PlannerParamItems that we intend to pass to
     512                 :             :  * a subquery-in-FROM.  (This was constructed in root->plan_params while
     513                 :             :  * planning the subquery, but isn't there anymore when this is called.)
     514                 :             :  *
     515                 :             :  * The subplan's references to the outer variables are already represented
     516                 :             :  * as PARAM_EXEC Params, since that conversion was done by the routines above
     517                 :             :  * while planning the subquery.  So we need not modify the subplan or the
     518                 :             :  * PlannerParamItems here.  What we do need to do is add entries to
     519                 :             :  * root->curOuterParams to signal the parent nestloop plan node that it must
     520                 :             :  * provide these values.  This differs from replace_nestloop_param_var in
     521                 :             :  * that the PARAM_EXEC slots to use have already been determined.
     522                 :             :  *
     523                 :             :  * Note that we also use root->curOuterRels as an implicit parameter for
     524                 :             :  * sanity checks.
     525                 :             :  */
     526                 :             : void
     527                 :          93 : process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
     528                 :             : {
     529                 :          93 :         ListCell   *lc;
     530                 :             : 
     531   [ +  +  +  +  :         206 :         foreach(lc, subplan_params)
                   +  + ]
     532                 :             :         {
     533                 :         113 :                 PlannerParamItem *pitem = lfirst_node(PlannerParamItem, lc);
     534                 :             : 
     535         [ +  + ]:         113 :                 if (IsA(pitem->item, Var))
     536                 :             :                 {
     537                 :         105 :                         Var                *var = (Var *) pitem->item;
     538                 :         105 :                         NestLoopParam *nlp;
     539                 :         105 :                         ListCell   *lc2;
     540                 :             : 
     541                 :             :                         /* If not from a nestloop outer rel, complain */
     542         [ +  - ]:         105 :                         if (!bms_is_member(var->varno, root->curOuterRels))
     543   [ #  #  #  # ]:           0 :                                 elog(ERROR, "non-LATERAL parameter required by subquery");
     544                 :             : 
     545                 :             :                         /* Is this param already listed in root->curOuterParams? */
     546   [ +  +  +  +  :         142 :                         foreach(lc2, root->curOuterParams)
                   +  + ]
     547                 :             :                         {
     548                 :          37 :                                 nlp = (NestLoopParam *) lfirst(lc2);
     549         [ +  - ]:          37 :                                 if (nlp->paramno == pitem->paramId)
     550                 :             :                                 {
     551         [ #  # ]:           0 :                                         Assert(equal(var, nlp->paramval));
     552                 :             :                                         /* Present, so nothing to do */
     553                 :           0 :                                         break;
     554                 :             :                                 }
     555                 :          37 :                         }
     556         [ -  + ]:         105 :                         if (lc2 == NULL)
     557                 :             :                         {
     558                 :             :                                 /* No, so add it */
     559                 :         105 :                                 nlp = makeNode(NestLoopParam);
     560                 :         105 :                                 nlp->paramno = pitem->paramId;
     561                 :         105 :                                 nlp->paramval = copyObject(var);
     562                 :         105 :                                 root->curOuterParams = lappend(root->curOuterParams, nlp);
     563                 :         105 :                         }
     564                 :         105 :                 }
     565         [ +  - ]:           8 :                 else if (IsA(pitem->item, PlaceHolderVar))
     566                 :             :                 {
     567                 :           8 :                         PlaceHolderVar *phv = (PlaceHolderVar *) pitem->item;
     568                 :           8 :                         NestLoopParam *nlp;
     569                 :           8 :                         ListCell   *lc2;
     570                 :             : 
     571                 :             :                         /* If not from a nestloop outer rel, complain */
     572   [ +  -  +  - ]:          16 :                         if (!bms_is_subset(find_placeholder_info(root, phv)->ph_eval_at,
     573                 :           8 :                                                            root->curOuterRels))
     574   [ #  #  #  # ]:           0 :                                 elog(ERROR, "non-LATERAL parameter required by subquery");
     575                 :             : 
     576                 :             :                         /* Is this param already listed in root->curOuterParams? */
     577   [ +  +  +  +  :          21 :                         foreach(lc2, root->curOuterParams)
                   +  + ]
     578                 :             :                         {
     579                 :          13 :                                 nlp = (NestLoopParam *) lfirst(lc2);
     580         [ +  - ]:          13 :                                 if (nlp->paramno == pitem->paramId)
     581                 :             :                                 {
     582         [ #  # ]:           0 :                                         Assert(equal(phv, nlp->paramval));
     583                 :             :                                         /* Present, so nothing to do */
     584                 :           0 :                                         break;
     585                 :             :                                 }
     586                 :          13 :                         }
     587         [ -  + ]:           8 :                         if (lc2 == NULL)
     588                 :             :                         {
     589                 :             :                                 /* No, so add it */
     590                 :           8 :                                 nlp = makeNode(NestLoopParam);
     591                 :           8 :                                 nlp->paramno = pitem->paramId;
     592                 :           8 :                                 nlp->paramval = (Var *) copyObject(phv);
     593                 :           8 :                                 root->curOuterParams = lappend(root->curOuterParams, nlp);
     594                 :           8 :                         }
     595                 :           8 :                 }
     596                 :             :                 else
     597   [ #  #  #  # ]:           0 :                         elog(ERROR, "unexpected type of subquery parameter");
     598                 :         113 :         }
     599                 :          93 : }
     600                 :             : 
     601                 :             : /*
     602                 :             :  * Identify any NestLoopParams that should be supplied by a NestLoop
     603                 :             :  * plan node with the specified lefthand rels and required-outer rels.
     604                 :             :  * Remove them from the active root->curOuterParams list and return
     605                 :             :  * them as the result list.
     606                 :             :  *
     607                 :             :  * Vars and PHVs appearing in the result list must have nullingrel sets
     608                 :             :  * that could validly appear in the lefthand rel's output.  Ordinarily that
     609                 :             :  * would be true already, but if we have applied outer join identity 3,
     610                 :             :  * there could be more or fewer nullingrel bits in the nodes appearing in
     611                 :             :  * curOuterParams than are in the nominal leftrelids.  We deal with that by
     612                 :             :  * forcing their nullingrel sets to include exactly the outer-join relids
     613                 :             :  * that appear in leftrelids and can null the respective Var or PHV.
     614                 :             :  * This fix is a bit ad-hoc and intellectually unsatisfactory, because it's
     615                 :             :  * essentially jumping to the conclusion that we've placed evaluation of
     616                 :             :  * the nestloop parameters correctly, and thus it defeats the intent of the
     617                 :             :  * subsequent nullingrel cross-checks in setrefs.c.  But the alternative
     618                 :             :  * seems to be to generate multiple versions of each laterally-parameterized
     619                 :             :  * subquery, which'd be unduly expensive.
     620                 :             :  */
     621                 :             : List *
     622                 :        9143 : identify_current_nestloop_params(PlannerInfo *root,
     623                 :             :                                                                  Relids leftrelids,
     624                 :             :                                                                  Relids outerrelids)
     625                 :             : {
     626                 :        9143 :         List       *result;
     627                 :        9143 :         Relids          allleftrelids;
     628                 :        9143 :         ListCell   *cell;
     629                 :             : 
     630                 :             :         /*
     631                 :             :          * We'll be able to evaluate a PHV in the lefthand path if it uses the
     632                 :             :          * lefthand rels plus any available required-outer rels.  But don't do so
     633                 :             :          * if it uses *only* required-outer rels; in that case it should be
     634                 :             :          * evaluated higher in the tree.  For Vars, no such hair-splitting is
     635                 :             :          * necessary since they depend on only one relid.
     636                 :             :          */
     637         [ +  + ]:        9143 :         if (outerrelids)
     638                 :         138 :                 allleftrelids = bms_union(leftrelids, outerrelids);
     639                 :             :         else
     640                 :        9005 :                 allleftrelids = leftrelids;
     641                 :             : 
     642                 :        9143 :         result = NIL;
     643   [ +  +  +  +  :       13545 :         foreach(cell, root->curOuterParams)
                   +  + ]
     644                 :             :         {
     645                 :        4402 :                 NestLoopParam *nlp = (NestLoopParam *) lfirst(cell);
     646                 :             : 
     647                 :             :                 /*
     648                 :             :                  * We are looking for Vars and PHVs that can be supplied by the
     649                 :             :                  * lefthand rels.  When we find one, it's okay to modify it in-place
     650                 :             :                  * because all the routines above make a fresh copy to put into
     651                 :             :                  * curOuterParams.
     652                 :             :                  */
     653   [ +  +  +  + ]:        4402 :                 if (IsA(nlp->paramval, Var) &&
     654                 :        4358 :                         bms_is_member(nlp->paramval->varno, leftrelids))
     655                 :             :                 {
     656                 :        4200 :                         Var                *var = (Var *) nlp->paramval;
     657                 :        4200 :                         RelOptInfo *rel = root->simple_rel_array[var->varno];
     658                 :             : 
     659                 :        4200 :                         root->curOuterParams = foreach_delete_current(root->curOuterParams,
     660                 :             :                                                                                                                   cell);
     661                 :        8400 :                         var->varnullingrels = bms_intersect(rel->nulling_relids,
     662                 :        4200 :                                                                                                 leftrelids);
     663                 :        4200 :                         result = lappend(result, nlp);
     664                 :        4200 :                 }
     665         [ +  + ]:         202 :                 else if (IsA(nlp->paramval, PlaceHolderVar))
     666                 :             :                 {
     667                 :          44 :                         PlaceHolderVar *phv = (PlaceHolderVar *) nlp->paramval;
     668                 :          44 :                         PlaceHolderInfo *phinfo = find_placeholder_info(root, phv);
     669                 :          44 :                         Relids          eval_at = phinfo->ph_eval_at;
     670                 :             : 
     671   [ +  -  +  + ]:          44 :                         if (bms_is_subset(eval_at, allleftrelids) &&
     672                 :          44 :                                 bms_overlap(eval_at, leftrelids))
     673                 :             :                         {
     674                 :          42 :                                 root->curOuterParams = foreach_delete_current(root->curOuterParams,
     675                 :             :                                                                                                                           cell);
     676                 :             : 
     677                 :             :                                 /*
     678                 :             :                                  * Deal with an edge case: if the PHV was pulled up out of a
     679                 :             :                                  * subquery and it contains a subquery that was originally
     680                 :             :                                  * pushed down from this query level, then that will still be
     681                 :             :                                  * represented as a SubLink, because SS_process_sublinks won't
     682                 :             :                                  * recurse into outer PHVs, so it didn't get transformed
     683                 :             :                                  * during expression preprocessing in the subquery.  We need a
     684                 :             :                                  * version of the PHV that has a SubPlan, which we can get
     685                 :             :                                  * from the current query level's placeholder_list.  This is
     686                 :             :                                  * quite grotty of course, but dealing with it earlier in the
     687                 :             :                                  * handling of subplan params would be just as grotty, and it
     688                 :             :                                  * might end up being a waste of cycles if we don't decide to
     689                 :             :                                  * treat the PHV as a NestLoopParam.  (Perhaps that whole
     690                 :             :                                  * mechanism should be redesigned someday, but today is not
     691                 :             :                                  * that day.)
     692                 :             :                                  */
     693         [ +  + ]:          42 :                                 if (root->parse->hasSubLinks)
     694                 :             :                                 {
     695                 :           4 :                                         phv = copyObject(phinfo->ph_var);
     696                 :             : 
     697                 :             :                                         /*
     698                 :             :                                          * The ph_var will have empty nullingrels, but that
     699                 :             :                                          * doesn't matter since we're about to overwrite
     700                 :             :                                          * phv->phnullingrels.  Other fields should be OK already.
     701                 :             :                                          */
     702                 :           4 :                                         nlp->paramval = (Var *) phv;
     703                 :           4 :                                 }
     704                 :             : 
     705                 :          42 :                                 phv->phnullingrels =
     706                 :          84 :                                         bms_intersect(get_placeholder_nulling_relids(root, phinfo),
     707                 :          42 :                                                                   leftrelids);
     708                 :             : 
     709                 :          42 :                                 result = lappend(result, nlp);
     710                 :          42 :                         }
     711                 :          44 :                 }
     712                 :        4402 :         }
     713                 :       18286 :         return result;
     714                 :        9143 : }
     715                 :             : 
     716                 :             : /*
     717                 :             :  * Generate a new Param node that will not conflict with any other.
     718                 :             :  *
     719                 :             :  * This is used to create Params representing subplan outputs or
     720                 :             :  * NestLoop parameters.
     721                 :             :  *
     722                 :             :  * We don't need to build a PlannerParamItem for such a Param, but we do
     723                 :             :  * need to make sure we record the type in paramExecTypes (otherwise,
     724                 :             :  * there won't be a slot allocated for it).
     725                 :             :  */
     726                 :             : Param *
     727                 :        5364 : generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod,
     728                 :             :                                                 Oid paramcollation)
     729                 :             : {
     730                 :        5364 :         Param      *retval;
     731                 :             : 
     732                 :        5364 :         retval = makeNode(Param);
     733                 :        5364 :         retval->paramkind = PARAM_EXEC;
     734                 :        5364 :         retval->paramid = list_length(root->glob->paramExecTypes);
     735                 :       10728 :         root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     736                 :        5364 :                                                                                          paramtype);
     737                 :        5364 :         retval->paramtype = paramtype;
     738                 :        5364 :         retval->paramtypmod = paramtypmod;
     739                 :        5364 :         retval->paramcollid = paramcollation;
     740                 :        5364 :         retval->location = -1;
     741                 :             : 
     742                 :       10728 :         return retval;
     743                 :        5364 : }
     744                 :             : 
     745                 :             : /*
     746                 :             :  * Assign a (nonnegative) PARAM_EXEC ID for a special parameter (one that
     747                 :             :  * is not actually used to carry a value at runtime).  Such parameters are
     748                 :             :  * used for special runtime signaling purposes, such as connecting a
     749                 :             :  * recursive union node to its worktable scan node or forcing plan
     750                 :             :  * re-evaluation within the EvalPlanQual mechanism.  No actual Param node
     751                 :             :  * exists with this ID, however.
     752                 :             :  */
     753                 :             : int
     754                 :        8540 : assign_special_exec_param(PlannerInfo *root)
     755                 :             : {
     756                 :        8540 :         int                     paramId = list_length(root->glob->paramExecTypes);
     757                 :             : 
     758                 :        8540 :         root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
     759                 :             :                                                                                          InvalidOid);
     760                 :       17080 :         return paramId;
     761                 :        8540 : }
        

Generated by: LCOV version 2.3.2-1