static TupleDesc ExecTypeFromTLInternal(List *targetList,
bool skipjunk);
static pg_attribute_always_inline void slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
- int natts);
+ int reqnatts);
static inline void tts_buffer_heap_store_tuple(TupleTableSlot *slot,
HeapTuple tuple,
Buffer buffer,
* slot_deform_heap_tuple
* Given a TupleTableSlot, extract data from the slot's physical tuple
* into its Datum/isnull arrays. Data is extracted up through the
- * natts'th column (caller must ensure this is a legal column number).
+ * reqnatts'th column. If there are insufficient attributes in the given
+ * tuple, then slot_getmissingattrs() is called to populate the
+ * remainder. If reqnatts is above the number of attributes in the
+ * slot's TupleDesc, an error is raised.
*
* This is essentially an incremental version of heap_deform_tuple:
* on each call we extract attributes up to the one needed, without
*/
static pg_attribute_always_inline void
slot_deform_heap_tuple(TupleTableSlot *slot, HeapTuple tuple, uint32 *offp,
- int natts)
+ int reqnatts)
{
bool hasnulls = HeapTupleHasNulls(tuple);
int attnum;
+ int natts;
uint32 off; /* offset in tuple data */
bool slow; /* can we use/set attcacheoff? */
/* We can only fetch as many attributes as the tuple has. */
- natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), natts);
+ natts = Min(HeapTupleHeaderGetNatts(tuple->t_data), reqnatts);
/*
* Check whether the first call for this tuple, and initialize or restore
* loop state.
*/
attnum = slot->tts_nvalid;
+ slot->tts_nvalid = reqnatts;
if (attnum == 0)
{
/* Start from the first attribute */
/*
* Save state for next execution
*/
- slot->tts_nvalid = attnum;
*offp = off;
if (slow)
slot->tts_flags |= TTS_FLAG_SLOW;
else
slot->tts_flags &= ~TTS_FLAG_SLOW;
+
+ /* Fetch any missing attrs and raise an error if reqnatts is invalid. */
+ if (unlikely(attnum < reqnatts))
+ slot_getmissingattrs(slot, attnum, reqnatts);
}
const TupleTableSlotOps TTSOpsVirtual = {
{
AttrMissing *attrmiss = NULL;
+ /* Check for invalid attnums */
+ if (unlikely(lastAttNum > slot->tts_tupleDescriptor->natts))
+ elog(ERROR, "invalid attribute number %d", lastAttNum);
+
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));
+ for (int attnum = startAttNum; attnum < lastAttNum; attnum++)
+ {
+ slot->tts_values[attnum] = (Datum) 0;
+ slot->tts_isnull[attnum] = true;
+ }
}
else
{
- int missattnum;
-
- /* if there is a missing values array we must process them one by one */
- for (missattnum = startAttNum;
- missattnum < lastAttNum;
- missattnum++)
+ /* use attrmiss to set the missing values */
+ for (int attnum = startAttNum; attnum < lastAttNum; attnum++)
{
- slot->tts_values[missattnum] = attrmiss[missattnum].am_value;
- slot->tts_isnull[missattnum] = !attrmiss[missattnum].am_present;
+ slot->tts_values[attnum] = attrmiss[attnum].am_value;
+ slot->tts_isnull[attnum] = !attrmiss[attnum].am_present;
}
}
}
/*
- * slot_getsomeattrs_int - workhorse for slot_getsomeattrs()
+ * slot_getsomeattrs_int
+ * external function to call getsomeattrs() for use in JIT
*/
void
slot_getsomeattrs_int(TupleTableSlot *slot, int attnum)
Assert(slot->tts_nvalid < attnum); /* checked in slot_getsomeattrs */
Assert(attnum > 0);
- if (unlikely(attnum > slot->tts_tupleDescriptor->natts))
- elog(ERROR, "invalid attribute number %d", attnum);
-
/* Fetch as many attributes as possible from the underlying tuple. */
slot->tts_ops->getsomeattrs(slot, attnum);
/*
- * If the underlying tuple doesn't have enough attributes, tuple
- * descriptor must have the missing attributes.
+ * Avoid putting new code here as that would prevent the compiler from
+ * using the sibling call optimization for the above function.
*/
- if (unlikely(slot->tts_nvalid < attnum))
- {
- slot_getmissingattrs(slot, slot->tts_nvalid, attnum);
- slot->tts_nvalid = attnum;
- }
}
/* ----------------------------------------------------------------
/*
* 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.
+ * values from the tuple contained in the slot and set the slot's
+ * tts_nvalid to natts. The function may be called with an natts value
+ * more than the number of attributes available in the tuple, in which
+ * case the function must call slot_getmissingattrs() to populate the
+ * remaining attributes. The function must raise an ERROR if 'natts' is
+ * higher than the number of attributes in the slot's TupleDesc.
*/
void (*getsomeattrs) (TupleTableSlot *slot, int natts);
static inline void
slot_getsomeattrs(TupleTableSlot *slot, int attnum)
{
+ /* Populate slot with attributes up to 'attnum', if it's not already */
if (slot->tts_nvalid < attnum)
- slot_getsomeattrs_int(slot, attnum);
+ slot->tts_ops->getsomeattrs(slot, attnum);
}
/*