YugabyteDB (2.13.0.0-b42, bfc6a6643e7399ac8a0e81d06a3ee6d6571b33ab)

Coverage Report

Created: 2022-03-09 17:30

/Users/deen/code/yugabyte-db/src/postgres/src/backend/executor/execAmi.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * execAmi.c
4
 *    miscellaneous executor access method routines
5
 *
6
 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *  src/backend/executor/execAmi.c
10
 *
11
 *-------------------------------------------------------------------------
12
 */
13
#include "postgres.h"
14
15
#include "access/amapi.h"
16
#include "access/htup_details.h"
17
#include "executor/execdebug.h"
18
#include "executor/nodeAgg.h"
19
#include "executor/nodeAppend.h"
20
#include "executor/nodeBitmapAnd.h"
21
#include "executor/nodeBitmapHeapscan.h"
22
#include "executor/nodeBitmapIndexscan.h"
23
#include "executor/nodeBitmapOr.h"
24
#include "executor/nodeCtescan.h"
25
#include "executor/nodeCustom.h"
26
#include "executor/nodeForeignscan.h"
27
#include "executor/nodeFunctionscan.h"
28
#include "executor/nodeGather.h"
29
#include "executor/nodeGatherMerge.h"
30
#include "executor/nodeGroup.h"
31
#include "executor/nodeGroup.h"
32
#include "executor/nodeHash.h"
33
#include "executor/nodeHashjoin.h"
34
#include "executor/nodeIndexonlyscan.h"
35
#include "executor/nodeIndexscan.h"
36
#include "executor/nodeLimit.h"
37
#include "executor/nodeLockRows.h"
38
#include "executor/nodeMaterial.h"
39
#include "executor/nodeMergeAppend.h"
40
#include "executor/nodeMergejoin.h"
41
#include "executor/nodeModifyTable.h"
42
#include "executor/nodeNamedtuplestorescan.h"
43
#include "executor/nodeNestloop.h"
44
#include "executor/nodeProjectSet.h"
45
#include "executor/nodeRecursiveunion.h"
46
#include "executor/nodeResult.h"
47
#include "executor/nodeSamplescan.h"
48
#include "executor/nodeSeqscan.h"
49
#include "executor/nodeSetOp.h"
50
#include "executor/nodeSort.h"
51
#include "executor/nodeSubplan.h"
52
#include "executor/nodeSubqueryscan.h"
53
#include "executor/nodeTableFuncscan.h"
54
#include "executor/nodeTidscan.h"
55
#include "executor/nodeUnique.h"
56
#include "executor/nodeValuesscan.h"
57
#include "executor/nodeWindowAgg.h"
58
#include "executor/nodeWorktablescan.h"
59
#include "nodes/nodeFuncs.h"
60
#include "nodes/relation.h"
61
#include "utils/rel.h"
62
#include "utils/syscache.h"
63
64
65
static bool IndexSupportsBackwardScan(Oid indexid);
66
67
68
/*
69
 * ExecReScan
70
 *    Reset a plan node so that its output can be re-scanned.
71
 *
72
 * Note that if the plan node has parameters that have changed value,
73
 * the output might be different from last time.
74
 */
