Age Owner TLA Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * execJunk.c
4 : * Junk attribute support stuff....
5 : *
6 : * Portions Copyright (c) 1996-2023, 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; otherwise, we create one.
58 : */
59 : JunkFilter *
1601 andres 60 CBC 18174 : ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
61 : {
62 : JunkFilter *junkfilter;
63 : TupleDesc cleanTupType;
64 : int cleanLength;
65 : AttrNumber *cleanMap;
66 :
67 : /*
68 : * Compute the tuple descriptor for the cleaned tuple.
69 : */
70 18174 : cleanTupType = ExecCleanTypeFromTL(targetList);
71 :
72 : /*
73 : * Use the given slot, or make a new slot if we weren't given one.
74 : */
6598 tgl 75 18174 : if (slot)
6141 76 18174 : ExecSetSlotDescriptor(slot, cleanTupType);
77 : else
1606 andres 78 UBC 0 : slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
79 :
80 : /*
81 : * Now calculate the mapping between the original tuple's attributes and
82 : * the "clean" tuple's attributes.
83 : *
84 : * The "map" is an array of "cleanLength" attribute numbers, i.e. one
85 : * entry for every attribute of the "clean" tuple. The value of this entry
86 : * is the attribute number of the corresponding attribute of the
87 : * "original" tuple. (Zero indicates a NULL output attribute, but we do
88 : * not use that feature in this routine.)
89 : */
6758 tgl 90 CBC 18174 : cleanLength = cleanTupType->natts;
91 18174 : if (cleanLength > 0)
92 : {
93 : AttrNumber cleanResno;
94 : ListCell *t;
95 :
96 18138 : cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
895 97 18138 : cleanResno = 0;
6758 98 67899 : foreach(t, targetList)
99 : {
100 49761 : TargetEntry *tle = lfirst(t);
101 :
6577 102 49761 : if (!tle->resjunk)
103 : {
895 104 37229 : cleanMap[cleanResno] = tle->resno;
6758 105 37229 : cleanResno++;
106 : }
107 : }
895 108 18138 : Assert(cleanResno == cleanLength);
109 : }
110 : else
6758 111 36 : cleanMap = NULL;
112 :
113 : /*
114 : * Finally create and initialize the JunkFilter struct.
115 : */
116 18174 : junkfilter = makeNode(JunkFilter);
117 :
118 18174 : junkfilter->jf_targetList = targetList;
119 18174 : junkfilter->jf_cleanTupType = cleanTupType;
120 18174 : junkfilter->jf_cleanMap = cleanMap;
121 18174 : junkfilter->jf_resultSlot = slot;
122 :
123 18174 : return junkfilter;
124 : }
125 :
126 : /*
127 : * ExecInitJunkFilterConversion
128 : *
129 : * Initialize a JunkFilter for rowtype conversions.
130 : *
131 : * Here, we are given the target "clean" tuple descriptor rather than
132 : * inferring it from the targetlist. The target descriptor can contain
133 : * deleted columns. It is assumed that the caller has checked that the
134 : * non-deleted columns match up with the non-junk columns of the targetlist.
135 : */
136 : JunkFilter *
137 609 : ExecInitJunkFilterConversion(List *targetList,
138 : TupleDesc cleanTupType,
139 : TupleTableSlot *slot)
140 : {
141 : JunkFilter *junkfilter;
142 : int cleanLength;
143 : AttrNumber *cleanMap;
144 : ListCell *t;
145 : int i;
146 :
147 : /*
148 : * Use the given slot, or make a new slot if we weren't given one.
149 : */
6598 150 609 : if (slot)
6141 151 609 : ExecSetSlotDescriptor(slot, cleanTupType);
152 : else
1606 andres 153 UBC 0 : slot = MakeSingleTupleTableSlot(cleanTupType, &TTSOpsVirtual);
154 :
155 : /*
156 : * Calculate the mapping between the original tuple's attributes and the
157 : * "clean" tuple's attributes.
158 : *
159 : * The "map" is an array of "cleanLength" attribute numbers, i.e. one
160 : * entry for every attribute of the "clean" tuple. The value of this entry
161 : * is the attribute number of the corresponding attribute of the
162 : * "original" tuple. We store zero for any deleted attributes, marking
163 : * that a NULL is needed in the output tuple.
164 : */
6758 tgl 165 CBC 609 : cleanLength = cleanTupType->natts;
9345 bruce 166 609 : if (cleanLength > 0)
167 : {
6758 tgl 168 609 : cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber));
169 609 : t = list_head(targetList);
170 2216 : for (i = 0; i < cleanLength; i++)
171 : {
2058 andres 172 1607 : if (TupleDescAttr(cleanTupType, i)->attisdropped)
6758 tgl 173 33 : continue; /* map entry is already zero */
174 : for (;;)
9345 bruce 175 UBC 0 : {
6758 tgl 176 CBC 1574 : TargetEntry *tle = lfirst(t);
177 :
1364 178 1574 : t = lnext(targetList, t);
6577 179 1574 : if (!tle->resjunk)
180 : {
181 1574 : cleanMap[i] = tle->resno;
6758 182 1574 : break;
183 : }
184 : }
185 : }
186 : }
187 : else
9345 bruce 188 UBC 0 : cleanMap = NULL;
189 :
190 : /*
191 : * Finally create and initialize the JunkFilter struct.
192 : */
9345 bruce 193 CBC 609 : junkfilter = makeNode(JunkFilter);
194 :
195 609 : junkfilter->jf_targetList = targetList;
196 609 : junkfilter->jf_cleanTupType = cleanTupType;
197 609 : junkfilter->jf_cleanMap = cleanMap;
7987 tgl 198 609 : junkfilter->jf_resultSlot = slot;
199 :
8986 bruce 200 609 : return junkfilter;
201 : }
202 :
203 : /*
204 : * ExecFindJunkAttribute
205 : *
206 : * Locate the specified junk attribute in the junk filter's targetlist,
207 : * and return its resno. Returns InvalidAttrNumber if not found.
208 : */
209 : AttrNumber
5970 tgl 210 UBC 0 : ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
211 : {
4470 212 0 : return ExecFindJunkAttributeInTlist(junkfilter->jf_targetList, attrName);
213 : }
214 :
215 : /*
216 : * ExecFindJunkAttributeInTlist
217 : *
218 : * Find a junk attribute given a subplan's targetlist (not necessarily
219 : * part of a JunkFilter).
220 : */
221 : AttrNumber
4470 tgl 222 CBC 85750 : ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
223 : {
224 : ListCell *t;
225 :
226 288426 : foreach(t, targetlist)
227 : {
9344 bruce 228 223970 : TargetEntry *tle = lfirst(t);
229 :
6577 tgl 230 223970 : if (tle->resjunk && tle->resname &&
231 39759 : (strcmp(tle->resname, attrName) == 0))
232 : {
233 : /* We found it ! */
5970 234 21294 : return tle->resno;
235 : }
236 : }
237 :
238 64456 : return InvalidAttrNumber;
239 : }
240 :
241 : /*
242 : * ExecFilterJunk
243 : *
244 : * Construct and return a slot with all the junk attributes removed.
245 : */
246 : TupleTableSlot *
6598 247 205727 : ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
248 : {
249 : TupleTableSlot *resultSlot;
250 : AttrNumber *cleanMap;
251 : TupleDesc cleanTupType;
252 : int cleanLength;
253 : int i;
254 : Datum *values;
255 : bool *isnull;
256 : Datum *old_values;
257 : bool *old_isnull;
258 :
259 : /*
260 : * Extract all the values of the old tuple.
261 : */
262 205727 : slot_getallattrs(slot);
263 205727 : old_values = slot->tts_values;
264 205727 : old_isnull = slot->tts_isnull;
265 :
266 : /*
267 : * get info from the junk filter
268 : */
8105 269 205727 : cleanTupType = junkfilter->jf_cleanTupType;
6758 270 205727 : cleanLength = cleanTupType->natts;
9345 bruce 271 205727 : cleanMap = junkfilter->jf_cleanMap;
6598 tgl 272 205727 : resultSlot = junkfilter->jf_resultSlot;
273 :
274 : /*
275 : * Prepare to build a virtual result tuple.
276 : */
277 205727 : ExecClearTuple(resultSlot);
278 205727 : values = resultSlot->tts_values;
279 205727 : isnull = resultSlot->tts_isnull;
280 :
281 : /*
282 : * Transpose data into proper fields of the new tuple.
283 : */
9345 bruce 284 668158 : for (i = 0; i < cleanLength; i++)
285 : {
6758 tgl 286 462431 : int j = cleanMap[i];
287 :
6598 288 462431 : if (j == 0)
289 : {
290 60 : values[i] = (Datum) 0;
291 60 : isnull[i] = true;
292 : }
293 : else
294 : {
295 462371 : values[i] = old_values[j - 1];
296 462371 : isnull[i] = old_isnull[j - 1];
297 : }
298 : }
299 :
300 : /*
301 : * And return the virtual tuple.
302 : */
303 205727 : return ExecStoreVirtualTuple(resultSlot);
304 : }
|