YugabyteDB (2.13.1.0-b60, 21121d69985fbf76aa6958d8f04a9bfa936293b5)

Coverage Report

Created: 2022-03-22 16:43

/Users/deen/code/yugabyte-db/src/postgres/src/backend/executor/nodeValuesscan.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * nodeValuesscan.c
4
 *    Support routines for scanning Values lists
5
 *    ("VALUES (...), (...), ..." in rangetable).
6
 *
7
 * Portions Copyright (c) 1996-2018, PostgreSQL Global Development Group
8
 * Portions Copyright (c) 1994, Regents of the University of California
9
 *
10
 *
11
 * IDENTIFICATION
12
 *    src/backend/executor/nodeValuesscan.c
13
 *
14
 *-------------------------------------------------------------------------
15
 */
16
/*
17
 * INTERFACE ROUTINES
18
 *    ExecValuesScan      scans a values list.
19
 *    ExecValuesNext      retrieve next tuple in sequential order.
20
 *    ExecInitValuesScan    creates and initializes a valuesscan node.
21
 *    ExecEndValuesScan   releases any storage allocated.
22
 *    ExecReScanValuesScan  rescans the values list
23
 */
24
#include "postgres.h"
25
26
#include "executor/executor.h"
27
#include "executor/nodeValuesscan.h"
28
#include "jit/jit.h"
29
#include "utils/expandeddatum.h"
30
31
32
static TupleTableSlot *ValuesNext(ValuesScanState *node);
33
34
35
/* ----------------------------------------------------------------
36
 *            Scan Support
37
 * ----------------------------------------------------------------
38
 */
39
40
/* ----------------------------------------------------------------
41
 *    ValuesNext
42
 *
43
 *    This is a workhorse for ExecValuesScan
44
 * ----------------------------------------------------------------
45
 */