75
void
76
ExecReScan(PlanState *node)
77
143k
{
78
  /* If collecting timing stats, update them */
79
143k
  if (node->instrument)
80
0
    InstrEndLoop(node->instrument);
81
82
  /*
83
   * If we have changed parameters, propagate that info.
84
   *
85
   * Note: ExecReScanSetParamPlan() can add bits to node->chgParam,
86
   * corresponding to the output param(s) that the InitPlan will update.
87
   * Since we make only one pass over the list, that means that an InitPlan
88
   * can depend on the output param(s) of a sibling InitPlan only if that
89
   * sibling appears earlier in the list.  This is workable for now given
90
   * the limited ways in which one InitPlan could depend on another, but
91
   * eventually we might need to work harder (or else make the planner
92
   * enlarge the extParam/allParam sets to include the params of depended-on
93
   * InitPlans).
94
   */
95
143k
  if (node->chgParam != NULL)
96
141k
  {
97
141k
    ListCell   *l;
98
99
141k
    foreach(l, node->initPlan)
100
0
    {
101
0
      SubPlanState *sstate = (SubPlanState *) lfirst(l);
102
0
      PlanState  *splan = sstate->planstate;
103
104
0
      if (splan->plan->extParam != NULL) /* don't care about child
105
                         * local Params */
106
0
        UpdateChangedParamSet(splan, node->chgParam);
107
0
      if (splan->chgParam != NULL)
108
0
        ExecReScanSetParamPlan(sstate, node);
109
0
    }
110
141k
    foreach(l, node->subPlan)
111
14
    {
112
14
      SubPlanState *sstate = (SubPlanState *) lfirst(l);
113
14
      PlanState  *splan = sstate->planstate;
114
115
14
      if (splan->plan->extParam != NULL)
116
11
        UpdateChangedParamSet(splan, node->chgParam);
117
14
    }
118
    /* Well. Now set chgParam for left/right trees. */
119
141k
    if (node->lefttree != NULL)
120
9.54k
      UpdateChangedParamSet(node->lefttree, node->chgParam);
121
141k
    if (node->righttree != NULL)
122
8.31k
      UpdateChangedParamSet(node->righttree, node->chgParam);
123
141k
  }
124
125
  /* Call expression callbacks */
126
143k
  if (node->ps_ExprContext)
127
141k
    ReScanExprContext(node->ps_ExprContext);
128
129
  /* And do node-type-specific processing */
130
143k
  switch (nodeTag(node))
131
143k
  {
132
67
    case T_ResultState:
133
67
      ExecReScanResult((ResultState *) node);
134
67
      break;
135
136
0
    case T_ProjectSetState:
137
0
      ExecReScanProjectSet((ProjectSetState *) node);
138
0
      break;
139
140
0
    case T_ModifyTableState:
141
0
      ExecReScanModifyTable((ModifyTableState *) node);
142
0
      break;
143
144
0
    case T_AppendState:
145
0
      ExecReScanAppend((AppendState *) node);
146
0
      break;
147
148
0
    case T_MergeAppendState:
149
0
      ExecReScanMergeAppend((MergeAppendState *) node);
150
0
      break;
151
152
0
    case T_RecursiveUnionState:
153
0
      ExecReScanRecursiveUnion((RecursiveUnionState *) node);
154
0
      break;
155
156
0
    case T_BitmapAndState:
157
0
      ExecReScanBitmapAnd((BitmapAndState *) node);
158
0
      break;
159
160
0
    case T_BitmapOrState:
161
0
      ExecReScanBitmapOr((BitmapOrState *) node);
162
0
      break;
163
164
0
    case T_SeqScanState:
165
0
      ExecReScanSeqScan((SeqScanState *) node);
166
0
      break;
167
168
0
    case T_SampleScanState:
169
0
      ExecReScanSampleScan((SampleScanState *) node);
170
0
      break;
171
172
0
    case T_GatherState:
173
0
      ExecReScanGather((GatherState *) node);
174
0
      break;
175
176
0
    case T_GatherMergeState:
177
0
      ExecReScanGatherMerge((GatherMergeState *) node);
178
0
      break;
179
180
129k
    case T_IndexScanState:
181
129k
      ExecReScanIndexScan((IndexScanState *) node);
182
129k
      break;
183
184
1
    case T_IndexOnlyScanState:
185
1
      ExecReScanIndexOnlyScan((IndexOnlyScanState *) node);
186
1
      break;
187
188
0
    case T_BitmapIndexScanState:
189
0
      ExecReScanBitmapIndexScan((BitmapIndexScanState *) node);
190
0
      break;
191
192
0
    case T_BitmapHeapScanState:
193
0
      ExecReScanBitmapHeapScan((BitmapHeapScanState *) node);
194
0
      break;
195
196
0
    case T_TidScanState:
197
0
      ExecReScanTidScan((TidScanState *) node);
198
0
      break;
199
200
129
    case T_SubqueryScanState:
201
129
      ExecReScanSubqueryScan((SubqueryScanState *) node);
202
129
      break;
203
204
298
    case T_FunctionScanState:
205
298
      ExecReScanFunctionScan((FunctionScanState *) node);
206
298
      break;
207
208
0
    case T_TableFuncScanState:
209
0
      ExecReScanTableFuncScan((TableFuncScanState *) node);
210
0
      break;
211
212
16
    case T_ValuesScanState:
213
16
      ExecReScanValuesScan((ValuesScanState *) node);
214
16
      break;
215
216
0
    case T_CteScanState:
217
0
      ExecReScanCteScan((CteScanState *) node);
218
0
      break;
219
220
0
    case T_NamedTuplestoreScanState:
221
0
      ExecReScanNamedTuplestoreScan((NamedTuplestoreScanState *) node);
222
0
      break;
223
224
0
    case T_WorkTableScanState:
225
0
      ExecReScanWorkTableScan((WorkTableScanState *) node);
226
0
      break;
227
228
2.04k
    case T_ForeignScanState:
229
2.04k
      ExecReScanForeignScan((ForeignScanState *) node);
230
2.04k
      break;
231
232
0
    case T_CustomScanState:
233
0
      ExecReScanCustomScan((CustomScanState *) node);
234
0
      break;
235
236
8.28k
    case T_NestLoopState:
237
8.28k
      ExecReScanNestLoop((NestLoopState *) node);
238
8.28k
      break;
239
240
0
    case T_MergeJoinState:
241
0
      ExecReScanMergeJoin((MergeJoinState *) node);
242
0
      break;
243
244
69
    case T_HashJoinState:
245
69
      ExecReScanHashJoin((HashJoinState *) node);
246
69
      break;
247
248
1.37k
    case T_MaterialState:
249
1.37k
      ExecReScanMaterial((MaterialState *) node);
250
1.37k
      break;
251
252
205
    case T_SortState:
253
205
      ExecReScanSort((SortState *) node);
254
205
      break;
255
256
0
    case T_GroupState:
257
0
      ExecReScanGroup((GroupState *) node);
258
0
      break;
259
260
1.04k
    case T_AggState:
261
1.04k
      ExecReScanAgg((AggState *) node);
262
1.04k
      break;
263
264
0
    case T_WindowAggState:
265
0
      ExecReScanWindowAgg((WindowAggState *) node);
266
0
      break;
267
268
0
    case T_UniqueState:
269
0
      ExecReScanUnique((UniqueState *) node);
270
0
      break;
271
272
24
    case T_HashState:
273
24
      ExecReScanHash((HashState *) node);
274
24
      break;
275
276
0
    case T_SetOpState:
277
0
      ExecReScanSetOp((SetOpState *) node);
278
0
      break;
279
280
0
    case T_LockRowsState:
281
0
      ExecReScanLockRows((LockRowsState *) node);
282
0
      break;
283
284
103
    case T_LimitState:
285
103
      ExecReScanLimit((LimitState *) node);
286
103
      break;
287
288
0
    default:
289
0
      elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
290
0
      break;
291
143k
  }
292
293
143k
  if (node->chgParam != NULL)
294
141k
  {
295
141k
    bms_free(node->chgParam);
296
141k
    node->chgParam = NULL;
297
141k
  }
298
143k
}
299
300
/*
301
 * ExecMarkPos
302
 *
303
 * Marks the current scan position.
304
 *
305
 * NOTE: mark/restore capability is currently needed only for plan nodes
306
 * that are the immediate inner child of a MergeJoin node.  Since MergeJoin
307
 * requires sorted input, there is never any need to support mark/restore in
308
 * node types that cannot produce sorted output.  There are some cases in
309
 * which a node can pass through sorted data from its child; if we don't
310
 * implement mark/restore for such a node type, the planner compensates by
311
 * inserting a Material node above that node.
312
 */
