diff options
Diffstat (limited to 'src/include')
| -rw-r--r-- | src/include/access/htup_details.h | 2 | ||||
| -rw-r--r-- | src/include/executor/tuptable.h | 409 | ||||
| -rw-r--r-- | src/include/jit/llvmjit.h | 2 |
3 files changed, 310 insertions, 103 deletions
diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index 97d240fdbb0..1867a70f6f3 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -835,7 +835,5 @@ extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup); extern size_t varsize_any(void *p); extern HeapTuple heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc); extern MinimalTuple minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc); -struct TupleTableSlot; -extern void slot_deform_tuple(struct TupleTableSlot *slot, int natts); #endif /* HTUP_DETAILS_H */ diff --git a/src/include/executor/tuptable.h b/src/include/executor/tuptable.h index 9470d385309..db5031f5746 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -20,11 +20,20 @@ /*---------- * The executor stores tuples in a "tuple table" which is a List of - * independent TupleTableSlots. There are several cases we need to handle: - * 1. physical tuple in a disk buffer page - * 2. physical tuple constructed in palloc'ed memory - * 3. "minimal" physical tuple constructed in palloc'ed memory - * 4. "virtual" tuple consisting of Datum/isnull arrays + * independent TupleTableSlots. + * + * There's various different types of tuple table slots, each being able to + * store different types of tuples. Additional types of slots can be added + * without modifying core code. The type of a slot is determined by the + * TupleTableSlotOps* passed to the slot creation routine. The builtin types + * of slots are + * + * 1. physical tuple in a disk buffer page (TTSOpsBufferHeapTuple) + * 2. physical tuple constructed in palloc'ed memory (TTSOpsHeapTuple) + * 3. "minimal" physical tuple constructed in palloc'ed memory + * (TTSOpsMinimalTuple) + * 4. "virtual" tuple consisting of Datum/isnull arrays (TTSOpsVirtual) + * * * The first two cases are similar in that they both deal with "materialized" * tuples, but resource management is different. For a tuple in a disk page @@ -37,39 +46,28 @@ * parallel to case 1. Note that a minimal tuple has no "system columns". * (Actually, it could have an OID, but we have no need to access the OID.) * - * A "virtual" tuple is an optimization used to minimize physical data - * copying in a nest of plan nodes. Any pass-by-reference Datums in the - * tuple point to storage that is not directly associated with the - * TupleTableSlot; generally they will point to part of a tuple stored in - * a lower plan node's output TupleTableSlot, or to a function result + * A "virtual" tuple is an optimization used to minimize physical data copying + * in a nest of plan nodes. Until materialized pass-by-reference Datums in + * the slot point to storage that is not directly associated with the + * TupleTableSlot; generally they will point to part of a tuple stored in a + * lower plan node's output TupleTableSlot, or to a function result * constructed in a plan node's per-tuple econtext. It is the responsibility - * of the generating plan node to be sure these resources are not released - * for as long as the virtual tuple needs to be valid. We only use virtual - * tuples in the result slots of plan nodes --- tuples to be copied anywhere - * else need to be "materialized" into physical tuples. Note also that a - * virtual tuple does not have any "system columns". + * of the generating plan node to be sure these resources are not released for + * as long as the virtual tuple needs to be valid or is materialized. Note + * also that a virtual tuple does not have any "system columns". * - * It is also possible for a TupleTableSlot to hold both physical and minimal - * copies of a tuple. This is done when the slot is requested to provide - * the format other than the one it currently holds. (Originally we attempted - * to handle such requests by replacing one format with the other, but that - * had the fatal defect of invalidating any pass-by-reference Datums pointing - * into the existing slot contents.) Both copies must contain identical data - * payloads when this is the case. + * The Datum/isnull arrays of a TupleTableSlot serve double duty. For virtual + * slots they they are the authoritative data. For the other builtin slots, + * the arrays contain data extracted from the tuple. (In this state, any + * pass-by-reference Datums point into the physical tuple.) The extracted + * information is built "lazily", ie, only as needed. This serves to avoid + * repeated extraction of data from the physical tuple. * - * The Datum/isnull arrays of a TupleTableSlot serve double duty. When the - * slot contains a virtual tuple, they are the authoritative data. When the - * slot contains a physical tuple, the arrays contain data extracted from - * the tuple. (In this state, any pass-by-reference Datums point into - * the physical tuple.) The extracted information is built "lazily", - * ie, only as needed. This serves to avoid repeated extraction of data - * from the physical tuple. - * - * A TupleTableSlot can also be "empty", indicated by flag TTS_EMPTY set in - * tts_flags, holding no valid data. This is the only valid state for a - * freshly-created slot that has not yet had a tuple descriptor assigned to it. - * In this state, TTS_SHOULDFREE should not be set in tts_flag, tts_tuple must - * be NULL, tts_buffer InvalidBuffer, and tts_nvalid zero. + * A TupleTableSlot can also be "empty", indicated by flag TTS_FLAG_EMPTY set + * in tts_flags, holding no valid data. This is the only valid state for a + * freshly-created slot that has not yet had a tuple descriptor assigned to + * it. In this state, TTS_SHOULDFREE should not be set in tts_flag, tts_tuple + * must be NULL, tts_buffer InvalidBuffer, and tts_nvalid zero. * * The tupleDescriptor is simply referenced, not copied, by the TupleTableSlot * code. The caller of ExecSetSlotDescriptor() is responsible for providing @@ -83,32 +81,12 @@ * the slot and should be freed when the slot's reference to the tuple is * dropped. * - * If tts_buffer is not InvalidBuffer, then the slot is holding a pin - * on the indicated buffer page; drop the pin when we release the - * slot's reference to that buffer. (tts_shouldFree should always be - * false in such a case, since presumably tts_tuple is pointing at the - * buffer page.) - * - * tts_nvalid indicates the number of valid columns in the tts_values/isnull - * arrays. When the slot is holding a "virtual" tuple this must be equal - * to the descriptor's natts. When the slot is holding a physical tuple - * this is equal to the number of columns we have extracted (we always - * extract columns from left to right, so there are no holes). - * - * tts_values/tts_isnull are allocated when a descriptor is assigned to the - * slot; they are of length equal to the descriptor's natts. + * tts_values/tts_isnull are allocated either when the slot is created (when + * the descriptor is provided), or when a descriptor is assigned to the slot; + * they are of length equal to the descriptor's natts. * - * tts_mintuple must always be NULL if the slot does not hold a "minimal" - * tuple. When it does, tts_mintuple points to the actual MinimalTupleData - * object (the thing to be pfree'd if tts_shouldFreeMin is true). If the slot - * has only a minimal and not also a regular physical tuple, then tts_tuple - * points at tts_minhdr and the fields of that struct are set correctly - * for access to the minimal tuple; in particular, tts_minhdr.t_data points - * MINIMAL_TUPLE_OFFSET bytes before tts_mintuple. This allows column - * extraction to treat the case identically to regular physical tuples. - * - * TTS_SLOW flag in tts_flags and tts_off are saved state for - * slot_deform_tuple, and should not be touched by any other code. + * The TTS_FLAG_SLOW flag and tts_off are saved state for + * slot_deform_heap_tuple, and should not be touched by any other code. *---------- */ @@ -116,25 +94,22 @@ #define TTS_FLAG_EMPTY (1 << 1) #define TTS_EMPTY(slot) (((slot)->tts_flags & TTS_FLAG_EMPTY) != 0) -/* should pfree tts_tuple? */ +/* should pfree tuple "owned" by the slot? */ #define TTS_FLAG_SHOULDFREE (1 << 2) #define TTS_SHOULDFREE(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREE) != 0) -/* should pfree tts_mintuple? */ -#define TTS_FLAG_SHOULDFREEMIN (1 << 3) -#define TTS_SHOULDFREEMIN(slot) (((slot)->tts_flags & TTS_FLAG_SHOULDFREEMIN) != 0) - -/* saved state for slot_deform_tuple */ -#define TTS_FLAG_SLOW (1 << 4) +/* saved state for slot_deform_heap_tuple */ +#define TTS_FLAG_SLOW (1 << 3) #define TTS_SLOW(slot) (((slot)->tts_flags & TTS_FLAG_SLOW) != 0) /* fixed tuple descriptor */ -#define TTS_FLAG_FIXED (1 << 5) +#define TTS_FLAG_FIXED (1 << 4) #define TTS_FIXED(slot) (((slot)->tts_flags & TTS_FLAG_FIXED) != 0) struct TupleTableSlotOps; typedef struct TupleTableSlotOps TupleTableSlotOps; +/* base tuple table slot type */ typedef struct TupleTableSlot { NodeTag type; @@ -142,28 +117,99 @@ typedef struct TupleTableSlot uint16 tts_flags; /* Boolean states */ #define FIELDNO_TUPLETABLESLOT_NVALID 2 AttrNumber tts_nvalid; /* # of valid values in tts_values */ -#define FIELDNO_TUPLETABLESLOT_TUPLE 3 - HeapTuple tts_tuple; /* physical tuple, or NULL if virtual */ const TupleTableSlotOps *const tts_ops; /* implementation of slot */ -#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 5 +#define FIELDNO_TUPLETABLESLOT_TUPLEDESCRIPTOR 4 TupleDesc tts_tupleDescriptor; /* slot's tuple descriptor */ - MemoryContext tts_mcxt; /* slot itself is in this context */ - Buffer tts_buffer; /* tuple's buffer, or InvalidBuffer */ -#define FIELDNO_TUPLETABLESLOT_OFF 8 - uint32 tts_off; /* saved state for slot_deform_tuple */ -#define FIELDNO_TUPLETABLESLOT_VALUES 9 +#define FIELDNO_TUPLETABLESLOT_VALUES 5 Datum *tts_values; /* current per-attribute values */ -#define FIELDNO_TUPLETABLESLOT_ISNULL 10 +#define FIELDNO_TUPLETABLESLOT_ISNULL 6 bool *tts_isnull; /* current per-attribute isnull flags */ - MinimalTuple tts_mintuple; /* minimal tuple, or NULL if none */ - HeapTupleData tts_minhdr; /* workspace for minimal-tuple-only case */ + MemoryContext tts_mcxt; /* slot itself is in this context */ } TupleTableSlot; /* routines for a TupleTableSlot implementation */ struct TupleTableSlotOps { - /* body will be replaced in later commit */ - int dummy; + /* Minimum size of the slot */ + size_t base_slot_size; + + /* Initialization. */ + void (*init)(TupleTableSlot *slot); + + /* Destruction. */ + void (*release)(TupleTableSlot *slot); + + /* + * Clear the contents of the slot. Only the contents are expected to be + * cleared and not the tuple descriptor. Typically an implementation of + * this callback should free the memory allocated for the tuple contained + * in the slot. + */ + void (*clear)(TupleTableSlot *slot); + + /* + * Fill up first natts entries of tts_values and tts_isnull arrays with + * values from the tuple contained in the slot. The function may be called + * with natts more than the number of attributes available in the tuple, + * in which case it should set tts_nvalid to the number of returned + * columns. + */ + void (*getsomeattrs)(TupleTableSlot *slot, int natts); + + /* + * Returns value of the given system attribute as a datum and sets isnull + * to false, if it's not NULL. Throws an error if the slot type does not + * support system attributes. + */ + Datum (*getsysattr)(TupleTableSlot *slot, int attnum, bool *isnull); + + /* + * Make the contents of the slot solely depend on the slot, and not on + * underlying resources (like another memory context, buffers, etc). + */ + void (*materialize)(TupleTableSlot *slot); + + /* + * Copy the contents of the source slot into the destination slot's own + * context. Invoked using callback of the destination slot. + */ + void (*copyslot) (TupleTableSlot *dstslot, TupleTableSlot *srcslot); + + /* + * Return a heap tuple "owned" by the slot. It is slot's responsibility to + * free the memory consumed by the heap tuple. If the slot can not "own" a + * heap tuple, it should not implement this callback and should set it as + * NULL. + */ + HeapTuple (*get_heap_tuple)(TupleTableSlot *slot); + + /* + * Return a minimal tuple "owned" by the slot. It is slot's responsibility + * to free the memory consumed by the minimal tuple. If the slot can not + * "own" a minimal tuple, it should not implement this callback and should + * set it as NULL. + */ + MinimalTuple (*get_minimal_tuple)(TupleTableSlot *slot); + + /* + * Return a copy of heap tuple representing the contents of the slot. The + * copy needs to be palloc'd in the current memory context. The slot + * itself is expected to remain unaffected. It is *not* expected to have + * meaningful "system columns" in the copy. The copy is not be "owned" by + * the slot i.e. the caller has to take responsibilty to free memory + * consumed by the slot. + */ + HeapTuple (*copy_heap_tuple)(TupleTableSlot *slot); + + /* + * Return a copy of minimal tuple representing the contents of the slot. The + * copy needs to be palloc'd in the current memory context. The slot + * itself is expected to remain unaffected. It is *not* expected to have + * meaningful "system columns" in the copy. The copy is not be "owned" by + * the slot i.e. the caller has to take responsibilty to free memory + * consumed by the slot. + */ + MinimalTuple (*copy_minimal_tuple)(TupleTableSlot *slot); }; /* @@ -173,10 +219,68 @@ struct TupleTableSlotOps extern PGDLLIMPORT const TupleTableSlotOps TTSOpsVirtual; extern PGDLLIMPORT const TupleTableSlotOps TTSOpsHeapTuple; extern PGDLLIMPORT const TupleTableSlotOps TTSOpsMinimalTuple; -extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferTuple; +extern PGDLLIMPORT const TupleTableSlotOps TTSOpsBufferHeapTuple; + +#define TTS_IS_VIRTUAL(slot) ((slot)->tts_ops == &TTSOpsVirtual) +#define TTS_IS_HEAPTUPLE(slot) ((slot)->tts_ops == &TTSOpsHeapTuple) +#define TTS_IS_MINIMALTUPLE(slot) ((slot)->tts_ops == &TTSOpsMinimalTuple) +#define TTS_IS_BUFFERTUPLE(slot) ((slot)->tts_ops == &TTSOpsBufferHeapTuple) -#define TTS_HAS_PHYSICAL_TUPLE(slot) \ - ((slot)->tts_tuple != NULL && (slot)->tts_tuple != &((slot)->tts_minhdr)) + +/* + * Tuple table slot implementations. + */ + +typedef struct VirtualTupleTableSlot +{ + TupleTableSlot base; + + char *data; /* data for materialized slots */ +} VirtualTupleTableSlot; + +typedef struct HeapTupleTableSlot +{ + TupleTableSlot base; + +#define FIELDNO_HEAPTUPLETABLESLOT_TUPLE 1 + HeapTuple tuple; /* physical tuple */ +#define FIELDNO_HEAPTUPLETABLESLOT_OFF 2 + uint32 off; /* saved state for slot_deform_heap_tuple */ +} HeapTupleTableSlot; + +/* heap tuple residing in a buffer */ +typedef struct BufferHeapTupleTableSlot +{ + HeapTupleTableSlot base; + + /* + * If buffer is not InvalidBuffer, then the slot is holding a pin on the + * indicated buffer page; drop the pin when we release the slot's + * reference to that buffer. (TTS_FLAG_SHOULDFREE should not be set be + * false in such a case, since presumably tts_tuple is pointing at the + * buffer page.) + */ + Buffer buffer; /* tuple's buffer, or InvalidBuffer */ +} BufferHeapTupleTableSlot; + +typedef struct MinimalTupleTableSlot +{ + TupleTableSlot base; + + /* + * In a minimal slot tuple points at minhdr and the fields of that struct + * are set correctly for access to the minimal tuple; in particular, + * minhdr.t_data points MINIMAL_TUPLE_OFFSET bytes before mintuple. This + * allows column extraction to treat the case identically to regular + * physical tuples. + */ +#define FIELDNO_MINIMALTUPLETABLESLOT_TUPLE 1 + HeapTuple tuple; /* tuple wrapper */ + MinimalTuple mintuple; /* minimal tuple, or NULL if none */ + HeapTupleData minhdr; /* workspace for minimal-tuple-only case */ +#define FIELDNO_MINIMALTUPLETABLESLOT_OFF 4 + uint32 off; /* saved state for slot_deform_heap_tuple */ +} MinimalTupleTableSlot; /* * TupIsNull -- is a TupleTableSlot empty? @@ -197,37 +301,26 @@ extern void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc); extern TupleTableSlot *ExecStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot, bool shouldFree); +extern void ExecForceStoreHeapTuple(HeapTuple tuple, TupleTableSlot *slot); extern TupleTableSlot *ExecStoreBufferHeapTuple(HeapTuple tuple, TupleTableSlot *slot, Buffer buffer); extern TupleTableSlot *ExecStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, bool shouldFree); -extern TupleTableSlot *ExecClearTuple(TupleTableSlot *slot); +extern void ExecForceStoreMinimalTuple(MinimalTuple mtup, TupleTableSlot *slot, + bool shouldFree); extern TupleTableSlot *ExecStoreVirtualTuple(TupleTableSlot *slot); extern TupleTableSlot *ExecStoreAllNullTuple(TupleTableSlot *slot); -extern HeapTuple ExecCopySlotTuple(TupleTableSlot *slot); -extern MinimalTuple ExecCopySlotMinimalTuple(TupleTableSlot *slot); -extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shoulFree); +extern HeapTuple ExecFetchSlotHeapTuple(TupleTableSlot *slot, bool materialize, bool *shouldFree); extern MinimalTuple ExecFetchSlotMinimalTuple(TupleTableSlot *slot, bool *shouldFree); extern Datum ExecFetchSlotHeapTupleDatum(TupleTableSlot *slot); -extern void ExecMaterializeSlot(TupleTableSlot *slot); -extern TupleTableSlot *ExecCopySlot(TupleTableSlot *dstslot, - TupleTableSlot *srcslot); extern void slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum); -extern Datum slot_getattr(TupleTableSlot *slot, int attnum, - bool *isnull); - -/* in access/common/heaptuple.c */ -extern bool slot_attisnull(TupleTableSlot *slot, int attnum); -extern bool slot_getsysattr(TupleTableSlot *slot, int attnum, - Datum *value, bool *isnull); -extern Datum getmissingattr(TupleDesc tupleDesc, - int attnum, bool *isnull); extern void slot_getsomeattrs_int(TupleTableSlot *slot, int attnum); + #ifndef FRONTEND /* @@ -253,6 +346,120 @@ slot_getallattrs(TupleTableSlot *slot) slot_getsomeattrs(slot, slot->tts_tupleDescriptor->natts); } -#endif + +/* + * slot_attisnull + * + * Detect whether an attribute of the slot is null, without actually fetching + * it. + */ +static inline bool +slot_attisnull(TupleTableSlot *slot, int attnum) +{ + AssertArg(attnum > 0); + + if (attnum > slot->tts_nvalid) + slot_getsomeattrs(slot, attnum); + + return slot->tts_isnull[attnum - 1]; +} + +/* + * slot_getattr - fetch one attribute of the slot's contents. + */ +static inline Datum +slot_getattr(TupleTableSlot *slot, int attnum, + bool *isnull) +{ + AssertArg(attnum > 0); + + if (attnum > slot->tts_nvalid) + slot_getsomeattrs(slot, attnum); + + *isnull = slot->tts_isnull[attnum - 1]; + + return slot->tts_values[attnum - 1]; +} + +/* + * slot_getsysattr - fetch a system attribute of the slot's current tuple. + * + * If the slot type does not contain system attributes, this will throw an + * error. Hence before calling this function, callers should make sure that + * the slot type is the one that supports system attributes. + */ +static inline Datum +slot_getsysattr(TupleTableSlot *slot, int attnum, bool *isnull) +{ + AssertArg(attnum < 0); /* caller error */ + + /* Fetch the system attribute from the underlying tuple. */ + return slot->tts_ops->getsysattr(slot, attnum, isnull); +} + +/* + * ExecClearTuple - clear the slot's contents + */ +static inline TupleTableSlot * +ExecClearTuple(TupleTableSlot *slot) +{ + slot->tts_ops->clear(slot); + + return slot; +} + +/* ExecMaterializeSlot - force a slot into the "materialized" state. + * + * This causes the slot's tuple to be a local copy not dependent on any + * external storage (i.e. pointing into a Buffer, or having allocations in + * another memory context). + * + * A typical use for this operation is to prepare a computed tuple for being + * stored on disk. The original data may or may not be virtual, but in any + * case we need a private copy for heap_insert to scribble on. + */ +static inline void +ExecMaterializeSlot(TupleTableSlot *slot) +{ + slot->tts_ops->materialize(slot); +} + +/* + * ExecCopySlotHeapTuple - return HeapTuple allocated in caller's context + */ +static inline HeapTuple +ExecCopySlotHeapTuple(TupleTableSlot *slot) +{ + Assert(!TTS_EMPTY(slot)); + + return slot->tts_ops->copy_heap_tuple(slot); +} + +/* + * ExecCopySlotMinimalTuple - return MinimalTuple allocated in caller's context + */ +static inline MinimalTuple +ExecCopySlotMinimalTuple(TupleTableSlot *slot) +{ + return slot->tts_ops->copy_minimal_tuple(slot); +} + +/* + * ExecCopySlot - copy one slot's contents into another. + * + * If a source's system attributes are supposed to be accessed in the target + * slot, the target slot and source slot types need to match. + */ +static inline TupleTableSlot * +ExecCopySlot(TupleTableSlot *dstslot, TupleTableSlot *srcslot) +{ + Assert(!TTS_EMPTY(srcslot)); + + dstslot->tts_ops->copyslot(dstslot, srcslot); + + return dstslot; +} + +#endif /* FRONTEND */ #endif /* TUPTABLE_H */ diff --git a/src/include/jit/llvmjit.h b/src/include/jit/llvmjit.h index 05c9740bc5e..1639846d8b5 100644 --- a/src/include/jit/llvmjit.h +++ b/src/include/jit/llvmjit.h @@ -65,6 +65,8 @@ extern LLVMTypeRef TypeStorageBool; extern LLVMTypeRef StructtupleDesc; extern LLVMTypeRef StructHeapTupleData; extern LLVMTypeRef StructTupleTableSlot; +extern LLVMTypeRef StructHeapTupleTableSlot; +extern LLVMTypeRef StructMinimalTupleTableSlot; extern LLVMTypeRef StructMemoryContextData; extern LLVMTypeRef StructFunctionCallInfoData; extern LLVMTypeRef StructExprContext; |
