Coverage Report

Created: 2026-11-09 07:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/postgres/src/backend/executor/execTuples.c
Line
Count
Source
1
/*-------------------------------------------------------------------------
2
 *
3
 * execTuples.c
4
 *    Routines dealing with TupleTableSlots.  These are used for resource
5
 *    management associated with tuples (eg, releasing buffer pins for
6
 *    tuples in disk buffers, or freeing the memory occupied by transient
7
 *    tuples).  Slots also provide access abstraction that lets us implement
8
 *    "virtual" tuples to reduce data-copying overhead.
9
 *
10
 *    Routines dealing with the type information for tuples. Currently,
11
 *    the type information for a tuple is an array of FormData_pg_attribute.
12
 *    This information is needed by routines manipulating tuples
13
 *    (getattribute, formtuple, etc.).
14
 *
15
 *
16
 *   EXAMPLE OF HOW TABLE ROUTINES WORK
17
 *    Suppose we have a query such as SELECT emp.name FROM emp and we have
18
 *    a single SeqScan node in the query plan.
19
 *
20
 *    At ExecutorStart()
21
 *    ----------------
22
 *
23
 *    - ExecInitSeqScan() calls ExecInitScanTupleSlot() to construct a
24
 *      TupleTableSlots for the tuples returned by the access method, and
25
 *      ExecInitResultTypeTL() to define the node's return
26
 *      type. ExecAssignScanProjectionInfo() will, if necessary, create
27
 *      another TupleTableSlot for the tuples resulting from performing
28
 *      target list projections.
29
 *
30
 *    During ExecutorRun()
31
 *    ----------------
32
 *    - SeqNext() calls ExecStoreBufferHeapTuple() to place the tuple
33
 *      returned by the access method into the scan tuple slot.
34
 *
35
 *    - ExecSeqScan() (via ExecScan), if necessary, calls ExecProject(),
36
 *      putting the result of the projection in the result tuple slot. If
37
 *      not necessary, it directly returns the slot returned by SeqNext().
38
 *
39
 *    - ExecutePlan() calls the output function.
40
 *
41
 *    The important thing to watch in the executor code is how pointers
42
 *    to the slots containing tuples are passed instead of the tuples
43
 *    themselves.  This facilitates the communication of related information
44
 *    (such as whether or not a tuple should be pfreed, what buffer contains
45
 *    this tuple, the tuple's tuple descriptor, etc).  It also allows us
46
 *    to avoid physically constructing projection tuples in many cases.
47
 *
48
 *
49
 * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
50
 * Portions Copyright (c) 1994, Regents of the University of California
51
 *
52
 *
53
 * IDENTIFICATION
54
 *    src/backend/executor/execTuples.c
55
 *
56
 *-------------------------------------------------------------------------
57
 */
58
#include "postgres.h"
59
60
#include "access/heaptoast.h"
61
#include "access/htup_details.h"
62
#include "access/tupdesc_details.h"
63
#include "access/xact.h"
64
#include "catalog/pg_type.h"
65
#include "funcapi.h"
66
#include "nodes/nodeFuncs.h"
67
#include "storage/bufmgr.h"
68
#include "utils/builtins.h"
69
#include "utils/expandeddatum.h"
70
#include "utils/lsyscache.h"
71
#include "utils/typcache.h"
72
73
static TupleDesc ExecTypeFromTLInternal(List *targetList,
74
                    bool skipjunk);
75
static pg_always_inline void slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
76
                          int reqnatts, bool support_cstring);
77
static inline void tts_buffer_heap_store_tuple(TupleTableSlot *slot,
78
                         HeapTuple tuple,
79
                         Buffer buffer,
80
                         bool transfer_pin);
81
static void tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree);
82
83
84
const TupleTableSlotOps TTSOpsVirtual;
85
const TupleTableSlotOps TTSOpsHeapTuple;
86
const TupleTableSlotOps TTSOpsMinimalTuple;
87
const TupleTableSlotOps TTSOpsBufferHeapTuple;
88
89
90
/*
91
 * TupleTableSlotOps implementations.
92
 */
93
94
/*
95
 * TupleTableSlotOps implementation for VirtualTupleTableSlot.
96
 */
97
static void
98
tts_virtual_init(TupleTableSlot *slot)
99
0
{
100
0
}
101
102
static void
103
tts_virtual_release(TupleTableSlot *slot)
104
0
{
105
0
}
106
107
static void
108
tts_virtual_clear(TupleTableSlot *slot)
109
0
{
110
0
  if (unlikely(TTS_SHOULDFREE(slot)))
111
0
  {
112
0
    VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
113
114
0
    pfree(vslot->data);
115
0
    vslot->data = NULL;
116
117
0
    slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
118
0
  }
119
120
0
  slot->tts_nvalid = 0;
121
0
  slot->tts_flags |= TTS_FLAG_EMPTY;
122
0
  ItemPointerSetInvalid(&slot->tts_tid);
123
0
}
124
125
/*
126
 * VirtualTupleTableSlots always have fully populated tts_values and
127
 * tts_isnull arrays.  So this function should never be called.
128
 */
129
static void
130
tts_virtual_getsomeattrs(TupleTableSlot *slot, int natts)
131
0
{
132
0
  elog(ERROR, "getsomeattrs is not required to be called on a virtual tuple table slot");
133
0
}
134
135
/*
136
 * VirtualTupleTableSlots never provide system attributes (except those
137
 * handled generically, such as tableoid).  We generally shouldn't get
138
 * here, but provide a user-friendly message if we do.
139
 */
140
static Datum
141
tts_virtual_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
142
0
{
143
0
  Assert(!TTS_EMPTY(slot));
144
145
0
  ereport(ERROR,
146
0
      (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
147
0
       errmsg("cannot retrieve a system column in this context")));
148
149
0
  return 0;         /* silence compiler warnings */
150
0
}
151
152
/*
153
 * VirtualTupleTableSlots never have storage tuples.  We generally
154
 * shouldn't get here, but provide a user-friendly message if we do.
155
 */
156
static bool
157
tts_virtual_is_current_xact_tuple(TupleTableSlot *slot)
158
0
{
159
0
  Assert(!TTS_EMPTY(slot));
160
161
0
  ereport(ERROR,
162
0
      (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
163
0
       errmsg("don't have transaction information for this type of tuple")));
164
165
0
  return false;       /* silence compiler warnings */
166
0
}
167
168
/*
169
 * To materialize a virtual slot all the datums that aren't passed by value
170
 * have to be copied into the slot's memory context.  To do so, compute the
171
 * required size, and allocate enough memory to store all attributes.  That's
172
 * good for cache hit ratio, but more importantly requires only memory
173
 * allocation/deallocation.
174
 */
175
static void
176
tts_virtual_materialize(TupleTableSlot *slot)
177
0
{
178
0
  VirtualTupleTableSlot *vslot = (VirtualTupleTableSlot *) slot;
179
0
  TupleDesc desc = slot->tts_tupleDescriptor;
180
0
  Size    sz = 0;
181
0
  char     *data;
182
183
  /* already materialized */
184
0
  if (TTS_SHOULDFREE(slot))
185
0
    return;
186
187
  /* compute size of memory required */
188
0
  for (int natt = 0; natt < desc->natts; natt++)
189
0
  {
190
0
    CompactAttribute *att = TupleDescCompactAttr(desc, natt);
191
0
    Datum   val;
192
193
0
    if (att->attbyval || slot->tts_isnull[natt])
194
0
      continue;
195
196
0
    val = slot->tts_values[natt];
197
198
0
    if (att->attlen == -1 &&
199
0
      VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
200
0
    {
201
      /*
202
       * We want to flatten the expanded value so that the materialized
203
       * slot doesn't depend on it.
204
       */
205
0
      sz = att_nominal_alignby(sz, att->attalignby);
206
0
      sz += EOH_get_flat_size(DatumGetEOHP(val));
207
0
    }
208
0
    else
209
0
    {
210
0
      sz = att_nominal_alignby(sz, att->attalignby);
211
0
      sz = att_addlength_datum(sz, att->attlen, val);
212
0
    }
213
0
  }
214
215
  /* all data is byval */
216
0
  if (sz == 0)
217
0
    return;
218
219
  /* allocate memory */
220
0
  vslot->data = data = MemoryContextAlloc(slot->tts_mcxt, sz);
221
0
  slot->tts_flags |= TTS_FLAG_SHOULDFREE;
222
223
  /* and copy all attributes into the pre-allocated space */
224
0
  for (int natt = 0; natt < desc->natts; natt++)
225
0
  {
226
0
    CompactAttribute *att = TupleDescCompactAttr(desc, natt);
227
0
    Datum   val;
228
229
0
    if (att->attbyval || slot->tts_isnull[natt])
230
0
      continue;
231
232
0
    val = slot->tts_values[natt];
233
234
0
    if (att->attlen == -1 &&
235
0
      VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val)))
236
0
    {
237
0
      Size    data_length;
238
239
      /*
240
       * We want to flatten the expanded value so that the materialized
241
       * slot doesn't depend on it.
242
       */
243
0
      ExpandedObjectHeader *eoh = DatumGetEOHP(val);
244
245
0
      data = (char *) att_nominal_alignby(data,
246
0
                        att->attalignby);
247
0
      data_length = EOH_get_flat_size(eoh);
248
0
      EOH_flatten_into(eoh, data, data_length);
249
250
0
      slot->tts_values[natt] = PointerGetDatum(data);
251
0
      data += data_length;
252
0
    }
253
0
    else
254
0
    {
255
0
      Size    data_length = 0;
256
257
0
      data = (char *) att_nominal_alignby(data, att->attalignby);
258
0
      data_length = att_addlength_datum(data_length, att->attlen, val);
259
260
0
      memcpy(data, DatumGetPointer(val), data_length);
261
262
0
      slot->tts_values[natt] = PointerGetDatum(data);
263
0
      data += data_length;
264
0
    }
265
0
  }
266
0
}
267
268
static void
269
tts_virtual_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
270
0
{
271
0
  TupleDesc srcdesc = srcslot->tts_tupleDescriptor;
272
273
0
  tts_virtual_clear(dstslot);
274
275
0
  slot_getallattrs(srcslot);
276
277
0
  for (int natt = 0; natt < srcdesc->natts; natt++)
278
0
  {
279
0
    dstslot->tts_values[natt] = srcslot->tts_values[natt];
280
0
    dstslot->tts_isnull[natt] = srcslot->tts_isnull[natt];
281
0
  }
282
283
0
  dstslot->tts_nvalid = srcdesc->natts;
284
0
  dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
285
286
  /* make sure storage doesn't depend on external memory */
287
0
  tts_virtual_materialize(dstslot);
288
0
}
289
290
static HeapTuple
291
tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
292
0
{
293
0
  Assert(!TTS_EMPTY(slot));
294
295
0
  return heap_form_tuple(slot->tts_tupleDescriptor,
296
0
               slot->tts_values,
297
0
               slot->tts_isnull);
298
0
}
299
300
static MinimalTuple
301
tts_virtual_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
302
0
{
303
0
  Assert(!TTS_EMPTY(slot));
304
305
0
  return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
306
0
                   slot->tts_values,
307
0
                   slot->tts_isnull,
308
0
                   extra);
309
0
}
310
311
312
/*
313
 * TupleTableSlotOps implementation for HeapTupleTableSlot.
314
 */
315
316
static void
317
tts_heap_init(TupleTableSlot *slot)
318
0
{
319
0
}
320
321
static void
322
tts_heap_release(TupleTableSlot *slot)
323
0
{
324
0
}
325
326
static void
327
tts_heap_clear(TupleTableSlot *slot)
328
0
{
329
0
  HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
330
331
  /* Free the memory for the heap tuple if it's allowed. */
332
0
  if (TTS_SHOULDFREE(slot))
333
0
  {
334
0
    heap_freetuple(hslot->tuple);
335
0
    slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
336
0
  }
337
338
0
  slot->tts_nvalid = 0;
339
0
  slot->tts_flags |= TTS_FLAG_EMPTY;
340
0
  ItemPointerSetInvalid(&slot->tts_tid);
341
0
  hslot->off = 0;
342
0
  hslot->tuple = NULL;
343
0
}
344
345
static void
346
tts_heap_getsomeattrs(TupleTableSlot *slot, int natts)
347
0
{
348
0
  HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
349
350
0
  Assert(!TTS_EMPTY(slot));
351
352
0
  slot_deform_heap_tuple(slot, hslot->tuple, &hslot->off, natts, false);
353
0
}
354
355
static Datum
356
tts_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
357
0
{
358
0
  HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
359
360
0
  Assert(!TTS_EMPTY(slot));
361
362
  /*
363
   * In some code paths it's possible to get here with a non-materialized
364
   * slot, in which case we can't retrieve system columns.
365
   */
366
0
  if (!hslot->tuple)
367
0
    ereport(ERROR,
368
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
369
0
         errmsg("cannot retrieve a system column in this context")));
