PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
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  Form_pg_attribute *attrs = typeinfo->attrs;
53  int natts = typeinfo->natts;
54  int i;
55 
56  /* Check if any columns require detoast work */
57  if (myState->detoast)
58  {
59  for (i = 0; i < natts; i++)
60  {
61  if (attrs[i]->attisdropped)
62  continue;
63  if (attrs[i]->attlen == -1)
64  {
65  needtoast = true;
66  break;
67  }
68  }
69  }
70 
71  /* Set up appropriate callback */
72  if (needtoast)
73  {
75  /* Create workspace */
76  myState->outvalues = (Datum *)
77  MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
78  myState->tofree = (Datum *)
79  MemoryContextAlloc(myState->cxt, natts * sizeof(Datum));
80  }
81  else
82  {
84  myState->outvalues = NULL;
85  myState->tofree = NULL;
86  }
87 }
88 
89 /*
90  * Receive a tuple from the executor and store it in the tuplestore.
91  * This is for the easy case where we don't have to detoast.
92  */
93 static bool
95 {
96  TStoreState *myState = (TStoreState *) self;
97 
98  tuplestore_puttupleslot(myState->tstore, slot);
99 
100  return true;
101 }
102 
103 /*
104  * Receive a tuple from the executor and store it in the tuplestore.
105  * This is for the case where we have to detoast any toasted values.
106  */
107 static bool
109 {
110  TStoreState *myState = (TStoreState *) self;
111  TupleDesc typeinfo = slot->tts_tupleDescriptor;
112  Form_pg_attribute *attrs = typeinfo->attrs;
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 
131  if (!attrs[i]->attisdropped &&
132  attrs[i]->attlen == -1 &&
133  !slot->tts_isnull[i])
134  {
136  {
138  DatumGetPointer(val)));
139  myState->tofree[nfree++] = val;
140  }
141  }
142 
143  myState->outvalues[i] = val;
144  }
145 
146  /*
147  * Push the modified tuple into the tuplestore.
148  */
149  oldcxt = MemoryContextSwitchTo(myState->cxt);
150  tuplestore_putvalues(myState->tstore, typeinfo,
151  myState->outvalues, slot->tts_isnull);
152  MemoryContextSwitchTo(oldcxt);
153 
154  /* And release any temporary detoasted values */
155  for (i = 0; i < nfree; i++)
156  pfree(DatumGetPointer(myState->tofree[i]));
157 
158  return true;
159 }
160 
161 /*
162  * Clean up at end of an executor run
163  */
164 static void
166 {
167  TStoreState *myState = (TStoreState *) self;
168 
169  /* Release workspace if any */
170  if (myState->outvalues)
171  pfree(myState->outvalues);
172  myState->outvalues = NULL;
173  if (myState->tofree)
174  pfree(myState->tofree);
175  myState->tofree = NULL;
176 }
177 
178 /*
179  * Destroy receiver when done with it
180  */
181 static void
183 {
184  pfree(self);
185 }
186 
187 /*
188  * Initially create a DestReceiver object.
189  */
190 DestReceiver *
192 {
193  TStoreState *self = (TStoreState *) palloc0(sizeof(TStoreState));
194 
195  self->pub.receiveSlot = tstoreReceiveSlot_notoast; /* might change */
196  self->pub.rStartup = tstoreStartupReceiver;
197  self->pub.rShutdown = tstoreShutdownReceiver;
198  self->pub.rDestroy = tstoreDestroyReceiver;
199  self->pub.mydest = DestTuplestore;
200 
201  /* private fields will be set by SetTuplestoreDestReceiverParams */
202 
203  return (DestReceiver *) self;
204 }
205 
206 /*
207  * Set parameters for a TuplestoreDestReceiver
208  */
209 void
211  Tuplestorestate *tStore,
212  MemoryContext tContext,
213  bool detoast)
214 {
215  TStoreState *myState = (TStoreState *) self;
216 
217  Assert(myState->pub.mydest == DestTuplestore);
218  myState->tstore = tStore;
219  myState->cxt = tContext;
220  myState->detoast = detoast;
221 }
void tuplestore_putvalues(Tuplestorestate *state, TupleDesc tdesc, Datum *values, bool *isnull)
Definition: tuplestore.c:750
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
MemoryContext cxt
CommandDest mydest
Definition: dest.h:128
void SetTuplestoreDestReceiverParams(DestReceiver *self, Tuplestorestate *tStore, MemoryContext tContext, bool detoast)
Form_pg_attribute * attrs
Definition: tupdesc.h:74
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Datum * tts_values
Definition: tuptable.h:125
DestReceiver pub
int natts
Definition: tupdesc.h:73
static bool tstoreReceiveSlot_notoast(TupleTableSlot *slot, DestReceiver *self)
#define VARATT_IS_EXTERNAL(PTR)
Definition: postgres.h:314
void pfree(void *pointer)
Definition: mcxt.c:950
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:1239
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:121
void * palloc0(Size size)
Definition: mcxt.c:878
uintptr_t Datum
Definition: postgres.h:372
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
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:707
Datum * outvalues
int i
bool(* receiveSlot)(TupleTableSlot *slot, DestReceiver *self)
Definition: dest.h:118
Definition: c.h:439
long val
Definition: informix.c:689