313
void
314
ExecMarkPos(PlanState *node)
315
56
{
316
56
  switch (nodeTag(node))
317
56
  {
318
0
    case T_IndexScanState:
319
0
      ExecIndexMarkPos((IndexScanState *) node);
320
0
      break;
321
322
0
    case T_IndexOnlyScanState:
323
0
      ExecIndexOnlyMarkPos((IndexOnlyScanState *) node);
324
0
      break;
325
326
0
    case T_CustomScanState:
327
0
      ExecCustomMarkPos((CustomScanState *) node);
328
0
      break;
329
330
35
    case T_MaterialState:
331
35
      ExecMaterialMarkPos((MaterialState *) node);
332
35
      break;
333
334
21
    case T_SortState:
335
21
      ExecSortMarkPos((SortState *) node);
336
21
      break;
337
338
0
    case T_ResultState:
339
0
      ExecResultMarkPos((ResultState *) node);
340
0
      break;
341
342
0
    default:
343
      /* don't make hard error unless caller asks to restore... */
344
0
      elog(DEBUG2, "unrecognized node type: %d", (int) nodeTag(node));
345
0
      break;
346
56
  }
347
56
}
348
349
/*
350
 * ExecRestrPos
351
 *
352
 * restores the scan position previously saved with ExecMarkPos()
353
 *
354
 * NOTE: the semantics of this are that the first ExecProcNode following
355
 * the restore operation will yield the same tuple as the first one following
356
 * the mark operation.  It is unspecified what happens to the plan node's
357
 * result TupleTableSlot.  (In most cases the result slot is unchanged by
358
 * a restore, but the node may choose to clear it or to load it with the
359
 * restored-to tuple.)  Hence the caller should discard any previously
360
 * returned TupleTableSlot after doing a restore.
361
 */
