1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-01 21:31:19 +03:00

Make TupleTableSlots extensible, finish split of existing slot type.

This commit completes the work prepared in 1a0586de36, 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
This commit is contained in:
Andres Freund
2018-11-16 16:35:11 -08:00
parent 0201d79a55
commit 4da597edf1
27 changed files with 1501 additions and 863 deletions

View File

@@ -71,6 +71,8 @@
#define VARLENA_ATT_IS_PACKABLE(att) \
((att)->attstorage != 'p')
static Datum getmissingattr(TupleDesc tupleDesc, int attnum, bool *isnull);
/* ----------------------------------------------------------------
* misc support routines
@@ -80,7 +82,7 @@
/*
* Return the missing value of an attribute, or NULL if there isn't one.
*/
Datum
static Datum
getmissingattr(TupleDesc tupleDesc,
int attnum, bool *isnull)
{
@@ -1350,186 +1352,6 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc,
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
*/

View File

@@ -2041,7 +2041,9 @@ FormIndexDatum(IndexInfo *indexInfo,
Datum iDatum;
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

View File

@@ -2850,7 +2850,7 @@ CopyFrom(CopyState cstate)
* freed after each batch insert.
*/
oldcontext = MemoryContextSwitchTo(GetPerTupleMemoryContext(estate));
tuple = ExecCopySlotTuple(slot);
tuple = ExecCopySlotHeapTuple(slot);
MemoryContextSwitchTo(oldcontext);
}

View File

@@ -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
* writable copy
*/
tuple = ExecCopySlotTuple(slot);
tuple = ExecCopySlotHeapTuple(slot);
/*
* force assignment of new OID (see comments in ExecInsert)

View File

@@ -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
* writable copy
*/
tuple = ExecCopySlotTuple(slot);
tuple = ExecCopySlotHeapTuple(slot);
heap_insert(myState->transientrel,
tuple,

View File

@@ -218,27 +218,25 @@ execCurrentOf(CurrentOfExpr *cexpr,
ItemPointer tuple_tid;
#ifdef USE_ASSERT_CHECKING
if (!slot_getsysattr(scanstate->ss_ScanTupleSlot,
TableOidAttributeNumber,
&ldatum,
&lisnull))
ldatum = slot_getsysattr(scanstate->ss_ScanTupleSlot,
TableOidAttributeNumber,
&lisnull);
if (lisnull)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"",
cursor_name, table_name)));
Assert(!lisnull);
Assert(DatumGetObjectId(ldatum) == table_oid);
#endif
if (!slot_getsysattr(scanstate->ss_ScanTupleSlot,
SelfItemPointerAttributeNumber,
&ldatum,
&lisnull))
ldatum = slot_getsysattr(scanstate->ss_ScanTupleSlot,
SelfItemPointerAttributeNumber,
&lisnull);
if (lisnull)
ereport(ERROR,
(errcode(ERRCODE_INVALID_CURSOR_STATE),
errmsg("cursor \"%s\" is not a simply updatable scan of table \"%s\"",
cursor_name, table_name)));
Assert(!lisnull);
tuple_tid = (ItemPointer) DatumGetPointer(ldatum);
*current_tid = *tuple_tid;

View File

