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-2025, 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 *
2482 andres@anarazel.de 60 :CBC 28794 : 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 : 28794 : cleanTupType = ExecCleanTypeFromTL(targetList);
71 : :
72 : : /*
73 : : * Use the given slot, or make a new slot if we weren't given one.
74 : : */
7479 tgl@sss.pgh.pa.us 75 [ + - ]: 28794 : if (slot)
7022 76 : 28794 : ExecSetSlotDescriptor(slot, cleanTupType);
77 : : else
2487 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 : : */
7639 tgl@sss.pgh.pa.us 90 :CBC 28794 : cleanLength = cleanTupType->natts;
91 [ + - ]: 28794 : if (cleanLength > 0)
92 : : {
93 : : AttrNumber cleanResno;
94 : : ListCell *t;
95 : :
96 : 28794 : cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
1776 97 : 28794 : cleanResno = 0;
7639 98 [ + - + + : 104057 : foreach(t, targetList)
+ + ]
99 : : {
100 : 75263 : TargetEntry *tle = lfirst(t);
101 : :
7458 102 [ + + ]: 75263 : if (!tle->resjunk)
103 : : {
1776 104 : 59103 : cleanMap[cleanResno] = tle->resno;
7639 105 : 59103 : cleanResno++;
106 : : }
107 : : }
1776 108 [ - + ]: 28794 : Assert(cleanResno == cleanLength);
109 : : }
110 : : else
7639 tgl@sss.pgh.pa.us 111 :UBC 0 : cleanMap = NULL;
112 : :
113 : : /*
114 : : * Finally create and initialize the JunkFilter struct.
115 : : */
7639 tgl@sss.pgh.pa.us 116 :CBC 28794 : junkfilter = makeNode(JunkFilter);
117 : :
118 : 28794 : junkfilter->jf_targetList = targetList;
119 : 28794 : junkfilter->jf_cleanTupType = cleanTupType;
120 : 28794 : junkfilter->jf_cleanMap = cleanMap;
121 : 28794 : junkfilter->jf_resultSlot = slot;
122 : :
123 : 28794 : 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 : 802 : 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 : : */
7479 150 [ + - ]: 802 : if (slot)
7022 151 : 802 : ExecSetSlotDescriptor(slot, cleanTupType);
152 : : else
2487 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 : : */
7639 tgl@sss.pgh.pa.us 165 :CBC 802 : cleanLength = cleanTupType->natts;
10226 bruce@momjian.us 166 [ + - ]: 802 : if (cleanLength > 0)
167 : : {
7639 tgl@sss.pgh.pa.us 168 : 802 : cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber));
169 : 802 : t = list_head(targetList);
170 [ + + ]: 2774 : for (i = 0; i < cleanLength; i++)
171 : : {
260 drowley@postgresql.o 172 [ + + ]: 1972 : if (TupleDescCompactAttr(cleanTupType, i)->attisdropped)
7639 tgl@sss.pgh.pa.us 173 : 33 : continue; /* map entry is already zero */
174 : : for (;;)
10226 bruce@momjian.us 175 :UBC 0 : {
7639 tgl@sss.pgh.pa.us 176 :CBC 1939 : TargetEntry *tle = lfirst(t);
177 : :
2245 178 : 1939 : t = lnext(targetList, t);
7458 179 [ + - ]: 1939 : if (!tle->resjunk)
180 : : {
181 : 1939 : cleanMap[i] = tle->resno;
7639 182 : 1939 : break;
183 : : }
184 : : }
185 : : }
186 : : }
187 : : else
10226 bruce@momjian.us 188 :UBC 0 : cleanMap = NULL;
189 : :
190 : : /*
191 : : * Finally create and initialize the JunkFilter struct.
192 : : */
10226 bruce@momjian.us 193 :CBC 802 : junkfilter = makeNode(JunkFilter);
194 : :
195 : 802 : junkfilter->jf_targetList = targetList;
196 : 802 : junkfilter->jf_cleanTupType = cleanTupType;
197 : 802 : junkfilter->jf_cleanMap = cleanMap;
8868 tgl@sss.pgh.pa.us 198 : 802 : junkfilter->jf_resultSlot = slot;
199 : :
9867 bruce@momjian.us 200 : 802 : 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
6851 tgl@sss.pgh.pa.us 210 :UBC 0 : ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
211 : : {
5351 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
5351 tgl@sss.pgh.pa.us 222 :CBC 77038 : ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
223 : : {
224 : : ListCell *t;
225 : :
226 [ + + + + : 216442 : foreach(t, targetlist)
+ + ]
227 : : {
10225 bruce@momjian.us 228 : 162384 : TargetEntry *tle = lfirst(t);
229 : :
7458 tgl@sss.pgh.pa.us 230 [ + + + + ]: 162384 : if (tle->resjunk && tle->resname &&
231 [ + + ]: 43227 : (strcmp(tle->resname, attrName) == 0))
232 : : {
233 : : /* We found it ! */
6851 234 : 22980 : return tle->resno;
235 : : }
236 : : }
237 : :
238 : 54058 : return InvalidAttrNumber;
239 : : }
240 : :
241 : : /*
242 : : * ExecFilterJunk
243 : : *
244 : : * Construct and return a slot with all the junk attributes removed.
245 : : */
246 : : TupleTableSlot *
7479 247 : 230134 : 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 : 230134 : slot_getallattrs(slot);
263 : 230134 : old_values = slot->tts_values;
264 : 230134 : old_isnull = slot->tts_isnull;
265 : :
266 : : /*
267 : : * get info from the junk filter
268 : : */
8986 269 : 230134 : cleanTupType = junkfilter->jf_cleanTupType;
7639 270 : 230134 : cleanLength = cleanTupType->natts;
10226 bruce@momjian.us 271 : 230134 : cleanMap = junkfilter->jf_cleanMap;
7479 tgl@sss.pgh.pa.us 272 : 230134 : resultSlot = junkfilter->jf_resultSlot;
273 : :
274 : : /*
275 : : * Prepare to build a virtual result tuple.
276 : : */
277 : 230134 : ExecClearTuple(resultSlot);
278 : 230134 : values = resultSlot->tts_values;
279 : 230134 : isnull = resultSlot->tts_isnull;
280 : :
281 : : /*
282 : : * Transpose data into proper fields of the new tuple.
283 : : */
10226 bruce@momjian.us 284 [ + + ]: 760657 : for (i = 0; i < cleanLength; i++)
285 : : {
7639 tgl@sss.pgh.pa.us 286 : 530523 : int j = cleanMap[i];
287 : :
7479 288 [ + + ]: 530523 : if (j == 0)
289 : : {
290 : 60 : values[i] = (Datum) 0;
291 : 60 : isnull[i] = true;
292 : : }
293 : : else
294 : : {
295 : 530463 : values[i] = old_values[j - 1];
296 : 530463 : isnull[i] = old_isnull[j - 1];
297 : : }
298 : : }
299 : :
300 : : /*
301 : : * And return the virtual tuple.
302 : : */
303 : 230134 : return ExecStoreVirtualTuple(resultSlot);
304 : : }
|