370
371
0
  return heap_getsysattr(hslot->tuple, attnum,
372
0
               slot->tts_tupleDescriptor, isnull);
373
0
}
374
375
static bool
376
tts_heap_is_current_xact_tuple(TupleTableSlot *slot)
377
0
{
378
0
  HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
379
0
  TransactionId xmin;
380
381
0
  Assert(!TTS_EMPTY(slot));
382
383
  /*
384
   * In some code paths it's possible to get here with a non-materialized
385
   * slot, in which case we can't check if tuple is created by the current
386
   * transaction.
387
   */
388
0
  if (!hslot->tuple)
389
0
    ereport(ERROR,
390
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
391
0
         errmsg("don't have a storage tuple in this context")));
392
393
0
  xmin = HeapTupleHeaderGetRawXmin(hslot->tuple->t_data);
394
395
0
  return TransactionIdIsCurrentTransactionId(xmin);
396
0
}
397
398
static void
399
tts_heap_materialize(TupleTableSlot *slot)
400
0
{
401
0
  HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
402
0
  MemoryContext oldContext;
403
404
0
  Assert(!TTS_EMPTY(slot));
405
406
  /* If slot has its tuple already materialized, nothing to do. */
407
0
  if (TTS_SHOULDFREE(slot))
408
0
    return;
409
410
0
  oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
411
412
  /*
413
   * Have to deform from scratch, otherwise tts_values[] entries could point
414
   * into the non-materialized tuple (which might be gone when accessed).
415
   */
416
0
  slot->tts_nvalid = 0;
417
0
  hslot->off = 0;
418
419
0
  if (!hslot->tuple)
420
0
    hslot->tuple = heap_form_tuple(slot->tts_tupleDescriptor,
421
0
                     slot->tts_values,
422
0
                     slot->tts_isnull);
423
0
  else
424
0
  {
425
    /*
426
     * The tuple contained in this slot is not allocated in the memory
427
     * context of the given slot (else it would have TTS_FLAG_SHOULDFREE
428
     * set).  Copy the tuple into the given slot's memory context.
429
     */
430
0
    hslot->tuple = heap_copytuple(hslot->tuple);
431
0
  }
432
433
0
  slot->tts_flags |= TTS_FLAG_SHOULDFREE;
434
435
0
  MemoryContextSwitchTo(oldContext);
436
0
}
437
438
static void
439
tts_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
440
0
{
441
0
  HeapTuple tuple;
442
0
  MemoryContext oldcontext;
443
444
0
  oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
445
0
  tuple = ExecCopySlotHeapTuple(srcslot);
446
0
  MemoryContextSwitchTo(oldcontext);
447
448
0
  ExecStoreHeapTuple(tuple, dstslot, true);
449
0
}
450
451
static HeapTuple
452
tts_heap_get_heap_tuple(TupleTableSlot *slot)
453
0
{
454
0
  HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
455
456
0
  Assert(!TTS_EMPTY(slot));
457
0
  if (!hslot->tuple)
458
0
    tts_heap_materialize(slot);
459
460
0
  return hslot->tuple;
461
0
}
462
463
static HeapTuple
464
tts_heap_copy_heap_tuple(TupleTableSlot *slot)
465
0
{
466
0
  HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
467
468
0
  Assert(!TTS_EMPTY(slot));
469
0
  if (!hslot->tuple)
470
0
    tts_heap_materialize(slot);
471
472
0
  return heap_copytuple(hslot->tuple);
473
0
}
474
475
static MinimalTuple
476
tts_heap_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
477
0
{
478
0
  HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
479
480
0
  if (!hslot->tuple)
481
0
    tts_heap_materialize(slot);
482
483
0
  return minimal_tuple_from_heap_tuple(hslot->tuple, extra);
484
0
}
485
486
static void
487
tts_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple, bool shouldFree)
488
0
{
489
0
  HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
490
491
0
  tts_heap_clear(slot);
492
493
0
  slot->tts_nvalid = 0;
494
0
  hslot->tuple = tuple;
495
0
  hslot->off = 0;
496
0
  slot->tts_flags &= ~(TTS_FLAG_EMPTY | TTS_FLAG_SHOULDFREE);
497
0
  slot->tts_tid = tuple->t_self;
498
499
0
  if (shouldFree)
500
0
    slot->tts_flags |= TTS_FLAG_SHOULDFREE;
501
0
}
502
503
504
/*
505
 * TupleTableSlotOps implementation for MinimalTupleTableSlot.
506
 */
507
508
static void
509
tts_minimal_init(TupleTableSlot *slot)
510
0
{
511
0
  MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
512
513
  /*
514
   * Initialize the heap tuple pointer to access attributes of the minimal
515
   * tuple contained in the slot as if it's a heap tuple.
516
   */
517
0
  mslot->tuple = &mslot->minhdr;
518
0
}
519
520
static void
521
tts_minimal_release(TupleTableSlot *slot)
522
0
{
523
0
}
524
525
static void
526
tts_minimal_clear(TupleTableSlot *slot)
527
0
{
528
0
  MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
529
530
0
  if (TTS_SHOULDFREE(slot))
531
0
  {
532
0
    heap_free_minimal_tuple(mslot->mintuple);
533
0
    slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
534
0
  }
535
536
0
  slot->tts_nvalid = 0;
537
0
  slot->tts_flags |= TTS_FLAG_EMPTY;
538
0
  ItemPointerSetInvalid(&slot->tts_tid);
539
0
  mslot->off = 0;
540
0
  mslot->mintuple = NULL;
541
0
}
542
543
static void
544
tts_minimal_getsomeattrs(TupleTableSlot *slot, int natts)
545
0
{
546
0
  MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
547
548
0
  Assert(!TTS_EMPTY(slot));
549
550
0
  slot_deform_heap_tuple(slot, mslot->tuple, &mslot->off, natts, true);
551
0
}
552
553
/*
554
 * MinimalTupleTableSlots never provide system attributes. We generally
555
 * shouldn't get here, but provide a user-friendly message if we do.
556
 */
557
static Datum
558
tts_minimal_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
559
0
{
560
0
  Assert(!TTS_EMPTY(slot));
561
562
0
  ereport(ERROR,
563
0
      (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
564
0
       errmsg("cannot retrieve a system column in this context")));
565
566
0
  return 0;         /* silence compiler warnings */
567
0
}
568
569
/*
570
 * Within MinimalTuple abstraction transaction information is unavailable.
571
 * We generally shouldn't get here, but provide a user-friendly message if
572
 * we do.
573
 */
574
static bool
575
tts_minimal_is_current_xact_tuple(TupleTableSlot *slot)
576
0
{
577
0
  Assert(!TTS_EMPTY(slot));
578
579
0
  ereport(ERROR,
580
0
      (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
581
0
       errmsg("don't have transaction information for this type of tuple")));
582
583
0
  return false;       /* silence compiler warnings */
584
0
}
585
586
static void
587
tts_minimal_materialize(TupleTableSlot *slot)
588
0
{
589
0
  MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
590
0
  MemoryContext oldContext;
591
592
0
  Assert(!TTS_EMPTY(slot));
593
594
  /* If slot has its tuple already materialized, nothing to do. */
595
0
  if (TTS_SHOULDFREE(slot))
596
0
    return;
597
598
0
  oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
599
600
  /*
601
   * Have to deform from scratch, otherwise tts_values[] entries could point
602
   * into the non-materialized tuple (which might be gone when accessed).
603
   */
604
0
  slot->tts_nvalid = 0;
605
0
  mslot->off = 0;
606
607
0
  if (!mslot->mintuple)
608
0
  {
609
0
    mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
610
0
                          slot->tts_values,
611
0
                          slot->tts_isnull,
612
0
                          0);
613
0
  }
614
0
  else
615
0
  {
616
    /*
617
     * The minimal tuple contained in this slot is not allocated in the
618
     * memory context of the given slot (else it would have
619
     * TTS_FLAG_SHOULDFREE set).  Copy the minimal tuple into the given
620
     * slot's memory context.
621
     */
622
0
    mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple, 0);
623
0
  }
624
625
0
  slot->tts_flags |= TTS_FLAG_SHOULDFREE;
626
627
0
  Assert(mslot->tuple == &mslot->minhdr);
628
629
0
  mslot->minhdr.t_len = mslot->mintuple->t_len + MINIMAL_TUPLE_OFFSET;
630
0
  mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mslot->mintuple - MINIMAL_TUPLE_OFFSET);
631
632
0
  MemoryContextSwitchTo(oldContext);
633
0
}
634
635
static void
636
tts_minimal_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
637
0
{
638
0
  MemoryContext oldcontext;
639
0
  MinimalTuple mintuple;
640
641
0
  oldcontext = MemoryContextSwitchTo(dstslot->tts_mcxt);
642
0
  mintuple = ExecCopySlotMinimalTuple(srcslot);
643
0
  MemoryContextSwitchTo(oldcontext);
644
645
0
  ExecStoreMinimalTuple(mintuple, dstslot, true);
646
0
}
647
648
static MinimalTuple
649
tts_minimal_get_minimal_tuple(TupleTableSlot *slot)
650
0
{
651
0
  MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
652
653
0
  if (!mslot->mintuple)
654
0
    tts_minimal_materialize(slot);
655
656
0
  return mslot->mintuple;
657
0
}
658
659
static HeapTuple
660
tts_minimal_copy_heap_tuple(TupleTableSlot *slot)
661
0
{
662
0
  MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
663
664
0
  if (!mslot->mintuple)
665
0
    tts_minimal_materialize(slot);
666
667
0
  return heap_tuple_from_minimal_tuple(mslot->mintuple);
668
0
}
669
670
static MinimalTuple
671
tts_minimal_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
672
0
{
673
0
  MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
674
675
0
  if (!mslot->mintuple)
676
0
    tts_minimal_materialize(slot);
677
678
0
  return heap_copy_minimal_tuple(mslot->mintuple, extra);
679
0
}
680
681
static void
682
tts_minimal_store_tuple(TupleTableSlot *slot, MinimalTuple mtup, bool shouldFree)
683
0
{
684
0
  MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
685
686
0
  tts_minimal_clear(slot);
687
688
0
  Assert(!TTS_SHOULDFREE(slot));
689
0
  Assert(TTS_EMPTY(slot));
690
691
0
  slot->tts_flags &= ~TTS_FLAG_EMPTY;
692
0
  slot->tts_nvalid = 0;
693
0
  mslot->off = 0;
694
695
0
  mslot->mintuple = mtup;
696
0
  Assert(mslot->tuple == &mslot->minhdr);
697
0
  mslot->minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
698
0
  mslot->minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
699
  /* no need to set t_self or t_tableOid since we won't allow access */
700
701
0
  if (shouldFree)
702
0
    slot->tts_flags |= TTS_FLAG_SHOULDFREE;
703
0
}
704
705
706
/*
707
 * TupleTableSlotOps implementation for BufferHeapTupleTableSlot.
708
 */
709
710
static void
711
tts_buffer_heap_init(TupleTableSlot *slot)
712
0
{
713
0
}
714
715
static void
716
tts_buffer_heap_release(TupleTableSlot *slot)
717
0
{
718
0
}
719
720
static void
721
tts_buffer_heap_clear(TupleTableSlot *slot)
722
0
{
723
0
  BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
724
725
  /*
726
   * Free the memory for heap tuple if allowed. A tuple coming from buffer
727
   * can never be freed. But we may have materialized a tuple from buffer.
728
   * Such a tuple can be freed.
729
   */
730
0
  if (TTS_SHOULDFREE(slot))
731
0
  {
732
    /* We should have unpinned the buffer while materializing the tuple. */
733
0
    Assert(!BufferIsValid(bslot->buffer));
734
735
0
    heap_freetuple(bslot->base.tuple);
736
0
    slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
737
0
  }
738
739
0
  if (BufferIsValid(bslot->buffer))
740
0
    ReleaseBuffer(bslot->buffer);
741
742
0
  slot->tts_nvalid = 0;
743
0
  slot->tts_flags |= TTS_FLAG_EMPTY;
744
0
  ItemPointerSetInvalid(&slot->tts_tid);
745
0
  bslot->base.tuple = NULL;
746
0
  bslot->base.off = 0;
747
0
  bslot->buffer = InvalidBuffer;
748
0
}
749
750
static void
751
tts_buffer_heap_getsomeattrs(TupleTableSlot *slot, int natts)
752
0
{
753
0
  BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
754
755
0
  Assert(!TTS_EMPTY(slot));
756
757
0
  slot_deform_heap_tuple(slot, bslot->base.tuple, &bslot->base.off, natts, false);
758
0
}
759
760
static Datum
761
tts_buffer_heap_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull)
762
0
{
763
0
  BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
764
765
0
  Assert(!TTS_EMPTY(slot));
766
767
  /*
768
   * In some code paths it's possible to get here with a non-materialized
769
   * slot, in which case we can't retrieve system columns.
770
   */
771
0
  if (!bslot->base.tuple)
772
0
    ereport(ERROR,
773
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
774
0
         errmsg("cannot retrieve a system column in this context")));