@@ -1875,11 +1875,11 @@ CheckOpSlotCompatibility(ExprEvalStep *op, TupleTableSlot *slot)
* Should probably fixed at some point, but for now it's easier to allow
* buffer and heap tuples to be used interchangably.
*/
if (slot->tts_ops == &TTSOpsBufferTuple &&
if (slot->tts_ops == &TTSOpsBufferHeapTuple &&
op->d.fetch.kind == &TTSOpsHeapTuple)
return;
if (slot->tts_ops == &TTSOpsHeapTuple &&
op->d.fetch.kind == &TTSOpsBufferTuple)
op->d.fetch.kind == &TTSOpsBufferHeapTuple)
return;
/*
@@ -4025,15 +4025,15 @@ void
ExecEvalSysVar(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
TupleTableSlot *slot)
{
bool success;
Datum d;
/* slot_getsysattr has sufficient defenses against bad attnums */
success = slot_getsysattr(slot,
op->d.var.attnum,
op->resvalue,
op->resnull);
d = slot_getsysattr(slot,
op->d.var.attnum,
op->resnull);
*op->resvalue = d;
/* 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");
}

View File

@@ -170,8 +170,11 @@ retry:
HeapUpdateFailureData hufd;
HTSU_Result res;
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());
@@ -334,8 +337,11 @@ retry:
HeapUpdateFailureData hufd;
HTSU_Result res;
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());
@@ -456,6 +462,12 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
HeapTuple tuple;
ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
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. */
Assert(rel->rd_rel->relkind == RELKIND_RELATION);
@@ -467,8 +479,7 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
resultRelInfo->ri_TrigDesc->trig_update_before_row)
{
slot = ExecBRUpdateTriggers(estate, epqstate, resultRelInfo,
&searchslot->tts_tuple->t_self,
NULL, slot);
&hsearchslot->tuple->t_self, NULL, slot);
if (slot == NULL) /* "do nothing" */
skip_tuple = true;
@@ -488,19 +499,18 @@ ExecSimpleRelationUpdate(EState *estate, EPQState *epqstate,
tuple = ExecFetchSlotHeapTuple(slot, true, NULL);
/* OK, update the tuple and index entries for it */
simple_heap_update(rel, &searchslot->tts_tuple->t_self,
slot->tts_tuple);
simple_heap_update(rel, &hsearchslot->tuple->t_self, hslot->tuple);
if (resultRelInfo->ri_NumIndices > 0 &&
!HeapTupleIsHeapOnly(slot->tts_tuple))
!HeapTupleIsHeapOnly(hslot->tuple))
recheckIndexes = ExecInsertIndexTuples(slot, &(tuple->t_self),
estate, false, NULL,
NIL);
/* AFTER ROW UPDATE Triggers */
ExecARUpdateTriggers(estate, resultRelInfo,
&searchslot->tts_tuple->t_self,
NULL, tuple, recheckIndexes, NULL);
&hsearchslot->tuple->t_self, NULL, tuple,
recheckIndexes, NULL);
list_free(recheckIndexes);
}
@@ -519,9 +529,11 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
bool skip_tuple = false;
ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
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(TTS_IS_HEAPTUPLE(searchslot) || TTS_IS_BUFFERTUPLE(searchslot));
CheckCmdReplicaIdentity(rel, CMD_DELETE);
@@ -530,8 +542,8 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
resultRelInfo->ri_TrigDesc->trig_delete_before_row)
{
skip_tuple = !ExecBRDeleteTriggers(estate, epqstate, resultRelInfo,
&searchslot->tts_tuple->t_self,
NULL, NULL);
&hsearchslot->tuple->t_self, NULL,
NULL);
}
if (!skip_tuple)
@@ -539,11 +551,11 @@ ExecSimpleRelationDelete(EState *estate, EPQState *epqstate,
List *recheckIndexes = NIL;
/* 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 */
ExecARDeleteTriggers(estate, resultRelInfo,
&searchslot->tts_tuple->t_self, NULL, NULL);
&hsearchslot->tuple->t_self, NULL, NULL);
list_free(recheckIndexes);
}

View File

@@ -78,8 +78,8 @@ ExecScanFetch(ScanState *node,
return ExecClearTuple(slot);
/* Store test tuple in the plan node's scan slot */
ExecStoreHeapTuple(estate->es_epqTuple[scanrelid - 1],
slot, false);
ExecForceStoreHeapTuple(estate->es_epqTuple[scanrelid - 1],
slot);
/* Check if it meets the access-method conditions */
if (!(*recheckMtd) (node, slot))

File diff suppressed because it is too large Load Diff

View File

@@ -1741,7 +1741,7 @@ agg_retrieve_direct(AggState *aggstate)
* Make a copy of the first input tuple; we will use this
* for comparisons (in group mode) and for projection.
*/
aggstate->grp_firstTuple = ExecCopySlotTuple(outerslot);
aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
}
else
{
@@ -1800,9 +1800,8 @@ agg_retrieve_direct(AggState *aggstate)
* reserved for it. The tuple will be deleted when it is
* cleared from the slot.
*/
ExecStoreHeapTuple(aggstate->grp_firstTuple,
firstSlot,
true);
ExecForceStoreHeapTuple(aggstate->grp_firstTuple,
firstSlot);
aggstate->grp_firstTuple = NULL; /* don't keep two pointers */
/* set up for first advance_aggregates call */
@@ -1858,7 +1857,7 @@ agg_retrieve_direct(AggState *aggstate)
if (!ExecQual(aggstate->phase->eqfunctions[node->numCols - 1],
tmpcontext))
{
aggstate->grp_firstTuple = ExecCopySlotTuple(outerslot);
aggstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
break;
}
}

