tstoreReceiver.c 5.6 KB
Newer Older
B
Bruce Momjian 已提交
1 2
/*-------------------------------------------------------------------------
 *
3
 * tstoreReceiver.c
4 5
 *	  An implementation of DestReceiver that stores the result tuples in
 *	  a Tuplestore.
B
Bruce Momjian 已提交
6
 *
7 8 9
 * 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.2 2009/12/29 17:41:18 heikki 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
{
	TStoreState *myState = (TStoreState *) self;

99
	tuplestore_puttupleslot(myState->tstore, slot);
B
Bruce Momjian 已提交
100 101
}

102 103 104 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
/*
 * 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;
	bool        *nulls;
	
	nulls = (bool *)MemoryContextAlloc(myState->cxt, natts * sizeof(bool));

	/* 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;
		bool         isnull;
		
		val = slot_getattr(slot,i+1,&isnull);

		if (!attrs[i]->attisdropped &&
			attrs[i]->attlen == -1 &&
			!slot_attisnull(slot,i+1))
		{
			if (VARATT_IS_EXTERNAL(DatumGetPointer(val)))
			{
				val = PointerGetDatum(heap_tuple_fetch_attr(
144
										  (struct varlena *) DatumGetPointer(val)));
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167
				myState->tofree[nfree++] = val;
			}
		}

		myState->outvalues[i] = val;
		nulls[i] = isnull;
	}

	/*
	 * Push the modified tuple into the tuplestore.
	 */
	tuple = heap_form_tuple(typeinfo,
							myState->outvalues, nulls);
	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]));
}

168
/*
169
 * Clean up at end of an executor run
170
 */
B
Bruce Momjian 已提交
171
static void
172
tstoreShutdownReceiver(DestReceiver *self)
B
Bruce Momjian 已提交
173
{
174 175 176 177 178 179 180 181 182
	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 已提交
183 184
}

185 186 187 188 189 190 191 192 193
/*
 * Destroy receiver when done with it
 */
static void
tstoreDestroyReceiver(DestReceiver *self)
{
	pfree(self);
}

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

203
	self->pub.receiveSlot = tstoreReceiveSlot_notoast;
204 205 206
	self->pub.rStartup = tstoreStartupReceiver;
	self->pub.rShutdown = tstoreShutdownReceiver;
	self->pub.rDestroy = tstoreDestroyReceiver;
207
	self->pub.mydest = DestTuplestore;
B
Bruce Momjian 已提交
208

209 210
	self->tstore = tStore;
	self->cxt = tContext;
211
	self->detoast = false;
B
Bruce Momjian 已提交
212 213 214

	return (DestReceiver *) self;
}
215 216 217 218 219 220 221 222 223 224 225 226 227

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

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