775
776
0
  return heap_getsysattr(bslot->base.tuple, attnum,
777
0
               slot->tts_tupleDescriptor, isnull);
778
0
}
779
780
static bool
781
tts_buffer_is_current_xact_tuple(TupleTableSlot *slot)
782
0
{
783
0
  BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
784
0
  TransactionId xmin;
785
786
0
  Assert(!TTS_EMPTY(slot));
787
788
  /*
789
   * In some code paths it's possible to get here with a non-materialized
790
   * slot, in which case we can't check if tuple is created by the current
791
   * transaction.
792
   */
793
0
  if (!bslot->base.tuple)
794
0
    ereport(ERROR,
795
0
        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
796
0
         errmsg("don't have a storage tuple in this context")));
797
798
0
  xmin = HeapTupleHeaderGetRawXmin(bslot->base.tuple->t_data);
799
800
0
  return TransactionIdIsCurrentTransactionId(xmin);
801
0
}
802
803
static void
804
tts_buffer_heap_materialize(TupleTableSlot *slot)
805
0
{
806
0
  BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
807
0
  MemoryContext oldContext;
808
809
0
  Assert(!TTS_EMPTY(slot));
810
811
  /* If slot has its tuple already materialized, nothing to do. */
812
0
  if (TTS_SHOULDFREE(slot))
813
0
    return;
814
815
0
  oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
816
817
  /*
818
   * Have to deform from scratch, otherwise tts_values[] entries could point
819
   * into the non-materialized tuple (which might be gone when accessed).
820
   */
821
0
  bslot->base.off = 0;
822
0
  slot->tts_nvalid = 0;
823
824
0
  if (!bslot->base.tuple)
825
0
  {
826
    /*
827
     * Normally BufferHeapTupleTableSlot should have a tuple + buffer
828
     * associated with it, unless it's materialized (which would've
829
     * returned above). But when it's useful to allow storing virtual
830
     * tuples in a buffer slot, which then also needs to be
831
     * materializable.
832
     */
833
0
    bslot->base.tuple = heap_form_tuple(slot->tts_tupleDescriptor,
834
0
                      slot->tts_values,
835
0
                      slot->tts_isnull);
836
0
  }
837
0
  else
838
0
  {
839
0
    bslot->base.tuple = heap_copytuple(bslot->base.tuple);
840
841
    /*
842
     * A heap tuple stored in a BufferHeapTupleTableSlot should have a
843
     * buffer associated with it, unless it's materialized or virtual.
844
     */
845
0
    if (likely(BufferIsValid(bslot->buffer)))
846
0
      ReleaseBuffer(bslot->buffer);
847
0
    bslot->buffer = InvalidBuffer;
848
0
  }
849
850
  /*
851
   * We don't set TTS_FLAG_SHOULDFREE until after releasing the buffer, if
852
   * any.  This avoids having a transient state that would fall foul of our
853
   * assertions that a slot with TTS_FLAG_SHOULDFREE doesn't own a buffer.
854
   * In the unlikely event that ReleaseBuffer() above errors out, we'd
855
   * effectively leak the copied tuple, but that seems fairly harmless.
856
   */
857
0
  slot->tts_flags |= TTS_FLAG_SHOULDFREE;
858
859
0
  MemoryContextSwitchTo(oldContext);
860
0
}
861
862
static void
863
tts_buffer_heap_copyslot(TupleTableSlot *dstslot, TupleTableSlot *srcslot)
864
0
{
865
0
  BufferHeapTupleTableSlot *bsrcslot = (BufferHeapTupleTableSlot *) srcslot;
866
0
  BufferHeapTupleTableSlot *bdstslot = (BufferHeapTupleTableSlot *) dstslot;
867
868
  /*
869
   * If the source slot is of a different kind, or is a buffer slot that has
870
   * been materialized / is virtual, make a new copy of the tuple. Otherwise
871
   * make a new reference to the in-buffer tuple.
872
   */
873
0
  if (dstslot->tts_ops != srcslot->tts_ops ||
874
0
    TTS_SHOULDFREE(srcslot) ||
875
0
    !bsrcslot->base.tuple)
876
0
  {
877
0
    MemoryContext oldContext;
878
879
0
    ExecClearTuple(dstslot);
880
0
    dstslot->tts_flags &= ~TTS_FLAG_EMPTY;
881
0
    oldContext = MemoryContextSwitchTo(dstslot->tts_mcxt);
882
0
    bdstslot->base.tuple = ExecCopySlotHeapTuple(srcslot);
883
0
    dstslot->tts_flags |= TTS_FLAG_SHOULDFREE;
884
0
    MemoryContextSwitchTo(oldContext);
885
0
  }
886
0
  else
887
0
  {
888
0
    Assert(BufferIsValid(bsrcslot->buffer));
889
890
0
    tts_buffer_heap_store_tuple(dstslot, bsrcslot->base.tuple,
891
0
                  bsrcslot->buffer, false);
892
893
    /*
894
     * The HeapTupleData portion of the source tuple might be shorter
895
     * lived than the destination slot. Therefore copy the HeapTuple into
896
     * our slot's tupdata, which is guaranteed to live long enough (but
897
     * will still point into the buffer).
898
     */
899
0
    memcpy(&bdstslot->base.tupdata, bdstslot->base.tuple, sizeof(HeapTupleData));
900
0
    bdstslot->base.tuple = &bdstslot->base.tupdata;
901
0
  }
902
0
}
903
904
static HeapTuple
905
tts_buffer_heap_get_heap_tuple(TupleTableSlot *slot)
906
0
{
907
0
  BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
908
909
0
  Assert(!TTS_EMPTY(slot));
910
911
0
  if (!bslot->base.tuple)
912
0
    tts_buffer_heap_materialize(slot);
913
914
0
  return bslot->base.tuple;
915
0
}
916
917
static HeapTuple
918
tts_buffer_heap_copy_heap_tuple(TupleTableSlot *slot)
919
0
{
920
0
  BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
921
922
0
  Assert(!TTS_EMPTY(slot));
923
924
0
  if (!bslot->base.tuple)
925
0
    tts_buffer_heap_materialize(slot);
926
927
0
  return heap_copytuple(bslot->base.tuple);
928
0
}
929
930
static MinimalTuple
931
tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
932
0
{
933
0
  BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
934
935
0
  Assert(!TTS_EMPTY(slot));
936
937
0
  if (!bslot->base.tuple)
938
0
    tts_buffer_heap_materialize(slot);
939
940
0
  return minimal_tuple_from_heap_tuple(bslot->base.tuple, extra);
941
0
}
942
943
static inline void
944
tts_buffer_heap_store_tuple(TupleTableSlot *slot, HeapTuple tuple,
945
              Buffer buffer, bool transfer_pin)
946
0
{
947
0
  BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
948
949
0
  if (TTS_SHOULDFREE(slot))
950
0
  {
951
    /* materialized slot shouldn't have a buffer to release */
952
0
    Assert(!BufferIsValid(bslot->buffer));
953
954
0
    heap_freetuple(bslot->base.tuple);
955
0
    slot->tts_flags &= ~TTS_FLAG_SHOULDFREE;
956
0
  }
957
958
0
  slot->tts_flags &= ~TTS_FLAG_EMPTY;
959
0
  slot->tts_nvalid = 0;
960
0
  bslot->base.tuple = tuple;
961
0
  bslot->base.off = 0;
962
0
  slot->tts_tid = tuple->t_self;
963
964
  /*
965
   * If tuple is on a disk page, keep the page pinned as long as we hold a
966
   * pointer into it.  We assume the caller already has such a pin.  If
967
   * transfer_pin is true, we'll transfer that pin to this slot, if not
968
   * we'll pin it again ourselves.
969
   *
970
   * This is coded to optimize the case where the slot previously held a
971
   * tuple on the same disk page: in that case releasing and re-acquiring
972
   * the pin is a waste of cycles.  This is a common situation during
973
   * seqscans, so it's worth troubling over.
974
   */
975
0
  if (bslot->buffer != buffer)
976
0
  {
977
0
    if (BufferIsValid(bslot->buffer))
978
0
      ReleaseBuffer(bslot->buffer);
979
980
0
    bslot->buffer = buffer;
981
982
0
    if (!transfer_pin && BufferIsValid(buffer))
983
0
      IncrBufferRefCount(buffer);
984
0
  }
985
0
  else if (transfer_pin && BufferIsValid(buffer))
986
0
  {
987
    /*
988
     * In transfer_pin mode the caller won't know about the same-page
989
     * optimization, so we gotta release its pin.
990
     */
991
0
    ReleaseBuffer(buffer);
992
0
  }
993
0
}
994
995
/*
996
 * slot_deform_heap_tuple
997
 *    Given a TupleTableSlot, extract data from the slot's physical tuple
998
 *    into its Datum/isnull arrays.  Data is extracted up through the
999
 *    reqnatts'th column.  If there are insufficient attributes in the given
1000
 *    tuple, then slot_getmissingattrs() is called to populate the
1001
 *    remainder.  If reqnatts is above the number of attributes in the
1002
 *    slot's TupleDesc, an error is raised.
1003
 *
1004
 *    This is essentially an incremental version of heap_deform_tuple:
1005
 *    on each call we extract attributes up to the one needed, without
1006
 *    re-computing information about previously extracted attributes.
1007
 *    slot->tts_nvalid is the number of attributes already extracted.
1008
 *
1009
 * This is marked as always inline, so the different offp for different types
1010
 * of slots gets optimized away.
1011
 *
1012
 * support_cstring should be passed as a const to allow the compiler only
1013
 * emit code during inlining for cstring deforming when it's required.
1014
 * cstrings can exist in MinimalTuples, but not in HeapTuples.
1015
 */
1016
static pg_always_inline void
1017
slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
1018
             int reqnatts, bool support_cstring)
1019
0
{
1020
0
  CompactAttribute *cattrs;
1021
0
  CompactAttribute *cattr;
1022
0
  TupleDesc tupleDesc = slot->tts_tupleDescriptor;
1023
0
  HeapTupleHeader tup = tuple->t_data;
1024
0
  size_t    attnum;
1025
0
  int     firstNonCacheOffsetAttr;
1026
0
  int     firstNonGuaranteedAttr;
1027
0
  int     firstNullAttr;
1028
0
  int     natts;
1029
0
  Datum    *values;
1030
0
  bool     *isnull;
1031
0
  char     *tp;       /* ptr to tuple data */
1032
0
  uint32    off;      /* offset in tuple data */
1033
1034
  /* Did someone forget to call TupleDescFinalize()? */
1035
0
  Assert(tupleDesc->firstNonCachedOffsetAttr >= 0);
1036
1037
0
  isnull = slot->tts_isnull;
1038
1039
  /*
1040
   * Some callers may form and deform tuples prior to NOT NULL constraints
1041
   * being checked.  Here we'd like to optimize the case where we only need
1042
   * to fetch attributes before or up to the point where the attribute is
1043
   * guaranteed to exist in the tuple.  We rely on the slot flag being set
1044
   * correctly to only enable this optimization when it's valid to do so.
1045
   * This optimization allows us to save fetching the number of attributes
1046
   * from the tuple and saves the additional cost of handling non-byval
1047
   * attrs.
1048
   */
1049
0
  firstNonGuaranteedAttr = Min(reqnatts, slot->tts_first_nonguaranteed);
1050
1051
0
  firstNonCacheOffsetAttr = tupleDesc->firstNonCachedOffsetAttr;
1052
1053
0
  if (HeapTupleHasNulls(tuple))
1054
0
  {
1055
0
    natts = HeapTupleHeaderGetNatts(tup);
1056
0
    tp = (char *) tup + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits) +
1057
0
                   BITMAPLEN(natts));
1058
1059
0
    natts = Min(natts, reqnatts);
1060
0
    if (natts > firstNonGuaranteedAttr)
1061
0
    {
1062
0
      uint8    *bp = tup->t_bits;
1063
1064
      /* Find the first NULL attr */
1065
0
      firstNullAttr = first_null_attr(bp, natts);
1066
1067
      /*
1068
       * And populate the isnull array for all attributes being fetched
1069
       * from the tuple.
1070
       */
1071
0
      populate_isnull_array(bp, natts, isnull);
1072
0
    }
1073
0
    else
