Custom TupleTableSlotOps while Initializing Custom Scan

From: V N G Samba Siva Reddy Chinta <sambasivareddychinta(at)gmail(dot)com>
To: pgsql-hackers(at)postgresql(dot)org
Subject: Custom TupleTableSlotOps while Initializing Custom Scan
Date: 2024-06-20 10:28:42
Message-ID: CAO3Kpf1kwWFwbj98Squye-MRSrmN4cbUS-fxDjba4d_33auwdQ@mail.gmail.com
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-hackers

Hello Team,
Good Day,

I have been working on adding a CustomScanState object in the executor
state in my project. As part of CustomScanState, I execute queries and
store their results in the Tuplestorestate object. After storing all tuples
in the Tuplestorestate, I retrieve each tuple and place it in the
TupleTableSlot using the tuplestore_gettupleslot() function.

However, I encounter an error: *"trying to store a minimal tuple into the
wrong type of slot."* Upon debugging, I discovered that the TupleTableSlot
only holds virtual tuples (tupleTableSlot->tts_ops is set to TTSOpsVirtual).
In contrast, tuplestore_gettupleslot() calls ExecStoreMinimalTuple(), which
expects TupleTableSlotOps of type TTSOpsMinimalTuple.

Further investigation revealed that in the ExecInitCustomScan() function
within the nodeCustom.c source file, where ScanTupleSlot and
ResultTupleSlots are initialized, users can choose custom slots by setting
slotOps in CustomScanState. We initialize the ScanTupleSlot based on
user-specified slotOps, but for ResultTupleSlot, we proceed with
TTSOpsVirtual instead of the custom slotOps, which is causing the issue.

Is this behavior expected? Is there a way to store tuples in slots
according to the TupleTableSlot type?

I found a function ExecForceStoreMinimalTuple() which can be used in my
case. We need to pass the MinimalTuple to this function, but I was unable
to find a way to fetch the tuple from tuple storestate. We do have
tuplestore_gettuple()
function to get the minimal tuple but it is a static function, is there any
other function like that?

Below is the code snippet of ExecInitCustomScan() , for simplicity I
removed some code in the function. I took it from the nodeCustom.c file in
the PG source.
CustomScanState *
ExecInitCustomScan(CustomScan *cscan, EState *estate, int eflags)
{
CustomScanState *css;
const TupleTableSlotOps *slotOps;

css = castNode(CustomScanState,
cscan->methods->CreateCustomScanState(cscan));
// ------------------------------- CODE STARTED ----------------

/*
* Use a custom slot if specified in CustomScanState or use virtual slot
* otherwise.
*/
slotOps = css->slotOps;
if (!slotOps)
slotOps = &TTSOpsVirtual;

if (cscan->custom_scan_tlist != NIL || scan_rel == NULL)
{
ExecInitScanTupleSlot(estate, &css->ss, scan_tupdesc, slotOps); // Here we
are using slotOps provided by user
}
else
{
ExecInitScanTupleSlot(estate, &css->ss, RelationGetDescr(scan_rel),
slotOps); // Here we are using slotOps provided by user
}

ExecInitResultTupleSlotTL(&css->ss.ps, &*TTSOpsVirtual*); // Here we have
hard coded TTSOpsVirtual
// -------------------------- CODE ENDED -----------------------
}

Responses

Browse pgsql-hackers by date

  From Date Subject
Next Message Amit Kapila 2024-06-20 10:40:39 Re: Conflict Detection and Resolution
Previous Message Tomas Vondra 2024-06-20 10:28:24 confusing valgrind report about tuplestore+wrapper_handler (?) on 32-bit arm