PostgreSQL Source Code  git master
execJunk.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * execJunk.c
4  * Junk attribute support stuff....
5  *
6  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/executor/execJunk.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "executor/executor.h"
18 
19 /*-------------------------------------------------------------------------
20  * XXX this stuff should be rewritten to take advantage
21  * of ExecProject() and the ProjectionInfo node.
22  * -cim 6/3/91
23  *
24  * An attribute of a tuple living inside the executor, can be
25  * either a normal attribute or a "junk" attribute. "junk" attributes
26  * never make it out of the executor, i.e. they are never printed,
27  * returned or stored on disk. Their only purpose in life is to
28  * store some information useful only to the executor, mainly the values
29  * of system attributes like "ctid", or sort key columns that are not to
30  * be output.
31  *
32  * The general idea is the following: A target list consists of a list of
33  * TargetEntry nodes containing expressions. Each TargetEntry has a field
34  * called 'resjunk'. If the value of this field is true then the
35  * corresponding attribute is a "junk" attribute.
36  *
37  * When we initialize a plan we call ExecInitJunkFilter to create a filter.
38  *
39  * We then execute the plan, treating the resjunk attributes like any others.
40  *
41  * Finally, when at the top level we get back a tuple, we can call
42  * ExecFindJunkAttribute/ExecGetJunkAttribute to retrieve the values of the
43  * junk attributes we are interested in, and ExecFilterJunk to remove all the
44  * junk attributes from a tuple. This new "clean" tuple is then printed,
45  * inserted, or updated.
46  *
47  *-------------------------------------------------------------------------
48  */
49 
50 /*
51  * ExecInitJunkFilter
52  *
53  * Initialize the Junk filter.
54  *
55  * The source targetlist is passed in. The output tuple descriptor is
56  * built from the non-junk tlist entries.
57  * An optional resultSlot can be passed as well.
58  */
59 JunkFilter *
61 {
62  JunkFilter *junkfilter;
63  TupleDesc cleanTupType;
64  int cleanLength;
65  AttrNumber *cleanMap;
66  ListCell *t;
67  AttrNumber cleanResno;
68 
69  /*
70  * Compute the tuple descriptor for the cleaned tuple.
71  */
72  cleanTupType = ExecCleanTypeFromTL(targetList);
73 
74  /*
75  * Use the given slot, or make a new slot if we weren't given one.
76  */
77  if (slot)
78  ExecSetSlotDescriptor(slot, cleanTupType);
79  else
80  slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
81 
82  /*
83  * Now calculate the mapping between the original tuple's attributes and
84  * the "clean" tuple's attributes.
85  *
86  * The "map" is an array of "cleanLength" attribute numbers, i.e. one
87  * entry for every attribute of the "clean" tuple. The value of this entry
88  * is the attribute number of the corresponding attribute of the
89  * "original" tuple. (Zero indicates a NULL output attribute, but we do
90  * not use that feature in this routine.)
91  */
92  cleanLength = cleanTupType->natts;
93  if (cleanLength > 0)
94  {
95  cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
96  cleanResno = 1;
97  foreach(t, targetList)
98  {
99  TargetEntry *tle = lfirst(t);
100 
101  if (!tle->resjunk)
102  {
103  cleanMap[cleanResno - 1] = tle->resno;
104  cleanResno++;
105  }
106  }
107  }
108  else
109  cleanMap = NULL;
110 
111  /*
112  * Finally create and initialize the JunkFilter struct.
113  */
114  junkfilter = makeNode(JunkFilter);
115 
116  junkfilter->jf_targetList = targetList;
117  junkfilter->jf_cleanTupType = cleanTupType;
118  junkfilter->jf_cleanMap = cleanMap;
119  junkfilter->jf_resultSlot = slot;
120 
121  return junkfilter;
122 }
123 
124 /*
125  * ExecInitJunkFilterConversion
126  *
127  * Initialize a JunkFilter for rowtype conversions.
128  *
129  * Here, we are given the target "clean" tuple descriptor rather than
130  * inferring it from the targetlist. The target descriptor can contain
131  * deleted columns. It is assumed that the caller has checked that the
132  * non-deleted columns match up with the non-junk columns of the targetlist.
133  */
134 JunkFilter *
136  TupleDesc cleanTupType,
137  TupleTableSlot *slot)
138 {
139  JunkFilter *junkfilter;
140  int cleanLength;
141  AttrNumber *cleanMap;
142  ListCell *t;
143  int i;
144 
145  /*
146  * Use the given slot, or make a new slot if we weren't given one.
147  */
148  if (slot)
149  ExecSetSlotDescriptor(slot, cleanTupType);
150  else
151  slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
152 
153  /*
154  * Calculate the mapping between the original tuple's attributes and the
155  * "clean" tuple's attributes.
156  *
157  * The "map" is an array of "cleanLength" attribute numbers, i.e. one
158  * entry for every attribute of the "clean" tuple. The value of this entry
159  * is the attribute number of the corresponding attribute of the
160  * "original" tuple. We store zero for any deleted attributes, marking
161  * that a NULL is needed in the output tuple.
162  */
163  cleanLength = cleanTupType->natts;
164  if (cleanLength > 0)
165  {
166  cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber));
167  t = list_head(targetList);
168  for (i = 0; i < cleanLength; i++)
169  {
170  if (TupleDescAttr(cleanTupType, i)->attisdropped)
171  continue; /* map entry is already zero */
172  for (;;)
173  {
174  TargetEntry *tle = lfirst(t);
175 
176  t = lnext(targetList, t);
177  if (!tle->resjunk)
178  {
179  cleanMap[i] = tle->resno;
180  break;
181  }
182  }
183  }
184  }
185  else
186  cleanMap = NULL;
187 
188  /*
189  * Finally create and initialize the JunkFilter struct.
190  */
191  junkfilter = makeNode(JunkFilter);
192 
193  junkfilter->jf_targetList = targetList;
194  junkfilter->jf_cleanTupType = cleanTupType;
195  junkfilter->jf_cleanMap = cleanMap;
196  junkfilter->jf_resultSlot = slot;
197 
198  return junkfilter;
199 }
200 
201 /*
202  * ExecFindJunkAttribute
203  *
204  * Locate the specified junk attribute in the junk filter's targetlist,
205  * and return its resno. Returns InvalidAttrNumber if not found.
206  */
208 ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
209 {
210  return ExecFindJunkAttributeInTlist(junkfilter->jf_targetList, attrName);
211 }
212 
213 /*
214  * ExecFindJunkAttributeInTlist
215  *
216  * Find a junk attribute given a subplan's targetlist (not necessarily
217  * part of a JunkFilter).
218  */
220 ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
221 {
222  ListCell *t;
223 
224  foreach(t, targetlist)
225  {
226  TargetEntry *tle = lfirst(t);
227 
228  if (tle->resjunk && tle->resname &&
229  (strcmp(tle->resname, attrName) == 0))
230  {
231  /* We found it ! */
232  return tle->resno;
233  }
234  }
235 
236  return InvalidAttrNumber;
237 }
238 
239 /*
240  * ExecGetJunkAttribute
241  *
242  * Given a junk filter's input tuple (slot) and a junk attribute's number
243  * previously found by ExecFindJunkAttribute, extract & return the value and
244  * isNull flag of the attribute.
245  */
246 Datum
248  bool *isNull)
249 {
250  Assert(attno > 0);
251 
252  return slot_getattr(slot, attno, isNull);
253 }
254 
255 /*
256  * ExecFilterJunk
257  *
258  * Construct and return a slot with all the junk attributes removed.
259  */
262 {
263  TupleTableSlot *resultSlot;
264  AttrNumber *cleanMap;
265  TupleDesc cleanTupType;
266  int cleanLength;
267  int i;
268  Datum *values;
269  bool *isnull;
270  Datum *old_values;
271  bool *old_isnull;
272 
273  /*
274  * Extract all the values of the old tuple.
275  */
276  slot_getallattrs(slot);
277  old_values = slot->tts_values;
278  old_isnull = slot->tts_isnull;
279 
280  /*
281  * get info from the junk filter
282  */
283  cleanTupType = junkfilter->jf_cleanTupType;
284  cleanLength = cleanTupType->natts;
285  cleanMap = junkfilter->jf_cleanMap;
286  resultSlot = junkfilter->jf_resultSlot;
287 
288  /*
289  * Prepare to build a virtual result tuple.
290  */
291  ExecClearTuple(resultSlot);
292  values = resultSlot->tts_values;
293  isnull = resultSlot->tts_isnull;
294 
295  /*
296  * Transpose data into proper fields of the new tuple.
297  */
298  for (i = 0; i < cleanLength; i++)
299  {
300  int j = cleanMap[i];
301 
302  if (j == 0)
303  {
304  values[i] = (Datum) 0;
305  isnull[i] = true;
306  }
307  else
308  {
309  values[i] = old_values[j - 1];
310  isnull[i] = old_isnull[j - 1];
311  }
312  }
313 
314  /*
315  * And return the virtual tuple.
316  */
317  return ExecStoreVirtualTuple(resultSlot);
318 }
AttrNumber * jf_cleanMap
Definition: execnodes.h:368
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:321
TupleDesc ExecCleanTypeFromTL(List *targetList)
Definition: execTuples.c:1920
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition: execJunk.c:220
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1208
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:208
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
JunkFilter * ExecInitJunkFilterConversion(List *targetList, TupleDesc cleanTupType, TupleTableSlot *slot)
Definition: execJunk.c:135
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:83
List * jf_targetList
Definition: execnodes.h:366
TupleTableSlot * jf_resultSlot
Definition: execnodes.h:369
Datum * tts_values
Definition: tuptable.h:126
char * resname
Definition: primnodes.h:1395
bool resjunk
Definition: primnodes.h:1400
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
bool * tts_isnull
Definition: tuptable.h:128
TupleDesc jf_cleanTupType
Definition: execnodes.h:367
AttrNumber resno
Definition: primnodes.h:1394
static ListCell * list_head(const List *l)
Definition: pg_list.h:125
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:261
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:1259
static Datum slot_getattr(TupleTableSlot *slot, int attnum, bool *isnull)
Definition: tuptable.h:381
#define makeNode(_type_)
Definition: nodes.h:573
#define Assert(condition)
Definition: c.h:739
#define lfirst(lc)
Definition: pg_list.h:190
#define InvalidAttrNumber
Definition: attnum.h:23
static Datum values[MAXATTR]
Definition: bootstrap.c:167
void * palloc(Size size)
Definition: mcxt.c:949
Datum ExecGetJunkAttribute(TupleTableSlot *slot, AttrNumber attno, bool *isNull)
Definition: execJunk.c:247
int i
Definition: pg_list.h:50
int16 AttrNumber
Definition: attnum.h:21
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522