1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-19 13:42:17 +03:00

Add ExecCopySlotMinimalTupleExtra().

Allows an "extra" argument that allocates extra memory at the end of
the MinimalTuple. This is important for callers that need to store
additional data, but do not want to perform an additional allocation.

Suggested-by: David Rowley <dgrowleyml@gmail.com>
Discussion: https://postgr.es/m/CAApHDvppeqw2pNM-+ahBOJwq2QmC0hOAGsmCpC89QVmEoOvsdg@mail.gmail.com
This commit is contained in:
Jeff Davis
2025-03-24 22:05:53 -07:00
parent 4d143509cb
commit a0942f441e
7 changed files with 61 additions and 27 deletions

View File

@@ -1452,9 +1452,11 @@ heap_freetuple(HeapTuple htup)
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.
@@ -1533,11 +1539,15 @@ heap_free_minimal_tuple(MinimalTuple mtup)
* 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;
}
@@ -1574,15 +1584,20 @@ heap_tuple_from_minimal_tuple(MinimalTuple mtup)
* 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;
}

View 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);
}
@@ -472,14 +473,14 @@ tts_heap_copy_heap_tuple(TupleTableSlot *slot)
}
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
@@ -1895,7 +1897,7 @@ ExecFetchSlotMinimalTuple(TupleTableSlot *slot,
{
if (shouldFree)
*shouldFree = true;
return slot->tts_ops->copy_minimal_tuple(slot);
return slot->tts_ops->copy_minimal_tuple(slot, 0);
}
}

View 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;
}
/*

View 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;

View 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);
@@ -1590,7 +1590,7 @@ copytup_heap(Tuplestorestate *state, void *tup)
{
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;
}