tstoreReceiver.c 5.5 KB
Newer Older
B
Bruce Momjian 已提交
1 2
/*-------------------------------------------------------------------------
 *
3
 * tstoreReceiver.c
4 5 6 7 8 9
 *	  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.
B
Bruce Momjian 已提交
10 11
 *
 *
12
 * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
B
Bruce Momjian 已提交
13 14 15
 * Portions Copyright (c) 1994, Regents of the University of California
 *
 * IDENTIFICATION
16
 *	  $PostgreSQL: pgsql/src/backend/executor/tstoreReceiver.c,v 1.19.2.1 2008/12/01 17:06:27 tgl Exp $
B
Bruce Momjian 已提交
17 18 19 20 21 22
 *
 *-------------------------------------------------------------------------
 */

#include "postgres.h"

23 24
#include "access/heapam.h"
#include "access/tuptoaster.h"
B
Bruce Momjian 已提交
25
#include "executor/tstoreReceiver.h"
26

B
Bruce Momjian 已提交
27 28 29

typedef struct
{
B
Bruce Momjian 已提交
30
	DestReceiver pub;
31 32 33 34 35 36 37
	/* 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 */
38
} TStoreState;
B
Bruce Momjian 已提交
39

40

41 42 43 44
static void tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self);
static void tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self);


B
Bruce Momjian 已提交
45
/*
46
 * Prepare to receive tuples from executor.
B
Bruce Momjian 已提交
47 48
 */
static void
49
tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
B
Bruce Momjian 已提交
50
{
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87
	TStoreState *myState = (TStoreState *) self;
	bool		needtoast = false;
	Form_pg_attribute *attrs = typeinfo->attrs;
	int			natts = typeinfo->natts;
	int			i;

	/* Check if any columns require detoast work */
	if (myState->detoast)
	{
		for (i = 0; i < natts; i++)
		{
			if (attrs[i]->attisdropped)
				continue;
			if (attrs[i]->attlen == -1)
			{
				needtoast = true;
				break;
			}
		}
	}

	/* Set up appropriate callback */
	if (needtoast)
	{
		myState->pub.receiveSlot = tstoreReceiveSlot_detoast;
		/* Create workspace */
		myState->outvalues = (Datum *)
			MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
		myState->tofree = (Datum *)
			MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
	}
	else
	{
		myState->pub.receiveSlot = tstoreReceiveSlot_notoast;
		myState->outvalues = NULL;
		myState->tofree = NULL;
	}
B
Bruce Momjian 已提交
88 89
}

90 91
/*
 * Receive a tuple from the executor and store it in the tuplestore.
92
 * This is for the easy case where we don't have to detoast.
93
 */
B
Bruce Momjian 已提交
94
static void
95
tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
B
Bruce Momjian 已提交
96 97 98 99
{
	TStoreState *myState = (TStoreState *) self;
	MemoryContext oldcxt = MemoryContextSwitchTo(myState->cxt);

100
	tuplestore_puttupleslot(myState->tstore, slot);
B
Bruce Momjian 已提交
101 102 103 104

	MemoryContextSwitchTo(oldcxt);
}

105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163
/*
 * 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 *myState = (TStoreState *) self;
	TupleDesc	typeinfo = slot->tts_tupleDescriptor;
	Form_pg_attribute *attrs = typeinfo->attrs;
	int			natts = typeinfo->natts;
	int			nfree;
	int			i;
	HeapTuple	tuple;
	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
	 * myState->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)));
				myState->tofree[nfree++] = val;
			}
		}

		myState->outvalues[i] = val;
	}

	/*
	 * Push the modified tuple into the tuplestore.
	 */
	tuple = heap_form_tuple(typeinfo,
							myState->outvalues, slot->tts_isnull);
	oldcxt = MemoryContextSwitchTo(myState->cxt);
	tuplestore_puttuple(myState->tstore, tuple);
	MemoryContextSwitchTo(oldcxt);
	heap_freetuple(tuple);

	/* And release any temporary detoasted values */
	for (i = 0; i < nfree; i++)
		pfree(DatumGetPointer(myState->tofree[i]));
}

164
/*
165
 * Clean up at end of an executor run
166
 */
B
Bruce Momjian 已提交
167
static void
168
tstoreShutdownReceiver(DestReceiver *self)
B
Bruce Momjian 已提交
169
{
170 171 172 173 174 175 176 177 178
	TStoreState *myState = (TStoreState *) self;

	/* Release workspace if any */
	if (myState->outvalues)
		pfree(myState->outvalues);
	myState->outvalues = NULL;
	if (myState->tofree)
		pfree(myState->tofree);
	myState->tofree = NULL;
B
Bruce Momjian 已提交
179 180
}

181 182 183 184 185 186 187 188 189
/*
 * Destroy receiver when done with it
 */
static void
tstoreDestroyReceiver(DestReceiver *self)
{
	pfree(self);
}

190 191 192
/*
 * Initially create a DestReceiver object.
 */
B
Bruce Momjian 已提交
193
DestReceiver *
194 195
CreateTuplestoreDestReceiver(Tuplestorestate *tStore,
							 MemoryContext tContext)
B
Bruce Momjian 已提交
196
{
197
	TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
B
Bruce Momjian 已提交
198

199
	self->pub.receiveSlot = tstoreReceiveSlot_notoast;
200 201 202
	self->pub.rStartup = tstoreStartupReceiver;
	self->pub.rShutdown = tstoreShutdownReceiver;
	self->pub.rDestroy = tstoreDestroyReceiver;
203
	self->pub.mydest = DestTuplestore;
B
Bruce Momjian 已提交
204

205 206
	self->tstore = tStore;
	self->cxt = tContext;
207
	self->detoast = false;
B
Bruce Momjian 已提交
208 209 210

	return (DestReceiver *) self;
}
211 212 213 214 215 216 217 218 219 220 221 222 223

/*
 * Set parameters for a TuplestoreDestReceiver
 */
void
SetTuplestoreDestReceiverDeToast(DestReceiver *self,
								 bool detoast)
{
	TStoreState *myState = (TStoreState *) self;

	Assert(myState->pub.mydest == DestTuplestore);
	myState->detoast = detoast;
}