LCOV - differential code coverage report
Current view: top level - src/backend/optimizer/util - paramassign.c (source / functions) Coverage Total Hit UBC CBC
Current: c70b6db34ffeab48beef1fb4ce61bcad3772b8dd vs 06473f5a344df8c9594ead90a609b86f6724cff8 Lines: 95.8 % 264 253 11 253
Current Date: 2025-09-06 07:49:51 +0900 Functions: 100.0 % 14 14 14
Baseline: lcov-20250906-005545-baseline Branches: 71.5 % 158 113 45 113
Baseline Date: 2025-09-05 08:21:35 +0100 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 40 40 40
(360..) days: 95.1 % 224 213 11 213
Function coverage date bins:
(30,360] days: 100.0 % 2 2 2
(360..) days: 100.0 % 12 12 12
Branch coverage date bins:
(30,360] days: 77.3 % 22 17 5 17
(360..) days: 70.6 % 136 96 40 96

 Age         Owner                    Branch data    TLA  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-2025, 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
 2430 tgl@sss.pgh.pa.us          66                 :CBC       26646 : 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         [ +  + ]:          53578 :     for (levelsup = var->varlevelsup; levelsup > 0; levelsup--)
                                 74                 :          26932 :         root = root->parent_root;
                                 75                 :                : 
                                 76                 :                :     /* If there's already a matching PlannerParamItem there, just use it */
                                 77   [ +  +  +  +  :          39150 :     foreach(ppl, root->plan_params)
                                              +  + ]
                                 78                 :                :     {
                                 79                 :          16552 :         pitem = (PlannerParamItem *) lfirst(ppl);
                                 80         [ +  - ]:          16552 :         if (IsA(pitem->item, Var))
                                 81                 :                :         {
                                 82                 :          16552 :             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         [ +  + ]:          16552 :             if (pvar->varno == var->varno &&
                                 90         [ +  + ]:          15458 :                 pvar->varattno == var->varattno &&
                                 91         [ +  - ]:           4057 :                 pvar->vartype == var->vartype &&
                                 92         [ +  - ]:           4057 :                 pvar->vartypmod == var->vartypmod &&
  589                            93         [ +  - ]:           4057 :                 pvar->varcollid == var->varcollid &&
  233 dean.a.rasheed@gmail       94   [ +  +  +  - ]:           8105 :                 pvar->varreturningtype == var->varreturningtype &&
  589 tgl@sss.pgh.pa.us          95                 :           4048 :                 bms_equal(pvar->varnullingrels, var->varnullingrels))
 2430                            96                 :           4048 :                 return pitem->paramId;
                                 97                 :                :         }
                                 98                 :                :     }
                                 99                 :                : 
                                100                 :                :     /* Nope, so make a new one */
                                101                 :          22598 :     var = copyObject(var);
                                102                 :          22598 :     var->varlevelsup = 0;
                                103                 :                : 
                                104                 :          22598 :     pitem = makeNode(PlannerParamItem);
                                105                 :          22598 :     pitem->item = (Node *) var;
                                106                 :          22598 :     pitem->paramId = list_length(root->glob->paramExecTypes);
                                107                 :          22598 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
                                108                 :                :                                              var->vartype);
                                109                 :                : 
                                110                 :          22598 :     root->plan_params = lappend(root->plan_params, pitem);
                                111                 :                : 
                                112                 :          22598 :     return pitem->paramId;
                                113                 :                : }
                                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                 :          26646 : replace_outer_var(PlannerInfo *root, Var *var)
                                122                 :                : {
                                123                 :                :     Param      *retval;
                                124                 :                :     int         i;
                                125                 :                : 
                                126   [ +  -  -  + ]:          26646 :     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                 :          26646 :     i = assign_param_for_var(root, var);
                                130                 :                : 
                                131                 :          26646 :     retval = makeNode(Param);
                                132                 :          26646 :     retval->paramkind = PARAM_EXEC;
                                133                 :          26646 :     retval->paramid = i;
                                134                 :          26646 :     retval->paramtype = var->vartype;
                                135                 :          26646 :     retval->paramtypmod = var->vartypmod;
                                136                 :          26646 :     retval->paramcollid = var->varcollid;
                                137                 :          26646 :     retval->location = var->location;
                                138                 :                : 
                                139                 :          26646 :     return retval;
                                140                 :                : }
                                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                 :             30 : assign_param_for_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
                                151                 :                : {
                                152                 :                :     ListCell   *ppl;
                                153                 :                :     PlannerParamItem *pitem;
                                154                 :                :     Index       levelsup;
                                155                 :                : 
                                156                 :                :     /* Find the query level the PHV belongs to */
                                157         [ +  + ]:             60 :     for (levelsup = phv->phlevelsup; levelsup > 0; levelsup--)
                                158                 :             30 :         root = root->parent_root;
                                159                 :                : 
                                160                 :                :     /* If there's already a matching PlannerParamItem there, just use it */
                                161   [ +  +  +  +  :             66 :     foreach(ppl, root->plan_params)
                                              +  + ]
                                162                 :                :     {
                                163                 :             36 :         pitem = (PlannerParamItem *) lfirst(ppl);
                                164         [ -  + ]:             36 :         if (IsA(pitem->item, PlaceHolderVar))
                                165                 :                :         {
 2430 tgl@sss.pgh.pa.us         166                 :UBC           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                 :                :         }
                                172                 :                :     }
                                173                 :                : 
                                174                 :                :     /* Nope, so make a new one */
 2430 tgl@sss.pgh.pa.us         175                 :CBC          30 :     phv = copyObject(phv);
                                176                 :             30 :     IncrementVarSublevelsUp((Node *) phv, -((int) phv->phlevelsup), 0);
                                177         [ -  + ]:             30 :     Assert(phv->phlevelsup == 0);
                                178                 :                : 
                                179                 :             30 :     pitem = makeNode(PlannerParamItem);
                                180                 :             30 :     pitem->item = (Node *) phv;
                                181                 :             30 :     pitem->paramId = list_length(root->glob->paramExecTypes);
                                182                 :             30 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
                                183                 :             30 :                                              exprType((Node *) phv->phexpr));
                                184                 :                : 
                                185                 :             30 :     root->plan_params = lappend(root->plan_params, pitem);
                                186                 :                : 
                                187                 :             30 :     return pitem->paramId;
                                188                 :                : }
                                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                 :             30 : replace_outer_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
                                199                 :                : {
                                200                 :                :     Param      *retval;
                                201                 :                :     int         i;
                                202                 :                : 
                                203   [ +  -  -  + ]:             30 :     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                 :             30 :     i = assign_param_for_placeholdervar(root, phv);
                                207                 :                : 
                                208                 :             30 :     retval = makeNode(Param);
                                209                 :             30 :     retval->paramkind = PARAM_EXEC;
                                210                 :             30 :     retval->paramid = i;
                                211                 :             30 :     retval->paramtype = exprType((Node *) phv->phexpr);
                                212                 :             30 :     retval->paramtypmod = exprTypmod((Node *) phv->phexpr);
                                213                 :             30 :     retval->paramcollid = exprCollation((Node *) phv->phexpr);
                                214                 :             30 :     retval->location = -1;
                                215                 :                : 
                                216                 :             30 :     return retval;
                                217                 :                : }
                                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                 :             26 : replace_outer_agg(PlannerInfo *root, Aggref *agg)
                                226                 :                : {
                                227                 :                :     Param      *retval;
                                228                 :                :     PlannerParamItem *pitem;
                                229                 :                :     Index       levelsup;
                                230                 :                : 
                                231   [ +  -  -  + ]:             26 :     Assert(agg->agglevelsup > 0 && agg->agglevelsup < root->query_level);
                                232                 :                : 
                                233                 :                :     /* Find the query level the Aggref belongs to */
                                234         [ +  + ]:             52 :     for (levelsup = agg->agglevelsup; levelsup > 0; levelsup--)
                                235                 :             26 :         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                 :             26 :     agg = copyObject(agg);
                                242                 :             26 :     IncrementVarSublevelsUp((Node *) agg, -((int) agg->agglevelsup), 0);
                                243         [ -  + ]:             26 :     Assert(agg->agglevelsup == 0);
                                244                 :                : 
                                245                 :             26 :     pitem = makeNode(PlannerParamItem);
                                246                 :             26 :     pitem->item = (Node *) agg;
                                247                 :             26 :     pitem->paramId = list_length(root->glob->paramExecTypes);
                                248                 :             26 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
                                249                 :                :                                              agg->aggtype);
                                250                 :                : 
                                251                 :             26 :     root->plan_params = lappend(root->plan_params, pitem);
                                252                 :                : 
                                253                 :             26 :     retval = makeNode(Param);
                                254                 :             26 :     retval->paramkind = PARAM_EXEC;
                                255                 :             26 :     retval->paramid = pitem->paramId;
                                256                 :             26 :     retval->paramtype = agg->aggtype;
                                257                 :             26 :     retval->paramtypmod = -1;
                                258                 :             26 :     retval->paramcollid = agg->aggcollid;
                                259                 :             26 :     retval->location = agg->location;
                                260                 :                : 
                                261                 :             26 :     return retval;
                                262                 :                : }
                                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                 :             32 : replace_outer_grouping(PlannerInfo *root, GroupingFunc *grp)
                                272                 :                : {
                                273                 :                :     Param      *retval;
                                274                 :                :     PlannerParamItem *pitem;
                                275                 :                :     Index       levelsup;
                                276                 :             32 :     Oid         ptype = exprType((Node *) grp);
                                277                 :                : 
                                278   [ +  -  -  + ]:             32 :     Assert(grp->agglevelsup > 0 && grp->agglevelsup < root->query_level);
                                279                 :                : 
                                280                 :                :     /* Find the query level the GroupingFunc belongs to */
                                281         [ +  + ]:             68 :     for (levelsup = grp->agglevelsup; levelsup > 0; levelsup--)
                                282                 :             36 :         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                 :             32 :     grp = copyObject(grp);
                                289                 :             32 :     IncrementVarSublevelsUp((Node *) grp, -((int) grp->agglevelsup), 0);
                                290         [ -  + ]:             32 :     Assert(grp->agglevelsup == 0);
                                291                 :                : 
                                292                 :             32 :     pitem = makeNode(PlannerParamItem);
                                293                 :             32 :     pitem->item = (Node *) grp;
                                294                 :             32 :     pitem->paramId = list_length(root->glob->paramExecTypes);
                                295                 :             32 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
                                296                 :                :                                              ptype);
                                297                 :                : 
                                298                 :             32 :     root->plan_params = lappend(root->plan_params, pitem);
                                299                 :                : 
                                300                 :             32 :     retval = makeNode(Param);
                                301                 :             32 :     retval->paramkind = PARAM_EXEC;
                                302                 :             32 :     retval->paramid = pitem->paramId;
                                303                 :             32 :     retval->paramtype = ptype;
                                304                 :             32 :     retval->paramtypmod = -1;
                                305                 :             32 :     retval->paramcollid = InvalidOid;
                                306                 :             32 :     retval->location = grp->location;
                                307                 :                : 
                                308                 :             32 :     return retval;
                                309                 :                : }
                                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 *
  538 dean.a.rasheed@gmail      318                 :              3 : replace_outer_merge_support(PlannerInfo *root, MergeSupportFunc *msf)
                                319                 :                : {
                                320                 :                :     Param      *retval;
                                321                 :                :     PlannerParamItem *pitem;
                                322                 :              3 :     Oid         ptype = exprType((Node *) msf);
                                323                 :                : 
                                324         [ -  + ]:              3 :     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                 :                :     do
                                331                 :                :     {
                                332                 :              3 :         root = root->parent_root;
                                333         [ -  + ]:              3 :         if (root == NULL)
  538 dean.a.rasheed@gmail      334         [ #  # ]:UBC           0 :             elog(ERROR, "MergeSupportFunc found outside MERGE");
  538 dean.a.rasheed@gmail      335         [ -  + ]:CBC           3 :     } 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                 :              3 :     msf = copyObject(msf);
                                342                 :                : 
                                343                 :              3 :     pitem = makeNode(PlannerParamItem);
                                344                 :              3 :     pitem->item = (Node *) msf;
                                345                 :              3 :     pitem->paramId = list_length(root->glob->paramExecTypes);
                                346                 :              3 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
                                347                 :                :                                              ptype);
                                348                 :                : 
                                349                 :              3 :     root->plan_params = lappend(root->plan_params, pitem);
                                350                 :                : 
                                351                 :              3 :     retval = makeNode(Param);
                                352                 :              3 :     retval->paramkind = PARAM_EXEC;
                                353                 :              3 :     retval->paramid = pitem->paramId;
                                354                 :              3 :     retval->paramtype = ptype;
                                355                 :              3 :     retval->paramtypmod = -1;
                                356                 :              3 :     retval->paramcollid = InvalidOid;
                                357                 :              3 :     retval->location = msf->location;
                                358                 :                : 
                                359                 :              3 :     return retval;
                                360                 :                : }
                                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 *
  233                           368                 :              9 : replace_outer_returning(PlannerInfo *root, ReturningExpr *rexpr)
                                369                 :                : {
                                370                 :                :     Param      *retval;
                                371                 :                :     PlannerParamItem *pitem;
                                372                 :                :     Index       levelsup;
                                373                 :              9 :     Oid         ptype = exprType((Node *) rexpr->retexpr);
                                374                 :                : 
                                375   [ +  -  -  + ]:              9 :     Assert(rexpr->retlevelsup > 0 && rexpr->retlevelsup < root->query_level);
                                376                 :                : 
                                377                 :                :     /* Find the query level the ReturningExpr belongs to */
                                378         [ +  + ]:             21 :     for (levelsup = rexpr->retlevelsup; levelsup > 0; levelsup--)
                                379                 :             12 :         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                 :              9 :     rexpr = copyObject(rexpr);
                                386                 :              9 :     IncrementVarSublevelsUp((Node *) rexpr, -((int) rexpr->retlevelsup), 0);
                                387         [ -  + ]:              9 :     Assert(rexpr->retlevelsup == 0);
                                388                 :                : 
                                389                 :              9 :     pitem = makeNode(PlannerParamItem);
                                390                 :              9 :     pitem->item = (Node *) rexpr;
                                391                 :              9 :     pitem->paramId = list_length(root->glob->paramExecTypes);
                                392                 :              9 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
                                393                 :                :                                              ptype);
                                394                 :                : 
                                395                 :              9 :     root->plan_params = lappend(root->plan_params, pitem);
                                396                 :                : 
                                397                 :              9 :     retval = makeNode(Param);
                                398                 :              9 :     retval->paramkind = PARAM_EXEC;
                                399                 :              9 :     retval->paramid = pitem->paramId;
                                400                 :              9 :     retval->paramtype = ptype;
                                401                 :              9 :     retval->paramtypmod = exprTypmod((Node *) rexpr->retexpr);
                                402                 :              9 :     retval->paramcollid = exprCollation((Node *) rexpr->retexpr);
                                403                 :              9 :     retval->location = exprLocation((Node *) rexpr->retexpr);
                                404                 :                : 
                                405                 :              9 :     return retval;
                                406                 :                : }
                                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 *
 2430 tgl@sss.pgh.pa.us         414                 :          45628 : replace_nestloop_param_var(PlannerInfo *root, Var *var)
                                415                 :                : {
                                416                 :                :     Param      *param;
                                417                 :                :     NestLoopParam *nlp;
                                418                 :                :     ListCell   *lc;
                                419                 :                : 
                                420                 :                :     /* Is this Var already listed in root->curOuterParams? */
                                421   [ +  +  +  +  :          50659 :     foreach(lc, root->curOuterParams)
                                              +  + ]
                                422                 :                :     {
                                423                 :          26118 :         nlp = (NestLoopParam *) lfirst(lc);
                                424         [ +  + ]:          26118 :         if (equal(var, nlp->paramval))
                                425                 :                :         {
                                426                 :                :             /* Yes, so just make a Param referencing this NLP's slot */
                                427                 :          21087 :             param = makeNode(Param);
                                428                 :          21087 :             param->paramkind = PARAM_EXEC;
                                429                 :          21087 :             param->paramid = nlp->paramno;
                                430                 :          21087 :             param->paramtype = var->vartype;
                                431                 :          21087 :             param->paramtypmod = var->vartypmod;
                                432                 :          21087 :             param->paramcollid = var->varcollid;
                                433                 :          21087 :             param->location = var->location;
                                434                 :          21087 :             return param;
                                435                 :                :         }
                                436                 :                :     }
                                437                 :                : 
                                438                 :                :     /* No, so assign a PARAM_EXEC slot for a new NLP */
                                439                 :          24541 :     param = generate_new_exec_param(root,
                                440                 :                :                                     var->vartype,
                                441                 :                :                                     var->vartypmod,
                                442                 :                :                                     var->varcollid);
                                443                 :          24541 :     param->location = var->location;
                                444                 :                : 
                                445                 :                :     /* Add it to the list of required NLPs */
                                446                 :          24541 :     nlp = makeNode(NestLoopParam);
                                447                 :          24541 :     nlp->paramno = param->paramid;
                                448                 :          24541 :     nlp->paramval = copyObject(var);
                                449                 :          24541 :     root->curOuterParams = lappend(root->curOuterParams, nlp);
                                450                 :                : 
                                451                 :                :     /* And return the replacement Param */
                                452                 :          24541 :     return param;
                                453                 :                : }
                                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                 :            162 : replace_nestloop_param_placeholdervar(PlannerInfo *root, PlaceHolderVar *phv)
                                464                 :                : {
                                465                 :                :     Param      *param;
                                466                 :                :     NestLoopParam *nlp;
                                467                 :                :     ListCell   *lc;
                                468                 :                : 
                                469                 :                :     /* Is this PHV already listed in root->curOuterParams? */
                                470   [ +  +  +  +  :            213 :     foreach(lc, root->curOuterParams)
                                              +  + ]
                                471                 :                :     {
                                472                 :            111 :         nlp = (NestLoopParam *) lfirst(lc);
                                473         [ +  + ]:            111 :         if (equal(phv, nlp->paramval))
                                474                 :                :         {
                                475                 :                :             /* Yes, so just make a Param referencing this NLP's slot */
                                476                 :             60 :             param = makeNode(Param);
                                477                 :             60 :             param->paramkind = PARAM_EXEC;
                                478                 :             60 :             param->paramid = nlp->paramno;
                                479                 :             60 :             param->paramtype = exprType((Node *) phv->phexpr);
                                480                 :             60 :             param->paramtypmod = exprTypmod((Node *) phv->phexpr);
                                481                 :             60 :             param->paramcollid = exprCollation((Node *) phv->phexpr);
                                482                 :             60 :             param->location = -1;
                                483                 :             60 :             return param;
                                484                 :                :         }
                                485                 :                :     }
                                486                 :                : 
                                487                 :                :     /* No, so assign a PARAM_EXEC slot for a new NLP */
                                488                 :            102 :     param = generate_new_exec_param(root,
                                489                 :            102 :                                     exprType((Node *) phv->phexpr),
                                490                 :            102 :                                     exprTypmod((Node *) phv->phexpr),
                                491                 :            102 :                                     exprCollation((Node *) phv->phexpr));
                                492                 :                : 
                                493                 :                :     /* Add it to the list of required NLPs */
                                494                 :            102 :     nlp = makeNode(NestLoopParam);
                                495                 :            102 :     nlp->paramno = param->paramid;
                                496                 :            102 :     nlp->paramval = (Var *) copyObject(phv);
                                497                 :            102 :     root->curOuterParams = lappend(root->curOuterParams, nlp);
                                498                 :                : 
                                499                 :                :     /* And return the replacement Param */
                                500                 :            102 :     return param;
                                501                 :                : }
                                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                 :            275 : process_subquery_nestloop_params(PlannerInfo *root, List *subplan_params)
                                528                 :                : {
                                529                 :                :     ListCell   *lc;
                                530                 :                : 
                                531   [ +  +  +  +  :            604 :     foreach(lc, subplan_params)
                                              +  + ]
                                532                 :                :     {
 1510 peter@eisentraut.org      533                 :            329 :         PlannerParamItem *pitem = lfirst_node(PlannerParamItem, lc);
                                534                 :                : 
 2430 tgl@sss.pgh.pa.us         535         [ +  + ]:            329 :         if (IsA(pitem->item, Var))
                                536                 :                :         {
                                537                 :            305 :             Var        *var = (Var *) pitem->item;
                                538                 :                :             NestLoopParam *nlp;
                                539                 :                :             ListCell   *lc2;
                                540                 :                : 
                                541                 :                :             /* If not from a nestloop outer rel, complain */
                                542         [ -  + ]:            305 :             if (!bms_is_member(var->varno, root->curOuterRels))
 2430 tgl@sss.pgh.pa.us         543         [ #  # ]:UBC           0 :                 elog(ERROR, "non-LATERAL parameter required by subquery");
                                544                 :                : 
                                545                 :                :             /* Is this param already listed in root->curOuterParams? */
 1067 drowley@postgresql.o      546   [ +  +  +  +  :CBC         410 :             foreach(lc2, root->curOuterParams)
                                              +  + ]
                                547                 :                :             {
                                548                 :            105 :                 nlp = (NestLoopParam *) lfirst(lc2);
 2430 tgl@sss.pgh.pa.us         549         [ -  + ]:            105 :                 if (nlp->paramno == pitem->paramId)
                                550                 :                :                 {
  809 tgl@sss.pgh.pa.us         551         [ #  # ]:UBC           0 :                     Assert(equal(var, nlp->paramval));
                                552                 :                :                     /* Present, so nothing to do */
 2430                           553                 :              0 :                     break;
                                554                 :                :                 }
                                555                 :                :             }
 1067 drowley@postgresql.o      556         [ +  - ]:CBC         305 :             if (lc2 == NULL)
                                557                 :                :             {
                                558                 :                :                 /* No, so add it */
 2430 tgl@sss.pgh.pa.us         559                 :            305 :                 nlp = makeNode(NestLoopParam);
                                560                 :            305 :                 nlp->paramno = pitem->paramId;
  809                           561                 :            305 :                 nlp->paramval = copyObject(var);
 2430                           562                 :            305 :                 root->curOuterParams = lappend(root->curOuterParams, nlp);
                                563                 :                :             }
                                564                 :                :         }
                                565         [ +  - ]:             24 :         else if (IsA(pitem->item, PlaceHolderVar))
                                566                 :                :         {
                                567                 :             24 :             PlaceHolderVar *phv = (PlaceHolderVar *) pitem->item;
                                568                 :                :             NestLoopParam *nlp;
                                569                 :                :             ListCell   *lc2;
                                570                 :                : 
                                571                 :                :             /* If not from a nestloop outer rel, complain */
 1116                           572         [ -  + ]:             24 :             if (!bms_is_subset(find_placeholder_info(root, phv)->ph_eval_at,
 2430                           573                 :             24 :                                root->curOuterRels))
 2430 tgl@sss.pgh.pa.us         574         [ #  # ]:UBC           0 :                 elog(ERROR, "non-LATERAL parameter required by subquery");
                                575                 :                : 
                                576                 :                :             /* Is this param already listed in root->curOuterParams? */
 1067 drowley@postgresql.o      577   [ +  +  +  +  :CBC          63 :             foreach(lc2, root->curOuterParams)
                                              +  + ]
                                578                 :                :             {
                                579                 :             39 :                 nlp = (NestLoopParam *) lfirst(lc2);
 2430 tgl@sss.pgh.pa.us         580         [ -  + ]:             39 :                 if (nlp->paramno == pitem->paramId)
                                581                 :                :                 {
  809 tgl@sss.pgh.pa.us         582         [ #  # ]:UBC           0 :                     Assert(equal(phv, nlp->paramval));
                                583                 :                :                     /* Present, so nothing to do */
 2430                           584                 :              0 :                     break;
                                585                 :                :                 }
                                586                 :                :             }
 1067 drowley@postgresql.o      587         [ +  - ]:CBC          24 :             if (lc2 == NULL)
                                588                 :                :             {
                                589                 :                :                 /* No, so add it */
 2430 tgl@sss.pgh.pa.us         590                 :             24 :                 nlp = makeNode(NestLoopParam);
                                591                 :             24 :                 nlp->paramno = pitem->paramId;
  809                           592                 :             24 :                 nlp->paramval = (Var *) copyObject(phv);
 2430                           593                 :             24 :                 root->curOuterParams = lappend(root->curOuterParams, nlp);
                                594                 :                :             }
                                595                 :                :         }
                                596                 :                :         else
 2430 tgl@sss.pgh.pa.us         597         [ #  # ]:UBC           0 :             elog(ERROR, "unexpected type of subquery parameter");
                                598                 :                :     }
 2430 tgl@sss.pgh.pa.us         599                 :CBC         275 : }
                                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 *
   69                           622                 :          45951 : identify_current_nestloop_params(PlannerInfo *root,
                                623                 :                :                                  Relids leftrelids,
                                624                 :                :                                  Relids outerrelids)
                                625                 :                : {
                                626                 :                :     List       *result;
                                627                 :                :     Relids      allleftrelids;
                                628                 :                :     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                 :                :      */
   78                           637         [ +  + ]:          45951 :     if (outerrelids)
                                638                 :            526 :         allleftrelids = bms_union(leftrelids, outerrelids);
                                639                 :                :     else
                                640                 :          45425 :         allleftrelids = leftrelids;
                                641                 :                : 
 2430                           642                 :          45951 :     result = NIL;
 2245                           643   [ +  +  +  +  :          71517 :     foreach(cell, root->curOuterParams)
                                              +  + ]
                                644                 :                :     {
 2430                           645                 :          25566 :         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   [ +  +  +  + ]:          51000 :         if (IsA(nlp->paramval, Var) &&
                                654                 :          25434 :             bms_is_member(nlp->paramval->varno, leftrelids))
                                655                 :          24846 :         {
  809                           656                 :          24846 :             Var        *var = (Var *) nlp->paramval;
   69                           657                 :          24846 :             RelOptInfo *rel = root->simple_rel_array[var->varno];
                                658                 :                : 
 2245                           659                 :          24846 :             root->curOuterParams = foreach_delete_current(root->curOuterParams,
                                660                 :                :                                                           cell);
   69                           661                 :          24846 :             var->varnullingrels = bms_intersect(rel->nulling_relids,
                                662                 :                :                                                 leftrelids);
 2430                           663                 :          24846 :             result = lappend(result, nlp);
                                664                 :                :         }
   78                           665         [ +  + ]:            720 :         else if (IsA(nlp->paramval, PlaceHolderVar))
                                666                 :                :         {
  809                           667                 :            132 :             PlaceHolderVar *phv = (PlaceHolderVar *) nlp->paramval;
   69                           668                 :            132 :             PlaceHolderInfo *phinfo = find_placeholder_info(root, phv);
                                669                 :            132 :             Relids      eval_at = phinfo->ph_eval_at;
                                670                 :                : 
   78                           671   [ +  -  +  + ]:            264 :             if (bms_is_subset(eval_at, allleftrelids) &&
                                672                 :            132 :                 bms_overlap(eval_at, leftrelids))
                                673                 :                :             {
                                674                 :            126 :                 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                 :                :                  */
   69                           693         [ +  + ]:            126 :                 if (root->parse->hasSubLinks)
                                694                 :                :                 {
                                695                 :             12 :                     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                 :             12 :                     nlp->paramval = (Var *) phv;
                                703                 :                :                 }
                                704                 :                : 
                                705                 :            126 :                 phv->phnullingrels =
                                706                 :            126 :                     bms_intersect(get_placeholder_nulling_relids(root, phinfo),
                                707                 :                :                                   leftrelids);
                                708                 :                : 
   78                           709                 :            126 :                 result = lappend(result, nlp);
                                710                 :                :             }
                                711                 :                :         }
                                712                 :                :     }
 2430                           713                 :          45951 :     return result;
                                714                 :                : }
                                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                 :          31784 : generate_new_exec_param(PlannerInfo *root, Oid paramtype, int32 paramtypmod,
                                728                 :                :                         Oid paramcollation)
                                729                 :                : {
                                730                 :                :     Param      *retval;
                                731                 :                : 
                                732                 :          31784 :     retval = makeNode(Param);
                                733                 :          31784 :     retval->paramkind = PARAM_EXEC;
                                734                 :          31784 :     retval->paramid = list_length(root->glob->paramExecTypes);
                                735                 :          31784 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
                                736                 :                :                                              paramtype);
                                737                 :          31784 :     retval->paramtype = paramtype;
                                738                 :          31784 :     retval->paramtypmod = paramtypmod;
                                739                 :          31784 :     retval->paramcollid = paramcollation;
                                740                 :          31784 :     retval->location = -1;
                                741                 :                : 
                                742                 :          31784 :     return retval;
                                743                 :                : }
                                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                 :          49549 : assign_special_exec_param(PlannerInfo *root)
                                755                 :                : {
                                756                 :          49549 :     int         paramId = list_length(root->glob->paramExecTypes);
                                757                 :                : 
                                758                 :          49549 :     root->glob->paramExecTypes = lappend_oid(root->glob->paramExecTypes,
                                759                 :                :                                              InvalidOid);
                                760                 :          49549 :     return paramId;
                                761                 :                : }
        

Generated by: LCOV version 2.4-beta