From 9d906f1119de893a4ca533c5e7b97207a3aa963b Mon Sep 17 00:00:00 2001 From: Andres Freund Date: Sun, 14 Oct 2018 15:18:16 -0700 Subject: [PATCH] Move generic slot support functions from heaptuple.c into execTuples.c. heaptuple.c was never a particular good fit for slot_getattr(), slot_getsomeattrs() and slot_getmissingattrs(), but in upcoming changes slots will be made more abstract (allowing slots that contain different types of tuples), making it clearly the wrong place. Note that slot_deform_tuple() remains in it's current place, as it clearly deals with a HeapTuple. getmissingattrs() also remains, but it's less clear that that's correct - but execTuples.c wouldn't be the right place. Author: Ashutosh Bapat. Discussion: https://postgr.es/m/20180220224318.gw4oe5jadhpmcdnm@alap3.anarazel.de --- src/backend/access/common/heaptuple.c | 188 +------------------------ src/backend/executor/execTuples.c | 190 ++++++++++++++++++++++++++ src/include/access/htup_details.h | 2 + src/include/executor/tuptable.h | 10 +- 4 files changed, 201 insertions(+), 189 deletions(-) diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 7fc2fee74a..6b4863b33a 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -80,7 +80,7 @@ /* * Return the missing value of an attribute, or NULL if there isn't one. */ -static Datum +Datum getmissingattr(TupleDesc tupleDesc, int attnum, bool *isnull) { @@ -111,43 +111,6 @@ getmissingattr(TupleDesc tupleDesc, return PointerGetDatum(NULL); } -/* - * Fill in missing values for a TupleTableSlot. - * - * This is only exposed because it's needed for JIT compiled tuple - * deforming. That exception aside, there should be no callers outside of this - * file. - */ -void -slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum) -{ - AttrMissing *attrmiss = NULL; - int missattnum; - - if (slot->tts_tupleDescriptor->constr) - attrmiss = slot->tts_tupleDescriptor->constr->missing; - - if (!attrmiss) - { - /* no missing values array at all, so just fill everything in as NULL */ - memset(slot->tts_values + startAttNum, 0, - (lastAttNum - startAttNum) * sizeof(Datum)); - memset(slot->tts_isnull + startAttNum, 1, - (lastAttNum - startAttNum) * sizeof(bool)); - } - else - { - /* if there is a missing values array we must process them one by one */ - for (missattnum = startAttNum; - missattnum < lastAttNum; - missattnum++) - { - slot->tts_values[missattnum] = attrmiss[missattnum].am_value; - slot->tts_isnull[missattnum] = !attrmiss[missattnum].am_present; - } - } -} - /* * heap_compute_data_size * Determine size of the data area of a tuple to be constructed @@ -1398,7 +1361,7 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, * re-computing information about previously extracted attributes. * slot->tts_nvalid is the number of attributes already extracted. */ -static void +void slot_deform_tuple(TupleTableSlot *slot, int natts) { HeapTuple tuple = slot->tts_tuple; @@ -1492,153 +1455,6 @@ slot_deform_tuple(TupleTableSlot *slot, int natts) slot->tts_slow = slow; } -/* - * slot_getattr - * This function fetches an attribute of the slot's current tuple. - * It is functionally equivalent to heap_getattr, but fetches of - * multiple attributes of the same tuple will be optimized better, - * because we avoid O(N^2) behavior from multiple calls of - * nocachegetattr(), even when attcacheoff isn't usable. - * - * A difference from raw heap_getattr is that attnums beyond the - * slot's tupdesc's last attribute will be considered NULL even - * when the physical tuple is longer than the tupdesc. - */ -Datum -slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull) -{ - HeapTuple tuple = slot->tts_tuple; - TupleDesc tupleDesc = slot->tts_tupleDescriptor; - HeapTupleHeader tup; - - /* - * system attributes are handled by heap_getsysattr - */ - if (attnum <= 0) - { - if (tuple == NULL) /* internal error */ - elog(ERROR, "cannot extract system attribute from virtual tuple"); - if (tuple == &(slot->tts_minhdr)) /* internal error */ - elog(ERROR, "cannot extract system attribute from minimal tuple"); - return heap_getsysattr(tuple, attnum, tupleDesc, isnull); - } - - /* - * fast path if desired attribute already cached - */ - if (attnum <= slot->tts_nvalid) - { - *isnull = slot->tts_isnull[attnum - 1]; - return slot->tts_values[attnum - 1]; - } - - /* - * return NULL if attnum is out of range according to the tupdesc - */ - if (attnum > tupleDesc->natts) - { - *isnull = true; - return (Datum) 0; - } - - /* - * otherwise we had better have a physical tuple (tts_nvalid should equal - * natts in all virtual-tuple cases) - */ - if (tuple == NULL) /* internal error */ - elog(ERROR, "cannot extract attribute from empty tuple slot"); - - /* - * return NULL or missing value if attnum is out of range according to the - * tuple - * - * (We have to check this separately because of various inheritance and - * table-alteration scenarios: the tuple could be either longer or shorter - * than the tupdesc.) - */ - tup = tuple->t_data; - if (attnum > HeapTupleHeaderGetNatts(tup)) - return getmissingattr(slot->tts_tupleDescriptor, attnum, isnull); - - /* - * check if target attribute is null: no point in groveling through tuple - */ - if (HeapTupleHasNulls(tuple) && att_isnull(attnum - 1, tup->t_bits)) - { - *isnull = true; - return (Datum) 0; - } - - /* - * If the attribute's column has been dropped, we force a NULL result. - * This case should not happen in normal use, but it could happen if we - * are executing a plan cached before the column was dropped. - */ - if (TupleDescAttr(tupleDesc, attnum - 1)->attisdropped) - { - *isnull = true; - return (Datum) 0; - } - - /* - * Extract the attribute, along with any preceding attributes. - */ - slot_deform_tuple(slot, attnum); - - /* - * The result is acquired from tts_values array. - */ - *isnull = slot->tts_isnull[attnum - 1]; - return slot->tts_values[attnum - 1]; -} - -/* - * slot_getsomeattrs - * This function forces the entries of the slot's Datum/isnull - * arrays to be valid at least up through the attnum'th entry. - */ -void -slot_getsomeattrs(TupleTableSlot *slot, int attnum) -{ - HeapTuple tuple; - int attno; - - /* Quick out if we have 'em all already */ - if (slot->tts_nvalid >= attnum) - return; - - /* Check for caller error */ - if (attnum <= 0 || attnum > slot->tts_tupleDescriptor->natts) - elog(ERROR, "invalid attribute number %d", attnum); - - /* - * otherwise we had better have a physical tuple (tts_nvalid should equal - * natts in all virtual-tuple cases) - */ - tuple = slot->tts_tuple; - if (tuple == NULL) /* internal error */ - elog(ERROR, "cannot extract attribute from empty tuple slot"); - - /* - * load up any slots available from physical tuple - */ - attno = HeapTupleHeaderGetNatts(tuple->t_data); - attno = Min(attno, attnum); - - slot_deform_tuple(slot, attno); - - attno = slot->tts_nvalid; - - /* - * If tuple doesn't have all the atts indicated by attnum, read the rest - * as NULLs or missing values - */ - if (attno < attnum) - slot_getmissingattrs(slot, attno, attnum); - - slot->tts_nvalid = attnum; -} - /* * slot_attisnull * Detect whether an attribute of the slot is null, without diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 716c04939c..fbbac1c6bf 100644 --- a/src/backend/executor/execTuples.c +++ b/src/backend/executor/execTuples.c @@ -54,6 +54,7 @@ #include "postgres.h" #include "access/htup_details.h" +#include "access/tupdesc_details.h" #include "access/tuptoaster.h" #include "funcapi.h" #include "catalog/pg_type.h" @@ -959,6 +960,195 @@ ExecInitNullTupleSlot(EState *estate, TupleDesc tupType) return ExecStoreAllNullTuple(slot); } +/* --------------------------------------------------------------- + * Routines for setting/accessing attributes in a slot. + * --------------------------------------------------------------- + */ + +/* + * Fill in missing values for a TupleTableSlot. + * + * This is only exposed because it's needed for JIT compiled tuple + * deforming. That exception aside, there should be no callers outside of this + * file. + */ +void +slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum) +{ + AttrMissing *attrmiss = NULL; + int missattnum; + + if (slot->tts_tupleDescriptor->constr) + attrmiss = slot->tts_tupleDescriptor->constr->missing; + + if (!attrmiss) + { + /* no missing values array at all, so just fill everything in as NULL */ + memset(slot->tts_values + startAttNum, 0, + (lastAttNum - startAttNum) * sizeof(Datum)); + memset(slot->tts_isnull + startAttNum, 1, + (lastAttNum - startAttNum) * sizeof(bool)); + } + else + { + /* if there is a missing values array we must process them one by one */ + for (missattnum = startAttNum; + missattnum < lastAttNum; + missattnum++) + { + slot->tts_values[missattnum] = attrmiss[missattnum].am_value; + slot->tts_isnull[missattnum] = !attrmiss[missattnum].am_present; + } + } +} + +/* + * slot_getattr + * This function fetches an attribute of the slot's current tuple. + * It is functionally equivalent to heap_getattr, but fetches of + * multiple attributes of the same tuple will be optimized better, + * because we avoid O(N^2) behavior from multiple calls of + * nocachegetattr(), even when attcacheoff isn't usable. + * + * A difference from raw heap_getattr is that attnums beyond the + * slot's tupdesc's last attribute will be considered NULL even + * when the physical tuple is longer than the tupdesc. + */ +Datum +slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull) +{ + HeapTuple tuple = slot->tts_tuple; + TupleDesc tupleDesc = slot->tts_tupleDescriptor; + HeapTupleHeader tup; + + /* + * system attributes are handled by heap_getsysattr + */ + if (attnum <= 0) + { + if (tuple == NULL) /* internal error */ + elog(ERROR, "cannot extract system attribute from virtual tuple"); + if (tuple == &(slot->tts_minhdr)) /* internal error */ + elog(ERROR, "cannot extract system attribute from minimal tuple"); + return heap_getsysattr(tuple, attnum, tupleDesc, isnull); + } + + /* + * fast path if desired attribute already cached + */ + if (attnum <= slot->tts_nvalid) + { + *isnull = slot->tts_isnull[attnum - 1]; + return slot->tts_values[attnum - 1]; + } + + /* + * return NULL if attnum is out of range according to the tupdesc + */ + if (attnum > tupleDesc->natts) + { + *isnull = true; + return (Datum) 0; + } + + /* + * otherwise we had better have a physical tuple (tts_nvalid should equal + * natts in all virtual-tuple cases) + */ + if (tuple == NULL) /* internal error */ + elog(ERROR, "cannot extract attribute from empty tuple slot"); + + /* + * return NULL or missing value if attnum is out of range according to the + * tuple + * + * (We have to check this separately because of various inheritance and + * table-alteration scenarios: the tuple could be either longer or shorter + * than the tupdesc.) + */ + tup = tuple->t_data; + if (attnum > HeapTupleHeaderGetNatts(tup)) + return getmissingattr(slot->tts_tupleDescriptor, attnum, isnull); + + /* + * check if target attribute is null: no point in groveling through tuple + */ + if (HeapTupleHasNulls(tuple) && att_isnull(attnum - 1, tup->t_bits)) + { + *isnull = true; + return (Datum) 0; + } + + /* + * If the attribute's column has been dropped, we force a NULL result. + * This case should not happen in normal use, but it could happen if we + * are executing a plan cached before the column was dropped. + */ + if (TupleDescAttr(tupleDesc, attnum - 1)->attisdropped) + { + *isnull = true; + return (Datum) 0; + } + + /* + * Extract the attribute, along with any preceding attributes. + */ + slot_deform_tuple(slot, attnum); + + /* + * The result is acquired from tts_values array. + */ + *isnull = slot->tts_isnull[attnum - 1]; + return slot->tts_values[attnum - 1]; +} + +/* + * slot_getsomeattrs + * This function forces the entries of the slot's Datum/isnull + * arrays to be valid at least up through the attnum'th entry. + */ +void +slot_getsomeattrs(TupleTableSlot *slot, int attnum) +{ + HeapTuple tuple; + int attno; + + /* Quick out if we have 'em all already */ + if (slot->tts_nvalid >= attnum) + return; + + /* Check for caller error */ + if (attnum <= 0 || attnum > slot->tts_tupleDescriptor->natts) + elog(ERROR, "invalid attribute number %d", attnum); + + /* + * otherwise we had better have a physical tuple (tts_nvalid should equal + * natts in all virtual-tuple cases) + */ + tuple = slot->tts_tuple; + if (tuple == NULL) /* internal error */ + elog(ERROR, "cannot extract attribute from empty tuple slot"); + + /* + * load up any slots available from physical tuple + */ + attno = HeapTupleHeaderGetNatts(tuple->t_data); + attno = Min(attno, attnum); + + slot_deform_tuple(slot, attno); + + attno = slot->tts_nvalid; + + /* + * If tuple doesn't have all the atts indicated by attnum, read the rest + * as NULLs or missing values + */ + if (attno < attnum) + slot_getmissingattrs(slot, attno, attnum); + + slot->tts_nvalid = attnum; +} + /* ---------------------------------------------------------------- * ExecTypeFromTL * diff --git a/src/include/access/htup_details.h b/src/include/access/htup_details.h index 1867a70f6f..97d240fdbb 100644 --- a/src/include/access/htup_details.h +++ b/src/include/access/htup_details.h @@ -835,5 +835,7 @@ 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 43150d13b1..3c8d57f377 100644 --- a/src/include/executor/tuptable.h +++ b/src/include/executor/tuptable.h @@ -173,14 +173,18 @@ extern Datum ExecFetchSlotTupleDatum(TupleTableSlot *slot); extern HeapTuple 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); +extern void slot_getsomeattrs(TupleTableSlot *slot, int attnum); /* in access/common/heaptuple.c */ -extern Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull); -extern void slot_getsomeattrs(TupleTableSlot *slot, int attnum); extern bool slot_attisnull(TupleTableSlot *slot, int attnum); extern bool slot_getsysattr(TupleTableSlot *slot, int attnum, Datum *value, bool *isnull); -extern void slot_getmissingattrs(TupleTableSlot *slot, int startAttNum, int lastAttNum); +extern Datum getmissingattr(TupleDesc tupleDesc, + int attnum, bool *isnull); #ifndef FRONTEND