Coverage Report

Created: 2025-09-27 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/executor/nodeNamedtuplestorescan.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * nodeNamedtuplestorescan.c
4
 *    routines to handle NamedTuplestoreScan nodes.
5
 *
6
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *
10
 * IDENTIFICATION
11
 *    src/backend/executor/nodeNamedtuplestorescan.c
12
 *
13
 *-------------------------------------------------------------------------
14
 */
15
16
#include "postgres.h"
17
18
#include "executor/executor.h"
19
#include "executor/nodeNamedtuplestorescan.h"
20
#include "utils/queryenvironment.h"
21
22
static TupleTableSlot *NamedTuplestoreScanNext(NamedTuplestoreScanState *node);
23
24
/* ----------------------------------------------------------------
25
 *    NamedTuplestoreScanNext
26
 *
27
 *    This is a workhorse for ExecNamedTuplestoreScan
28
 * ----------------------------------------------------------------
29
 */
30
static TupleTableSlot *
31
NamedTuplestoreScanNext(NamedTuplestoreScanState *node)
32
0
{
33
0
  TupleTableSlot *slot;
34
35
  /* We intentionally do not support backward scan. */
36
0
  Assert(ScanDirectionIsForward(node->ss.ps.state->es_direction));
37
38
  /*
39
   * Get the next tuple from tuplestore. Return NULL if no more tuples.
40
   */
41
0
  slot = node->ss.ss_ScanTupleSlot;
42
0
  tuplestore_select_read_pointer(node->relation, node->readptr);
43
0
  (void) tuplestore_gettupleslot(node->relation, true, false, slot);
44
0
  return slot;
45
0
}
46
47
/*
48
 * NamedTuplestoreScanRecheck -- access method routine to recheck a tuple in
49
 * EvalPlanQual
50
 */
51
static bool
52
NamedTuplestoreScanRecheck(NamedTuplestoreScanState *node, TupleTableSlot *slot)
53
0
{
54
  /* nothing to check */
55
0
  return true;
56
0
}
57
58
/* ----------------------------------------------------------------
59
 *    ExecNamedTuplestoreScan(node)
60
 *
61
 *    Scans the CTE sequentially and returns the next qualifying tuple.
62
 *    We call the ExecScan() routine and pass it the appropriate
63
 *    access method functions.
64
 * ----------------------------------------------------------------
65
 */
66
static TupleTableSlot *
67
ExecNamedTuplestoreScan(PlanState *pstate)
68
0
{
69
0
  NamedTuplestoreScanState *node = castNode(NamedTuplestoreScanState, pstate);
70
71
0
  return ExecScan(&node->ss,
72
0
          (ExecScanAccessMtd) NamedTuplestoreScanNext,
73
0
          (ExecScanRecheckMtd) NamedTuplestoreScanRecheck);
74
0
}
75
76
77
/* ----------------------------------------------------------------
78
 *    ExecInitNamedTuplestoreScan
79
 * ----------------------------------------------------------------
80
 */
81
NamedTuplestoreScanState *
82
ExecInitNamedTuplestoreScan(NamedTuplestoreScan *node, EState *estate, int eflags)
83
0
{
84
0
  NamedTuplestoreScanState *scanstate;
85
0
  EphemeralNamedRelation enr;
86
87
  /* check for unsupported flags */
88
0
  Assert(!(eflags & (EXEC_FLAG_BACKWARD | EXEC_FLAG_MARK)));
89
90
  /*
91
   * NamedTuplestoreScan should not have any children.
92
   */
93
0
  Assert(outerPlan(node) == NULL);
94
0
  Assert(innerPlan(node) == NULL);
95
96
  /*
97
   * create new NamedTuplestoreScanState for node
98
   */
99
0
  scanstate = makeNode(NamedTuplestoreScanState);
100
0
  scanstate->ss.ps.plan = (Plan *) node;
101
0
  scanstate->ss.ps.state = estate;
102
0
  scanstate->ss.ps.ExecProcNode = ExecNamedTuplestoreScan;
103
104
0
  enr = get_ENR(estate->es_queryEnv, node->enrname);
105
0
  if (!enr)
106
0
    elog(ERROR, "executor could not find named tuplestore \"%s\"",
107
0
       node->enrname);
108
109
0
  Assert(enr->reldata);
110
0
  scanstate->relation = (Tuplestorestate *) enr->reldata;
111
0
  scanstate->tupdesc = ENRMetadataGetTupDesc(&(enr->md));
112
0
  scanstate->readptr =
113
0
    tuplestore_alloc_read_pointer(scanstate->relation, EXEC_FLAG_REWIND);
114
115
  /*
116
   * The new read pointer copies its position from read pointer 0, which
117
   * could be anywhere, so explicitly rewind it.
118
   */
119
0
  tuplestore_select_read_pointer(scanstate->relation, scanstate->readptr);
120
0
  tuplestore_rescan(scanstate->relation);
121
122
  /*
123
   * XXX: Should we add a function to free that read pointer when done?
124
   *
125
   * This was attempted, but it did not improve performance or memory usage
126
   * in any tested cases.
127
   */
128
129
  /*
130
   * Miscellaneous initialization
131
   *
132
   * create expression context for node
133
   */
134
0
  ExecAssignExprContext(estate, &scanstate->ss.ps);
135
136
  /*
137
   * The scan tuple type is specified for the tuplestore.
138
   */
139
0
  ExecInitScanTupleSlot(estate, &scanstate->ss, scanstate->tupdesc,
140
0
              &TTSOpsMinimalTuple);
141
142
  /*
143
   * Initialize result type and projection.
144
   */
145
0
  ExecInitResultTypeTL(&scanstate->ss.ps);
146
0
  ExecAssignScanProjectionInfo(&scanstate->ss);
147
148
  /*
149
   * initialize child expressions
150
   */
151
0
  scanstate->ss.ps.qual =
152
0
    ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
153
154
0
  return scanstate;
155
0
}
156
157
/* ----------------------------------------------------------------
158
 *    ExecReScanNamedTuplestoreScan
159
 *
160
 *    Rescans the relation.
161
 * ----------------------------------------------------------------
162
 */
163
void
164
ExecReScanNamedTuplestoreScan(NamedTuplestoreScanState *node)
165
0
{
166
0
  Tuplestorestate *tuplestorestate = node->relation;
167
168
0
  if (node->ss.ps.ps_ResultTupleSlot)
169
0
    ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
170
171
0
  ExecScanReScan(&node->ss);
172
173
  /*
174
   * Rewind my own pointer.
175
   */
176
0
  tuplestore_select_read_pointer(tuplestorestate, node->readptr);
177
0
  tuplestore_rescan(tuplestorestate);
178
0
}