PostgreSQL Source Code  git master
tstoreReceiver.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * tstoreReceiver.c
4  * An implementation of DestReceiver that stores the result tuples in
5  * a Tuplestore.
6  *
7  * Optionally, we can force detoasting (but not decompression) of out-of-line
8  * toasted values. This is to support cursors WITH HOLD, which must retain
9  * data even if the underlying table is dropped.
10  *
11  *
12  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
13  * Portions Copyright (c) 1994, Regents of the University of California
14  *
15  * IDENTIFICATION
16  * src/backend/executor/tstoreReceiver.c
17  *
18  *-------------------------------------------------------------------------
19  */
20 
21 #include "postgres.h"
22 
23 #include "access/tuptoaster.h"
25 
26 
27 typedef struct
28 {
30  /* parameters: */
31  Tuplestorestate *tstore; /* where to put the data */
32  MemoryContext cxt; /* context containing tstore */
33  bool detoast; /* were we told to detoast? */
34  /* workspace: */
35  Datum *outvalues; /* values array for result tuple */
36  Datum *tofree; /* temp values to be pfree'd */
37 } TStoreState;
38 
39 
40 static bool tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self);
41 static bool tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self);
42 
43 
44 /*
45  * Prepare to receive tuples from executor.
46  */
47 static void
48 tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
49 {
50  TStoreState *myState = (TStoreState *) self;
51  bool needtoast = false;
52  int natts = typeinfo->natts;
53  int i;
54 
55  /* Check if any columns require detoast work */
56  if (myState->detoast)
57  {
58  for (i = 0; i < natts; i++)
59  {
60  Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
61 
62  if (attr->attisdropped)
63  continue;
64  if (attr->attlen == -1)
65  {
66  needtoast = true;
67  break;
68  }
69  }
70  }
71 
72  /* Set up appropriate callback */
73  if (needtoast)
74  {
76  /* Create workspace */
77  myState->outvalues = (Datum *)
78  MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
79  myState->tofree = (Datum *)
80  MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
81  }
82  else
83  {
85  myState->outvalues = NULL;
86  myState->tofree = NULL;
87  }
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  */
94 static bool
96 {
97  TStoreState *myState = (TStoreState *) self;
98 
99  tuplestore_puttupleslot(myState->tstore, slot);
100 
101  return true;
102 }
103 
104 /*
105  * Receive a tuple from the executor and store it in the tuplestore.
106  * This is for the case where we have to detoast any toasted values.
107  */
108 static bool
110 {
111  TStoreState *myState = (TStoreState *) self;
112  TupleDesc typeinfo = slot->tts_tupleDescriptor;
113  int natts = typeinfo->natts;
114  int nfree;
115  int i;
116  MemoryContext oldcxt;
117 
118  /* Make sure the tuple is fully deconstructed */
119  slot_getallattrs(slot);
120 
121  /*
122  * Fetch back any out-of-line datums. We build the new datums array in
123  * myState->outvalues[] (but we can re-use the slot's isnull array). Also,
124  * remember the fetched values to free afterwards.
125  */
126  nfree = 0;
127  for (i = 0; i < natts; i++)
128  {
129  Datum val = slot->tts_values[i];
130  Form_pg_attribute attr = TupleDescAttr(typeinfo, i);
131 
132  if (!attr->attisdropped && attr->attlen == -1 && !slot->tts_isnull[i])
133  {
135  {
137  DatumGetPointer(val)));
138  myState->tofree[nfree++] = val;
139  }
140  }
141 
142  myState->outvalues[i] = val;
143  }
144 
145  /*
146  * Push the modified tuple into the tuplestore.
147  */
148  oldcxt = MemoryContextSwitchTo(myState->cxt);
149  tuplestore_putvalues(myState->tstore, typeinfo,
150  myState->outvalues, slot->tts_isnull);
151  MemoryContextSwitchTo(oldcxt);
152 
153  /* And release any temporary detoasted values */
154  for (i = 0; i < nfree; i++)
155  pfree(DatumGetPointer(myState->tofree[i]));
156 
157  return true;
158 }
159 
160 /*
161  * Clean up at end of an executor run
162  */
163 static void
165 {
166  TStoreState *myState = (TStoreState *) self;
167 
168  /* Release workspace if any */
169  if (myState->outvalues)
170  pfree(myState->outvalues);
171  myState->outvalues = NULL;
172  if (myState->tofree)
173  pfree(myState->tofree);
174  myState->tofree = NULL;
175 }
176 
177 /*
178  * Destroy receiver when done with it
179  */
180 static void
182 {
183  pfree(self);
184 }
185 
186 /*
187  * Initially create a DestReceiver object.
188  */
189 DestReceiver *
191 {
192  TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
193 
194  self->pub.receiveSlot = tstoreReceiveSlot_notoast; /* might change */
195  self->pub.rStartup = tstoreStartupReceiver;
196  self->pub.rShutdown = tstoreShutdownReceiver;
197  self->pub.rDestroy = tstoreDestroyReceiver;
198  self->pub.mydest = DestTuplestore;
199 
200  /* private fields will be set by SetTuplestoreDestReceiverParams */
201 
202  return (DestReceiver *) self;
203 }
204 
205 /*
206  * Set parameters for a TuplestoreDestReceiver
207  */
208 void
210  Tuplestorestate *tStore,
211  MemoryContext tContext,
212  bool detoast)
213 {
214  TStoreState *myState = (TStoreState *) self;
215 
216  Assert(myState->pub.mydest == DestTuplestore);
217  myState->tstore = tStore;
218  myState->cxt = tContext;
219  myState->detoast = detoast;
220 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
Definition: dest.h:118
void tuplestore_puttupleslot(Tuplestorestate *state, TupleTableSlot *slot)
Definition: tuplestore.c:708
static void tstoreShutdownReceiver(DestReceiver *self)
Datum * tofree
#define PointerGetDatum(X)
Definition: postgres.h:562
struct varlena * heap_tuple_fetch_attr(struct varlena *attr)
Definition: tuptoaster.c:101
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:90
MemoryContext cxt
CommandDest mydest
Definition: dest.h:128
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast)
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Datum * tts_values
Definition: tuptable.h:125
DestReceiver pub
int natts
Definition: tupdesc.h:79
static bool tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:314
void pfree(void *pointer)
Definition: mcxt.c:936
Tuplestorestate * tstore
bool * tts_isnull
Definition: tuptable.h:126
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
static void tstoreStartupReceiver(DestReceiver *self, int operation, TupleDesc typeinfo)
void slot_getallattrs(TupleTableSlot *slot)
Definition: heaptuple.c:1238
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
void * palloc0(Size size)
Definition: mcxt.c:864
uintptr_t Datum
Definition: postgres.h:372
#define Assert(condition)
Definition: c.h:680
static bool tstoreReceiveSlot_detoast(TupleTableSlot *slot, DestReceiver *self)
#define DatumGetPointer(X)
Definition: postgres.h:555
DestReceiver * CreateTuplestoreDestReceiver(void)
static void tstoreDestroyReceiver(DestReceiver *self)
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:693
Datum * outvalues
int i
Definition: c.h:497
long val
Definition: informix.c:689