]> granicus.if.org Git - postgresql/blob - src/backend/executor/execJunk.c
Rename SortMem and VacuumMem to work_mem and maintenance_work_mem.
[postgresql] / src / backend / executor / execJunk.c
1 /*-------------------------------------------------------------------------
2  *
3  * junk.c
4  *        Junk attribute support stuff....
5  *
6  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.38 2004/01/07 18:56:26 neilc Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/heapam.h"
18 #include "executor/executor.h"
19 #include "nodes/makefuncs.h"
20
21 /*-------------------------------------------------------------------------
22  *              XXX this stuff should be rewritten to take advantage
23  *                      of ExecProject() and the ProjectionInfo node.
24  *                      -cim 6/3/91
25  *
26  * An attribute of a tuple living inside the executor, can be
27  * either a normal attribute or a "junk" attribute. "junk" attributes
28  * never make it out of the executor, i.e. they are never printed,
29  * returned or stored in disk. Their only purpose in life is to
30  * store some information useful only to the executor, mainly the values
31  * of some system attributes like "ctid" or rule locks.
32  *
33  * The general idea is the following: A target list consists of a list of
34  * Resdom nodes & expression pairs. Each Resdom node has an attribute
35  * called 'resjunk'. If the value of this attribute is true then the
36  * corresponding attribute is a "junk" attribute.
37  *
38  * When we initialize a plan we call 'ExecInitJunkFilter' to create
39  * and store the appropriate information in the 'es_junkFilter' attribute of
40  * EState.
41  *
42  * We then execute the plan ignoring the "resjunk" attributes.
43  *
44  * Finally, when at the top level we get back a tuple, we can call
45  * 'ExecGetJunkAttribute' to retrieve the value of the junk attributes we
46  * are interested in, and 'ExecRemoveJunk' to remove all the junk attributes
47  * from a tuple. This new "clean" tuple is then printed, replaced, deleted
48  * or inserted.
49  *
50  *-------------------------------------------------------------------------
51  */
52
53 /*-------------------------------------------------------------------------
54  * ExecInitJunkFilter
55  *
56  * Initialize the Junk filter.
57  *
58  * The initial targetlist and associated tuple descriptor are passed in.
59  * An optional resultSlot can be passed as well.
60  *-------------------------------------------------------------------------
61  */
62 JunkFilter *
63 ExecInitJunkFilter(List *targetList, TupleDesc tupType,
64                                    TupleTableSlot *slot)
65 {
66         JunkFilter *junkfilter;
67         List       *cleanTargetList;
68         int                     len,
69                                 cleanLength;
70         TupleDesc       cleanTupType;
71         List       *t;
72         TargetEntry *tle;
73         Resdom     *resdom,
74                            *cleanResdom;
75         bool            resjunk;
76         AttrNumber      cleanResno;
77         AttrNumber *cleanMap;
78         Expr       *expr;
79
80         /*
81          * First find the "clean" target list, i.e. all the entries in the
82          * original target list which have a false 'resjunk' NOTE: make copy
83          * of the Resdom nodes, because we have to change the 'resno's...
84          */
85         cleanTargetList = NIL;
86         cleanResno = 1;
87
88         foreach(t, targetList)
89         {
90                 TargetEntry *rtarget = lfirst(t);
91
92                 resdom = rtarget->resdom;
93                 expr = rtarget->expr;
94                 resjunk = resdom->resjunk;
95                 if (!resjunk)
96                 {
97                         /*
98                          * make a copy of the resdom node, changing its resno.
99                          */
100                         cleanResdom = (Resdom *) copyObject(resdom);
101                         cleanResdom->resno = cleanResno;
102                         cleanResno++;
103
104                         /*
105                          * create a new target list entry
106                          */
107                         tle = makeTargetEntry(cleanResdom, expr);
108                         cleanTargetList = lappend(cleanTargetList, tle);
109                 }
110         }
111
112         /*
113          * Now calculate the tuple type for the cleaned tuple (we were already
114          * given the type for the original targetlist).
115          */
116         cleanTupType = ExecTypeFromTL(cleanTargetList, tupType->tdhasoid);
117
118         len = ExecTargetListLength(targetList);
119         cleanLength = ExecTargetListLength(cleanTargetList);
120
121         /*
122          * Now calculate the "map" between the original tuple's attributes and
123          * the "clean" tuple's attributes.
124          *
125          * The "map" is an array of "cleanLength" attribute numbers, i.e. one
126          * entry for every attribute of the "clean" tuple. The value of this
127          * entry is the attribute number of the corresponding attribute of the
128          * "original" tuple.
129          */
130         if (cleanLength > 0)
131         {
132                 cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
133                 cleanResno = 1;
134                 foreach(t, targetList)
135                 {
136                         TargetEntry *tle = lfirst(t);
137
138                         resdom = tle->resdom;
139                         resjunk = resdom->resjunk;
140                         if (!resjunk)
141                         {
142                                 cleanMap[cleanResno - 1] = resdom->resno;
143                                 cleanResno++;
144                         }
145                 }
146         }
147         else
148                 cleanMap = NULL;
149
150         /*
151          * Finally create and initialize the JunkFilter struct.
152          */
153         junkfilter = makeNode(JunkFilter);
154
155         junkfilter->jf_targetList = targetList;
156         junkfilter->jf_length = len;
157         junkfilter->jf_tupType = tupType;
158         junkfilter->jf_cleanTargetList = cleanTargetList;
159         junkfilter->jf_cleanLength = cleanLength;
160         junkfilter->jf_cleanTupType = cleanTupType;
161         junkfilter->jf_cleanMap = cleanMap;
162         junkfilter->jf_resultSlot = slot;
163
164         if (slot)
165                 ExecSetSlotDescriptor(slot, cleanTupType, false);
166
167         return junkfilter;
168 }
169
170 /*-------------------------------------------------------------------------
171  * ExecGetJunkAttribute
172  *
173  * Given a tuple (slot), the junk filter and a junk attribute's name,
174  * extract & return the value and isNull flag of this attribute.
175  *
176  * It returns false iff no junk attribute with such name was found.
177  *-------------------------------------------------------------------------
178  */
179 bool
180 ExecGetJunkAttribute(JunkFilter *junkfilter,
181                                          TupleTableSlot *slot,
182                                          char *attrName,
183                                          Datum *value,
184                                          bool *isNull)
185 {
186         List       *targetList;
187         List       *t;
188         AttrNumber      resno;
189         TupleDesc       tupType;
190         HeapTuple       tuple;
191
192         /*
193          * first look in the junkfilter's target list for an attribute with
194          * the given name
195          */
196         resno = InvalidAttrNumber;
197         targetList = junkfilter->jf_targetList;
198
199         foreach(t, targetList)
200         {
201                 TargetEntry *tle = lfirst(t);
202                 Resdom     *resdom = tle->resdom;
203
204                 if (resdom->resjunk && resdom->resname &&
205                         (strcmp(resdom->resname, attrName) == 0))
206                 {
207                         /* We found it ! */
208                         resno = resdom->resno;
209                         break;
210                 }
211         }
212
213         if (resno == InvalidAttrNumber)
214         {
215                 /* Ooops! We couldn't find this attribute... */
216                 return false;
217         }
218
219         /*
220          * Now extract the attribute value from the tuple.
221          */
222         tuple = slot->val;
223         tupType = junkfilter->jf_tupType;
224
225         *value = heap_getattr(tuple, resno, tupType, isNull);
226
227         return true;
228 }
229
230 /*-------------------------------------------------------------------------
231  * ExecRemoveJunk
232  *
233  * Construct and return a tuple with all the junk attributes removed.
234  *
235  * Note: for historical reasons, this does not store the constructed
236  * tuple into the junkfilter's resultSlot.  The caller should do that
237  * if it wants to.
238  *-------------------------------------------------------------------------
239  */
240 HeapTuple
241 ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
242 {
243         HeapTuple       tuple;
244         HeapTuple       cleanTuple;
245         AttrNumber *cleanMap;
246         TupleDesc       cleanTupType;
247         TupleDesc       tupType;
248         int                     cleanLength;
249         bool            isNull;
250         int                     i;
251         Datum      *values;
252         char       *nulls;
253         Datum           values_array[64];
254         char            nulls_array[64];
255
256         /*
257          * get info from the slot and the junk filter
258          */
259         tuple = slot->val;
260
261         tupType = junkfilter->jf_tupType;
262         cleanTupType = junkfilter->jf_cleanTupType;
263         cleanLength = junkfilter->jf_cleanLength;
264         cleanMap = junkfilter->jf_cleanMap;
265
266         /*
267          * Handle the trivial case first.
268          */
269         if (cleanLength == 0)
270                 return NULL;
271
272         /*
273          * Create the arrays that will hold the attribute values and the null
274          * information for the new "clean" tuple.
275          *
276          * Note: we use memory on the stack to optimize things when we are
277          * dealing with a small number of attributes. for large tuples we just
278          * use palloc.
279          */
280         if (cleanLength > 64)
281         {
282                 values = (Datum *) palloc(cleanLength * sizeof(Datum));
283                 nulls = (char *) palloc(cleanLength * sizeof(char));
284         }
285         else
286         {
287                 values = values_array;
288                 nulls = nulls_array;
289         }
290
291         /*
292          * Exctract one by one all the values of the "clean" tuple.
293          */
294         for (i = 0; i < cleanLength; i++)
295         {
296                 values[i] = heap_getattr(tuple, cleanMap[i], tupType, &isNull);
297
298                 if (isNull)
299                         nulls[i] = 'n';
300                 else
301                         nulls[i] = ' ';
302         }
303
304         /*
305          * Now form the new tuple.
306          */
307         cleanTuple = heap_formtuple(cleanTupType,
308                                                                 values,
309                                                                 nulls);
310
311         /*
312          * We are done.  Free any space allocated for 'values' and 'nulls' and
313          * return the new tuple.
314          */
315         if (cleanLength > 64)
316         {
317                 pfree(values);
318                 pfree(nulls);
319         }
320
321         return cleanTuple;
322 }