YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

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