1074
0
    {
1075
      /* Otherwise all required columns are guaranteed to exist */
1076
0
      firstNullAttr = natts;
1077
1078
      /*
1079
       * Check TupleDescFinalize() didn't get confused when setting
1080
       * firstNonGuaranteedAttr.  There should never be a NULL in a
1081
       * guaranteed column.
1082
       */
1083
0
      Assert(first_null_attr(tup->t_bits, natts) >= firstNullAttr);
1084
0
    }
1085
0
  }
1086
0
  else
1087
0
  {
1088
0
    tp = (char *) tup + MAXALIGN(offsetof(HeapTupleHeaderData, t_bits));
1089
1090
    /*
1091
     * We only need to look at the tuple's natts if we need more than the
1092
     * guaranteed number of columns
1093
     */
1094
0
    if (reqnatts > firstNonGuaranteedAttr)
1095
0
      natts = Min(HeapTupleHeaderGetNatts(tup), reqnatts);
1096
0
    else
1097
0
    {
1098
      /* No need to access the number of attributes in the tuple */
1099
0
      natts = reqnatts;
1100
0
    }
1101
1102
    /* All attrs can be fetched without checking for NULLs */
1103
0
    firstNullAttr = natts;
1104
0
  }
1105
1106
0
  attnum = slot->tts_nvalid;
1107
0
  values = slot->tts_values;
1108
0
  slot->tts_nvalid = reqnatts;
1109
1110
  /*
1111
   * We store the tupleDesc's CompactAttribute array in 'cattrs' as gcc
1112
   * seems to be unwilling to optimize accessing the CompactAttribute
1113
   * element efficiently when accessing it via TupleDescCompactAttr().
1114
   */
1115
0
  cattrs = tupleDesc->compact_attrs;
1116
1117
  /* Ensure we calculated tp correctly */
1118
0
  Assert(tp == (char *) tup + tup->t_hoff);
1119
1120
0
  if (attnum < firstNonGuaranteedAttr)
1121
0
  {
1122
0
    int     attlen;
1123
1124
0
    do
1125
0
    {
1126
0
      isnull[attnum] = false;
1127
0
      cattr = &cattrs[attnum];
1128
0
      attlen = cattr->attlen;
1129
1130
      /* We don't expect any non-byval types */
1131
0
      pg_assume(attlen > 0);
1132
0
      Assert(cattr->attbyval == true);
1133
1134
0
      off = cattr->attcacheoff;
1135
0
      values[attnum] = fetch_att_noerr(tp + off, true, attlen);
1136
0
      attnum++;
1137
0
    } while (attnum < firstNonGuaranteedAttr);
1138
1139
0
    off += attlen;
1140
1141
0
    if (attnum == reqnatts)
1142
0
      goto done;
1143
0
  }
1144
0
  else
1145
0
  {
1146
    /*
1147
     * We may be incrementally deforming the tuple, so set 'off' to the
1148
     * previously cached value.  This may be 0, if the slot has just
1149
     * received a new tuple.
1150
     */
1151
0
    off = *offp;
1152
1153
    /* We expect *offp to be set to 0 when attnum == 0 */
1154
0
    Assert(off == 0 || attnum > 0);
1155
0
  }
1156
1157
  /* We can use attcacheoff up until the first NULL */
1158
0
  firstNonCacheOffsetAttr = Min(firstNonCacheOffsetAttr, firstNullAttr);
1159
1160
  /*
1161
   * Handle the portion of the tuple that we have cached the offset for up
1162
   * to the first NULL attribute.  The offset is effectively fixed for
1163
   * these, so we can use the CompactAttribute's attcacheoff.
1164
   */
1165
0
  if (attnum < firstNonCacheOffsetAttr)
1166
0
  {
1167
0
    int     attlen;
1168
1169
0
    do
1170
0
    {
1171
0
      isnull[attnum] = false;
1172
0
      cattr = &cattrs[attnum];
1173
0
      attlen = cattr->attlen;
1174
0
      off = cattr->attcacheoff;
1175
0
      values[attnum] = fetch_att_noerr(tp + off,
1176
0
                       cattr->attbyval,
1177
0
                       attlen);
1178
0
      attnum++;
1179
0
    } while (attnum < firstNonCacheOffsetAttr);
1180
1181
    /*
1182
     * Point the offset after the end of the last attribute with a cached
1183
     * offset.  We expect the final cached offset attribute to have a
1184
     * fixed width, so just add the attlen to the attcacheoff
1185
     */
1186
0
    Assert(attlen > 0);
1187
0
    off += attlen;
1188
0
  }
1189
1190
  /*
1191
   * Handle any portion of the tuple that doesn't have a fixed offset up
1192
   * until the first NULL attribute.  This loop only differs from the one
1193
   * after it by the NULL checks.
1194
   */
1195
0
  for (; attnum < firstNullAttr; attnum++)
1196
0
  {
1197
0
    int     attlen;
1198
1199
0
    isnull[attnum] = false;
1200
0
    cattr = &cattrs[attnum];
1201
0
    attlen = cattr->attlen;
1202
1203
    /*
1204
     * Only emit the cstring-related code in align_fetch_then_add() when
1205
     * cstring support is needed.  We assume support_cstring will be
1206
     * passed as a const to allow the compiler to eliminate this branch.
1207
     */
1208
0
    if (!support_cstring)
1209
0
      pg_assume(attlen > 0 || attlen == -1);
1210
1211
    /* align 'off', fetch the datum, and increment off beyond the datum */
1212
0
    values[attnum] = align_fetch_then_add(tp,
1213
0
                        &off,
1214
0
                        cattr->attbyval,
1215
0
                        attlen,
1216
0
                        cattr->attalignby);
1217
0
  }
1218
1219
  /*
1220
   * Now handle any remaining attributes in the tuple up to the requested
1221
   * attnum.  This time, include NULL checks as we're now at the first NULL
1222
   * attribute.
1223
   */
1224
0
  for (; attnum < natts; attnum++)
1225
0
  {
1226
0
    int     attlen;
1227
1228
0
    if (isnull[attnum])
1229
0
    {
1230
0
      values[attnum] = (Datum) 0;
1231
0
      continue;
1232
0
    }
1233
1234
0
    cattr = &cattrs[attnum];
1235
0
    attlen = cattr->attlen;
1236
1237
    /* As above, only emit cstring code when needed. */
1238
0
    if (!support_cstring)
1239
0
      pg_assume(attlen > 0 || attlen == -1);
1240
1241
    /* align 'off', fetch the datum, and increment off beyond the datum */
1242
0
    values[attnum] = align_fetch_then_add(tp,
1243
0
                        &off,
1244
0
                        cattr->attbyval,
1245
0
                        attlen,
1246
0
                        cattr->attalignby);
1247
0
  }
1248
1249
  /* Fetch any missing attrs and raise an error if reqnatts is invalid */
1250
0
  if (unlikely(attnum < reqnatts))
1251
0
  {
1252
    /*
1253
     * Cache the offset before calling the function to allow the compiler
1254
     * to implement a tail-call optimization
1255
     */
1256
0
    *offp = off;
1257
1258
0
    Assert(HeapTupleHeaderGetNatts(tup) <= attnum);
1259
1260
    /*
1261
     * Fetch all missing attributes.  We pass natts rather than attnum as
1262
     * if we're deforming attributes after having already deformed some
1263
     * missing attributes, then the call to populate_isnull_array() may
1264
     * have overwritten the previous tts_isnull values from what was
1265
     * stored in the previous call to slot_getmissingattrs().
1266
     */
1267
0
    slot_getmissingattrs(slot, HeapTupleHeaderGetNatts(tup), reqnatts);
1268
0
    return;
1269
0
  }
1270
0
done:
1271
1272
  /* Save current offset for next execution */
1273
0
  *offp = off;
1274
0
}
1275
1276
const TupleTableSlotOps TTSOpsVirtual = {
1277
  .base_slot_size = sizeof(VirtualTupleTableSlot),
1278
  .init = tts_virtual_init,
1279
  .release = tts_virtual_release,
1280
  .clear = tts_virtual_clear,
1281
  .getsomeattrs = tts_virtual_getsomeattrs,
1282
  .getsysattr = tts_virtual_getsysattr,
1283
  .materialize = tts_virtual_materialize,
1284
  .is_current_xact_tuple = tts_virtual_is_current_xact_tuple,
1285
  .copyslot = tts_virtual_copyslot,
1286
1287
  /*
1288
   * A virtual tuple table slot can not "own" a heap tuple or a minimal
1289
   * tuple.
1290
   */
1291
  .get_heap_tuple = NULL,
1292
  .get_minimal_tuple = NULL,
1293
  .copy_heap_tuple = tts_virtual_copy_heap_tuple,
1294
  .copy_minimal_tuple = tts_virtual_copy_minimal_tuple
1295
};
1296
1297
const TupleTableSlotOps TTSOpsHeapTuple = {
1298
  .base_slot_size = sizeof(HeapTupleTableSlot),
1299
  .init = tts_heap_init,
1300
  .release = tts_heap_release,
1301
  .clear = tts_heap_clear,
1302
  .getsomeattrs = tts_heap_getsomeattrs,
1303
  .getsysattr = tts_heap_getsysattr,
1304
  .is_current_xact_tuple = tts_heap_is_current_xact_tuple,
1305
  .materialize = tts_heap_materialize,
1306
  .copyslot = tts_heap_copyslot,
1307
  .get_heap_tuple = tts_heap_get_heap_tuple,
1308
1309
  /* A heap tuple table slot can not "own" a minimal tuple. */
1310
  .get_minimal_tuple = NULL,
1311
  .copy_heap_tuple = tts_heap_copy_heap_tuple,
1312
  .copy_minimal_tuple = tts_heap_copy_minimal_tuple
1313
};
1314
1315
const TupleTableSlotOps TTSOpsMinimalTuple = {
1316
  .base_slot_size = sizeof(MinimalTupleTableSlot),
1317
  .init = tts_minimal_init,
1318
  .release = tts_minimal_release,
1319
  .clear = tts_minimal_clear,
1320
  .getsomeattrs = tts_minimal_getsomeattrs,
1321
  .getsysattr = tts_minimal_getsysattr,
1322
  .is_current_xact_tuple = tts_minimal_is_current_xact_tuple,
1323
  .materialize = tts_minimal_materialize,
1324
  .copyslot = tts_minimal_copyslot,
1325
1326
  /* A minimal tuple table slot can not "own" a heap tuple. */
1327
  .get_heap_tuple = NULL,
1328
  .get_minimal_tuple = tts_minimal_get_minimal_tuple,
1329
  .copy_heap_tuple = tts_minimal_copy_heap_tuple,
1330
  .copy_minimal_tuple = tts_minimal_copy_minimal_tuple
1331
};
1332
1333
const TupleTableSlotOps TTSOpsBufferHeapTuple = {
1334
  .base_slot_size = sizeof(BufferHeapTupleTableSlot),
1335
  .init = tts_buffer_heap_init,
1336
  .release = tts_buffer_heap_release,
1337
  .clear = tts_buffer_heap_clear,
1338
  .getsomeattrs = tts_buffer_heap_getsomeattrs,
1339
  .getsysattr = tts_buffer_heap_getsysattr,
1340
  .is_current_xact_tuple = tts_buffer_is_current_xact_tuple,
1341
  .materialize = tts_buffer_heap_materialize,
1342
  .copyslot = tts_buffer_heap_copyslot,
1343
  .get_heap_tuple = tts_buffer_heap_get_heap_tuple,
1344
1345
  /* A buffer heap tuple table slot can not "own" a minimal tuple. */
1346
  .get_minimal_tuple = NULL,
1347
  .copy_heap_tuple = tts_buffer_heap_copy_heap_tuple,
1348
  .copy_minimal_tuple = tts_buffer_heap_copy_minimal_tuple
1349
};
1350
1351
1352
/* ----------------------------------------------------------------
1353
 *          tuple table create/delete functions
1354
 * ----------------------------------------------------------------
1355
 */
1356
1357
/* --------------------------------
1358
 *    MakeTupleTableSlot
1359
 *
1360
 *    Basic routine to make an empty TupleTableSlot of given
1361
 *    TupleTableSlotType. If tupleDesc is specified the slot's descriptor is
1362
 *    fixed for its lifetime, gaining some efficiency. If that's
1363
 *    undesirable, pass NULL.  'flags' allows any of non-TTS_FLAGS_TRANSIENT
1364
 *    flags to be set in tts_flags.
1365
 * --------------------------------
1366
 */
1367
TupleTableSlot *
1368
MakeTupleTableSlot(TupleDesc tupleDesc,
1369
           const TupleTableSlotOps *tts_ops, uint16 flags)
