index acd5da4ccf80ddde9c39a2ad8c96dfd84b83a07d..969d1028cae89d10c6909652dbb95bd288aa7d20 100644 (file)
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;
@@ -1462,6 +1464,8 @@ heap_form_minimal_tuple(TupleDesc tupleDescriptor,
int numberOfAttributes = tupleDescriptor->natts;
int i;
+ Assert(extra == MAXALIGN(extra));
+
if (numberOfAttributes > MaxTupleAttributeNumber)
ereport(ERROR,
(errcode(ERRCODE_TOO_MANY_COLUMNS),
@@ -1497,7 +1501,9 @@ heap_form_minimal_tuple(TupleDesc tupleDescriptor,
/*
* 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;
}
index 7de490462d437f8c2ff313a1ae34459a62e6aa7b..8e02d68824fad80a2c39b926a37547c9e5bcc7ba 100644 (file)
@@ -298,13 +298,14 @@ tts_virtual_copy_heap_tuple(TupleTableSlot *slot)
}
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
@@ -607,7 +608,8 @@ tts_minimal_materialize(TupleTableSlot *slot)
{
mslot->mintuple = heap_form_minimal_tuple(slot->tts_tupleDescriptor,
slot->tts_values,
- slot->tts_isnull);
+ slot->tts_isnull,
+ 0);
}
else
{
@@ -617,7 +619,7 @@ tts_minimal_materialize(TupleTableSlot *slot)
* 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;
@@ -666,14 +668,14 @@ tts_minimal_copy_heap_tuple(TupleTableSlot *slot)
}
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
@@ -926,7 +928,7 @@ tts_buffer_heap_copy_heap_tuple(TupleTableSlot *slot)
}
static MinimalTuple
-tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot)
+tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *slot, Size extra)
{
BufferHeapTupleTableSlot *bslot = (BufferHeapTupleTableSlot *) slot;
@@ -935,7 +937,7 @@ tts_buffer_heap_copy_minimal_tuple(TupleTableSlot *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);
}
}
index 01a6e3a8553f0fdbc79a19cb20440053e3af1726..15f8459706773c8b98396ee5cf10410b218c3cf7 100644 (file)
@@ -735,7 +735,7 @@ gm_readnext_tuple(GatherMergeState *gm_state, int nreader, bool nowait,
* 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;
}
/*
index 4059af5bb7189b7a6fd795c579b34e8b760caeef..471d1197060d81c5ec0b33155defc121c2272f83 100644 (file)
@@ -1002,7 +1002,7 @@ tuplesort_gettupleslot(Tuplesortstate *state, bool forward, bool copy,
*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;
index d61b601053c907ecba4c48b7c699334806fac9c2..c9aecab8d66cbe06ff735f8174864237e8249eaf 100644 (file)
@@ -787,7 +787,7 @@ tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc,
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);
@@ -1139,7 +1139,7 @@ tuplestore_gettupleslot(Tuplestorestate *state, bool forward,
{
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;
}
index 6cd4b95bfdb277fb5c3738074de63eeabf1218b4..aa957cf3b0165f7530695a812bbf237633c004c5 100644 (file)
@@ -839,11 +839,12 @@ extern void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
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);
index a044d78e4d05bb7a4721a0cf47bbacf82a447a9d..095e4cc82e3d8ff719f2bb903559c737f9b5185d 100644 (file)
* 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);
}
/*