362
void
363
ExecRestrPos(PlanState *node)
364
1.00k
{
365
1.00k
  switch (nodeTag(node))
366
1.00k
  {
367
0
    case T_IndexScanState:
368
0
      ExecIndexRestrPos((IndexScanState *) node);
369
0
      break;
370
371
0
    case T_IndexOnlyScanState:
372
0
      ExecIndexOnlyRestrPos((IndexOnlyScanState *) node);
373
0
      break;
374
375
0
    case T_CustomScanState:
376
0
      ExecCustomRestrPos((CustomScanState *) node);
377
0
      break;
378
379
5
    case T_MaterialState:
380
5
      ExecMaterialRestrPos((MaterialState *) node);
381
5
      break;
382
383
1.00k
    case T_SortState:
384
1.00k
      ExecSortRestrPos((SortState *) node);
385
1.00k
      break;
386
387
0
    case T_ResultState:
388
0
      ExecResultRestrPos((ResultState *) node);
389
0
      break;
390
391
0
    default:
392
0
      elog(ERROR, "unrecognized node type: %d", (int) nodeTag(node));
393
0
      break;
394
1.00k
  }
395
1.00k
}
396
397
/*
398
 * ExecSupportsMarkRestore - does a Path support mark/restore?
399
 *
400
 * This is used during planning and so must accept a Path, not a Plan.
401
 * We keep it here to be adjacent to the routines above, which also must
402
 * know which plan types support mark/restore.
403
 */
404
bool
405
ExecSupportsMarkRestore(Path *pathnode)
406
227
{
407
  /*
408
   * For consistency with the routines above, we do not examine the nodeTag
409
   * but rather the pathtype, which is the Plan node type the Path would
410
   * produce.
411
   */
412
227
  switch (pathnode->pathtype)
413
227
  {
414
139
    case T_IndexScan:
415
139
    case T_IndexOnlyScan:
416
417
      /*
418
       * Yugabyte index scan do not support mark/restore, that would force
419
       * a Materialize plan node on top of the scan.
420
       * TODO Consider to support mark/restore. Though Materialize remote
421
       * index scan may be more efficient solution anyway.
422
       */
423
139
      return false;
424
425
0
    case T_Material:
426
0
    case T_Sort:
427
0
      return true;
428
429
0
    case T_CustomScan:
430
0
      {
431
0
        CustomPath *customPath = castNode(CustomPath, pathnode);
432
433
0
        if (customPath->flags & CUSTOMPATH_SUPPORT_MARK_RESTORE)
434
0
          return true;
435
0
        return false;
436
0
      }
437
0
    case T_Result:
438
439
      /*
440
       * Result supports mark/restore iff it has a child plan that does.
441
       *
442
       * We have to be careful here because there is more than one Path
443
       * type that can produce a Result plan node.
444
       */
445
0
      if (IsA(pathnode, ProjectionPath))
446
0
        return ExecSupportsMarkRestore(((ProjectionPath *) pathnode)->subpath);
447
0
      else if (IsA(pathnode, MinMaxAggPath))
448
0
        return false; /* childless Result */
449
0
      else
450
0
      {
451
0
        Assert(IsA(pathnode, ResultPath));
452
0
        return false; /* childless Result */
453
0
      }
454
455
88
    default:
456
88
      break;
457
88
  }
458
459
88
  return false;
460
88
}
461
462
/*
463
 * ExecSupportsBackwardScan - does a plan type support backwards scanning?
464
 *
465
 * Ideally, all plan types would support backwards scan, but that seems
466
 * unlikely to happen soon.  In some cases, a plan node passes the backwards
467
 * scan down to its children, and so supports backwards scan only if its
468
 * children do.  Therefore, this routine must be passed a complete plan tree.
469
 */
