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-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 *
2883 andres@anarazel.de 60 :CBC 34409 : 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 : 34409 : cleanTupType = ExecCleanTypeFromTL(targetList);
71 : :
72 : : /*
73 : : * Use the given slot, or make a new slot if we weren't given one.
74 : : */
7880 tgl@sss.pgh.pa.us 75 [ + - ]: 34409 : if (slot)
7423 76 : 34409 : ExecSetSlotDescriptor(slot, cleanTupType);
77 : : else
2888 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 : : */
8040 tgl@sss.pgh.pa.us 90 :CBC 34409 : cleanLength = cleanTupType->natts;
91 [ + - ]: 34409 : if (cleanLength > 0)
92 : : {
93 : : AttrNumber cleanResno;
94 : : ListCell *t;
95 : :
56 michael@paquier.xyz 96 :GNC 34409 : cleanMap = palloc_array(AttrNumber, cleanLength);
2177 tgl@sss.pgh.pa.us 97 :CBC 34409 : cleanResno = 0;
8040 98 [ + - + + : 127145 : foreach(t, targetList)
+ + ]
99 : : {
100 : 92736 : TargetEntry *tle = lfirst(t);
101 : :
7859 102 [ + + ]: 92736 : if (!tle->resjunk)
103 : : {
2177 104 : 73688 : cleanMap[cleanResno] = tle->resno;
8040 105 : 73688 : cleanResno++;
106 : : }
107 : : }
2177 108 [ - + ]: 34409 : Assert(cleanResno == cleanLength);
109 : : }
110 : : else
8040 tgl@sss.pgh.pa.us 111 :UBC 0 : cleanMap = NULL;
112 : :
113 : : /*
114 : : * Finally create and initialize the JunkFilter struct.
115 : : */
8040 tgl@sss.pgh.pa.us 116 :CBC 34409 : junkfilter = makeNode(JunkFilter);
117 : :
118 : 34409 : junkfilter->jf_targetList = targetList;
119 : 34409 : junkfilter->jf_cleanTupType = cleanTupType;
120 : 34409 : junkfilter->jf_cleanMap = cleanMap;
121 : 34409 : junkfilter->jf_resultSlot = slot;
122 : :
123 : 34409 : 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 : 1286 : 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 : : */
7880 150 [ + - ]: 1286 : if (slot)
7423 151 : 1286 : ExecSetSlotDescriptor(slot, cleanTupType);
152 : : else
2888 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 : : */
8040 tgl@sss.pgh.pa.us 165 :CBC 1286 : cleanLength = cleanTupType->natts;
10627 bruce@momjian.us 166 [ + - ]: 1286 : if (cleanLength > 0)
167 : : {
56 michael@paquier.xyz 168 :GNC 1286 : cleanMap = palloc0_array(AttrNumber, cleanLength);
8040 tgl@sss.pgh.pa.us 169 :CBC 1286 : t = list_head(targetList);
170 [ + + ]: 5719 : for (i = 0; i < cleanLength; i++)
171 : : {
661 drowley@postgresql.o 172 [ + + ]: 4433 : if (TupleDescCompactAttr(cleanTupType, i)->attisdropped)
8040 tgl@sss.pgh.pa.us 173 : 44 : continue; /* map entry is already zero */
174 : : for (;;)
10627 bruce@momjian.us 175 :UBC 0 : {
8040 tgl@sss.pgh.pa.us 176 :CBC 4389 : TargetEntry *tle = lfirst(t);
177 : :
2646 178 : 4389 : t = lnext(targetList, t);
7859 179 [ + - ]: 4389 : if (!tle->resjunk)
180 : : {
181 : 4389 : cleanMap[i] = tle->resno;
8040 182 : 4389 : break;
183 : : }
184 : : }
185 : : }
186 : : }
187 : : else
10627 bruce@momjian.us 188 :UBC 0 : cleanMap = NULL;
189 : :
190 : : /*
191 : : * Finally create and initialize the JunkFilter struct.
192 : : */
10627 bruce@momjian.us 193 :CBC 1286 : junkfilter = makeNode(JunkFilter);
194 : :
195 : 1286 : junkfilter->jf_targetList = targetList;
196 : 1286 : junkfilter->jf_cleanTupType = cleanTupType;
197 : 1286 : junkfilter->jf_cleanMap = cleanMap;
9269 tgl@sss.pgh.pa.us 198 : 1286 : junkfilter->jf_resultSlot = slot;
199 : :
10268 bruce@momjian.us 200 : 1286 : 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
7252 tgl@sss.pgh.pa.us 210 :UBC 0 : ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
211 : : {
5752 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
5752 tgl@sss.pgh.pa.us 222 :CBC 112138 : ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
223 : : {
224 : : ListCell *t;
225 : :
226 [ + + + + : 317358 : foreach(t, targetlist)
+ + ]
227 : : {
10626 bruce@momjian.us 228 : 235982 : TargetEntry *tle = lfirst(t);
229 : :
7859 tgl@sss.pgh.pa.us 230 [ + + + + ]: 235982 : if (tle->resjunk && tle->resname &&
231 [ + + ]: 57088 : (strcmp(tle->resname, attrName) == 0))
232 : : {
233 : : /* We found it ! */
7252 234 : 30762 : return tle->resno;
235 : : }
236 : : }
237 : :
238 : 81376 : return InvalidAttrNumber;
239 : : }
240 : :
241 : : /*
242 : : * ExecFilterJunk
243 : : *
244 : : * Construct and return a slot with all the junk attributes removed.
245 : : */
246 : : TupleTableSlot *
7880 247 : 292840 : 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 : 292840 : slot_getallattrs(slot);
263 : 292840 : old_values = slot->tts_values;
264 : 292840 : old_isnull = slot->tts_isnull;
265 : :
266 : : /*
267 : : * get info from the junk filter
268 : : */
9387 269 : 292840 : cleanTupType = junkfilter->jf_cleanTupType;
8040 270 : 292840 : cleanLength = cleanTupType->natts;
10627 bruce@momjian.us 271 : 292840 : cleanMap = junkfilter->jf_cleanMap;
7880 tgl@sss.pgh.pa.us 272 : 292840 : resultSlot = junkfilter->jf_resultSlot;
273 : :
274 : : /*
275 : : * Prepare to build a virtual result tuple.
276 : : */
277 : 292840 : ExecClearTuple(resultSlot);
278 : 292840 : values = resultSlot->tts_values;
279 : 292840 : isnull = resultSlot->tts_isnull;
280 : :
281 : : /*
282 : : * Transpose data into proper fields of the new tuple.
283 : : */
10627 bruce@momjian.us 284 [ + + ]: 982506 : for (i = 0; i < cleanLength; i++)
285 : : {
8040 tgl@sss.pgh.pa.us 286 : 689666 : int j = cleanMap[i];
287 : :
7880 288 [ + + ]: 689666 : if (j == 0)
289 : : {
290 : 80 : values[i] = (Datum) 0;
291 : 80 : isnull[i] = true;
292 : : }
293 : : else
294 : : {
295 : 689586 : values[i] = old_values[j - 1];
296 : 689586 : isnull[i] = old_isnull[j - 1];
297 : : }
298 : : }
299 : :
300 : : /*
301 : : * And return the virtual tuple.
302 : : */
303 : 292840 : return ExecStoreVirtualTuple(resultSlot);
304 : : }
|