192 lines
5.8 KiB
C++
Executable File
192 lines
5.8 KiB
C++
Executable File
/* -------------------------------------------------------------------------
|
|
*
|
|
* tstoreReceiver.cpp
|
|
* An implementation of DestReceiver that stores the result tuples in
|
|
* a Tuplestore.
|
|
*
|
|
* Optionally, we can force detoasting (but not decompression) of out-of-line
|
|
* toasted values. This is to support cursors WITH HOLD, which must retain
|
|
* data even if the underlying table is dropped.
|
|
*
|
|
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
|
* Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*
|
|
* IDENTIFICATION
|
|
* src/gausskernel/runtime/executor/tstoreReceiver.cpp
|
|
*
|
|
* -------------------------------------------------------------------------
|
|
*/
|
|
#include "postgres.h"
|
|
#include "knl/knl_variable.h"
|
|
|
|
#include "access/tuptoaster.h"
|
|
#include "executor/tstoreReceiver.h"
|
|
|
|
typedef struct {
|
|
DestReceiver pub;
|
|
/* parameters: */
|
|
Tuplestorestate *tstore; /* where to put the data */
|
|
MemoryContext cxt; /* context containing tstore */
|
|
bool detoast; /* were we told to detoast? */
|
|
/* workspace: */
|
|
Datum *outvalues; /* values array for result tuple */
|
|
Datum *tofree; /* temp values to be pfree'd */
|
|
} TStoreState;
|
|
|
|
static void tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self);
|
|
static void tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self);
|
|
|
|
/*
|
|
* Prepare to receive tuples from executor.
|
|
*/
|
|
static void tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
|
|
{
|
|
TStoreState *my_stat = (TStoreState *)self;
|
|
bool need_toast = false;
|
|
Form_pg_attribute *attrs = typeinfo->attrs;
|
|
int natts = typeinfo->natts;
|
|
int i;
|
|
|
|
/* Check if any columns require detoast work */
|
|
if (my_stat->detoast) {
|
|
for (i = 0; i < natts; i++) {
|
|
if (attrs[i]->attisdropped) {
|
|
continue;
|
|
}
|
|
if (attrs[i]->attlen == -1) {
|
|
need_toast = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Set up appropriate callback */
|
|
if (need_toast) {
|
|
my_stat->pub.receiveSlot = tstoreReceiveSlot_detoast;
|
|
/* Create workspace */
|
|
my_stat->outvalues = (Datum *)MemoryContextAlloc(my_stat->cxt, natts * sizeof(Datum));
|
|
my_stat->tofree = (Datum *)MemoryContextAlloc(my_stat->cxt, natts * sizeof(Datum));
|
|
} else {
|
|
my_stat->pub.receiveSlot = tstoreReceiveSlot_notoast;
|
|
my_stat->outvalues = NULL;
|
|
my_stat->tofree = NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Receive a tuple from the executor and store it in the tuplestore.
|
|
* This is for the easy case where we don't have to detoast.
|
|
*/
|
|
static void tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
|
|
{
|
|
TStoreState *my_stat = (TStoreState *)self;
|
|
tuplestore_puttupleslot(my_stat->tstore, slot);
|
|
}
|
|
|
|
/*
|
|
* Receive a tuple from the executor and store it in the tuplestore.
|
|
* This is for the case where we have to detoast any toasted values.
|
|
*/
|
|
static void tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
|
|
{
|
|
TStoreState *my_stat = (TStoreState *)self;
|
|
TupleDesc typeinfo = slot->tts_tupleDescriptor;
|
|
Form_pg_attribute *attrs = typeinfo->attrs;
|
|
int natts = typeinfo->natts;
|
|
int nfree;
|
|
int i;
|
|
MemoryContext oldcxt;
|
|
|
|
/* Make sure the tuple is fully deconstructed */
|
|
slot_getallattrs(slot);
|
|
|
|
/*
|
|
* Fetch back any out-of-line datums. We build the new datums array in
|
|
* my_stat->outvalues[] (but we can re-use the slot's isnull array). Also,
|
|
* remember the fetched values to free afterwards.
|
|
*/
|
|
nfree = 0;
|
|
for (i = 0; i < natts; i++) {
|
|
Datum val = slot->tts_values[i];
|
|
|
|
if (!attrs[i]->attisdropped && attrs[i]->attlen == -1 && !slot->tts_isnull[i]) {
|
|
if (VARATT_IS_EXTERNAL(DatumGetPointer(val))) {
|
|
val = PointerGetDatum(heap_tuple_fetch_attr((struct varlena *)DatumGetPointer(val)));
|
|
my_stat->tofree[nfree++] = val;
|
|
}
|
|
}
|
|
|
|
my_stat->outvalues[i] = val;
|
|
}
|
|
|
|
/*
|
|
* Push the modified tuple into the tuplestore.
|
|
*/
|
|
oldcxt = MemoryContextSwitchTo(my_stat->cxt);
|
|
tuplestore_putvalues(my_stat->tstore, typeinfo, my_stat->outvalues, slot->tts_isnull);
|
|
(void)MemoryContextSwitchTo(oldcxt);
|
|
|
|
/* And release any temporary detoasted values */
|
|
for (i = 0; i < nfree; i++) {
|
|
pfree(DatumGetPointer(my_stat->tofree[i]));
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Clean up at end of an executor run
|
|
*/
|
|
static void tstoreShutdownReceiver(DestReceiver *self)
|
|
{
|
|
TStoreState *my_stat = (TStoreState *)self;
|
|
|
|
/* Release workspace if any */
|
|
if (my_stat->outvalues != NULL) {
|
|
pfree_ext(my_stat->outvalues);
|
|
}
|
|
|
|
my_stat->outvalues = NULL;
|
|
if (my_stat->tofree != NULL) {
|
|
pfree_ext(my_stat->tofree);
|
|
}
|
|
my_stat->tofree = NULL;
|
|
}
|
|
|
|
/*
|
|
* Destroy receiver when done with it
|
|
*/
|
|
static void tstoreDestroyReceiver(DestReceiver *self)
|
|
{
|
|
pfree_ext(self);
|
|
}
|
|
|
|
/*
|
|
* Initially create a DestReceiver object.
|
|
*/
|
|
DestReceiver *CreateTuplestoreDestReceiver(void)
|
|
{
|
|
TStoreState *self = (TStoreState *)palloc0(sizeof(TStoreState));
|
|
|
|
self->pub.receiveSlot = tstoreReceiveSlot_notoast; /* might change */
|
|
self->pub.rStartup = tstoreStartupReceiver;
|
|
self->pub.rShutdown = tstoreShutdownReceiver;
|
|
self->pub.rDestroy = tstoreDestroyReceiver;
|
|
self->pub.mydest = DestTuplestore;
|
|
|
|
/* private fields will be set by SetTuplestoreDestReceiverParams */
|
|
return (DestReceiver *)self;
|
|
}
|
|
|
|
/*
|
|
* Set parameters for a TuplestoreDestReceiver
|
|
*/
|
|
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast)
|
|
{
|
|
TStoreState *my_stat = (TStoreState *)self;
|
|
|
|
Assert(my_stat->pub.mydest == DestTuplestore);
|
|
my_stat->tstore = tStore;
|
|
my_stat->cxt = tContext;
|
|
my_stat->detoast = detoast;
|
|
}
|