1370
0
{
1371
0
  Size    basesz,
1372
0
        allocsz;
1373
0
  TupleTableSlot *slot;
1374
1375
0
  basesz = tts_ops->base_slot_size;
1376
1377
  /* Ensure callers don't have any way to set transient flags permanently */
1378
0
  flags &= ~TTS_FLAGS_TRANSIENT;
1379
1380
  /*
1381
   * When a fixed descriptor is specified, we can reduce overhead by
1382
   * allocating the entire slot in one go.
1383
   *
1384
   * We round the size of tts_isnull up to the next highest multiple of 8.
1385
   * This is needed as populate_isnull_array() operates on 8 elements at a
1386
   * time when converting a tuple's NULL bitmap into a boolean array.
1387
   */
1388
0
  if (tupleDesc)
1389
0
    allocsz = MAXALIGN(basesz) +
1390
0
      MAXALIGN(tupleDesc->natts * sizeof(Datum)) +
1391
0
      TYPEALIGN(8, tupleDesc->natts * sizeof(bool));
1392
0
  else
1393
0
    allocsz = basesz;
1394
1395
0
  slot = palloc0(allocsz);
1396
  /* const for optimization purposes, OK to modify at allocation time */
1397
0
  *((const TupleTableSlotOps **) &slot->tts_ops) = tts_ops;
1398
0
  slot->type = T_TupleTableSlot;
1399
0
  slot->tts_flags = TTS_FLAG_EMPTY | flags;
1400
0
  if (tupleDesc != NULL)
1401
0
    slot->tts_flags |= TTS_FLAG_FIXED;
1402
0
  slot->tts_tupleDescriptor = tupleDesc;
1403
0
  slot->tts_mcxt = CurrentMemoryContext;
1404
0
  slot->tts_nvalid = 0;
1405
1406
0
  if (tupleDesc != NULL)
1407
0
  {
1408
0
    slot->tts_values = (Datum *)
1409
0
      (((char *) slot)
1410
0
       + MAXALIGN(basesz));
1411
1412
0
    slot->tts_isnull = (bool *)
1413
0
      (((char *) slot)
1414
0
       + MAXALIGN(basesz)
1415
0
       + MAXALIGN(tupleDesc->natts * sizeof(Datum)));
1416
1417
0
    PinTupleDesc(tupleDesc);
1418
1419
    /*
1420
     * Precalculate the maximum guaranteed attribute that has to exist in
1421
     * every tuple which gets deformed into this slot.  When the
1422
     * TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS flag is enabled, we simply take
1423
     * the pre-calculated value from the tupleDesc, otherwise the
1424
     * optimization is disabled, and we set the value to 0.
1425
     */
1426
0
    if ((flags & TTS_FLAG_OBEYS_NOT_NULL_CONSTRAINTS) != 0)
1427
0
      slot->tts_first_nonguaranteed = tupleDesc->firstNonGuaranteedAttr;
1428
0
    else
1429
0
      slot->tts_first_nonguaranteed = 0;
1430
0
  }
1431
1432
  /*
1433
   * And allow slot type specific initialization.
1434
   */
1435
0
  slot->tts_ops->init(slot);
1436
1437
0
  return slot;
1438
0
}
1439
1440
/* --------------------------------
1441
 *    ExecAllocTableSlot
1442
 *
1443
 *    Create a tuple table slot within a tuple table (which is just a List).
1444
 * --------------------------------
1445
 */
1446
TupleTableSlot *
1447
ExecAllocTableSlot(List **tupleTable, TupleDesc desc,
1448
           const TupleTableSlotOps *tts_ops, uint16 flags)
1449
0
{
1450
0
  TupleTableSlot *slot = MakeTupleTableSlot(desc, tts_ops, flags);
1451
1452
0
  *tupleTable = lappend(*tupleTable, slot);
1453
1454
0
  return slot;
1455
0
}
1456
1457
/* --------------------------------
1458
 *    ExecResetTupleTable
1459
 *
1460
 *    This releases any resources (buffer pins, tupdesc refcounts)
1461
 *    held by the tuple table, and optionally releases the memory
1462
 *    occupied by the tuple table data structure.
1463
 *    It is expected that this routine be called by ExecEndPlan().
1464
 * --------------------------------
1465
 */
1466
void
1467
ExecResetTupleTable(List *tupleTable, /* tuple table */
1468
          bool shouldFree)  /* true if we should free memory */
1469
0
{
1470
0
  ListCell   *lc;
1471
1472
0
  foreach(lc, tupleTable)
1473
0
  {
1474
0
    TupleTableSlot *slot = lfirst_node(TupleTableSlot, lc);
1475
1476
    /* Always release resources and reset the slot to empty */
1477
0
    ExecClearTuple(slot);
1478
0
    slot->tts_ops->release(slot);
1479
0
    if (slot->tts_tupleDescriptor)
1480
0
    {
1481
0
      ReleaseTupleDesc(slot->tts_tupleDescriptor);
1482
0
      slot->tts_tupleDescriptor = NULL;
1483
0
    }
1484
1485
    /* If shouldFree, release memory occupied by the slot itself */
1486
0
    if (shouldFree)
1487
0
    {
1488
0
      if (!TTS_FIXED(slot))
1489
0
      {
1490
0
        if (slot->tts_values)
1491
0
          pfree(slot->tts_values);
1492
0
        if (slot->tts_isnull)
1493
0
          pfree(slot->tts_isnull);
1494
0
      }
1495
0
      pfree(slot);
1496
0
    }
1497
0
  }
1498
1499
  /* If shouldFree, release the list structure */
1500
0
  if (shouldFree)
1501
0
    list_free(tupleTable);
1502
0
}
1503
1504
/* --------------------------------
1505
 *    MakeSingleTupleTableSlot
1506
 *
1507
 *    This is a convenience routine for operations that need a standalone
1508
 *    TupleTableSlot not gotten from the main executor tuple table.  It makes
1509
 *    a single slot of given TupleTableSlotType and initializes it to use the
1510
 *    given tuple descriptor.
1511
 * --------------------------------
1512
 */
1513
TupleTableSlot *
1514
MakeSingleTupleTableSlot(TupleDesc tupdesc,
1515
             const TupleTableSlotOps *tts_ops)
1516
0
{
1517
0
  TupleTableSlot *slot = MakeTupleTableSlot(tupdesc, tts_ops, 0);
1518
1519
0
  return slot;
1520
0
}
1521
1522
/* --------------------------------
1523
 *    ExecDropSingleTupleTableSlot
1524
 *
1525
 *    Release a TupleTableSlot made with MakeSingleTupleTableSlot.
1526
 *    DON'T use this on a slot that's part of a tuple table list!
1527
 * --------------------------------
1528
 */
1529
void
1530
ExecDropSingleTupleTableSlot(TupleTableSlot *slot)
1531
0
{
1532
  /* This should match ExecResetTupleTable's processing of one slot */
1533
0
  Assert(IsA(slot, TupleTableSlot));
1534
0
  ExecClearTuple(slot);
1535
0
  slot->tts_ops->release(slot);
1536
0
  if (slot->tts_tupleDescriptor)
1537
0
    ReleaseTupleDesc(slot->tts_tupleDescriptor);
1538
0
  if (!TTS_FIXED(slot))
1539
0
  {
1540
0
    if (slot->tts_values)
1541
0
      pfree(slot->tts_values);
1542
0
    if (slot->tts_isnull)
1543
0
      pfree(slot->tts_isnull);
1544
0
  }
1545
0
  pfree(slot);
1546
0
}
1547
1548
1549
/* ----------------------------------------------------------------
1550
 *          tuple table slot accessor functions
1551
 * ----------------------------------------------------------------
1552
 */
1553
1554
/* --------------------------------
1555
 *    ExecSetSlotDescriptor
1556
 *
1557
 *    This function is used to set the tuple descriptor associated
1558
 *    with the slot's tuple.  The passed descriptor must have lifespan
1559
 *    at least equal to the slot's.  If it is a reference-counted descriptor
1560
 *    then the reference count is incremented for as long as the slot holds
1561
 *    a reference.
1562
 * --------------------------------
1563
 */
1564
void
1565
ExecSetSlotDescriptor(TupleTableSlot *slot, /* slot to change */
1566
            TupleDesc tupdesc)  /* new tuple descriptor */
1567
0
{
1568
0
  Assert(!TTS_FIXED(slot));
1569
1570
  /* For safety, make sure slot is empty before changing it */
1571
0
  ExecClearTuple(slot);
1572
1573
  /*
1574
   * Release any old descriptor.  Also release old Datum/isnull arrays if
1575
   * present (we don't bother to check if they could be re-used).
1576
   */
1577
0
  if (slot->tts_tupleDescriptor)
1578
0
    ReleaseTupleDesc(slot->tts_tupleDescriptor);
1579
1580
0
  if (slot->tts_values)
1581
0
    pfree(slot->tts_values);
1582
0
  if (slot->tts_isnull)
1583
0
    pfree(slot->tts_isnull);
1584
1585
  /*
1586
   * Install the new descriptor; if it's refcounted, bump its refcount.
1587
   */
1588
0
  slot->tts_tupleDescriptor = tupdesc;
1589
0
  PinTupleDesc(tupdesc);
1590
1591
  /*
1592
   * Allocate Datum/isnull arrays of the appropriate size.  These must have
1593
   * the same lifetime as the slot, so allocate in the slot's own context.
1594
   */
1595
0
  slot->tts_values = (Datum *)
1596
0
    MemoryContextAlloc(slot->tts_mcxt, tupdesc->natts * sizeof(Datum));
1597
1598
  /*
1599
   * We round the size of tts_isnull up to the next highest multiple of 8.
1600
   * This is needed as populate_isnull_array() operates on 8 elements at a
1601
   * time when converting a tuple's NULL bitmap into a boolean array.
1602
   */
1603
0
  slot->tts_isnull = (bool *)
1604
0
    MemoryContextAlloc(slot->tts_mcxt, TYPEALIGN(8, tupdesc->natts * sizeof(bool)));
1605
0
}
1606
1607
/* --------------------------------
1608
 *    ExecStoreHeapTuple
1609
 *
1610
 *    This function is used to store an on-the-fly physical tuple into a specified
1611
 *    slot in the tuple table.
1612
 *
1613
 *    tuple:  tuple to store
1614
 *    slot: TTSOpsHeapTuple type slot to store it in
1615
 *    shouldFree: true if ExecClearTuple should pfree() the tuple
1616
 *          when done with it
1617
 *
1618
 * shouldFree is normally set 'true' for tuples constructed on-the-fly.  But it
1619
 * can be 'false' when the referenced tuple is held in a tuple table slot
1620
 * belonging to a lower-level executor Proc node.  In this case the lower-level
1621
 * slot retains ownership and responsibility for eventually releasing the
1622
 * tuple.  When this method is used, we must be certain that the upper-level
1623
 * Proc node will lose interest in the tuple sooner than the lower-level one
1624
 * does!  If you're not certain, copy the lower-level tuple with heap_copytuple
1625
 * and let the upper-level table slot assume ownership of the copy!
1626
 *
1627
 * Return value is just the passed-in slot pointer.
1628
 *
1629
 * If the target slot is not guaranteed to be TTSOpsHeapTuple type slot, use
1630
 * the, more expensive, ExecForceStoreHeapTuple().
1631
 * --------------------------------
1632
 */
1633
TupleTableSlot *
1634
ExecStoreHeapTuple(HeapTuple tuple,
1635
           TupleTableSlot *slot,
1636
           bool shouldFree)
1637
0
{
1638
  /*
1639
   * sanity checks
1640
   */
1641
0
  Assert(tuple != NULL);
1642
0
  Assert(slot != NULL);
1643
0
  Assert(slot->tts_tupleDescriptor != NULL);
1644
1645
0
  if (unlikely(!TTS_IS_HEAPTUPLE(slot)))
1646
0
    elog(ERROR, "trying to store a heap tuple into wrong type of slot");
1647
0
  tts_heap_store_tuple(slot, tuple, shouldFree);
1648
1649
0
  slot->tts_tableOid = tuple->t_tableOid;
1650
1651
0
  return slot;
1652
0
}
1653
1654
/* --------------------------------
1655
 *    ExecStoreBufferHeapTuple
1656
 *
1657
 *    This function is used to store an on-disk physical tuple from a buffer
1658
 *    into a specified slot in the tuple table.
1659
 *
1660
 *    tuple:  tuple to store
1661
 *    slot: TTSOpsBufferHeapTuple type slot to store it in
1662
 *    buffer: disk buffer if tuple is in a disk page, else InvalidBuffer
1663
 *
1664
 * The tuple table code acquires a pin on the buffer which is held until the
1665
 * slot is cleared, so that the tuple won't go away on us.
1666
 *
1667
 * Return value is just the passed-in slot pointer.
1668
 *
1669
 * If the target slot is not guaranteed to be TTSOpsBufferHeapTuple type slot,
1670
 * use the, more expensive, ExecForceStoreHeapTuple().
1671
 * --------------------------------
1672
 */
