diff options
Diffstat (limited to 'src/backend/executor')
-rw-r--r-- | src/backend/executor/execTuples.c | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/backend/executor/execTuples.c b/src/backend/executor/execTuples.c index 716c04939cd..fbbac1c6bf8 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 * |