Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * execJunk.c
4 : : * Junk attribute support stuff....
5 : : *
6 : : * Portions Copyright (c) 1996-2024, 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 *
1972 andres@anarazel.de 60 :CBC 28681 : 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 : 28681 : cleanTupType = ExecCleanTypeFromTL(targetList);
71 : :
72 : : /*
73 : : * Use the given slot, or make a new slot if we weren't given one.
74 : : */
6969 tgl@sss.pgh.pa.us 75 [ + - ]: 28681 : if (slot)
6512 76 : 28681 : ExecSetSlotDescriptor(slot, cleanTupType);
77 : : else
1977 andres@anarazel.de 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 : : */
7129 tgl@sss.pgh.pa.us 90 :CBC 28681 : cleanLength = cleanTupType->natts;
91 [ + + ]: 28681 : if (cleanLength > 0)
92 : : {
93 : : AttrNumber cleanResno;
94 : : ListCell *t;
95 : :
96 : 28645 : cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
1266 97 : 28645 : cleanResno = 0;
7129 98 [ + - + + : 96072 : foreach(t, targetList)
+ + ]
99 : : {
100 : 67427 : TargetEntry *tle = lfirst(t);
101 : :
6948 102 [ + + ]: 67427 : if (!tle->resjunk)
103 : : {
1266 104 : 52859 : cleanMap[cleanResno] = tle->resno;
7129 105 : 52859 : cleanResno++;
106 : : }
107 : : }
1266 108 [ - + ]: 28645 : Assert(cleanResno == cleanLength);
109 : : }
110 : : else
7129 111 : 36 : cleanMap = NULL;
112 : :
113 : : /*
114 : : * Finally create and initialize the JunkFilter struct.
115 : : */
116 : 28681 : junkfilter = makeNode(JunkFilter);
117 : :
118 : 28681 : junkfilter->jf_targetList = targetList;
119 : 28681 : junkfilter->jf_cleanTupType = cleanTupType;
120 : 28681 : junkfilter->jf_cleanMap = cleanMap;
121 : 28681 : junkfilter->jf_resultSlot = slot;
122 : :
123 : 28681 : 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 : 618 : 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 : : */
6969 150 [ + - ]: 618 : if (slot)
6512 151 : 618 : ExecSetSlotDescriptor(slot, cleanTupType);
152 : : else
1977 andres@anarazel.de 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 : : */
7129 tgl@sss.pgh.pa.us 165 :CBC 618 : cleanLength = cleanTupType->natts;
9716 bruce@momjian.us 166 [ + - ]: 618 : if (cleanLength > 0)
167 : : {
7129 tgl@sss.pgh.pa.us 168 : 618 : cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber));
169 : 618 : t = list_head(targetList);
170 [ + + ]: 2246 : for (i = 0; i < cleanLength; i++)
171 : : {
2429 andres@anarazel.de 172 [ + + ]: 1628 : if (TupleDescAttr(cleanTupType, i)->attisdropped)
7129 tgl@sss.pgh.pa.us 173 : 33 : continue; /* map entry is already zero */
174 : : for (;;)
9716 bruce@momjian.us 175 :UBC 0 : {
7129 tgl@sss.pgh.pa.us 176 :CBC 1595 : TargetEntry *tle = lfirst(t);
177 : :
1735 178 : 1595 : t = lnext(targetList, t);
6948 179 [ + - ]: 1595 : if (!tle->resjunk)
180 : : {
181 : 1595 : cleanMap[i] = tle->resno;
7129 182 : 1595 : break;
183 : : }
184 : : }
185 : : }
186 : : }
187 : : else
9716 bruce@momjian.us 188 :UBC 0 : cleanMap = NULL;
189 : :
190 : : /*
191 : : * Finally create and initialize the JunkFilter struct.
192 : : */
9716 bruce@momjian.us 193 :CBC 618 : junkfilter = makeNode(JunkFilter);
194 : :
195 : 618 : junkfilter->jf_targetList = targetList;
196 : 618 : junkfilter->jf_cleanTupType = cleanTupType;
197 : 618 : junkfilter->jf_cleanMap = cleanMap;
8358 tgl@sss.pgh.pa.us 198 : 618 : junkfilter->jf_resultSlot = slot;
199 : :
9357 bruce@momjian.us 200 : 618 : 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
6341 tgl@sss.pgh.pa.us 210 :UBC 0 : ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
211 : : {
4841 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
4841 tgl@sss.pgh.pa.us 222 :CBC 77528 : ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
223 : : {
224 : : ListCell *t;
225 : :
226 [ + + + + : 215392 : foreach(t, targetlist)
+ + ]
227 : : {
9715 bruce@momjian.us 228 : 159981 : TargetEntry *tle = lfirst(t);
229 : :
6948 tgl@sss.pgh.pa.us 230 [ + + + + ]: 159981 : if (tle->resjunk && tle->resname &&
231 [ + + ]: 41462 : (strcmp(tle->resname, attrName) == 0))
232 : : {
233 : : /* We found it ! */
6341 234 : 22117 : return tle->resno;
235 : : }
236 : : }
237 : :
238 : 55411 : return InvalidAttrNumber;
239 : : }
240 : :
241 : : /*
242 : : * ExecFilterJunk
243 : : *
244 : : * Construct and return a slot with all the junk attributes removed.
245 : : */
246 : : TupleTableSlot *
6969 247 : 234607 : 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 : 234607 : slot_getallattrs(slot);
263 : 234607 : old_values = slot->tts_values;
264 : 234607 : old_isnull = slot->tts_isnull;
265 : :
266 : : /*
267 : : * get info from the junk filter
268 : : */
8476 269 : 234607 : cleanTupType = junkfilter->jf_cleanTupType;
7129 270 : 234607 : cleanLength = cleanTupType->natts;
9716 bruce@momjian.us 271 : 234607 : cleanMap = junkfilter->jf_cleanMap;
6969 tgl@sss.pgh.pa.us 272 : 234607 : resultSlot = junkfilter->jf_resultSlot;
273 : :
274 : : /*
275 : : * Prepare to build a virtual result tuple.
276 : : */
277 : 234607 : ExecClearTuple(resultSlot);
278 : 234607 : values = resultSlot->tts_values;
279 : 234607 : isnull = resultSlot->tts_isnull;
280 : :
281 : : /*
282 : : * Transpose data into proper fields of the new tuple.
283 : : */
9716 bruce@momjian.us 284 [ + + ]: 735840 : for (i = 0; i < cleanLength; i++)
285 : : {
7129 tgl@sss.pgh.pa.us 286 : 501233 : int j = cleanMap[i];
287 : :
6969 288 [ + + ]: 501233 : if (j == 0)
289 : : {
290 : 60 : values[i] = (Datum) 0;
291 : 60 : isnull[i] = true;
292 : : }
293 : : else
294 : : {
295 : 501173 : values[i] = old_values[j - 1];
296 : 501173 : isnull[i] = old_isnull[j - 1];
297 : : }
298 : : }
299 : :
300 : : /*
301 : : * And return the virtual tuple.
302 : : */
303 : 234607 : return ExecStoreVirtualTuple(resultSlot);
304 : : }
|