1673
TupleTableSlot *
1674
ExecStoreBufferHeapTuple(HeapTuple tuple,
1675
             TupleTableSlot *slot,
1676
             Buffer buffer)
1677
0
{
1678
  /*
1679
   * sanity checks
1680
   */
1681
0
  Assert(tuple != NULL);
1682
0
  Assert(slot != NULL);
1683
0
  Assert(slot->tts_tupleDescriptor != NULL);
1684
0
  Assert(BufferIsValid(buffer));
1685
1686
0
  if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1687
0
    elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1688
0
  tts_buffer_heap_store_tuple(slot, tuple, buffer, false);
1689
1690
0
  slot->tts_tableOid = tuple->t_tableOid;
1691
1692
0
  return slot;
1693
0
}
1694
1695
/*
1696
 * Like ExecStoreBufferHeapTuple, but transfer an existing pin from the caller
1697
 * to the slot, i.e. the caller doesn't need to, and may not, release the pin.
1698
 */
1699
TupleTableSlot *
1700
ExecStorePinnedBufferHeapTuple(HeapTuple tuple,
1701
                 TupleTableSlot *slot,
1702
                 Buffer buffer)
1703
0
{
1704
  /*
1705
   * sanity checks
1706
   */
1707
0
  Assert(tuple != NULL);
1708
0
  Assert(slot != NULL);
1709
0
  Assert(slot->tts_tupleDescriptor != NULL);
1710
0
  Assert(BufferIsValid(buffer));
1711
1712
0
  if (unlikely(!TTS_IS_BUFFERTUPLE(slot)))
1713
0
    elog(ERROR, "trying to store an on-disk heap tuple into wrong type of slot");
1714
0
  tts_buffer_heap_store_tuple(slot, tuple, buffer, true);
1715
1716
0
  slot->tts_tableOid = tuple->t_tableOid;
1717
1718
0
  return slot;
1719
0
}
1720
1721
/*
1722
 * Store a minimal tuple into TTSOpsMinimalTuple type slot.
1723
 *
1724
 * If the target slot is not guaranteed to be TTSOpsMinimalTuple type slot,
1725
 * use the, more expensive, ExecForceStoreMinimalTuple().
1726
 */
1727
TupleTableSlot *
1728
ExecStoreMinimalTuple(MinimalTuple mtup,
1729
            TupleTableSlot *slot,
1730
            bool shouldFree)
1731
0
{
1732
  /*
1733
   * sanity checks
1734
   */
1735
0
  Assert(mtup != NULL);
1736
0
  Assert(slot != NULL);
1737
0
  Assert(slot->tts_tupleDescriptor != NULL);
1738
1739
0
  if (unlikely(!TTS_IS_MINIMALTUPLE(slot)))
1740
0
    elog(ERROR, "trying to store a minimal tuple into wrong type of slot");
1741
0
  tts_minimal_store_tuple(slot, mtup, shouldFree);
1742
1743
0
  return slot;
1744
0
}
1745
1746
/*
1747
 * Store a HeapTuple into any kind of slot, performing conversion if
1748
 * necessary.
1749
 */
1750
void
1751
ExecForceStoreHeapTuple(HeapTuple tuple,
1752
            TupleTableSlot *slot,
1753
            bool shouldFree)
1754
0
{
1755
0
  if (TTS_IS_HEAPTUPLE(slot))
1756
0
  {
1757
0
    ExecStoreHeapTuple(tuple, slot, shouldFree);
1758
0
  }
1759
0
  else if (TTS_IS_BUFFERTUPLE(slot))
1760
0
  {
1761
0
    MemoryContext oldContext;
1762
0
    BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
1763
1764
0
    ExecClearTuple(slot);
1765
0
    slot->tts_flags &= ~TTS_FLAG_EMPTY;
1766
0
    oldContext = MemoryContextSwitchTo(slot->tts_mcxt);
1767
0
    bslot->base.tuple = heap_copytuple(tuple);
1768
0
    slot->tts_flags |= TTS_FLAG_SHOULDFREE;
1769
0
    slot->tts_tid = tuple->t_self;
1770
0
    MemoryContextSwitchTo(oldContext);
1771
1772
0
    if (shouldFree)
1773
0
      pfree(tuple);
1774
0
  }
1775
0
  else
1776
0
  {
1777
0
    ExecClearTuple(slot);
1778
0
    heap_deform_tuple(tuple, slot->tts_tupleDescriptor,
1779
0
              slot->tts_values, slot->tts_isnull);
1780
0
    ExecStoreVirtualTuple(slot);
1781
0
    slot->tts_tid = tuple->t_self;
1782
1783
0
    if (shouldFree)
1784
0
    {
1785
0
      ExecMaterializeSlot(slot);
1786
0
      pfree(tuple);
1787
0
    }
1788
0
  }
1789
0
}
1790
1791
/*
1792
 * Store a MinimalTuple into any kind of slot, performing conversion if
1793
 * necessary.
1794
 */
1795
void
1796
ExecForceStoreMinimalTuple(MinimalTuple mtup,
1797
               TupleTableSlot *slot,
1798
               bool shouldFree)
1799
0
{
1800
0
  if (TTS_IS_MINIMALTUPLE(slot))
1801
0
  {
1802
0
    tts_minimal_store_tuple(slot, mtup, shouldFree);
1803
0
  }
1804
0
  else
1805
0
  {
1806
0
    HeapTupleData htup;
1807
1808
0
    ExecClearTuple(slot);
1809
1810
0
    htup.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
1811
0
    htup.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
1812
0
    heap_deform_tuple(&htup, slot->tts_tupleDescriptor,
1813
0
              slot->tts_values, slot->tts_isnull);
1814
0
    ExecStoreVirtualTuple(slot);
1815
1816
0
    if (shouldFree)
1817
0
    {
1818
0
      ExecMaterializeSlot(slot);
1819
0
      pfree(mtup);
1820
0
    }
1821
0
  }
1822
0
}
1823
1824
/* --------------------------------
1825
 *    ExecStoreVirtualTuple
1826
 *      Mark a slot as containing a virtual tuple.
1827
 *
1828
 * The protocol for loading a slot with virtual tuple data is:
1829
 *    * Call ExecClearTuple to mark the slot empty.
1830
 *    * Store data into the Datum/isnull arrays.
1831
 *    * Call ExecStoreVirtualTuple to mark the slot valid.
1832
 * This is a bit unclean but it avoids one round of data copying.
1833
 * --------------------------------
1834
 */
1835
TupleTableSlot *
1836
ExecStoreVirtualTuple(TupleTableSlot *slot)
1837
0
{
1838
  /*
1839
   * sanity checks
1840
   */
1841
0
  Assert(slot != NULL);
1842
0
  Assert(slot->tts_tupleDescriptor != NULL);
1843
0
  Assert(TTS_EMPTY(slot));
1844
1845
0
  slot->tts_flags &= ~TTS_FLAG_EMPTY;
1846
0
  slot->tts_nvalid = slot->tts_tupleDescriptor->natts;
1847
1848
0
  return slot;
1849
0
}
1850
1851
/* --------------------------------
1852
 *    ExecStoreAllNullTuple
1853
 *      Set up the slot to contain a null in every column.
1854
 *
1855
 * At first glance this might sound just like ExecClearTuple, but it's
1856
 * entirely different: the slot ends up full, not empty.
1857
 * --------------------------------
1858
 */
1859
TupleTableSlot *
1860
ExecStoreAllNullTuple(TupleTableSlot *slot)
1861
0
{
1862
  /*
1863
   * sanity checks
1864
   */
1865
0
  Assert(slot != NULL);
1866
0
  Assert(slot->tts_tupleDescriptor != NULL);
1867
1868
  /* Clear any old contents */
1869
0
  ExecClearTuple(slot);
1870
1871
  /*
1872
   * Fill all the columns of the virtual tuple with nulls
1873
   */
1874
0
  MemSet(slot->tts_values, 0,
1875
0
       slot->tts_tupleDescriptor->natts * sizeof(Datum));
1876
0
  memset(slot->tts_isnull, true,
1877
0
       slot->tts_tupleDescriptor->natts * sizeof(bool));
1878
1879
0
  return ExecStoreVirtualTuple(slot);
1880
0
}
1881
1882
/*
1883
 * Store a HeapTuple in datum form, into a slot. That always requires
1884
 * deforming it and storing it in virtual form.
1885
 *
1886
 * Until the slot is materialized, the contents of the slot depend on the
1887
 * datum.
1888
 */
1889
void
1890
ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot)
1891
0
{
1892
0
  HeapTupleData tuple = {0};
1893
0
  HeapTupleHeader td;
1894
1895
0
  td = DatumGetHeapTupleHeader(data);
1896
1897
0
  tuple.t_len = HeapTupleHeaderGetDatumLength(td);
1898
0
  tuple.t_self = td->t_ctid;
1899
0
  tuple.t_data = td;
1900
1901
0
  ExecClearTuple(slot);
1902
1903
0
  heap_deform_tuple(&tuple, slot->tts_tupleDescriptor,
1904
0
            slot->tts_values, slot->tts_isnull);
1905
0
  ExecStoreVirtualTuple(slot);
1906
0
}
1907
1908
/*
1909
 * ExecFetchSlotHeapTuple - fetch HeapTuple representing the slot's content
1910
 *
1911
 * The returned HeapTuple represents the slot's content as closely as
1912
 * possible.
1913
 *
1914
 * If materialize is true, the contents of the slots will be made independent
1915
 * from the underlying storage (i.e. all buffer pins are released, memory is
1916
 * allocated in the slot's context).
1917
 *
1918
 * If shouldFree is not-NULL it'll be set to true if the returned tuple has
1919
 * been allocated in the calling memory context, and must be freed by the
1920
 * caller (via explicit pfree() or a memory context reset).
1921
 *
1922
 * NB: If materialize is true, modifications of the returned tuple are
1923
 * allowed. But it depends on the type of the slot whether such modifications
1924
 * will also affect the slot's contents. While that is not the nicest
1925
 * behaviour, all such modifications are in the process of being removed.
1926
 */
1927
HeapTuple
1928
ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree)
1929
0
{
1930
  /*
1931
   * sanity checks
1932
   */
1933
0
  Assert(slot != NULL);
1934
0
  Assert(!TTS_EMPTY(slot));
1935
1936
  /* Materialize the tuple so that the slot "owns" it, if requested. */
1937
0
  if (materialize)
1938
0
    slot->tts_ops->materialize(slot);
1939
1940
0
  if (slot->tts_ops->get_heap_tuple == NULL)
1941
0
  {
1942
0
    if (shouldFree)
1943
0
      *shouldFree = true;
1944
0
    return slot->tts_ops->copy_heap_tuple(slot);
1945
0
  }
1946
0
  else
1947
0
  {
1948
0
    if (shouldFree)
1949
0
      *shouldFree = false;
1950
0
    return slot->tts_ops->get_heap_tuple(slot);
1951
0
  }
1952
0
}
1953
1954
/* --------------------------------
1955
 *    ExecFetchSlotMinimalTuple
1956
 *      Fetch the slot's minimal physical tuple.
1957
 *
1958
 *    If the given tuple table slot can hold a minimal tuple, indicated by a
1959
 *    non-NULL get_minimal_tuple callback, the function returns the minimal
1960
 *    tuple returned by that callback. It assumes that the minimal tuple
1961
 *    returned by the callback is "owned" by the slot i.e. the slot is
1962
 *    responsible for freeing the memory consumed by the tuple. Hence it sets
1963
 *    *shouldFree to false, indicating that the caller should not free the
1964
 *    memory consumed by the minimal tuple. In this case the returned minimal
1965
 *    tuple should be considered as read-only.
1966
 *
1967
 *    If that callback is not supported, it calls copy_minimal_tuple callback
1968
 *    which is expected to return a copy of minimal tuple representing the
1969
 *    contents of the slot. In this case *shouldFree is set to true,
1970
 *    indicating the caller that it should free the memory consumed by the
1971
 *    minimal tuple. In this case the returned minimal tuple may be written
1972
 *    up.
1973
 * --------------------------------
1974
 */
1975
MinimalTuple
1976
ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
1977
              bool *shouldFree)
