mirror of
https://github.com/postgres/postgres.git
synced 2025-07-08 11:42:09 +03:00
Create infrastructure for 'MinimalTuple' representation of in-memory
tuples with less header overhead than a regular HeapTuple, per my recent proposal. Teach TupleTableSlot code how to deal with these. As proof of concept, change tuplestore.c to store MinimalTuples instead of HeapTuples. Future patches will expand the concept to other places where it is useful.
This commit is contained in:
@ -15,7 +15,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.94 2006/06/16 18:42:22 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execTuples.c,v 1.95 2006/06/27 02:51:39 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -25,6 +25,8 @@
|
||||
* TABLE CREATE/DELETE
|
||||
* ExecCreateTupleTable - create a new tuple table
|
||||
* ExecDropTupleTable - destroy a table
|
||||
* MakeSingleTupleTableSlot - make a single-slot table
|
||||
* ExecDropSingleTupleTableSlot - destroy same
|
||||
*
|
||||
* SLOT RESERVATION
|
||||
* ExecAllocTableSlot - find an available slot in the table
|
||||
@ -32,9 +34,11 @@
|
||||
* SLOT ACCESSORS
|
||||
* ExecSetSlotDescriptor - set a slot's tuple descriptor
|
||||
* ExecStoreTuple - store a physical tuple in the slot
|
||||
* ExecStoreMinimalTuple - store a minimal physical tuple in the slot
|
||||
* ExecClearTuple - clear contents of a slot
|
||||
* ExecStoreVirtualTuple - mark slot as containing a virtual tuple
|
||||
* ExecCopySlotTuple - build a physical tuple from a slot
|
||||
* ExecCopySlotMinimalTuple - build a minimal physical tuple from a slot
|
||||
* ExecMaterializeSlot - convert virtual to physical storage
|
||||
* ExecCopySlot - copy one slot's contents to another
|
||||
*
|
||||
@ -150,6 +154,7 @@ ExecCreateTupleTable(int tableSize)
|
||||
slot->tts_nvalid = 0;
|
||||
slot->tts_values = NULL;
|
||||
slot->tts_isnull = NULL;
|
||||
slot->tts_mintuple = NULL;
|
||||
}
|
||||
|
||||
return newtable;
|
||||
@ -227,6 +232,7 @@ MakeSingleTupleTableSlot(TupleDesc tupdesc)
|
||||
slot->tts_nvalid = 0;
|
||||
slot->tts_values = NULL;
|
||||
slot->tts_isnull = NULL;
|
||||
slot->tts_mintuple = NULL;
|
||||
|
||||
ExecSetSlotDescriptor(slot, tupdesc);
|
||||
|
||||
@ -405,7 +411,12 @@ ExecStoreTuple(HeapTuple tuple,
|
||||
* Free any old physical tuple belonging to the slot.
|
||||
*/
|
||||
if (slot->tts_shouldFree)
|
||||
heap_freetuple(slot->tts_tuple);
|
||||
{
|
||||
if (slot->tts_mintuple)
|
||||
heap_free_minimal_tuple(slot->tts_mintuple);
|
||||
else
|
||||
heap_freetuple(slot->tts_tuple);
|
||||
}
|
||||
|
||||
/*
|
||||
* Store the new tuple into the specified slot.
|
||||
@ -413,6 +424,7 @@ ExecStoreTuple(HeapTuple tuple,
|
||||
slot->tts_isempty = false;
|
||||
slot->tts_shouldFree = shouldFree;
|
||||
slot->tts_tuple = tuple;
|
||||
slot->tts_mintuple = NULL;
|
||||
|
||||
/* Mark extracted state invalid */
|
||||
slot->tts_nvalid = 0;
|
||||
@ -438,6 +450,63 @@ ExecStoreTuple(HeapTuple tuple,
|
||||
return slot;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* ExecStoreMinimalTuple
|
||||
*
|
||||
* Like ExecStoreTuple, but insert a "minimal" tuple into the slot.
|
||||
*
|
||||
* No 'buffer' parameter since minimal tuples are never stored in relations.
|
||||
* --------------------------------
|
||||
*/
|
||||
TupleTableSlot *
|
||||
ExecStoreMinimalTuple(MinimalTuple mtup,
|
||||
TupleTableSlot *slot,
|
||||
bool shouldFree)
|
||||
{
|
||||
/*
|
||||
* sanity checks
|
||||
*/
|
||||
Assert(mtup != NULL);
|
||||
Assert(slot != NULL);
|
||||
Assert(slot->tts_tupleDescriptor != NULL);
|
||||
|
||||
/*
|
||||
* Free any old physical tuple belonging to the slot.
|
||||
*/
|
||||
if (slot->tts_shouldFree)
|
||||
{
|
||||
if (slot->tts_mintuple)
|
||||
heap_free_minimal_tuple(slot->tts_mintuple);
|
||||
else
|
||||
heap_freetuple(slot->tts_tuple);
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop the pin on the referenced buffer, if there is one.
|
||||
*/
|
||||
if (BufferIsValid(slot->tts_buffer))
|
||||
ReleaseBuffer(slot->tts_buffer);
|
||||
|
||||
slot->tts_buffer = InvalidBuffer;
|
||||
|
||||
/*
|
||||
* Store the new tuple into the specified slot.
|
||||
*/
|
||||
slot->tts_isempty = false;
|
||||
slot->tts_shouldFree = shouldFree;
|
||||
slot->tts_tuple = &slot->tts_minhdr;
|
||||
slot->tts_mintuple = mtup;
|
||||
|
||||
slot->tts_minhdr.t_len = mtup->t_len + MINIMAL_TUPLE_OFFSET;
|
||||
slot->tts_minhdr.t_data = (HeapTupleHeader) ((char *) mtup - MINIMAL_TUPLE_OFFSET);
|
||||
/* no need to set t_self or t_tableOid since we won't allow access */
|
||||
|
||||
/* Mark extracted state invalid */
|
||||
slot->tts_nvalid = 0;
|
||||
|
||||
return slot;
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* ExecClearTuple
|
||||
*
|
||||
@ -458,9 +527,15 @@ ExecClearTuple(TupleTableSlot *slot) /* slot in which to store tuple */
|
||||
* Free the old physical tuple if necessary.
|
||||
*/
|
||||
if (slot->tts_shouldFree)
|
||||
heap_freetuple(slot->tts_tuple);
|
||||
{
|
||||
if (slot->tts_mintuple)
|
||||
heap_free_minimal_tuple(slot->tts_mintuple);
|
||||
else
|
||||
heap_freetuple(slot->tts_tuple);
|
||||
}
|
||||
|
||||
slot->tts_tuple = NULL;
|
||||
slot->tts_mintuple = NULL;
|
||||
slot->tts_shouldFree = false;
|
||||
|
||||
/*
|
||||
@ -540,10 +615,10 @@ ExecStoreAllNullTuple(TupleTableSlot *slot)
|
||||
|
||||
/* --------------------------------
|
||||
* ExecCopySlotTuple
|
||||
* Obtain a copy of a slot's physical tuple. The copy is
|
||||
* Obtain a copy of a slot's regular physical tuple. The copy is
|
||||
* palloc'd in the current memory context.
|
||||
*
|
||||
* This works even if the slot contains a virtual tuple;
|
||||
* This works even if the slot contains a virtual or minimal tuple;
|
||||
* however the "system columns" of the result will not be meaningful.
|
||||
* --------------------------------
|
||||
*/
|
||||
@ -560,7 +635,12 @@ ExecCopySlotTuple(TupleTableSlot *slot)
|
||||
* If we have a physical tuple then just copy it.
|
||||
*/
|
||||
if (slot->tts_tuple)
|
||||
return heap_copytuple(slot->tts_tuple);
|
||||
{
|
||||
if (slot->tts_mintuple)
|
||||
return heap_tuple_from_minimal_tuple(slot->tts_mintuple);
|
||||
else
|
||||
return heap_copytuple(slot->tts_tuple);
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we need to build a tuple from the Datum array.
|
||||
@ -570,12 +650,47 @@ ExecCopySlotTuple(TupleTableSlot *slot)
|
||||
slot->tts_isnull);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* ExecCopySlotMinimalTuple
|
||||
* Obtain a copy of a slot's minimal physical tuple. The copy is
|
||||
* palloc'd in the current memory context.
|
||||
* --------------------------------
|
||||
*/
|
||||
MinimalTuple
|
||||
ExecCopySlotMinimalTuple(TupleTableSlot *slot)
|
||||
{
|
||||
/*
|
||||
* sanity checks
|
||||
*/
|
||||
Assert(slot != NULL);
|
||||
Assert(!slot->tts_isempty);
|
||||
|
||||
/*
|
||||
* If we have a physical tuple then just copy it.
|
||||
*/
|
||||
if (slot->tts_tuple)
|
||||
{
|
||||
if (slot->tts_mintuple)
|
||||
return heap_copy_minimal_tuple(slot->tts_mintuple);
|
||||
else
|
||||
return minimal_tuple_from_heap_tuple(slot->tts_tuple);
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise we need to build a tuple from the Datum array.
|
||||
*/
|
||||
return heap_form_minimal_tuple(slot->tts_tupleDescriptor,
|
||||
slot->tts_values,
|
||||
slot->tts_isnull);
|
||||
}
|
||||
|
||||
/* --------------------------------
|
||||
* ExecFetchSlotTuple
|
||||
* Fetch the slot's physical tuple.
|
||||
* Fetch the slot's regular physical tuple.
|
||||
*
|
||||
* If the slot contains a virtual tuple, we convert it to physical
|
||||
* form. The slot retains ownership of the physical tuple.
|
||||
* Likewise, if it contains a minimal tuple we convert to regular form.
|
||||
*
|
||||
* The difference between this and ExecMaterializeSlot() is that this
|
||||
* does not guarantee that the contained tuple is local storage.
|
||||
@ -592,9 +707,9 @@ ExecFetchSlotTuple(TupleTableSlot *slot)
|
||||
Assert(!slot->tts_isempty);
|
||||
|
||||
/*
|
||||
* If we have a physical tuple then just return it.
|
||||
* If we have a regular physical tuple then just return it.
|
||||
*/
|
||||
if (slot->tts_tuple)
|
||||
if (slot->tts_tuple && slot->tts_mintuple == NULL)
|
||||
return slot->tts_tuple;
|
||||
|
||||
/*
|
||||
@ -629,10 +744,10 @@ ExecMaterializeSlot(TupleTableSlot *slot)
|
||||
Assert(!slot->tts_isempty);
|
||||
|
||||
/*
|
||||
* If we have a physical tuple, and it's locally palloc'd, we have nothing
|
||||
* to do.
|
||||
* If we have a regular physical tuple, and it's locally palloc'd,
|
||||
* we have nothing to do.
|
||||
*/
|
||||
if (slot->tts_tuple && slot->tts_shouldFree)
|
||||
if (slot->tts_tuple && slot->tts_shouldFree && slot->tts_mintuple == NULL)
|
||||
return slot->tts_tuple;
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user