Branch data Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * execJunk.c
4 : : * Junk attribute support stuff....
5 : : *
6 : : * Portions Copyright (c) 1996-2026, 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 *
60 : 408033 : ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
61 : : {
62 : 408033 : JunkFilter *junkfilter;
63 : 408033 : TupleDesc cleanTupType;
64 : 408033 : int cleanLength;
65 : 408033 : AttrNumber *cleanMap;
66 : :
67 : : /*
68 : : * Compute the tuple descriptor for the cleaned tuple.
69 : : */
70 : 408033 : cleanTupType = ExecCleanTypeFromTL(targetList);
71 : :
72 : : /*
73 : : * Use the given slot, or make a new slot if we weren't given one.
74 : : */
75 [ + - ]: 408033 : if (slot)
76 : 408033 : ExecSetSlotDescriptor(slot, cleanTupType);
77 : : else
78 : 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 : : */
90 : 408033 : cleanLength = cleanTupType->natts;
91 [ + - ]: 408033 : if (cleanLength > 0)
92 : : {
93 : 408033 : AttrNumber cleanResno;
94 : 408033 : ListCell *t;
95 : :
96 : 408033 : cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
97 : 408033 : cleanResno = 0;
98 [ + - + + : 1228634 : foreach(t, targetList)
+ + ]
99 : : {
100 : 820601 : TargetEntry *tle = lfirst(t);
101 : :
102 [ + + ]: 820601 : if (!tle->resjunk)
103 : : {
104 : 416283 : cleanMap[cleanResno] = tle->resno;
105 : 416283 : cleanResno++;
106 : 416283 : }
107 : 820601 : }
108 [ + - ]: 408033 : Assert(cleanResno == cleanLength);
109 : 408033 : }
110 : : else
111 : 0 : cleanMap = NULL;
112 : :
113 : : /*
114 : : * Finally create and initialize the JunkFilter struct.
115 : : */
116 : 408033 : junkfilter = makeNode(JunkFilter);
117 : :
118 : 408033 : junkfilter->jf_targetList = targetList;
119 : 408033 : junkfilter->jf_cleanTupType = cleanTupType;
120 : 408033 : junkfilter->jf_cleanMap = cleanMap;
121 : 408033 : junkfilter->jf_resultSlot = slot;
122 : :
123 : 816066 : return junkfilter;
124 : 408033 : }
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 : 253 : ExecInitJunkFilterConversion(List *targetList,
138 : : TupleDesc cleanTupType,
139 : : TupleTableSlot *slot)
140 : : {
141 : 253 : JunkFilter *junkfilter;
142 : 253 : int cleanLength;
143 : 253 : AttrNumber *cleanMap;
144 : 253 : ListCell *t;
145 : 253 : int i;
146 : :
147 : : /*
148 : : * Use the given slot, or make a new slot if we weren't given one.
149 : : */
150 [ + - ]: 253 : if (slot)
151 : 253 : ExecSetSlotDescriptor(slot, cleanTupType);
152 : : else
153 : 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 : : */
165 : 253 : cleanLength = cleanTupType->natts;
166 [ + - ]: 253 : if (cleanLength > 0)
167 : : {
168 : 253 : cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber));
169 : 253 : t = list_head(targetList);
170 [ + + ]: 860 : for (i = 0; i < cleanLength; i++)
171 : : {
172 [ + + ]: 607 : if (TupleDescCompactAttr(cleanTupType, i)->attisdropped)
173 : 11 : continue; /* map entry is already zero */
174 : 596 : for (;;)
175 : : {
176 : 596 : TargetEntry *tle = lfirst(t);
177 : :
178 : 596 : t = lnext(targetList, t);
179 [ - + ]: 596 : if (!tle->resjunk)
180 : : {
181 : 596 : cleanMap[i] = tle->resno;
182 : 596 : break;
183 : : }
184 [ - - + ]: 596 : }
185 : 596 : }
186 : 253 : }
187 : : else
188 : 0 : cleanMap = NULL;
189 : :
190 : : /*
191 : : * Finally create and initialize the JunkFilter struct.
192 : : */
193 : 253 : junkfilter = makeNode(JunkFilter);
194 : :
195 : 253 : junkfilter->jf_targetList = targetList;
196 : 253 : junkfilter->jf_cleanTupType = cleanTupType;
197 : 253 : junkfilter->jf_cleanMap = cleanMap;
198 : 253 : junkfilter->jf_resultSlot = slot;
199 : :
200 : 506 : return junkfilter;
201 : 253 : }
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
210 : 0 : ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
211 : : {
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
222 : 415212 : ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
223 : : {
224 : 415212 : ListCell *t;
225 : :
226 [ + + + + : 1246825 : foreach(t, targetlist)
+ + + + ]
227 : : {
228 : 831613 : TargetEntry *tle = lfirst(t);
229 : :
230 [ + + + + : 831613 : if (tle->resjunk && tle->resname &&
+ + ]
231 : 410393 : (strcmp(tle->resname, attrName) == 0))
232 : : {
233 : : /* We found it ! */
234 : 405468 : return tle->resno;
235 : : }
236 [ + + ]: 831613 : }
237 : :
238 : 9744 : return InvalidAttrNumber;
239 : 415212 : }
240 : :
241 : : /*
242 : : * ExecFilterJunk
243 : : *
244 : : * Construct and return a slot with all the junk attributes removed.
245 : : */
246 : : TupleTableSlot *
247 : 460890 : ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
248 : : {
249 : 460890 : TupleTableSlot *resultSlot;
250 : 460890 : AttrNumber *cleanMap;
251 : 460890 : TupleDesc cleanTupType;
252 : 460890 : int cleanLength;
253 : 460890 : int i;
254 : 460890 : Datum *values;
255 : 460890 : bool *isnull;
256 : 460890 : Datum *old_values;
257 : 460890 : bool *old_isnull;
258 : :
259 : : /*
260 : : * Extract all the values of the old tuple.
261 : : */
262 : 460890 : slot_getallattrs(slot);
263 : 460890 : old_values = slot->tts_values;
264 : 460890 : old_isnull = slot->tts_isnull;
265 : :
266 : : /*
267 : : * get info from the junk filter
268 : : */
269 : 460890 : cleanTupType = junkfilter->jf_cleanTupType;
270 : 460890 : cleanLength = cleanTupType->natts;
271 : 460890 : cleanMap = junkfilter->jf_cleanMap;
272 : 460890 : resultSlot = junkfilter->jf_resultSlot;
273 : :
274 : : /*
275 : : * Prepare to build a virtual result tuple.
276 : : */
277 : 460890 : ExecClearTuple(resultSlot);
278 : 460890 : values = resultSlot->tts_values;
279 : 460890 : isnull = resultSlot->tts_isnull;
280 : :
281 : : /*
282 : : * Transpose data into proper fields of the new tuple.
283 : : */
284 [ + + ]: 1003720 : for (i = 0; i < cleanLength; i++)
285 : : {
286 : 542830 : int j = cleanMap[i];
287 : :
288 [ + + ]: 542830 : if (j == 0)
289 : : {
290 : 20 : values[i] = (Datum) 0;
291 : 20 : isnull[i] = true;
292 : 20 : }
293 : : else
294 : : {
295 : 542810 : values[i] = old_values[j - 1];
296 : 542810 : isnull[i] = old_isnull[j - 1];
297 : : }
298 : 542830 : }
299 : :
300 : : /*
301 : : * And return the virtual tuple.
302 : : */
303 : 921780 : return ExecStoreVirtualTuple(resultSlot);
304 : 460890 : }
|