1978
0
{
1979
  /*
1980
   * sanity checks
1981
   */
1982
0
  Assert(slot != NULL);
1983
0
  Assert(!TTS_EMPTY(slot));
1984
1985
0
  if (slot->tts_ops->get_minimal_tuple)
1986
0
  {
1987
0
    if (shouldFree)
1988
0
      *shouldFree = false;
1989
0
    return slot->tts_ops->get_minimal_tuple(slot);
1990
0
  }
1991
0
  else
1992
0
  {
1993
0
    if (shouldFree)
1994
0
      *shouldFree = true;
1995
0
    return slot->tts_ops->copy_minimal_tuple(slot, 0);
1996
0
  }
1997
0
}
1998
1999
/* --------------------------------
2000
 *    ExecFetchSlotHeapTupleDatum
2001
 *      Fetch the slot's tuple as a composite-type Datum.
2002
 *
2003
 *    The result is always freshly palloc'd in the caller's memory context.
2004
 * --------------------------------
2005
 */
2006
Datum
2007
ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot)
2008
0
{
2009
0
  HeapTuple tup;
2010
0
  TupleDesc tupdesc;
2011
0
  bool    shouldFree;
2012
0
  Datum   ret;
2013
2014
  /* Fetch slot's contents in regular-physical-tuple form */
2015
0
  tup = ExecFetchSlotHeapTuple(slot, false, &shouldFree);
2016
0
  tupdesc = slot->tts_tupleDescriptor;
2017
2018
  /* Convert to Datum form */
2019
0
  ret = heap_copy_tuple_as_datum(tup, tupdesc);
2020
2021
0
  if (shouldFree)
2022
0
    pfree(tup);
2023
2024
0
  return ret;
2025
0
}
2026
2027
/* ----------------------------------------------------------------
2028
 *        convenience initialization routines
2029
 * ----------------------------------------------------------------
2030
 */
2031
2032
/* ----------------
2033
 *    ExecInitResultTypeTL
2034
 *
2035
 *    Initialize result type, using the plan node's targetlist.
2036
 * ----------------
2037
 */
2038
void
2039
ExecInitResultTypeTL(PlanState *planstate)
2040
0
{
2041
0
  TupleDesc tupDesc = ExecTypeFromTL(planstate->plan->targetlist);
2042
2043
0
  planstate->ps_ResultTupleDesc = tupDesc;
2044
0
}
2045
2046
/* --------------------------------
2047
 *    ExecInit{Result,Scan,Extra}TupleSlot[TL]
2048
 *
2049
 *    These are convenience routines to initialize the specified slot
2050
 *    in nodes inheriting the appropriate state.  ExecInitExtraTupleSlot
2051
 *    is used for initializing special-purpose slots.
2052
 * --------------------------------
2053
 */
2054
2055
/* ----------------
2056
 *    ExecInitResultTupleSlotTL
2057
 *
2058
 *    Initialize result tuple slot, using the tuple descriptor previously
2059
 *    computed with ExecInitResultTypeTL().
2060
 * ----------------
2061
 */
2062
void
2063
ExecInitResultSlot(PlanState *planstate, const TupleTableSlotOps *tts_ops)
2064
0
{
2065
0
  TupleTableSlot *slot;
2066
2067
0
  slot = ExecAllocTableSlot(&planstate->state->es_tupleTable,
2068
0
                planstate->ps_ResultTupleDesc, tts_ops, 0);
2069
0
  planstate->ps_ResultTupleSlot = slot;
2070
2071
0
  planstate->resultopsfixed = planstate->ps_ResultTupleDesc != NULL;
2072
0
  planstate->resultops = tts_ops;
2073
0
  planstate->resultopsset = true;
2074
0
}
2075
2076
/* ----------------
2077
 *    ExecInitResultTupleSlotTL
2078
 *
2079
 *    Initialize result tuple slot, using the plan node's targetlist.
2080
 * ----------------
2081
 */
2082
void
2083
ExecInitResultTupleSlotTL(PlanState *planstate,
2084
              const TupleTableSlotOps *tts_ops)
2085
0
{
2086
0
  ExecInitResultTypeTL(planstate);
2087
0
  ExecInitResultSlot(planstate, tts_ops);
2088
0
}
2089
2090
/* ----------------
2091
 *    ExecInitScanTupleSlot
2092
 * ----------------
2093
 */
2094
void
2095
ExecInitScanTupleSlot(EState *estate, ScanState *scanstate,
2096
            TupleDesc tupledesc, const TupleTableSlotOps *tts_ops,
2097
            uint16 flags)
2098
0
{
2099
0
  scanstate->ss_ScanTupleSlot = ExecAllocTableSlot(&estate->es_tupleTable,
2100
0
                           tupledesc, tts_ops, flags);
2101
0
  scanstate->ps.scandesc = tupledesc;
2102
0
  scanstate->ps.scanopsfixed = tupledesc != NULL;
2103
0
  scanstate->ps.scanops = tts_ops;
2104
0
  scanstate->ps.scanopsset = true;
2105
0
}
2106
2107
/* ----------------
2108
 *    ExecInitExtraTupleSlot
2109
 *
2110
 * Return a newly created slot. If tupledesc is non-NULL the slot will have
2111
 * that as its fixed tupledesc. Otherwise the caller needs to use
2112
 * ExecSetSlotDescriptor() to set the descriptor before use.
2113
 * ----------------
2114
 */
2115
TupleTableSlot *
2116
ExecInitExtraTupleSlot(EState *estate,
2117
             TupleDesc tupledesc,
2118
             const TupleTableSlotOps *tts_ops)
2119
0
{
2120
0
  return ExecAllocTableSlot(&estate->es_tupleTable, tupledesc, tts_ops, 0);
2121
0
}
2122
2123
/* ----------------
2124
 *    ExecInitNullTupleSlot
2125
 *
2126
 * Build a slot containing an all-nulls tuple of the given type.
2127
 * This is used as a substitute for an input tuple when performing an
2128
 * outer join.
2129
 * ----------------
2130
 */
2131
TupleTableSlot *
2132
ExecInitNullTupleSlot(EState *estate, TupleDesc tupType,
2133
            const TupleTableSlotOps *tts_ops)
2134
0
{
2135
0
  TupleTableSlot *slot = ExecInitExtraTupleSlot(estate, tupType, tts_ops);
2136
2137
0
  return ExecStoreAllNullTuple(slot);
2138
0
}
2139
2140
/* ---------------------------------------------------------------
2141
 *      Routines for setting/accessing attributes in a slot.
2142
 * ---------------------------------------------------------------
2143
 */
2144
2145
/*
2146
 * Fill in missing values for a TupleTableSlot.
2147
 *
2148
 * This is only exposed because it's needed for JIT compiled tuple
2149
 * deforming. That exception aside, there should be no callers outside of this
2150
 * file.
2151
 */
2152
void
2153
slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum)
2154
0
{
2155
0
  AttrMissing *attrmiss = NULL;
2156
2157
  /* Check for invalid attnums */
2158
0
  if (unlikely(lastAttNum > slot->tts_tupleDescriptor->natts))
2159
0
    elog(ERROR, "invalid attribute number %d", lastAttNum);
2160
2161
0
  if (slot->tts_tupleDescriptor->constr)
2162
0
    attrmiss = slot->tts_tupleDescriptor->constr->missing;
2163
2164
0
  if (!attrmiss)
2165
0
  {
2166
    /* no missing values array at all, so just fill everything in as NULL */
2167
0
    for (int attnum = startAttNum; attnum < lastAttNum; attnum++)
2168
0
    {
2169
0
      slot->tts_values[attnum] = (Datum) 0;
2170
0
      slot->tts_isnull[attnum] = true;
2171
0
    }
2172
0
  }
2173
0
  else
2174
0
  {
2175
    /* use attrmiss to set the missing values */
2176
0
    for (int attnum = startAttNum; attnum < lastAttNum; attnum++)
2177
0
    {
2178
0
      slot->tts_values[attnum] = attrmiss[attnum].am_value;
2179
0
      slot->tts_isnull[attnum] = !attrmiss[attnum].am_present;
2180
0
    }
2181
0
  }
2182
0
}
2183
2184
/*
2185
 * slot_getsomeattrs_int
2186
 *    external function to call getsomeattrs() for use in JIT
2187
 */
2188
void
2189
slot_getsomeattrs_int(TupleTableSlot *slot, int attnum)
2190
0
{
2191
  /* Check for caller errors */
2192
0
  Assert(slot->tts_nvalid < attnum);  /* checked in slot_getsomeattrs */
2193
0
  Assert(attnum > 0);
2194
2195
  /* Fetch as many attributes as possible from the underlying tuple. */
2196
0
  slot->tts_ops->getsomeattrs(slot, attnum);
2197
2198
  /*
2199
   * Avoid putting new code here as that would prevent the compiler from
2200
   * using the sibling call optimization for the above function.
2201
   */
2202
0
}
2203
2204
/* ----------------------------------------------------------------
2205
 *    ExecTypeFromTL
2206
 *
2207
 *    Generate a tuple descriptor for the result tuple of a targetlist.
2208
 *    (A parse/plan tlist must be passed, not an ExprState tlist.)
2209
 *    Note that resjunk columns, if any, are included in the result.
2210
 *
2211
 *    Currently there are about 4 different places where we create
2212
 *    TupleDescriptors.  They should all be merged, or perhaps
2213
 *    be rewritten to call BuildDesc().
2214
 * ----------------------------------------------------------------
2215
 */
2216
TupleDesc
2217
ExecTypeFromTL(List *targetList)
2218
0
{
2219
0
  return ExecTypeFromTLInternal(targetList, false);
2220
0
}
2221
2222
/* ----------------------------------------------------------------
2223
 *    ExecCleanTypeFromTL
2224
 *
2225
 *    Same as above, but resjunk columns are omitted from the result.
2226
 * ----------------------------------------------------------------
2227
 */
2228
TupleDesc
2229
ExecCleanTypeFromTL(List *targetList)
2230
0
{
2231
0
  return ExecTypeFromTLInternal(targetList, true);
2232
0
}
2233
2234
static TupleDesc
2235
ExecTypeFromTLInternal(List *targetList, bool skipjunk)
2236
0
{
2237
0
  TupleDesc typeInfo;
2238
0
  ListCell   *l;
2239
0
  int     len;
2240
0
  int     cur_resno = 1;
2241
2242
0
  if (skipjunk)
2243
0
    len = ExecCleanTargetListLength(targetList);
2244
0
  else
2245
0
    len = ExecTargetListLength(targetList);
2246
0
  typeInfo = CreateTemplateTupleDesc(len);
2247
2248
0
  foreach(l, targetList)
2249
0
  {
2250
0
    TargetEntry *tle = lfirst(l);
2251
2252
0
    if (skipjunk && tle->resjunk)
2253
0
      continue;
2254
0
    TupleDescInitEntry(typeInfo,
2255
0
               cur_resno,
2256
0
               tle->resname,
2257
0
               exprType((Node *) tle->expr),
2258
0
               exprTypmod((Node *) tle->expr),
2259
0
               0);
2260
0
    TupleDescInitEntryCollation(typeInfo,
2261
0
                  cur_resno,
2262
0
                  exprCollation((Node *) tle->expr));
2263
0
    cur_resno++;
2264
0
  }
2265
2266
0
  TupleDescFinalize(typeInfo);
2267
2268
0
  return typeInfo;
2269
0
}
2270
2271
/*
2272
 * ExecTypeFromExprList - build a tuple descriptor from a list of Exprs
2273
 *
2274
 * This is roughly like ExecTypeFromTL, but we work from bare expressions
2275
 * not TargetEntrys.  No names are attached to the tupledesc's columns.
2276
 */
2277
TupleDesc
2278
ExecTypeFromExprList(List *exprList)
2279
0
{
2280
0
  TupleDesc typeInfo;
2281
0
  ListCell   *lc;
2282
0
  int     cur_resno = 1;
2283
2284
0
  typeInfo = CreateTemplateTupleDesc(list_length(exprList));
2285
2286
0
  foreach(lc, exprList)
2287
0
  {
2288
0
    Node     *e = lfirst(lc);
2289
2290
0
    TupleDescInitEntry(typeInfo,
2291
0
               cur_resno,
2292
0
               NULL,
2293
0
               exprType(e),
2294
0
               exprTypmod(e),
2295
0
               0);
2296
0
    TupleDescInitEntryCollation(typeInfo,
2297
0
                  cur_resno,
2298
0
                  exprCollation(e));
2299
0
    cur_resno++;
2300
0
  }
2301
2302
0
  TupleDescFinalize(typeInfo);
2303
2304
0
  return typeInfo;
2305
0
}
2306
2307
/*
2308
 * ExecTypeSetColNames - set column names in a RECORD TupleDesc
2309
 *
2310
 * Column names must be provided as an alias list (list of String nodes).
2311
 */
