Commit 4da597ed authored by Andres Freund's avatar Andres Freund

Make TupleTableSlots extensible, finish split of existing slot type.

This commit completes the work prepared in 1a0586de, splitting the
old TupleTableSlot implementation (which could store buffer, heap,
minimal and virtual slots) into four different slot types.  As
described in the aforementioned commit, this is done with the goal of
making tuple table slots extensible, to allow for pluggable table
access methods.

To achieve runtime extensibility for TupleTableSlots, operations on
slots that can differ between types of slots are performed using the
TupleTableSlotOps struct provided at slot creation time.  That
includes information from the size of TupleTableSlot struct to be
allocated, initialization, deforming etc.  See the struct's definition
for more detailed information about callbacks TupleTableSlotOps.

I decided to rename TTSOpsBufferTuple to TTSOpsBufferHeapTuple and
ExecCopySlotTuple to ExecCopySlotHeapTuple, as that seems more
consistent with other naming introduced in recent patches.

There's plenty optimization potential in the slot implementation, but
according to benchmarking the state after this commit has similar
performance characteristics to before this set of changes, which seems
sufficient.

There's a few changes in execReplication.c that currently need to poke
through the slot abstraction, that'll be repaired once the pluggable
storage patchset provides the necessary infrastructure.

Author: Andres Freund and  Ashutosh Bapat, with changes by Amit Khandekar
Discussion: https://postgr.es/m/20181105210039.hh4vvi4vwoq5ba2q@alap3.anarazel.de
parent 0201d79a
...@@ -71,6 +71,8 @@ ...@@ -71,6 +71,8 @@
#define VARLENA_ATT_IS_PACKABLE(att) \ #define VARLENA_ATT_IS_PACKABLE(att) \
((att)->attstorage != 'p') ((att)->attstorage != 'p')
static Datum getmissingattr(TupleDesc tupleDesc, int attnum, bool *isnull);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* misc support routines * misc support routines
...@@ -80,7 +82,7 @@ ...@@ -80,7 +82,7 @@
/* /*
* Return the missing value of an attribute, or NULL if there isn't one. * Return the missing value of an attribute, or NULL if there isn't one.
*/ */
Datum static Datum
getmissingattr(TupleDesc tupleDesc, getmissingattr(TupleDesc tupleDesc,
int attnum, bool *isnull) int attnum, bool *isnull)
{ {
...@@ -1350,186 +1352,6 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, ...@@ -1350,186 +1352,6 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]); values[attnum] = getmissingattr(tupleDesc, attnum + 1, &isnull[attnum]);
} }
/*
* slot_deform_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).
*
* This is essentially an incremental version of heap_deform_tuple:
* on each call we extract attributes up to the one needed, without
* re-computing information about previously extracted attributes.
* slot->tts_nvalid is the number of attributes already extracted.
*/
void
slot_deform_tuple(TupleTableSlot *slot, int natts)
{
HeapTuple tuple = slot->tts_tuple;
TupleDesc tupleDesc = slot->tts_tupleDescriptor;
Datum *values = slot->tts_values;
bool *isnull = slot->tts_isnull;
HeapTupleHeader tup = tuple->t_data;
bool hasnulls = HeapTupleHasNulls(tuple);
int attnum;
char *tp; /* ptr to tuple data */
uint32 off; /* offset in tuple data */
bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */
bool slow; /* can we use/set attcacheoff? */
/*
* Check whether the first call for this tuple, and initialize or restore
* loop state.
*/
attnum = slot->tts_nvalid;
if (attnum == 0)
{
/* Start from the first attribute */
off = 0;
slow = false;
}
else
{
/* Restore state from previous execution */
off = slot->tts_off;
slow = TTS_SLOW(slot);
}
tp = (char *) tup + tup->t_hoff;
for (; attnum < natts; attnum++)
{
Form_pg_attribute thisatt = TupleDescAttr(tupleDesc, attnum);
if (hasnulls && att_isnull(attnum, bp))
{
values[attnum] = (Datum) 0;
isnull[attnum] = true;
slow = true; /* can't use attcacheoff anymore */
continue;
}
isnull[attnum] = false;
if (!slow && thisatt->attcacheoff >= 0)
off = thisatt->attcacheoff;
else if (thisatt->attlen == -1)
{
/*
* We can only cache the offset for a varlena attribute if the
* offset is already suitably aligned, so that there would be no
* pad bytes in any case: then the offset will be valid for either
* an aligned or unaligned value.
*/
if (!slow &&
off == att_align_nominal(off, thisatt->attalign))
thisatt->attcacheoff = off;
else
{
off = att_align_pointer(off, thisatt->attalign, -1,
tp + off);
slow = true;
}
}
else
{
/* not varlena, so safe to use att_align_nominal */
off = att_align_nominal(off, thisatt->attalign);
if (!slow)
thisatt->attcacheoff = off;
}
values[attnum] = fetchatt(thisatt, tp + off);
off = att_addlength_pointer(off, thisatt->attlen, tp + off);
if (thisatt->attlen <= 0)
slow = true; /* can't use attcacheoff anymore */
}
/*
* Save state for next execution
*/
slot->tts_nvalid = attnum;
slot->tts_off = off;
if (slow)
slot->tts_flags |= TTS_FLAG_SLOW;
else
slot->tts_flags &= ~TTS_FLAG_SLOW;
}
/*
* slot_attisnull
* Detect whether an attribute of the slot is null, without
* actually fetching it.
*/
bool
slot_attisnull(TupleTableSlot *slot, int attnum)
{
HeapTuple tuple = slot->tts_tuple;
TupleDesc tupleDesc = slot->tts_tupleDescriptor;
/*
* system attributes are handled by heap_attisnull
*/
if (attnum <= 0)
{
if (tuple == NULL) /* internal error */
elog(ERROR, "cannot extract system attribute from virtual tuple");
if (tuple == &(slot->tts_minhdr)) /* internal error */
elog(ERROR, "cannot extract system attribute from minimal tuple");
return heap_attisnull(tuple, attnum, tupleDesc);
}
/*
* fast path if desired attribute already cached
*/
if (attnum <= slot->tts_nvalid)
return slot->tts_isnull[attnum - 1];
/*
* return NULL if attnum is out of range according to the tupdesc
*/
if (attnum > tupleDesc->natts)
return true;
/*
* otherwise we had better have a physical tuple (tts_nvalid should equal
* natts in all virtual-tuple cases)
*/
if (tuple == NULL) /* internal error */
elog(ERROR, "cannot extract attribute from empty tuple slot");
/* and let the tuple tell it */
return heap_attisnull(tuple, attnum, tupleDesc);
}
/*
* slot_getsysattr
* This function fetches a system attribute of the slot's current tuple.
* Unlike slot_getattr, if the slot does not contain system attributes,
* this will return false (with a NULL attribute value) instead of
* throwing an error.
*/
bool
slot_getsysattr(TupleTableSlot *slot, int attnum,
Datum *value, bool *isnull)
{
HeapTuple tuple = slot->tts_tuple;
Assert(attnum < 0); /* else caller error */
if (tuple == NULL ||
tuple == &(slot->tts_minhdr))
{
/* No physical tuple, or minimal tuple, so fail */
*value = (Datum) 0;
*isnull = true;
return false;
}
*value = heap_getsysattr(tuple, attnum, slot->tts_tupleDescriptor, isnull);
return true;
}
/* /*
* heap_freetuple * heap_freetuple
*/ */
......
...@@ -2041,7 +2041,9 @@ FormIndexDatum(IndexInfo *indexInfo, ...@@ -2041,7 +2041,9 @@ FormIndexDatum(IndexInfo *indexInfo,
Datum iDatum; Datum iDatum;
bool isNull; bool isNull;
if (keycol != 0) if (keycol < 0)
iDatum = slot_getsysattr(slot, keycol, &isNull);
else if (keycol != 0)
{ {
/* /*
* Plain index column; get the value we need directly from the * Plain index column; get the value we need directly from the
......
...@@ -2850,7 +2850,7 @@ CopyFrom(CopyState cstate) ...@@ -2850,7 +2850,7 @@ CopyFrom(CopyState cstate)
* freed after each batch insert. * freed after each batch insert.
*/ */
oldcontext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate)); oldcontext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
tuple = ExecCopySlotTuple(slot); tuple = ExecCopySlotHeapTuple(slot);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
} }
......
...@@ -589,7 +589,7 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self) ...@@ -589,7 +589,7 @@ intorel_receive(TupleTableSlot *slot, DestReceiver *self)
* get the heap tuple out of the tuple table slot, making sure we have a * get the heap tuple out of the tuple table slot, making sure we have a
* writable copy * writable copy
*/ */
tuple = ExecCopySlotTuple(slot); tuple = ExecCopySlotHeapTuple(slot);
/* /*
* force assignment of new OID (see comments in ExecInsert) * force assignment of new OID (see comments in ExecInsert)
......
...@@ -484,7 +484,7 @@ transientrel_receive(TupleTableSlot *slot, DestReceiver *self) ...@@ -484,7 +484,7 @@ transientrel_receive(TupleTableSlot *slot, DestReceiver *self)
* get the heap tuple out of the tuple table slot, making sure we have a * get the heap tuple out of the tuple table slot, making sure we have a
* writable copy * writable copy
*/ */
tuple = ExecCopySlotTuple(slot); tuple = ExecCopySlotHeapTuple(slot);
heap_insert(myState->transientrel, heap_insert(myState->transientrel,
tuple, tuple,
......
...@@ -218,27 +218,25 @@ execCurrentOf(CurrentOfExpr *cexpr, ...@@ -218,27 +218,25 @@ execCurrentOf(CurrentOfExpr *cexpr,
ItemPointer tuple_tid; ItemPointer tuple_tid;
#ifdef USE_ASSERT_CHECKING #ifdef USE_ASSERT_CHECKING
if (!slot_getsysattr(scanstate->ss_ScanTupleSlot, ldatum = slot_getsysattr(scanstate->ss_ScanTupleSlot,
TableOidAttributeNumber, TableOidAttributeNumber,
&ldatum, &lisnull);
&lisnull)) if (lisnull)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE), (errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"", errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"",
cursor_name, table_name))); cursor_name, table_name)));
Assert(!lisnull);
Assert(DatumGetObjectId(ldatum) == table_oid); Assert(DatumGetObjectId(ldatum) == table_oid);
#endif #endif
if (!slot_getsysattr(scanstate->ss_ScanTupleSlot, ldatum = slot_getsysattr(scanstate->ss_ScanTupleSlot,
SelfItemPointerAttributeNumber, SelfItemPointerAttributeNumber,
&ldatum, &lisnull);
&lisnull)) if (lisnull)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE), (errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"", errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"",
cursor_name, table_name))); cursor_name, table_name)));
Assert(!lisnull);
tuple_tid = (ItemPointer) DatumGetPointer(ldatum); tuple_tid = (ItemPointer) DatumGetPointer(ldatum);
*current_tid = *tuple_tid; *current_tid = *tuple_tid;
......
...@@ -1875,11 +1875,11 @@ CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot) ...@@ -1875,11 +1875,11 @@ CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot)
* Should probably fixed at some point, but for now it's easier to allow * Should probably fixed at some point, but for now it's easier to allow
* buffer and heap tuples to be used interchangably. * buffer and heap tuples to be used interchangably.
*/ */
if (slot->tts_ops == &TTSOpsBufferTuple && if (slot->tts_ops == &TTSOpsBufferHeapTuple &&
op->d.fetch.kind == &TTSOpsHeapTuple) op->d.fetch.kind == &TTSOpsHeapTuple)
return; return;
if (slot->tts_ops == &TTSOpsHeapTuple && if (slot->tts_ops == &TTSOpsHeapTuple &&
op->d.fetch.kind == &TTSOpsBufferTuple) op->d.fetch.kind == &TTSOpsBufferHeapTuple)
return; return;
/* /*
...@@ -4025,15 +4025,15 @@ void ...@@ -4025,15 +4025,15 @@ void
ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext, ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
TupleTableSlot *slot) TupleTableSlot *slot)
{ {
bool success; Datum d;
/* slot_getsysattr has sufficient defenses against bad attnums */ /* slot_getsysattr has sufficient defenses against bad attnums */
success = slot_getsysattr(slot, d = slot_getsysattr(slot,
op->d.var.attnum, op->d.var.attnum,
op->resvalue, op->resnull);
op->resnull); *op->resvalue = d;
/* this ought to be unreachable, but it's cheap enough to check */ /* this ought to be unreachable, but it's cheap enough to check */
if (unlikely(!success)) if (unlikely(*op->resnull))
elog(ERROR, "failed to fetch attribute from slot"); elog(ERROR, "failed to fetch attribute from slot");
} }
......
...@@ -170,8 +170,11 @@ retry: ...@@ -170,8 +170,11 @@ retry:
HeapUpdateFailureData hufd; HeapUpdateFailureData hufd;
HTSU_Result res; HTSU_Result res;
HeapTupleData locktup; HeapTupleData locktup;
HeapTupleTableSlot *hslot = (HeapTupleTableSlot *)outslot;
ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self); /* Only a heap tuple has item pointers. */
Assert(TTS_IS_HEAPTUPLE(outslot) || TTS_IS_BUFFERTUPLE(outslot));
ItemPointerCopy(&hslot->tuple->t_self, &locktup.t_self);
PushActiveSnapshot(GetLatestSnapshot()); PushActiveSnapshot(GetLatestSnapshot());
...@@ -334,8 +337,11 @@ retry: ...@@ -334,8 +337,11 @@ retry:
HeapUpdateFailureData hufd; HeapUpdateFailureData hufd;
HTSU_Result res; HTSU_Result res;
HeapTupleData locktup; HeapTupleData locktup;
HeapTupleTableSlot *hslot = (HeapTupleTableSlot *)outslot;
ItemPointerCopy(&outslot->tts_tuple->t_self, &locktup.t_self); /* Only a heap tuple has item pointers. */
Assert(TTS_IS_HEAPTUPLE(outslot) || TTS_IS_BUFFERTUPLE(outslot));
ItemPointerCopy(&hslot->tuple->t_self, &locktup.t_self);
PushActiveSnapshot(GetLatestSnapshot()); PushActiveSnapshot(GetLatestSnapshot());
...@@ -456,6 +462,12 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, ...@@ -456,6 +462,12 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
HeapTuple tuple; HeapTuple tuple;
ResultRelInfo *resultRelInfo = estate->es_result_relation_info; ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
Relation rel = resultRelInfo->ri_RelationDesc; Relation rel = resultRelInfo->ri_RelationDesc;
HeapTupleTableSlot *hsearchslot = (HeapTupleTableSlot *)searchslot;
HeapTupleTableSlot *hslot = (HeapTupleTableSlot *)slot;
/* We expect both searchslot and the slot to contain a heap tuple. */
Assert(TTS_IS_HEAPTUPLE(searchslot) || TTS_IS_BUFFERTUPLE(searchslot));
Assert(TTS_IS_HEAPTUPLE(slot) || TTS_IS_BUFFERTUPLE(slot));
/* For now we support only tables. */ /* For now we support only tables. */
Assert(rel->rd_rel->relkind == RELKIND_RELATION); Assert(rel->rd_rel->relkind == RELKIND_RELATION);
...@@ -467,8 +479,7 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, ...@@ -467,8 +479,7 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
resultRelInfo->ri_TrigDesc->trig_update_before_row) resultRelInfo->ri_TrigDesc->trig_update_before_row)
{ {
slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo, slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
&searchslot->tts_tuple->t_self, &hsearchslot->tuple->t_self, NULL, slot);
NULL, slot);
if (slot == NULL) /* "do nothing" */ if (slot == NULL) /* "do nothing" */
skip_tuple = true; skip_tuple = true;
...@@ -488,19 +499,18 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate, ...@@ -488,19 +499,18 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
tuple = ExecFetchSlotHeapTuple(slot, true, NULL); tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/* OK, update the tuple and index entries for it */ /* OK, update the tuple and index entries for it */
simple_heap_update(rel, &searchslot->tts_tuple->t_self, simple_heap_update(rel, &hsearchslot->tuple->t_self, hslot->tuple);
slot->tts_tuple);
if (resultRelInfo->ri_NumIndices > 0 && if (resultRelInfo->ri_NumIndices > 0 &&
!HeapTupleIsHeapOnly(slot->tts_tuple)) !HeapTupleIsHeapOnly(hslot->tuple))
recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self), recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
estate, false, NULL, estate, false, NULL,
NIL); NIL);
/* AFTER ROW UPDATE Triggers */ /* AFTER ROW UPDATE Triggers */
ExecARUpdateTriggers(estate, resultRelInfo, ExecARUpdateTriggers(estate, resultRelInfo,
&searchslot->tts_tuple->t_self, &hsearchslot->tuple->t_self, NULL, tuple,
NULL, tuple, recheckIndexes, NULL); recheckIndexes, NULL);
list_free(recheckIndexes); list_free(recheckIndexes);
} }
...@@ -519,9 +529,11 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate, ...@@ -519,9 +529,11 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
bool skip_tuple = false; bool skip_tuple = false;
ResultRelInfo *resultRelInfo = estate->es_result_relation_info; ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
Relation rel = resultRelInfo->ri_RelationDesc; Relation rel = resultRelInfo->ri_RelationDesc;
HeapTupleTableSlot *hsearchslot = (HeapTupleTableSlot *)searchslot;
/* For now we support only tables. */ /* For now we support only tables and heap tuples. */
Assert(rel->rd_rel->relkind == RELKIND_RELATION); Assert(rel->rd_rel->relkind == RELKIND_RELATION);
Assert(TTS_IS_HEAPTUPLE(searchslot) || TTS_IS_BUFFERTUPLE(searchslot));
CheckCmdReplicaIdentity(rel, CMD_DELETE); CheckCmdReplicaIdentity(rel, CMD_DELETE);
...@@ -530,8 +542,8 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate, ...@@ -530,8 +542,8 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
resultRelInfo->ri_TrigDesc->trig_delete_before_row) resultRelInfo->ri_TrigDesc->trig_delete_before_row)
{ {
skip_tuple = !ExecBRDeleteTriggers(estate, epqstate, resultRelInfo, skip_tuple = !ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
&searchslot->tts_tuple->t_self, &hsearchslot->tuple->t_self, NULL,
NULL, NULL); NULL);
} }
if (!skip_tuple) if (!skip_tuple)
...@@ -539,11 +551,11 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate, ...@@ -539,11 +551,11 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
List *recheckIndexes = NIL; List *recheckIndexes = NIL;
/* OK, delete the tuple */ /* OK, delete the tuple */
simple_heap_delete(rel, &searchslot->tts_tuple->t_self); simple_heap_delete(rel, &hsearchslot->tuple->t_self);
/* AFTER ROW DELETE Triggers */ /* AFTER ROW DELETE Triggers */
ExecARDeleteTriggers(estate, resultRelInfo, ExecARDeleteTriggers(estate, resultRelInfo,
&searchslot->tts_tuple->t_self, NULL, NULL); &hsearchslot->tuple->t_self, NULL, NULL);
list_free(recheckIndexes); list_free(recheckIndexes);
} }
......
...@@ -78,8 +78,8 @@ ExecScanFetch(ScanState *node, ...@@ -78,8 +78,8 @@ ExecScanFetch(ScanState *node,
return ExecClearTuple(slot); return ExecClearTuple(slot);
/* Store test tuple in the plan node's scan slot */ /* Store test tuple in the plan node's scan slot */
ExecStoreHeapTuple(estate->es_epqTuple[scanrelid - 1], ExecForceStoreHeapTuple(estate->es_epqTuple[scanrelid - 1],
slot, false); slot);
/* Check if it meets the access-method conditions */ /* Check if it meets the access-method conditions */
if (!(*recheckMtd) (node, slot)) if (!(*recheckMtd) (node, slot))
......
This diff is collapsed.
...@@ -1741,7 +1741,7 @@ agg_retrieve_direct(AggState *aggstate) ...@@ -1741,7 +1741,7 @@ agg_retrieve_direct(AggState *aggstate)
* Make a copy of the first input tuple; we will use this * Make a copy of the first input tuple; we will use this
* for comparisons (in group mode) and for projection. * for comparisons (in group mode) and for projection.
*/ */
aggstate->grp_firstTuple = ExecCopySlotTuple(outerslot); aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
} }
else else
{ {
...@@ -1800,9 +1800,8 @@ agg_retrieve_direct(AggState *aggstate) ...@@ -1800,9 +1800,8 @@ agg_retrieve_direct(AggState *aggstate)
* reserved for it. The tuple will be deleted when it is * reserved for it. The tuple will be deleted when it is
* cleared from the slot. * cleared from the slot.
*/ */
ExecStoreHeapTuple(aggstate->grp_firstTuple, ExecForceStoreHeapTuple(aggstate->grp_firstTuple,
firstSlot, firstSlot);
true);
aggstate->grp_firstTuple = NULL; /* don't keep two pointers */ aggstate->grp_firstTuple = NULL; /* don't keep two pointers */
/* set up for first advance_aggregates call */ /* set up for first advance_aggregates call */
...@@ -1858,7 +1857,7 @@ agg_retrieve_direct(AggState *aggstate) ...@@ -1858,7 +1857,7 @@ agg_retrieve_direct(AggState *aggstate)
if (!ExecQual(aggstate->phase->eqfunctions[node->numCols - 1], if (!ExecQual(aggstate->phase->eqfunctions[node->numCols - 1],
tmpcontext)) tmpcontext))
{ {
aggstate->grp_firstTuple = ExecCopySlotTuple(outerslot); aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
break; break;
} }
} }
......
...@@ -914,7 +914,7 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags) ...@@ -914,7 +914,7 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
*/ */
ExecInitScanTupleSlot(estate, &scanstate->ss, ExecInitScanTupleSlot(estate, &scanstate->ss,
RelationGetDescr(currentRelation), RelationGetDescr(currentRelation),
&TTSOpsBufferTuple); &TTSOpsBufferHeapTuple);
/* /*
......
...@@ -931,9 +931,10 @@ ExecParallelHashJoinOuterGetTuple(PlanState *outerNode, ...@@ -931,9 +931,10 @@ ExecParallelHashJoinOuterGetTuple(PlanState *outerNode,
hashvalue); hashvalue);
if (tuple != NULL) if (tuple != NULL)
{ {
slot = ExecStoreMinimalTuple(tuple, ExecForceStoreMinimalTuple(tuple,
hjstate->hj_OuterTupleSlot, hjstate->hj_OuterTupleSlot,
false); false);
slot = hjstate->hj_OuterTupleSlot;
return slot; return slot;
} }
else else
...@@ -1160,9 +1161,10 @@ ExecParallelHashJoinNewBatch(HashJoinState *hjstate) ...@@ -1160,9 +1161,10 @@ ExecParallelHashJoinNewBatch(HashJoinState *hjstate)
while ((tuple = sts_parallel_scan_next(inner_tuples, while ((tuple = sts_parallel_scan_next(inner_tuples,
&hashvalue))) &hashvalue)))
{ {
slot = ExecStoreMinimalTuple(tuple, ExecForceStoreMinimalTuple(tuple,
hjstate->hj_HashTupleSlot, hjstate->hj_HashTupleSlot,
false); false);
slot = hjstate->hj_HashTupleSlot;
ExecParallelHashTableInsertCurrentBatch(hashtable, slot, ExecParallelHashTableInsertCurrentBatch(hashtable, slot,
hashvalue); hashvalue);
} }
...@@ -1296,7 +1298,8 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate, ...@@ -1296,7 +1298,8 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read from hash-join temporary file: %m"))); errmsg("could not read from hash-join temporary file: %m")));
return ExecStoreMinimalTuple(tuple, tupleSlot, true); ExecForceStoreMinimalTuple(tuple, tupleSlot, true);
return tupleSlot;
} }
......
...@@ -950,7 +950,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags) ...@@ -950,7 +950,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
*/ */
ExecInitScanTupleSlot(estate, &indexstate->ss, ExecInitScanTupleSlot(estate, &indexstate->ss,
RelationGetDescr(currentRelation), RelationGetDescr(currentRelation),
&TTSOpsBufferTuple); &TTSOpsBufferHeapTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.
......
...@@ -2384,7 +2384,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) ...@@ -2384,7 +2384,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->mt_existing = mtstate->mt_existing =
ExecInitExtraTupleSlot(mtstate->ps.state, ExecInitExtraTupleSlot(mtstate->ps.state,
mtstate->mt_partition_tuple_routing ? mtstate->mt_partition_tuple_routing ?
NULL : relationDesc, &TTSOpsBufferTuple); NULL : relationDesc, &TTSOpsBufferHeapTuple);
/* carried forward solely for the benefit of explain */ /* carried forward solely for the benefit of explain */
mtstate->mt_excludedtlist = node->exclRelTlist; mtstate->mt_excludedtlist = node->exclRelTlist;
......
...@@ -147,7 +147,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags) ...@@ -147,7 +147,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
/* and create slot with appropriate rowtype */ /* and create slot with appropriate rowtype */
ExecInitScanTupleSlot(estate, &scanstate->ss, ExecInitScanTupleSlot(estate, &scanstate->ss,
RelationGetDescr(scanstate->ss.ss_currentRelation), RelationGetDescr(scanstate->ss.ss_currentRelation),
&TTSOpsBufferTuple); &TTSOpsBufferHeapTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.
......
...@@ -173,7 +173,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags) ...@@ -173,7 +173,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
/* and create slot with the appropriate rowtype */ /* and create slot with the appropriate rowtype */
ExecInitScanTupleSlot(estate, &scanstate->ss, ExecInitScanTupleSlot(estate, &scanstate->ss,
RelationGetDescr(scanstate->ss.ss_currentRelation), RelationGetDescr(scanstate->ss.ss_currentRelation),
&TTSOpsBufferTuple); &TTSOpsBufferHeapTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.
......
...@@ -252,7 +252,7 @@ setop_retrieve_direct(SetOpState *setopstate) ...@@ -252,7 +252,7 @@ setop_retrieve_direct(SetOpState *setopstate)
if (!TupIsNull(outerslot)) if (!TupIsNull(outerslot))
{ {
/* Make a copy of the first input tuple */ /* Make a copy of the first input tuple */
setopstate->grp_firstTuple = ExecCopySlotTuple(outerslot); setopstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
} }
else else
{ {
...@@ -303,7 +303,7 @@ setop_retrieve_direct(SetOpState *setopstate) ...@@ -303,7 +303,7 @@ setop_retrieve_direct(SetOpState *setopstate)
/* /*
* Save the first input tuple of the next group. * Save the first input tuple of the next group.
*/ */
setopstate->grp_firstTuple = ExecCopySlotTuple(outerslot); setopstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
break; break;
} }
......
...@@ -357,7 +357,7 @@ ExecScanSubPlan(SubPlanState *node, ...@@ -357,7 +357,7 @@ ExecScanSubPlan(SubPlanState *node,
*/ */
if (node->curTuple) if (node->curTuple)
heap_freetuple(node->curTuple); heap_freetuple(node->curTuple);
node->curTuple = ExecCopySlotTuple(slot); node->curTuple = ExecCopySlotHeapTuple(slot);
result = heap_getattr(node->curTuple, 1, tdesc, isNull); result = heap_getattr(node->curTuple, 1, tdesc, isNull);
/* keep scanning subplan to make sure there's only one tuple */ /* keep scanning subplan to make sure there's only one tuple */
...@@ -1137,7 +1137,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) ...@@ -1137,7 +1137,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
*/ */
if (node->curTuple) if (node->curTuple)
heap_freetuple(node->curTuple); heap_freetuple(node->curTuple);
node->curTuple = ExecCopySlotTuple(slot); node->curTuple = ExecCopySlotHeapTuple(slot);
/* /*
* Now set all the setParam params from the columns of the tuple * Now set all the setParam params from the columns of the tuple
......
...@@ -544,7 +544,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags) ...@@ -544,7 +544,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
*/ */
ExecInitScanTupleSlot(estate, &tidstate->ss, ExecInitScanTupleSlot(estate, &tidstate->ss,
RelationGetDescr(currentRelation), RelationGetDescr(currentRelation),
&TTSOpsBufferTuple); &TTSOpsBufferHeapTuple);
/* /*
* Initialize result type and projection. * Initialize result type and projection.
......
...@@ -1857,7 +1857,7 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self) ...@@ -1857,7 +1857,7 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
} }
tuptable->vals[tuptable->alloced - tuptable->free] = tuptable->vals[tuptable->alloced - tuptable->free] =
ExecCopySlotTuple(slot); ExecCopySlotHeapTuple(slot);
(tuptable->free)--; (tuptable->free)--;
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
......
...@@ -65,6 +65,8 @@ LLVMTypeRef StructFormPgAttribute; ...@@ -65,6 +65,8 @@ LLVMTypeRef StructFormPgAttribute;
LLVMTypeRef StructTupleConstr; LLVMTypeRef StructTupleConstr;
LLVMTypeRef StructtupleDesc; LLVMTypeRef StructtupleDesc;
LLVMTypeRef StructTupleTableSlot; LLVMTypeRef StructTupleTableSlot;
LLVMTypeRef StructHeapTupleTableSlot;
LLVMTypeRef StructMinimalTupleTableSlot;
LLVMTypeRef StructMemoryContextData; LLVMTypeRef StructMemoryContextData;
LLVMTypeRef StructPGFinfoRecord; LLVMTypeRef StructPGFinfoRecord;
LLVMTypeRef StructFmgrInfo; LLVMTypeRef StructFmgrInfo;
...@@ -811,6 +813,8 @@ llvm_create_types(void) ...@@ -811,6 +813,8 @@ llvm_create_types(void)
StructFunctionCallInfoData = load_type(mod, "StructFunctionCallInfoData"); StructFunctionCallInfoData = load_type(mod, "StructFunctionCallInfoData");
StructMemoryContextData = load_type(mod, "StructMemoryContextData"); StructMemoryContextData = load_type(mod, "StructMemoryContextData");
StructTupleTableSlot = load_type(mod, "StructTupleTableSlot"); StructTupleTableSlot = load_type(mod, "StructTupleTableSlot");
StructHeapTupleTableSlot = load_type(mod, "StructHeapTupleTableSlot");
StructMinimalTupleTableSlot = load_type(mod, "StructMinimalTupleTableSlot");
StructHeapTupleData = load_type(mod, "StructHeapTupleData"); StructHeapTupleData = load_type(mod, "StructHeapTupleData");
StructtupleDesc = load_type(mod, "StructtupleDesc"); StructtupleDesc = load_type(mod, "StructtupleDesc");
StructAggState = load_type(mod, "StructAggState"); StructAggState = load_type(mod, "StructAggState");
......
...@@ -93,6 +93,11 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, ...@@ -93,6 +93,11 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc,
if (ops == &TTSOpsVirtual) if (ops == &TTSOpsVirtual)
return NULL; return NULL;
/* decline to JIT for slot types we don't know to handle */
if (ops != &TTSOpsHeapTuple && ops != &TTSOpsBufferHeapTuple &&
ops != &TTSOpsMinimalTuple)
return NULL;
mod = llvm_mutable_module(context); mod = llvm_mutable_module(context);
funcname = llvm_expand_funcname(context, "deform"); funcname = llvm_expand_funcname(context, "deform");
...@@ -171,14 +176,44 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc, ...@@ -171,14 +176,44 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc,
v_tts_nulls = v_tts_nulls =
l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_ISNULL, l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_ISNULL,
"tts_ISNULL"); "tts_ISNULL");
v_slotoffp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_OFF, "");
v_flagsp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_FLAGS, ""); v_flagsp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_FLAGS, "");
v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, ""); v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, "");
v_tupleheaderp = if (ops == &TTSOpsHeapTuple || ops == &TTSOpsBufferHeapTuple)
l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_TUPLE, {
"tupleheader"); LLVMValueRef v_heapslot;
v_heapslot =
LLVMBuildBitCast(b,
v_slot,
l_ptr(StructHeapTupleTableSlot),
"heapslot");
v_slotoffp = LLVMBuildStructGEP(b, v_heapslot, FIELDNO_HEAPTUPLETABLESLOT_OFF, "");
v_tupleheaderp =
l_load_struct_gep(b, v_heapslot, FIELDNO_HEAPTUPLETABLESLOT_TUPLE,
"tupleheader");
}
else if (ops == &TTSOpsMinimalTuple)
{
LLVMValueRef v_minimalslot;
v_minimalslot =
LLVMBuildBitCast(b,
v_slot,
l_ptr(StructMinimalTupleTableSlot),
"minimalslotslot");
v_slotoffp = LLVMBuildStructGEP(b, v_minimalslot, FIELDNO_MINIMALTUPLETABLESLOT_OFF, "");
v_tupleheaderp =
l_load_struct_gep(b, v_minimalslot, FIELDNO_MINIMALTUPLETABLESLOT_TUPLE,
"tupleheader");
}
else
{
/* should've returned at the start of the function */
pg_unreachable();
}
v_tuplep = v_tuplep =
l_load_struct_gep(b, v_tupleheaderp, FIELDNO_HEAPTUPLEDATA_DATA, l_load_struct_gep(b, v_tupleheaderp, FIELDNO_HEAPTUPLEDATA_DATA,
"tuple"); "tuple");
......
...@@ -59,6 +59,8 @@ FunctionCallInfoData StructFunctionCallInfoData; ...@@ -59,6 +59,8 @@ FunctionCallInfoData StructFunctionCallInfoData;
HeapTupleData StructHeapTupleData; HeapTupleData StructHeapTupleData;
MemoryContextData StructMemoryContextData; MemoryContextData StructMemoryContextData;
TupleTableSlot StructTupleTableSlot; TupleTableSlot StructTupleTableSlot;
HeapTupleTableSlot StructHeapTupleTableSlot;
MinimalTupleTableSlot StructMinimalTupleTableSlot;
struct tupleDesc StructtupleDesc; struct tupleDesc StructtupleDesc;
......
...@@ -835,7 +835,5 @@ extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup); ...@@ -835,7 +835,5 @@ extern MinimalTuple minimal_tuple_from_heap_tuple(HeapTuple htup);
extern size_t varsize_any(void *p); extern size_t varsize_any(void *p);
extern HeapTuple heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc); extern HeapTuple heap_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc);
extern MinimalTuple minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc); extern MinimalTuple minimal_expand_tuple(HeapTuple sourceTuple, TupleDesc tupleDesc);
struct TupleTableSlot;
extern void slot_deform_tuple(struct TupleTableSlot *slot, int natts);
#endif /* HTUP_DETAILS_H */ #endif /* HTUP_DETAILS_H */
This diff is collapsed.
...@@ -65,6 +65,8 @@ extern LLVMTypeRef TypeStorageBool; ...@@ -65,6 +65,8 @@ extern LLVMTypeRef TypeStorageBool;
extern LLVMTypeRef StructtupleDesc; extern LLVMTypeRef StructtupleDesc;
extern LLVMTypeRef StructHeapTupleData; extern LLVMTypeRef StructHeapTupleData;
extern LLVMTypeRef StructTupleTableSlot; extern LLVMTypeRef StructTupleTableSlot;
extern LLVMTypeRef StructHeapTupleTableSlot;
extern LLVMTypeRef StructMinimalTupleTableSlot;
extern LLVMTypeRef StructMemoryContextData; extern LLVMTypeRef StructMemoryContextData;
extern LLVMTypeRef StructFunctionCallInfoData; extern LLVMTypeRef StructFunctionCallInfoData;
extern LLVMTypeRef StructExprContext; extern LLVMTypeRef StructExprContext;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment