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