2312
void
2313
ExecTypeSetColNames(TupleDesc typeInfo, List *namesList)
2314
0
{
2315
0
  int     colno = 0;
2316
0
  ListCell   *lc;
2317
2318
  /* It's only OK to change col names in a not-yet-blessed RECORD type */
2319
0
  Assert(typeInfo->tdtypeid == RECORDOID);
2320
0
  Assert(typeInfo->tdtypmod < 0);
2321
2322
0
  foreach(lc, namesList)
2323
0
  {
2324
0
    char     *cname = strVal(lfirst(lc));
2325
0
    Form_pg_attribute attr;
2326
2327
    /* Guard against too-long names list (probably can't happen) */
2328
0
    if (colno >= typeInfo->natts)
2329
0
      break;
2330
0
    attr = TupleDescAttr(typeInfo, colno);
2331
0
    colno++;
2332
2333
    /*
2334
     * Do nothing for empty aliases or dropped columns (these cases
2335
     * probably can't arise in RECORD types, either)
2336
     */
2337
0
    if (cname[0] == '\0' || attr->attisdropped)
2338
0
      continue;
2339
2340
    /* OK, assign the column name */
2341
0
    namestrcpy(&(attr->attname), cname);
2342
0
  }
2343
0
}
2344
2345
/*
2346
 * BlessTupleDesc - make a completed tuple descriptor useful for SRFs
2347
 *
2348
 * Rowtype Datums returned by a function must contain valid type information.
2349
 * This happens "for free" if the tupdesc came from a relcache entry, but
2350
 * not if we have manufactured a tupdesc for a transient RECORD datatype.
2351
 * In that case we have to notify typcache.c of the existence of the type.
2352
 *
2353
 * TupleDescFinalize() must be called on the TupleDesc before calling this
2354
 * function.
2355
 */
2356
TupleDesc
2357
BlessTupleDesc(TupleDesc tupdesc)
2358
0
{
2359
  /* Did someone forget to call TupleDescFinalize()? */
2360
0
  Assert(tupdesc->firstNonCachedOffsetAttr >= 0);
2361
2362
0
  if (tupdesc->tdtypeid == RECORDOID &&
2363
0
    tupdesc->tdtypmod < 0)
2364
0
    assign_record_type_typmod(tupdesc);
2365
2366
0
  return tupdesc;       /* just for notational convenience */
2367
0
}
2368
2369
/*
2370
 * TupleDescGetAttInMetadata - Build an AttInMetadata structure based on the
2371
 * supplied TupleDesc. AttInMetadata can be used in conjunction with C strings
2372
 * to produce a properly formed tuple.
2373
 */
2374
AttInMetadata *
2375
TupleDescGetAttInMetadata(TupleDesc tupdesc)
2376
0
{
2377
0
  int     natts = tupdesc->natts;
2378
0
  int     i;
2379
0
  Oid     atttypeid;
2380
0
  Oid     attinfuncid;
2381
0
  FmgrInfo   *attinfuncinfo;
2382
0
  Oid      *attioparams;
2383
0
  int32    *atttypmods;
2384
0
  AttInMetadata *attinmeta;
2385
2386
0
  attinmeta = palloc_object(AttInMetadata);
2387
2388
  /* "Bless" the tupledesc so that we can make rowtype datums with it */
2389
0
  attinmeta->tupdesc = BlessTupleDesc(tupdesc);
2390
2391
  /*
2392
   * Gather info needed later to call the "in" function for each attribute
2393
   */
2394
0
  attinfuncinfo = palloc0_array(FmgrInfo, natts);
2395
0
  attioparams = palloc0_array(Oid, natts);
2396
0
  atttypmods = palloc0_array(int32, natts);
2397
2398
0
  for (i = 0; i < natts; i++)
2399
0
  {
2400
0
    Form_pg_attribute att = TupleDescAttr(tupdesc, i);
2401
2402
    /* Ignore dropped attributes */
2403
0
    if (!att->attisdropped)
2404
0
    {
2405
0
      atttypeid = att->atttypid;
2406
0
      getTypeInputInfo(atttypeid, &attinfuncid, &attioparams[i]);
2407
0
      fmgr_info(attinfuncid, &attinfuncinfo[i]);
2408
0
      atttypmods[i] = att->atttypmod;
2409
0
    }
2410
0
  }
2411
0
  attinmeta->attinfuncs = attinfuncinfo;
2412
0
  attinmeta->attioparams = attioparams;
2413
0
  attinmeta->atttypmods = atttypmods;
2414
2415
0
  return attinmeta;
2416
0
}
2417
2418
/*
2419
 * BuildTupleFromCStrings - build a HeapTuple given user data in C string form.
2420
 * values is an array of C strings, one for each attribute of the return tuple.
2421
 * A NULL string pointer indicates we want to create a NULL field.
2422
 */
2423
HeapTuple
2424
BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
2425
0
{
2426
0
  TupleDesc tupdesc = attinmeta->tupdesc;
2427
0
  int     natts = tupdesc->natts;
2428
0
  Datum    *dvalues;
2429
0
  bool     *nulls;
2430
0
  int     i;
2431
0
  HeapTuple tuple;
2432
2433
0
  dvalues = palloc_array(Datum, natts);
2434
0
  nulls = palloc_array(bool, natts);
2435
2436
  /*
2437
   * Call the "in" function for each non-dropped attribute, even for nulls,
2438
   * to support domains.
2439
   */
2440
0
  for (i = 0; i < natts; i++)
2441
0
  {
2442
0
    if (!TupleDescCompactAttr(tupdesc, i)->attisdropped)
2443
0
    {
2444
      /* Non-dropped attributes */
2445
0
      dvalues[i] = InputFunctionCall(&attinmeta->attinfuncs[i],
2446
0
                       values[i],
2447
0
                       attinmeta->attioparams[i],
2448
0
                       attinmeta->atttypmods[i]);
2449
0
      if (values[i] != NULL)
2450
0
        nulls[i] = false;
2451
0
      else
2452
0
        nulls[i] = true;
2453
0
    }
2454
0
    else
2455
0
    {
2456
      /* Handle dropped attributes by setting to NULL */
2457
0
      dvalues[i] = (Datum) 0;
2458
0
      nulls[i] = true;
2459
0
    }
2460
0
  }
2461
2462
  /*
2463
   * Form a tuple
2464
   */
2465
0
  tuple = heap_form_tuple(tupdesc, dvalues, nulls);
2466
2467
  /*
2468
   * Release locally palloc'd space.  XXX would probably be good to pfree
2469
   * values of pass-by-reference datums, as well.
2470
   */
2471
0
  pfree(dvalues);
2472
0
  pfree(nulls);
2473
2474
0
  return tuple;
2475
0
}
2476
2477
/*
2478
 * HeapTupleHeaderGetDatum - convert a HeapTupleHeader pointer to a Datum.
2479
 *
2480
 * This must *not* get applied to an on-disk tuple; the tuple should be
2481
 * freshly made by heap_form_tuple or some wrapper routine for it (such as
2482
 * BuildTupleFromCStrings).  Be sure also that the tupledesc used to build
2483
 * the tuple has a properly "blessed" rowtype.
2484
 *
2485
 * Formerly this was a macro equivalent to PointerGetDatum, relying on the
2486
 * fact that heap_form_tuple fills in the appropriate tuple header fields
2487
 * for a composite Datum.  However, we now require that composite Datums not
2488
 * contain any external TOAST pointers.  We do not want heap_form_tuple itself
2489
 * to enforce that; more specifically, the rule applies only to actual Datums
2490
 * and not to HeapTuple structures.  Therefore, HeapTupleHeaderGetDatum is
2491
 * now a function that detects whether there are externally-toasted fields
2492
 * and constructs a new tuple with inlined fields if so.  We still need
2493
 * heap_form_tuple to insert the Datum header fields, because otherwise this
2494
 * code would have no way to obtain a tupledesc for the tuple.
2495
 *
2496
 * Note that if we do build a new tuple, it's palloc'd in the current
2497
 * memory context.  Beware of code that changes context between the initial
2498
 * heap_form_tuple/etc call and calling HeapTuple(Header)GetDatum.
2499
 *
2500
 * For performance-critical callers, it could be worthwhile to take extra
2501
 * steps to ensure that there aren't TOAST pointers in the output of
2502
 * heap_form_tuple to begin with.  It's likely however that the costs of the
2503
 * typcache lookup and tuple disassembly/reassembly are swamped by TOAST
2504
 * dereference costs, so that the benefits of such extra effort would be
2505
 * minimal.
2506
 *
2507
 * XXX it would likely be better to create wrapper functions that produce
2508
 * a composite Datum from the field values in one step.  However, there's
2509
 * enough code using the existing APIs that we couldn't get rid of this
2510
 * hack anytime soon.
2511
 */
2512
Datum
2513
HeapTupleHeaderGetDatum(HeapTupleHeader tuple)
2514
0
{
2515
0
  Datum   result;
2516
0
  TupleDesc tupDesc;
2517
2518
  /* No work if there are no external TOAST pointers in the tuple */
2519
0
  if (!HeapTupleHeaderHasExternal(tuple))
2520
0
    return PointerGetDatum(tuple);
2521
2522
  /* Use the type data saved by heap_form_tuple to look up the rowtype */
2523
0
  tupDesc = lookup_rowtype_tupdesc(HeapTupleHeaderGetTypeId(tuple),
2524
0
                   HeapTupleHeaderGetTypMod(tuple));
2525
2526
  /* And do the flattening */
2527
0
  result = toast_flatten_tuple_to_datum(tuple,
2528
0
                      HeapTupleHeaderGetDatumLength(tuple),
2529
0
                      tupDesc);
2530
2531
0
  ReleaseTupleDesc(tupDesc);
2532
2533
0
  return result;
2534
0
}
2535
2536
2537
/*
2538
 * Functions for sending tuples to the frontend (or other specified destination)
2539
 * as though it is a SELECT result. These are used by utility commands that
2540
 * need to project directly to the destination and don't need or want full
2541
 * table function capability. Currently used by EXPLAIN and SHOW ALL.
2542
 */
2543
TupOutputState *
2544
begin_tup_output_tupdesc(DestReceiver *dest,
2545
             TupleDesc tupdesc,
2546
             const TupleTableSlotOps *tts_ops)
2547
0
{
2548
0
  TupOutputState *tstate;
2549
2550
0
  tstate = palloc_object(TupOutputState);
2551
2552
0
  tstate->slot = MakeSingleTupleTableSlot(tupdesc, tts_ops);
2553
0
  tstate->dest = dest;
2554
2555
0
  tstate->dest->rStartup(tstate->dest, (int) CMD_SELECT, tupdesc);
2556
2557
0
  return tstate;
2558
0
}
2559
2560
/*
2561
 * write a single tuple
2562
 */
2563
void
2564
do_tup_output(TupOutputState *tstate, const Datum *values, const bool *isnull)
2565
0
{
2566
0
  TupleTableSlot *slot = tstate->slot;
2567
0
  int     natts = slot->tts_tupleDescriptor->natts;
2568
2569
  /* make sure the slot is clear */
2570
0
  ExecClearTuple(slot);
2571
2572
  /* insert data */
2573
0
  memcpy(slot->tts_values, values, natts * sizeof(Datum));
2574
0
  memcpy(slot->tts_isnull, isnull, natts * sizeof(bool));
2575
2576
  /* mark slot as containing a virtual tuple */
2577
0
  ExecStoreVirtualTuple(slot);
2578
2579
  /* send the tuple to the receiver */
2580
0
  (void) tstate->dest->receiveSlot(slot, tstate->dest);
2581
2582
  /* clean up */
2583
0
  ExecClearTuple(slot);
2584
0
}
2585
2586
/*
2587
 * write a chunk of text, breaking at newline characters
2588
 *
2589
 * Should only be used with a single-TEXT-attribute tupdesc.
2590
 */
2591
void
2592
do_text_output_multiline(TupOutputState *tstate, const char *txt)
2593
0
{
2594
0
  Datum   values[1];
2595
0
  bool    isnull[1] = {false};
2596
2597
0
  while (*txt)
2598
0
  {
2599
0
    const char *eol;
2600
0
    int     len;
2601
2602
0
    eol = strchr(txt, '\n');
2603
0
    if (eol)
2604
0
    {
2605
0
      len = eol - txt;
2606
0
      eol++;
2607
0
    }
2608
0
    else
2609
0
    {
2610
0
      len = strlen(txt);
2611
0
      eol = txt + len;
2612
0
    }
2613
2614
0
    values[0] = PointerGetDatum(cstring_to_text_with_len(txt, len));
2615
0
    do_tup_output(tstate, values, isnull);
2616
0
    pfree(DatumGetPointer(values[0]));
2617
0
    txt = eol;
2618
0
  }
2619
0
}
2620
2621
void
2622
end_tup_output(TupOutputState *tstate)
2623
0
{
2624
0
  tstate->dest->rShutdown(tstate->dest);
2625
  /* note that destroying the dest is not ours to do */
2626
0
  ExecDropSingleTupleTableSlot(tstate->slot);
2627
0
  pfree(tstate);
2628
0
}