MinimalTuple
heap_form_minimal_tuple(TupleDesc tupleDescriptor,
const Datum *values,
- const bool *isnull)
+ const bool *isnull,
+ Size extra)
{
MinimalTuple tuple; /* return tuple */
+ char *mem;
Size len,
data_len;
int hoff;
int numberOfAttributes = tupleDescriptor->natts;
int i;
+ Assert(extra == MAXALIGN(extra));
+
if (numberOfAttributes > MaxTupleAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
/*
* Allocate and zero the space needed.
*/
- tuple = (MinimalTuple) palloc0(len);
+ mem = palloc0(len + extra);
+ memset(mem, 0, extra);
+ tuple = (MinimalTuple) (mem + extra);
/*
* And fill in the information.
* The result is allocated in the current memory context.
*/
MinimalTuple
-heap_copy_minimal_tuple(MinimalTuple mtup)
+heap_copy_minimal_tuple(MinimalTuple mtup, Size extra)
{
MinimalTuple result;
+ char *mem;
- result = (MinimalTuple) palloc(mtup->t_len);
+ Assert(extra == MAXALIGN(extra));
+ mem = palloc(mtup->t_len + extra);
+ memset(mem, 0, extra);
+ result = (MinimalTuple) (mem + extra);
memcpy(result, mtup, mtup->t_len);
return result;
}
* The result is allocated in the current memory context.
*/
MinimalTuple
-minimal_tuple_from_heap_tuple(HeapTuple htup)
+minimal_tuple_from_heap_tuple(HeapTuple htup, Size extra)
{
MinimalTuple result;
+ char *mem;
uint32 len;
+ Assert(extra == MAXALIGN(extra));
Assert(htup->t_len > MINIMAL_TUPLE_OFFSET);
len = htup->t_len - MINIMAL_TUPLE_OFFSET;
- result = (MinimalTuple) palloc(len);
+ mem = palloc(len + extra);
+ memset(mem, 0, extra);
+ result = (MinimalTuple) (mem + extra);
memcpy(result, (char *) htup->t_data + MINIMAL_TUPLE_OFFSET, len);
+
result->t_len = len;
return result;
}
}
static MinimalTuple
-tts_virtual_copy_minimal_tuple(TupleTableSlot *slot)
+tts_virtual_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
{
Assert(!TTS_EMPTY(slot));
return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
slot->tts_values,
- slot->tts_isnull);
+ slot->tts_isnull,
+ extra);
}
}
static MinimalTuple
-tts_heap_copy_minimal_tuple(TupleTableSlot *slot)
+tts_heap_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
{
HeapTupleTableSlot *hslot = (HeapTupleTableSlot *) slot;
if (!hslot->tuple)
tts_heap_materialize(slot);
- return minimal_tuple_from_heap_tuple(hslot->tuple);
+ return minimal_tuple_from_heap_tuple(hslot->tuple, extra);
}
static void
{
mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
slot->tts_values,
- slot->tts_isnull);
+ slot->tts_isnull,
+ 0);
}
else
{
* TTS_FLAG_SHOULDFREE set). Copy the minimal tuple into the given
* slot's memory context.
*/
- mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple);
+ mslot->mintuple = heap_copy_minimal_tuple(mslot->mintuple, 0);
}
slot->tts_flags |= TTS_FLAG_SHOULDFREE;
}
static MinimalTuple
-tts_minimal_copy_minimal_tuple(TupleTableSlot *slot)
+tts_minimal_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
{
MinimalTupleTableSlot *mslot = (MinimalTupleTableSlot *) slot;
if (!mslot->mintuple)
tts_minimal_materialize(slot);
- return heap_copy_minimal_tuple(mslot->mintuple);
+ return heap_copy_minimal_tuple(mslot->mintuple, extra);
}
static void
}
static MinimalTuple
-tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
+tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
{
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
if (!bslot->base.tuple)
tts_buffer_heap_materialize(slot);
- return minimal_tuple_from_heap_tuple(bslot->base.tuple);
+ return minimal_tuple_from_heap_tuple(bslot->base.tuple, extra);
}
static inline void
{
if (shouldFree)
*shouldFree = true;
- return slot->tts_ops->copy_minimal_tuple(slot);
+ return slot->tts_ops->copy_minimal_tuple(slot, 0);
}
}
* Since we'll be buffering these across multiple calls, we need to make a
* copy.
*/
- return tup ? heap_copy_minimal_tuple(tup) : NULL;
+ return tup ? heap_copy_minimal_tuple(tup, 0) : NULL;
}
/*
*abbrev = stup.datum1;
if (copy)
- stup.tuple = heap_copy_minimal_tuple((MinimalTuple) stup.tuple);
+ stup.tuple = heap_copy_minimal_tuple((MinimalTuple) stup.tuple, 0);
ExecStoreMinimalTuple((MinimalTuple) stup.tuple, slot, copy);
return true;
MinimalTuple tuple;
MemoryContext oldcxt = MemoryContextSwitchTo(state->context);
- tuple = heap_form_minimal_tuple(tdesc, values, isnull);
+ tuple = heap_form_minimal_tuple(tdesc, values, isnull, 0);
USEMEM(state, GetMemoryChunkSpace(tuple));
tuplestore_puttuple_common(state, tuple);
{
if (copy && !should_free)
{
- tuple = heap_copy_minimal_tuple(tuple);
+ tuple = heap_copy_minimal_tuple(tuple, 0);
should_free = true;
}
ExecStoreMinimalTuple(tuple, slot, should_free);
{
MinimalTuple tuple;
- tuple = minimal_tuple_from_heap_tuple((HeapTuple) tup);
+ tuple = minimal_tuple_from_heap_tuple((HeapTuple) tup, 0);
USEMEM(state, GetMemoryChunkSpace(tuple));
return tuple;
}
Datum *values, bool *isnull);
extern void heap_freetuple(HeapTuple htup);
extern MinimalTuple heap_form_minimal_tuple(TupleDesc tupleDescriptor,
- const Datum *values, const bool *isnull);
+ const Datum *values, const bool *isnull,
+ Size extra);
extern void heap_free_minimal_tuple(MinimalTuple mtup);
-extern MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup);
+extern MinimalTuple heap_copy_minimal_tuple(MinimalTuple mtup, Size extra);
extern HeapTuple heap_tuple_from_minimal_tuple(MinimalTuple mtup);
-extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup);
+extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup, Size extra);
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);
* meaningful "system columns" in the copy. The copy is not be "owned" by
* the slot i.e. the caller has to take responsibility to free memory
* consumed by the slot.
+ *
+ * The copy has "extra" bytes (maxaligned and zeroed) available before the
+ * tuple, which is useful so that some callers may store extra data along
+ * with the minimal tuple without the need for an additional allocation.
*/
- MinimalTuple (*copy_minimal_tuple) (TupleTableSlot *slot);
+ MinimalTuple (*copy_minimal_tuple) (TupleTableSlot *slot, Size extra);
};
/*
static inline MinimalTuple
ExecCopySlotMinimalTuple(TupleTableSlot *slot)
{
- return slot->tts_ops->copy_minimal_tuple(slot);
+ return slot->tts_ops->copy_minimal_tuple(slot, 0);
+}
+
+/*
+ * ExecCopySlotMinimalTupleExtra - return MinimalTuple allocated in caller's
+ * context, with extra bytes (maxaligned and zeroed) before the tuple for data
+ * the caller wishes to store along with the tuple (without requiring the
+ * caller to make an additional allocation).
+ */
+static inline MinimalTuple
+ExecCopySlotMinimalTupleExtra(TupleTableSlot *slot, Size extra)
+{
+ return slot->tts_ops->copy_minimal_tuple(slot, extra);
}
/*