470
bool
471
ExecSupportsBackwardScan(Plan *node)
472
1.45k
{
473
1.45k
  if (node == NULL)
474
0
    return false;
475
476
  /*
477
   * Parallel-aware nodes return a subset of the tuples in each worker, and
478
   * in general we can't expect to have enough bookkeeping state to know
479
   * which ones we returned in this worker as opposed to some other worker.
480
   */
481
1.45k
  if (node->parallel_aware)
482
0
    return false;
483
484
1.45k
  switch (nodeTag(node))
485
1.45k
  {
486
0
    case T_Result:
487
0
      if (outerPlan(node) != NULL)
488
0
        return ExecSupportsBackwardScan(outerPlan(node));
489
0
      else
490
0
        return false;
491
492
0
    case T_Append:
493
0
      {
494
0
        ListCell   *l;
495
496
0
        foreach(l, ((Append *) node)->appendplans)
497
0
        {
498
0
          if (!ExecSupportsBackwardScan((Plan *) lfirst(l)))
499
0
            return false;
500
0
        }
501
        /* need not check tlist because Append doesn't evaluate it */
502
0
        return true;
503
0
      }
504
505
0
    case T_SampleScan:
506
      /* Simplify life for tablesample methods by disallowing this */
507
0
      return false;
508
509
0
    case T_Gather:
510
0
      return false;
511
512
9
    case T_IndexScan:
513
9
      return IndexSupportsBackwardScan(((IndexScan *) node)->indexid);
514
515
0
    case T_IndexOnlyScan:
516
0
      return IndexSupportsBackwardScan(((IndexOnlyScan *) node)->indexid);
517
518
0
    case T_SubqueryScan:
519
0
      return ExecSupportsBackwardScan(((SubqueryScan *) node)->subplan);
520
521
0
    case T_CustomScan:
522
0
      {
523
0
        uint32    flags = ((CustomScan *) node)->flags;
524
525
0
        if (flags & CUSTOMPATH_SUPPORT_BACKWARD_SCAN)
526
0
          return true;
527
0
      }
528
0
      return false;
529
530
0
    case T_SeqScan:
531
0
    case T_TidScan:
532
0
    case T_FunctionScan:
533
0
    case T_ValuesScan:
534
0
    case T_CteScan:
535
0
    case T_Material:
536
53
    case T_Sort:
537
53
      return true;
538
539
0
    case T_LockRows:
540
0
    case T_Limit:
541
0
      return ExecSupportsBackwardScan(outerPlan(node));
542
543
1.39k
    default:
544
1.39k
      return false;
545
1.45k
  }
546
1.45k
}
547
548
/*
549
 * An IndexScan or IndexOnlyScan node supports backward scan only if the
550
 * index's AM does.
551
 */
552
static bool
553
IndexSupportsBackwardScan(Oid indexid)
554
9
{
555
9
  bool    result;
556
9
  HeapTuple ht_idxrel;
557
9
  Form_pg_class idxrelrec;
558
9
  IndexAmRoutine *amroutine;
559
560
  /* Fetch the pg_class tuple of the index relation */
561
9
  ht_idxrel = SearchSysCache1(RELOID, ObjectIdGetDatum(indexid));
562
9
  if (!HeapTupleIsValid(ht_idxrel))
563
0
    elog(ERROR, "cache lookup failed for relation %u", indexid);
564
9
  idxrelrec = (Form_pg_class) GETSTRUCT(ht_idxrel);
565
566
  /* Fetch the index AM's API struct */
567
9
  amroutine = GetIndexAmRoutineByAmId(idxrelrec->relam, false);
568
569
9
  result = amroutine->amcanbackward;
570
571
9
  pfree(amroutine);
572
9
  ReleaseSysCache(ht_idxrel);
573
574
9
  return result;
575
9
}
576
577
/*
578
 * ExecMaterializesOutput - does a plan type materialize its output?
579
 *
580
 * Returns true if the plan node type is one that automatically materializes
581
 * its output (typically by keeping it in a tuplestore).  For such plans,
582
 * a rescan without any parameter change will have zero startup cost and
583
 * very low per-tuple cost.
584
 */
585
bool
586
ExecMaterializesOutput(NodeTag plantype)
587
27.4k
{
588
27.4k
  switch (plantype)
589
27.4k
  {
590
0
    case T_Material:
591
1.13k
    case T_FunctionScan:
592
1.13k
    case T_TableFuncScan:
593
7.43k
    case T_CteScan:
594
7.43k
    case T_NamedTuplestoreScan:
595
7.43k
    case T_WorkTableScan:
596
7.43k
    case T_Sort:
597
7.43k
      return true;
598
599
20.0k
    default:
600
20.0k
      break;
601
20.0k
  }
602
603
20.0k
  return false;
604
20.0k
}