View File

@@ -914,7 +914,7 @@ ExecInitBitmapHeapScan(BitmapHeapScan *node, EState *estate, int eflags)
*/
ExecInitScanTupleSlot(estate, &scanstate->ss,
RelationGetDescr(currentRelation),
&TTSOpsBufferTuple);
&TTSOpsBufferHeapTuple);
/*

View File

@@ -931,9 +931,10 @@ ExecParallelHashJoinOuterGetTuple(PlanState *outerNode,
hashvalue);
if (tuple != NULL)
{
slot = ExecStoreMinimalTuple(tuple,
hjstate->hj_OuterTupleSlot,
false);
ExecForceStoreMinimalTuple(tuple,
hjstate->hj_OuterTupleSlot,
false);
slot = hjstate->hj_OuterTupleSlot;
return slot;
}
else
@@ -1160,9 +1161,10 @@ ExecParallelHashJoinNewBatch(HashJoinState *hjstate)
while ((tuple = sts_parallel_scan_next(inner_tuples,
&hashvalue)))
{
slot = ExecStoreMinimalTuple(tuple,
hjstate->hj_HashTupleSlot,
false);
ExecForceStoreMinimalTuple(tuple,
hjstate->hj_HashTupleSlot,
false);
slot = hjstate->hj_HashTupleSlot;
ExecParallelHashTableInsertCurrentBatch(hashtable, slot,
hashvalue);
}
@@ -1296,7 +1298,8 @@ ExecHashJoinGetSavedTuple(HashJoinState *hjstate,
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read from hash-join temporary file: %m")));
return ExecStoreMinimalTuple(tuple, tupleSlot, true);
ExecForceStoreMinimalTuple(tuple, tupleSlot, true);
return tupleSlot;
}

View File

@@ -950,7 +950,7 @@ ExecInitIndexScan(IndexScan *node, EState *estate, int eflags)
*/
ExecInitScanTupleSlot(estate, &indexstate->ss,
RelationGetDescr(currentRelation),
&TTSOpsBufferTuple);
&TTSOpsBufferHeapTuple);
/*
* Initialize result type and projection.

View File

@@ -2384,7 +2384,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->mt_existing =
ExecInitExtraTupleSlot(mtstate->ps.state,
mtstate->mt_partition_tuple_routing ?
NULL : relationDesc, &TTSOpsBufferTuple);
NULL : relationDesc, &TTSOpsBufferHeapTuple);
/* carried forward solely for the benefit of explain */
mtstate->mt_excludedtlist = node->exclRelTlist;

View File

@@ -147,7 +147,7 @@ ExecInitSampleScan(SampleScan *node, EState *estate, int eflags)
/* and create slot with appropriate rowtype */
ExecInitScanTupleSlot(estate, &scanstate->ss,
RelationGetDescr(scanstate->ss.ss_currentRelation),
&TTSOpsBufferTuple);
&TTSOpsBufferHeapTuple);
/*
* Initialize result type and projection.

View File

@@ -173,7 +173,7 @@ ExecInitSeqScan(SeqScan *node, EState *estate, int eflags)
/* and create slot with the appropriate rowtype */
ExecInitScanTupleSlot(estate, &scanstate->ss,
RelationGetDescr(scanstate->ss.ss_currentRelation),
&TTSOpsBufferTuple);
&TTSOpsBufferHeapTuple);
/*
* Initialize result type and projection.

View File

@@ -252,7 +252,7 @@ setop_retrieve_direct(SetOpState *setopstate)
if (!TupIsNull(outerslot))
{
/* Make a copy of the first input tuple */
setopstate->grp_firstTuple = ExecCopySlotTuple(outerslot);
setopstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
}
else
{
@@ -303,7 +303,7 @@ setop_retrieve_direct(SetOpState *setopstate)
/*
* Save the first input tuple of the next group.
*/
setopstate->grp_firstTuple = ExecCopySlotTuple(outerslot);
setopstate->grp_firstTuple = ExecCopySlotHeapTuple(outerslot);
break;
}