46
static TupleTableSlot *
47
ValuesNext(ValuesScanState *node)
48
125k
{
49
125k
  TupleTableSlot *slot;
50
125k
  EState     *estate;
51
125k
  ExprContext *econtext;
52
125k
  ScanDirection direction;
53
125k
  List     *exprlist;
54
55
  /*
56
   * get information from the estate and scan state
57
   */
58
125k
  estate = node->ss.ps.state;
59
125k
  direction = estate->es_direction;
60
125k
  slot = node->ss.ss_ScanTupleSlot;
61
125k
  econtext = node->rowcontext;
62
63
  /*
64
   * Get the next tuple. Return NULL if no more tuples.
65
   */
66
125k
  if (ScanDirectionIsForward(direction))
67
125k
  {
68
125k
    if (node->curr_idx < node->array_len)
69
125k
      node->curr_idx++;
70
125k
    if (node->curr_idx < node->array_len)
71
123k
      exprlist = node->exprlists[node->curr_idx];
72
1.45k
    else
73
1.45k
      exprlist = NIL;
74
125k
  }
75
18.4E
  else
76
18.4E
  {
77
18.4E
    if (node->curr_idx >= 0)
78
0
      node->curr_idx--;
79
18.4E
    if (node->curr_idx >= 0)
80
0
      exprlist = node->exprlists[node->curr_idx];
81
18.4E
    else
82
18.4E
      exprlist = NIL;
83
18.4E
  }
84
85
  /*
86
   * Always clear the result slot; this is appropriate if we are at the end
87
   * of the data, and if we're not, we still need it as the first step of
88
   * the store-virtual-tuple protocol.  It seems wise to clear the slot
89
   * before we reset the context it might have pointers into.
90
   */
91
125k
  ExecClearTuple(slot);
92
93
125k
  if (exprlist)
94
123k
  {
95
123k
    MemoryContext oldContext;
96
123k
    List     *oldsubplans;
97
123k
    List     *exprstatelist;
98
123k
    Datum    *values;
99
123k
    bool     *isnull;
100
123k
    ListCell   *lc;
101
123k
    int     resind;
102
123k
    int     saved_jit_flags;
103
104
    /*
105
     * Get rid of any prior cycle's leftovers.  We use ReScanExprContext
106
     * not just ResetExprContext because we want any registered shutdown
107
     * callbacks to be called.
108
     */
109
123k
    ReScanExprContext(econtext);
110
111
    /*
112
     * Build the expression eval state in the econtext's per-tuple memory.
113
     * This is a tad unusual, but we want to delete the eval state again
114
     * when we move to the next row, to avoid growth of memory
115
     * requirements over a long values list.
116
     */
117
123k
    oldContext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
118
119
    /*
120
     * The expressions might contain SubPlans (this is currently only
121
     * possible if there's a sub-select containing a LATERAL reference,
122
     * otherwise sub-selects in a VALUES list should be InitPlans). Those
123
     * subplans will want to hook themselves into our subPlan list, which
124
     * would result in a corrupted list after we delete the eval state. We
125
     * can work around this by saving and restoring the subPlan list.
126
     * (There's no need for the functionality that would be enabled by
127
     * having the list entries, since the SubPlans aren't going to be
128
     * re-executed anyway.)
129
     */
130
123k
    oldsubplans = node->ss.ps.subPlan;
131
123k
    node->ss.ps.subPlan = NIL;
132
133
    /*
134
     * As the expressions are only ever used once, disable JIT for them.
135
     * This is worthwhile because it's common to insert significant
136
     * amounts of data via VALUES().
137
     */
138
123k
    saved_jit_flags = econtext->ecxt_estate->es_jit_flags;
139
123k
    econtext->ecxt_estate->es_jit_flags = PGJIT_NONE;
140
123k
    exprstatelist = ExecInitExprList(exprlist, &node->ss.ps);
141
123k
    econtext->ecxt_estate->es_jit_flags = saved_jit_flags;
142
143
123k
    node->ss.ps.subPlan = oldsubplans;
144
145
    /* parser should have checked all sublists are the same length */
146
123k
    Assert(list_length(exprstatelist) == slot->tts_tupleDescriptor->natts);
147
148
    /*
149
     * Compute the expressions and build a virtual result tuple. We
150
     * already did ExecClearTuple(slot).
151
     */
152
123k
    values = slot->tts_values;
153
123k
    isnull = slot->tts_isnull;
154
155
123k
    resind = 0;
156
123k
    foreach(lc, exprstatelist)
157
445k
    {
158
445k
      ExprState  *estate = (ExprState *) lfirst(lc);
159
445k
      Form_pg_attribute attr = TupleDescAttr(slot->tts_tupleDescriptor,
160
445k
                           resind);
161
162
445k
      values[resind] = ExecEvalExpr(estate,
163
445k
                      econtext,
164
445k
                      &isnull[resind]);
165
166
      /*
167
       * We must force any R/W expanded datums to read-only state, in
168
       * case they are multiply referenced in the plan node's output
169
       * expressions, or in case we skip the output projection and the
170
       * output column is multiply referenced in higher plan nodes.
171
       */
172
445k
      values[resind] = MakeExpandedObjectReadOnly(values[resind],
173
445k
                            isnull[resind],
174
445k
                            attr->attlen);
175
176
445k
      resind++;
177
445k
    }
178
179
123k
    MemoryContextSwitchTo(oldContext);
180
181
    /*
182
     * And return the virtual tuple.
183
     */
184
123k
    ExecStoreVirtualTuple(slot);
185
123k
  }
186
187
125k
  return slot;
188
125k
}
189
190
/*
191
 * ValuesRecheck -- access method routine to recheck a tuple in EvalPlanQual
192
 */
193
static bool
194
ValuesRecheck(ValuesScanState *node, TupleTableSlot *slot)
195
0
{
196
  /* nothing to check */
197
0
  return true;
198
0
}
199
200
/* ----------------------------------------------------------------
201
 *    ExecValuesScan(node)
202
 *
203
 *    Scans the values lists sequentially and returns the next qualifying
204
 *    tuple.
205
 *    We call the ExecScan() routine and pass it the appropriate
206
 *    access method functions.
207
 * ----------------------------------------------------------------
208
 */
209
static TupleTableSlot *
210
ExecValuesScan(PlanState *pstate)
211
124k
{
212
124k
  ValuesScanState *node = castNode(ValuesScanState, pstate);
213
214
124k
  return ExecScan(&node->ss,
215
124k
          (ExecScanAccessMtd) ValuesNext,
216
124k
          (ExecScanRecheckMtd) ValuesRecheck);
217
124k
}
218
219
/* ----------------------------------------------------------------
220
 *    ExecInitValuesScan
221
 * ----------------------------------------------------------------
222
 */
223
ValuesScanState *
224
ExecInitValuesScan(ValuesScan *node, EState *estate, int eflags)
225
2.52k
{
226
2.52k
  ValuesScanState *scanstate;
227
2.52k
  TupleDesc tupdesc;
228
2.52k
  ListCell   *vtl;
229
2.52k
  int     i;
230
2.52k
  PlanState  *planstate;
231
232
  /*
233
   * ValuesScan should not have any children.
234
   */
235
2.52k
  Assert(outerPlan(node) == NULL);
236
2.52k
  Assert(innerPlan(node) == NULL);
237
238
  /*
239
   * create new ScanState for node
240
   */
241
2.52k
  scanstate = makeNode(ValuesScanState);
242
0
  scanstate->ss.ps.plan = (Plan *) node;
243
2.52k
  scanstate->ss.ps.state = estate;
244
2.52k
  scanstate->ss.ps.ExecProcNode = ExecValuesScan;
245
246
  /*
247
   * Miscellaneous initialization
248
   */
249
2.52k
  planstate = &scanstate->ss.ps;
250
251
  /*
252
   * Create expression contexts.  We need two, one for per-sublist
253
   * processing and one for execScan.c to use for quals and projections. We
254
   * cheat a little by using ExecAssignExprContext() to build both.
255
   */
256
2.52k
  ExecAssignExprContext(estate, planstate);
257
2.52k
  scanstate->rowcontext = planstate->ps_ExprContext;
258
2.52k
  ExecAssignExprContext(estate, planstate);
259
260
  /*
261
   * Get info about values list, initialize scan slot with it.
262
   */
263
2.52k
  tupdesc = ExecTypeFromExprList((List *) linitial(node->values_lists));
264
2.52k
  ExecInitScanTupleSlot(estate, &scanstate->ss, tupdesc);
265
266
  /*
267
   * Initialize result type and projection.
268
   */
269
2.52k
  ExecInitResultTypeTL(&scanstate->ss.ps);
270
2.52k
  ExecAssignScanProjectionInfo(&scanstate->ss);
271
272
  /*
273
   * initialize child expressions
274
   */
275
2.52k
  scanstate->ss.ps.qual =
276
2.52k
    ExecInitQual(node->scan.plan.qual, (PlanState *) scanstate);
277
278
  /*
279
   * Other node-specific setup
280
   */
281
2.52k
  scanstate->curr_idx = -1;
282
2.52k
  scanstate->array_len = list_length(node->values_lists);
283
284
  /* convert list of sublists into array of sublists for easy addressing */
285
2.52k
  scanstate->exprlists = (List **)
286
2.52k
    palloc(scanstate->array_len * sizeof(List *));
287
2.52k
  i = 0;
288
2.52k
  foreach(vtl, node->values_lists)
289
124k
  {
290
124k
    scanstate->exprlists[i++] = (List *) lfirst(vtl);
291
124k
  }
292
293
2.52k
  return scanstate;
294
2.52k
}
295
296
/* ----------------------------------------------------------------
297
 *    ExecEndValuesScan
298
 *
299
 *    frees any storage allocated through C routines.
300
 * ----------------------------------------------------------------
301
 */
302
void
303
ExecEndValuesScan(ValuesScanState *node)
304
1.44k
{
305
  /*
306
   * Free both exprcontexts
307
   */
308
1.44k
  ExecFreeExprContext(&node->ss.ps);
309
1.44k
  node->ss.ps.ps_ExprContext = node->rowcontext;
310
1.44k
  ExecFreeExprContext(&node->ss.ps);
311
312
  /*
313
   * clean out the tuple table
314
   */
315
1.44k
  if (node->ss.ps.ps_ResultTupleSlot)
316
468
    ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
317
1.44k
  ExecClearTuple(node->ss.ss_ScanTupleSlot);
318
1.44k
}
319
320
/* ----------------------------------------------------------------
321
 *    ExecReScanValuesScan
322
 *
323
 *    Rescans the relation.
324
 * ----------------------------------------------------------------
325
 */
326
void
327
ExecReScanValuesScan(ValuesScanState *node)
328
16
{
329
16
  if (node->ss.ps.ps_ResultTupleSlot)
330
0
    ExecClearTuple(node->ss.ps.ps_ResultTupleSlot);
331
332
16
  ExecScanReScan(&node->ss);
333
334
16
  node->curr_idx = -1;
335
16
}