1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * tuptable.h |
4 | * tuple table support stuff |
5 | * |
6 | * |
7 | * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group |
8 | * Portions Copyright (c) 1994, Regents of the University of California |
9 | * |
10 | * src/include/executor/tuptable.h |
11 | * |
12 | *------------------------------------------------------------------------- |
13 | */ |
14 | #ifndef TUPTABLE_H |
15 | #define TUPTABLE_H |
16 | |
17 | #include "access/htup.h" |
18 | #include "access/sysattr.h" |
19 | #include "access/tupdesc.h" |
20 | #include "access/htup_details.h" |
21 | #include "storage/buf.h" |
22 | |
23 | /*---------- |
24 | * The executor stores tuples in a "tuple table" which is a List of |
25 | * independent TupleTableSlots. |
26 | * |
27 | * There's various different types of tuple table slots, each being able to |
28 | * store different types of tuples. Additional types of slots can be added |
29 | * without modifying core code. The type of a slot is determined by the |
30 | * TupleTableSlotOps* passed to the slot creation routine. The builtin types |
31 | * of slots are |
32 | * |
33 | * 1. physical tuple in a disk buffer page (TTSOpsBufferHeapTuple) |
34 | * 2. physical tuple constructed in palloc'ed memory (TTSOpsHeapTuple) |
35 | * 3. "minimal" physical tuple constructed in palloc'ed memory |
36 | * (TTSOpsMinimalTuple) |
37 | * 4. "virtual" tuple consisting of Datum/isnull arrays (TTSOpsVirtual) |
38 | * |
39 | * |
40 | * The first two cases are similar in that they both deal with "materialized" |
41 | * tuples, but resource management is different. For a tuple in a disk page |
42 | * we need to hold a pin on the buffer until the TupleTableSlot's reference |
43 | * to the tuple is dropped; while for a palloc'd tuple we usually want the |
44 | * tuple pfree'd when the TupleTableSlot's reference is dropped. |
45 | * |
46 | * A "minimal" tuple is handled similarly to a palloc'd regular tuple. |
47 | * At present, minimal tuples never are stored in buffers, so there is no |
48 | * parallel to case 1. Note that a minimal tuple has no "system columns". |
49 | * (Actually, it could have an OID, but we have no need to access the OID.) |
50 | * |
51 | * A "virtual" tuple is an optimization used to minimize physical data copying |
52 | * in a nest of plan nodes. Until materialized pass-by-reference Datums in |
53 | * the slot point to storage that is not directly associated with the |
54 | * TupleTableSlot; generally they will point to part of a tuple stored in a |
55 | * lower plan node's output TupleTableSlot, or to a function result |
56 | * constructed in a plan node's per-tuple econtext. It is the responsibility |
57 | * of the generating plan node to be sure these resources are not released for |
58 | * as long as the virtual tuple needs to be valid or is materialized. Note |
59 | * also that a virtual tuple does not have any "system columns". |
60 | * |
61 | * The Datum/isnull arrays of a TupleTableSlot serve double duty. For virtual |
62 | * slots they are the authoritative data. For the other builtin slots, |
63 | * the arrays contain data extracted from the tuple. (In this state, any |
64 | * pass-by-reference Datums point into the physical tuple.) The extracted |
65 | * information is built "lazily", ie, only as needed. This serves to avoid |
66 | * repeated extraction of data from the physical tuple. |
67 | * |
68 | * A TupleTableSlot can also be "empty", indicated by flag TTS_FLAG_EMPTY set |
69 | * in tts_flags, holding no valid data. This is the only valid state for a |
70 | * freshly-created slot that has not yet had a tuple descriptor assigned to |
71 | * it. In this state, TTS_SHOULDFREE should not be set in tts_flags, tts_tuple |
72 | * must be NULL and tts_nvalid zero. |
73 | * |
74 | * The tupleDescriptor is simply referenced, not copied, by the TupleTableSlot |
75 | * code. The caller of ExecSetSlotDescriptor() is responsible for providing |
76 | * a descriptor that will live as long as the slot does. (Typically, both |
77 | * slots and descriptors are in per-query memory and are freed by memory |
78 | * context deallocation at query end; so it's not worth providing any extra |
79 | * mechanism to do more. However, the slot will increment the tupdesc |
80 | * reference count if a reference-counted tupdesc is supplied.) |
81 | * |
82 | * When TTS_SHOULDFREE is set in tts_flags, the physical tuple is "owned" by |
83 | * the slot and should be freed when the slot's reference to the tuple is |
84 | * dropped. |
85 | * |
86 | * tts_values/tts_isnull are allocated either when the slot is created (when |
87 | * the descriptor is provided), or when a descriptor is assigned to the slot; |
88 | * they are of length equal to the descriptor's natts. |
89 | * |
90 | * The TTS_FLAG_SLOW flag is saved state for |
91 | * slot_deform_heap_tuple, and should not be touched by any other code. |
92 | *---------- |
93 | */ |
94 | |
95 | /* true = slot is empty */ |
96 | #define TTS_FLAG_EMPTY (1 << 1) |
97 | #define TTS_EMPTY(slot) (((slot)->tts_flags & TTS_FLAG_EMPTY) != 0) |
98 | |
99 | /* should pfree tuple "owned" by the slot? */ |
100 | #define TTS_FLAG_SHOULDFREE (1 << 2) |
101 | #define TTS_SHOULDFREE(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREE) != 0) |
102 | |
103 | /* saved state for slot_deform_heap_tuple */ |
104 | #define TTS_FLAG_SLOW (1 << 3) |
105 | #define TTS_SLOW(slot) (((slot)->tts_flags & TTS_FLAG_SLOW) != 0) |
106 | |
107 | /* fixed tuple descriptor */ |
108 | #define TTS_FLAG_FIXED (1 << 4) |
109 | #define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0) |
110 | |
111 | struct TupleTableSlotOps; |
112 | typedef struct TupleTableSlotOps TupleTableSlotOps; |
113 | |
114 | /* base tuple table slot type */ |
115 | typedef struct TupleTableSlot |
116 | { |
117 | NodeTag type; |
118 | #define FIELDNO_TUPLETABLESLOT_FLAGS 1 |
119 | uint16 tts_flags; /* Boolean states */ |
120 | #define FIELDNO_TUPLETABLESLOT_NVALID 2 |
121 | AttrNumber tts_nvalid; /* # of valid values in tts_values */ |
122 | const TupleTableSlotOps *const tts_ops; /* implementation of slot */ |
123 | #define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4 |
124 | TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */ |
125 | #define FIELDNO_TUPLETABLESLOT_VALUES 5 |
126 | Datum *tts_values; /* current per-attribute values */ |
127 | #define FIELDNO_TUPLETABLESLOT_ISNULL 6 |
128 | bool *tts_isnull; /* current per-attribute isnull flags */ |
129 | MemoryContext tts_mcxt; /* slot itself is in this context */ |
130 | ItemPointerData tts_tid; /* stored tuple's tid */ |
131 | Oid tts_tableOid; /* table oid of tuple */ |
132 | } TupleTableSlot; |
133 | |
134 | /* routines for a TupleTableSlot implementation */ |
135 | struct TupleTableSlotOps |
136 | { |
137 | /* Minimum size of the slot */ |
138 | size_t base_slot_size; |
139 | |
140 | /* Initialization. */ |
141 | void (*init) (TupleTableSlot *slot); |
142 | |
143 | /* Destruction. */ |
144 | void (*release) (TupleTableSlot *slot); |
145 | |
146 | /* |
147 | * Clear the contents of the slot. Only the contents are expected to be |
148 | * cleared and not the tuple descriptor. Typically an implementation of |
149 | * this callback should free the memory allocated for the tuple contained |
150 | * in the slot. |
151 | */ |
152 | void (*clear) (TupleTableSlot *slot); |
153 | |
154 | /* |
155 | * Fill up first natts entries of tts_values and tts_isnull arrays with |
156 | * values from the tuple contained in the slot. The function may be called |
157 | * with natts more than the number of attributes available in the tuple, |
158 | * in which case it should set tts_nvalid to the number of returned |
159 | * columns. |
160 | */ |
161 | void (*getsomeattrs) (TupleTableSlot *slot, int natts); |
162 | |
163 | /* |
164 | * Returns value of the given system attribute as a datum and sets isnull |
165 | * to false, if it's not NULL. Throws an error if the slot type does not |
166 | * support system attributes. |
167 | */ |
168 | Datum (*getsysattr) (TupleTableSlot *slot, int attnum, bool *isnull); |
169 | |
170 | /* |
171 | * Make the contents of the slot solely depend on the slot, and not on |
172 | * underlying resources (like another memory context, buffers, etc). |
173 | */ |
174 | void (*materialize) (TupleTableSlot *slot); |
175 | |
176 | /* |
177 | * Copy the contents of the source slot into the destination slot's own |
178 | * context. Invoked using callback of the destination slot. |
179 | */ |
180 | void (*copyslot) (TupleTableSlot *dstslot, TupleTableSlot *srcslot); |
181 | |
182 | /* |
183 | * Return a heap tuple "owned" by the slot. It is slot's responsibility to |
184 | * free the memory consumed by the heap tuple. If the slot can not "own" a |
185 | * heap tuple, it should not implement this callback and should set it as |
186 | * NULL. |
187 | */ |
188 | HeapTuple (*get_heap_tuple) (TupleTableSlot *slot); |
189 | |
190 | /* |
191 | * Return a minimal tuple "owned" by the slot. It is slot's responsibility |
192 | * to free the memory consumed by the minimal tuple. If the slot can not |
193 | * "own" a minimal tuple, it should not implement this callback and should |
194 | * set it as NULL. |
195 | */ |
196 | MinimalTuple (*get_minimal_tuple) (TupleTableSlot *slot); |
197 | |
198 | /* |
199 | * Return a copy of heap tuple representing the contents of the slot. The |
200 | * copy needs to be palloc'd in the current memory context. The slot |
201 | * itself is expected to remain unaffected. It is *not* expected to have |
202 | * meaningful "system columns" in the copy. The copy is not be "owned" by |
203 | * the slot i.e. the caller has to take responsibility to free memory |
204 | * consumed by the slot. |
205 | */ |
206 | HeapTuple (*copy_heap_tuple) (TupleTableSlot *slot); |
207 | |
208 | /* |
209 | * Return a copy of minimal tuple representing the contents of the slot. |
210 | * The copy needs to be palloc'd in the current memory context. The slot |
211 | * itself is expected to remain unaffected. It is *not* expected to have |
212 | * meaningful "system columns" in the copy. The copy is not be "owned" by |
213 | * the slot i.e. the caller has to take responsibility to free memory |
214 | * consumed by the slot. |
215 | */ |
216 | MinimalTuple (*copy_minimal_tuple) (TupleTableSlot *slot); |
217 | }; |
218 | |
219 | /* |
220 | * Predefined TupleTableSlotOps for various types of TupleTableSlotOps. The |
221 | * same are used to identify the type of a given slot. |
222 | */ |
223 | extern PGDLLIMPORT const TupleTableSlotOps TTSOpsVirtual; |
224 | extern PGDLLIMPORT const TupleTableSlotOps TTSOpsHeapTuple; |
225 | extern PGDLLIMPORT const TupleTableSlotOps TTSOpsMinimalTuple; |
226 | extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferHeapTuple; |
227 | |
228 | #define TTS_IS_VIRTUAL(slot) ((slot)->tts_ops == &TTSOpsVirtual) |
229 | #define TTS_IS_HEAPTUPLE(slot) ((slot)->tts_ops == &TTSOpsHeapTuple) |
230 | #define TTS_IS_MINIMALTUPLE(slot) ((slot)->tts_ops == &TTSOpsMinimalTuple) |
231 | #define TTS_IS_BUFFERTUPLE(slot) ((slot)->tts_ops == &TTSOpsBufferHeapTuple) |
232 | |
233 | |
234 | /* |
235 | * Tuple table slot implementations. |
236 | */ |
237 | |
238 | typedef struct VirtualTupleTableSlot |
239 | { |
240 | TupleTableSlot base; |
241 | |
242 | char *data; /* data for materialized slots */ |
243 | } VirtualTupleTableSlot; |
244 | |
245 | typedef struct HeapTupleTableSlot |
246 | { |
247 | TupleTableSlot base; |
248 | |
249 | #define FIELDNO_HEAPTUPLETABLESLOT_TUPLE 1 |
250 | HeapTuple tuple; /* physical tuple */ |
251 | #define FIELDNO_HEAPTUPLETABLESLOT_OFF 2 |
252 | uint32 off; /* saved state for slot_deform_heap_tuple */ |
253 | HeapTupleData tupdata; /* optional workspace for storing tuple */ |
254 | } HeapTupleTableSlot; |
255 | |
256 | /* heap tuple residing in a buffer */ |
257 | typedef struct BufferHeapTupleTableSlot |
258 | { |
259 | HeapTupleTableSlot base; |
260 | |
261 | /* |
262 | * If buffer is not InvalidBuffer, then the slot is holding a pin on the |
263 | * indicated buffer page; drop the pin when we release the slot's |
264 | * reference to that buffer. (TTS_FLAG_SHOULDFREE should not be set be |
265 | * false in such a case, since presumably tts_tuple is pointing at the |
266 | * buffer page.) |
267 | */ |
268 | Buffer buffer; /* tuple's buffer, or InvalidBuffer */ |
269 | } BufferHeapTupleTableSlot; |
270 | |
271 | typedef struct MinimalTupleTableSlot |
272 | { |
273 | TupleTableSlot base; |
274 | |
275 | /* |
276 | * In a minimal slot tuple points at minhdr and the fields of that struct |
277 | * are set correctly for access to the minimal tuple; in particular, |
278 | * minhdr.t_data points MINIMAL_TUPLE_OFFSET bytes before mintuple. This |
279 | * allows column extraction to treat the case identically to regular |
280 | * physical tuples. |
281 | */ |
282 | #define FIELDNO_MINIMALTUPLETABLESLOT_TUPLE 1 |
283 | HeapTuple tuple; /* tuple wrapper */ |
284 | MinimalTuple mintuple; /* minimal tuple, or NULL if none */ |
285 | HeapTupleData minhdr; /* workspace for minimal-tuple-only case */ |
286 | #define FIELDNO_MINIMALTUPLETABLESLOT_OFF 4 |
287 | uint32 off; /* saved state for slot_deform_heap_tuple */ |
288 | } MinimalTupleTableSlot; |
289 | |
290 | /* |
291 | * TupIsNull -- is a TupleTableSlot empty? |
292 | */ |
293 | #define TupIsNull(slot) \ |
294 | ((slot) == NULL || TTS_EMPTY(slot)) |
295 | |
296 | /* in executor/execTuples.c */ |
297 | extern TupleTableSlot *MakeTupleTableSlot(TupleDesc tupleDesc, |
298 | const TupleTableSlotOps *tts_ops); |
299 | extern TupleTableSlot *ExecAllocTableSlot(List **tupleTable, TupleDesc desc, |
300 | const TupleTableSlotOps *tts_ops); |
301 | extern void ExecResetTupleTable(List *tupleTable, bool shouldFree); |
302 | extern TupleTableSlot *MakeSingleTupleTableSlot(TupleDesc tupdesc, |
303 | const TupleTableSlotOps *tts_ops); |
304 | extern void ExecDropSingleTupleTableSlot(TupleTableSlot *slot); |
305 | extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc); |
306 | extern TupleTableSlot *ExecStoreHeapTuple(HeapTuple tuple, |
307 | TupleTableSlot *slot, |
308 | bool shouldFree); |
309 | extern void ExecForceStoreHeapTuple(HeapTuple tuple, |
310 | TupleTableSlot *slot, |
311 | bool shouldFree); |
312 | extern TupleTableSlot *ExecStoreBufferHeapTuple(HeapTuple tuple, |
313 | TupleTableSlot *slot, |
314 | Buffer buffer); |
315 | extern TupleTableSlot *ExecStorePinnedBufferHeapTuple(HeapTuple tuple, |
316 | TupleTableSlot *slot, |
317 | Buffer buffer); |
318 | extern TupleTableSlot *ExecStoreMinimalTuple(MinimalTuple mtup, |
319 | TupleTableSlot *slot, |
320 | bool shouldFree); |
321 | extern void ExecForceStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, |
322 | bool shouldFree); |
323 | extern TupleTableSlot *ExecStoreVirtualTuple(TupleTableSlot *slot); |
324 | extern TupleTableSlot *ExecStoreAllNullTuple(TupleTableSlot *slot); |
325 | extern void ExecStoreHeapTupleDatum(Datum data, TupleTableSlot *slot); |
326 | extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree); |
327 | extern MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot, |
328 | bool *shouldFree); |
329 | extern Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot); |
330 | extern void slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, |
331 | int lastAttNum); |
332 | extern void slot_getsomeattrs_int(TupleTableSlot *slot, int attnum); |
333 | |
334 | |
335 | #ifndef FRONTEND |
336 | |
337 | /* |
338 | * This function forces the entries of the slot's Datum/isnull arrays to be |
339 | * valid at least up through the attnum'th entry. |
340 | */ |
341 | static inline void |
342 | slot_getsomeattrs(TupleTableSlot *slot, int attnum) |
343 | { |
344 | if (slot->tts_nvalid < attnum) |
345 | slot_getsomeattrs_int(slot, attnum); |
346 | } |
347 | |
348 | /* |
349 | * slot_getallattrs |
350 | * This function forces all the entries of the slot's Datum/isnull |
351 | * arrays to be valid. The caller may then extract data directly |
352 | * from those arrays instead of using slot_getattr. |
353 | */ |
354 | static inline void |
355 | slot_getallattrs(TupleTableSlot *slot) |
356 | { |
357 | slot_getsomeattrs(slot, slot->tts_tupleDescriptor->natts); |
358 | } |
359 | |
360 | |
361 | /* |
362 | * slot_attisnull |
363 | * |
364 | * Detect whether an attribute of the slot is null, without actually fetching |
365 | * it. |
366 | */ |
367 | static inline bool |
368 | slot_attisnull(TupleTableSlot *slot, int attnum) |
369 | { |
370 | AssertArg(attnum > 0); |
371 | |
372 | if (attnum > slot->tts_nvalid) |
373 | slot_getsomeattrs(slot, attnum); |
374 | |
375 | return slot->tts_isnull[attnum - 1]; |
376 | } |
377 | |
378 | /* |
379 | * slot_getattr - fetch one attribute of the slot's contents. |
380 | */ |
381 | static inline Datum |
382 | slot_getattr(TupleTableSlot *slot, int attnum, |
383 | bool *isnull) |
384 | { |
385 | AssertArg(attnum > 0); |
386 | |
387 | if (attnum > slot->tts_nvalid) |
388 | slot_getsomeattrs(slot, attnum); |
389 | |
390 | *isnull = slot->tts_isnull[attnum - 1]; |
391 | |
392 | return slot->tts_values[attnum - 1]; |
393 | } |
394 | |
395 | /* |
396 | * slot_getsysattr - fetch a system attribute of the slot's current tuple. |
397 | * |
398 | * If the slot type does not contain system attributes, this will throw an |
399 | * error. Hence before calling this function, callers should make sure that |
400 | * the slot type is the one that supports system attributes. |
401 | */ |
402 | static inline Datum |
403 | slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull) |
404 | { |
405 | AssertArg(attnum < 0); /* caller error */ |
406 | |
407 | if (attnum == TableOidAttributeNumber) |
408 | { |
409 | *isnull = false; |
410 | return ObjectIdGetDatum(slot->tts_tableOid); |
411 | } |
412 | else if (attnum == SelfItemPointerAttributeNumber) |
413 | { |
414 | *isnull = false; |
415 | return PointerGetDatum(&slot->tts_tid); |
416 | } |
417 | |
418 | /* Fetch the system attribute from the underlying tuple. */ |
419 | return slot->tts_ops->getsysattr(slot, attnum, isnull); |
420 | } |
421 | |
422 | /* |
423 | * ExecClearTuple - clear the slot's contents |
424 | */ |
425 | static inline TupleTableSlot * |
426 | ExecClearTuple(TupleTableSlot *slot) |
427 | { |
428 | slot->tts_ops->clear(slot); |
429 | |
430 | return slot; |
431 | } |
432 | |
433 | /* ExecMaterializeSlot - force a slot into the "materialized" state. |
434 | * |
435 | * This causes the slot's tuple to be a local copy not dependent on any |
436 | * external storage (i.e. pointing into a Buffer, or having allocations in |
437 | * another memory context). |
438 | * |
439 | * A typical use for this operation is to prepare a computed tuple for being |
440 | * stored on disk. The original data may or may not be virtual, but in any |
441 | * case we need a private copy for heap_insert to scribble on. |
442 | */ |
443 | static inline void |
444 | ExecMaterializeSlot(TupleTableSlot *slot) |
445 | { |
446 | slot->tts_ops->materialize(slot); |
447 | } |
448 | |
449 | /* |
450 | * ExecCopySlotHeapTuple - return HeapTuple allocated in caller's context |
451 | */ |
452 | static inline HeapTuple |
453 | ExecCopySlotHeapTuple(TupleTableSlot *slot) |
454 | { |
455 | Assert(!TTS_EMPTY(slot)); |
456 | |
457 | return slot->tts_ops->copy_heap_tuple(slot); |
458 | } |
459 | |
460 | /* |
461 | * ExecCopySlotMinimalTuple - return MinimalTuple allocated in caller's context |
462 | */ |
463 | static inline MinimalTuple |
464 | ExecCopySlotMinimalTuple(TupleTableSlot *slot) |
465 | { |
466 | return slot->tts_ops->copy_minimal_tuple(slot); |
467 | } |
468 | |
469 | /* |
470 | * ExecCopySlot - copy one slot's contents into another. |
471 | * |
472 | * If a source's system attributes are supposed to be accessed in the target |
473 | * slot, the target slot and source slot types need to match. |
474 | */ |
475 | static inline TupleTableSlot * |
476 | ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) |
477 | { |
478 | Assert(!TTS_EMPTY(srcslot)); |
479 | |
480 | dstslot->tts_ops->copyslot(dstslot, srcslot); |
481 | |
482 | return dstslot; |
483 | } |
484 | |
485 | #endif /* FRONTEND */ |
486 | |
487 | #endif /* TUPTABLE_H */ |
488 | |