View File

@@ -357,7 +357,7 @@ ExecScanSubPlan(SubPlanState *node,
*/
if (node->curTuple)
heap_freetuple(node->curTuple);
node->curTuple = ExecCopySlotTuple(slot);
node->curTuple = ExecCopySlotHeapTuple(slot);
result = heap_getattr(node->curTuple, 1, tdesc, isNull);
/* keep scanning subplan to make sure there's only one tuple */
@@ -1137,7 +1137,7 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
*/
if (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

View File

@@ -544,7 +544,7 @@ ExecInitTidScan(TidScan *node, EState *estate, int eflags)
*/
ExecInitScanTupleSlot(estate, &tidstate->ss,
RelationGetDescr(currentRelation),
&TTSOpsBufferTuple);
&TTSOpsBufferHeapTuple);
/*
* Initialize result type and projection.

View File

@@ -1857,7 +1857,7 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
}
tuptable->vals[tuptable->alloced - tuptable->free] =
ExecCopySlotTuple(slot);
ExecCopySlotHeapTuple(slot);
(tuptable->free)--;
MemoryContextSwitchTo(oldcxt);

View File

@@ -65,6 +65,8 @@ LLVMTypeRef StructFormPgAttribute;
LLVMTypeRef StructTupleConstr;
LLVMTypeRef StructtupleDesc;
LLVMTypeRef StructTupleTableSlot;
LLVMTypeRef StructHeapTupleTableSlot;
LLVMTypeRef StructMinimalTupleTableSlot;
LLVMTypeRef StructMemoryContextData;
LLVMTypeRef StructPGFinfoRecord;
LLVMTypeRef StructFmgrInfo;
@@ -811,6 +813,8 @@ llvm_create_types(void)
StructFunctionCallInfoData = load_type(mod, "StructFunctionCallInfoData");
StructMemoryContextData = load_type(mod, "StructMemoryContextData");
StructTupleTableSlot = load_type(mod, "StructTupleTableSlot");
StructHeapTupleTableSlot = load_type(mod, "StructHeapTupleTableSlot");
StructMinimalTupleTableSlot = load_type(mod, "StructMinimalTupleTableSlot");
StructHeapTupleData = load_type(mod, "StructHeapTupleData");
StructtupleDesc = load_type(mod, "StructtupleDesc");
StructAggState = load_type(mod, "StructAggState");

View File

@@ -93,6 +93,11 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc,
if (ops == &TTSOpsVirtual)
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);
funcname = llvm_expand_funcname(context, "deform");
@@ -171,14 +176,44 @@ slot_compile_deform(LLVMJitContext *context, TupleDesc desc,
v_tts_nulls =
l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_ISNULL,
"tts_ISNULL");
v_slotoffp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_OFF, "");
v_flagsp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_FLAGS, "");
v_nvalidp = LLVMBuildStructGEP(b, v_slot, FIELDNO_TUPLETABLESLOT_NVALID, "");
v_tupleheaderp =
l_load_struct_gep(b, v_slot, FIELDNO_TUPLETABLESLOT_TUPLE,
"tupleheader");
if (ops == &TTSOpsHeapTuple || ops == &TTSOpsBufferHeapTuple)
{
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 =
l_load_struct_gep(b, v_tupleheaderp, FIELDNO_HEAPTUPLEDATA_DATA,
"tuple");

View File

@@ -59,6 +59,8 @@ FunctionCallInfoData StructFunctionCallInfoData;
HeapTupleData StructHeapTupleData;
MemoryContextData StructMemoryContextData;
TupleTableSlot StructTupleTableSlot;
HeapTupleTableSlot StructHeapTupleTableSlot;
MinimalTupleTableSlot StructMinimalTupleTableSlot;
struct tupleDesc StructtupleDesc;