1 /*-------------------------------------------------------------------------
4 * Junk attribute support stuff....
6 * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.38 2004/01/07 18:56:26 neilc Exp $
13 *-------------------------------------------------------------------------
17 #include "access/heapam.h"
18 #include "executor/executor.h"
19 #include "nodes/makefuncs.h"
21 /*-------------------------------------------------------------------------
22 * XXX this stuff should be rewritten to take advantage
23 * of ExecProject() and the ProjectionInfo node.
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.
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.
38 * When we initialize a plan we call 'ExecInitJunkFilter' to create
39 * and store the appropriate information in the 'es_junkFilter' attribute of
42 * We then execute the plan ignoring the "resjunk" attributes.
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
50 *-------------------------------------------------------------------------
53 /*-------------------------------------------------------------------------
56 * Initialize the Junk filter.
58 * The initial targetlist and associated tuple descriptor are passed in.
59 * An optional resultSlot can be passed as well.
60 *-------------------------------------------------------------------------
63 ExecInitJunkFilter(List *targetList, TupleDesc tupType,
66 JunkFilter *junkfilter;
67 List *cleanTargetList;
70 TupleDesc cleanTupType;
76 AttrNumber cleanResno;
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...
85 cleanTargetList = NIL;
88 foreach(t, targetList)
90 TargetEntry *rtarget = lfirst(t);
92 resdom = rtarget->resdom;
94 resjunk = resdom->resjunk;
98 * make a copy of the resdom node, changing its resno.
100 cleanResdom = (Resdom *) copyObject(resdom);
101 cleanResdom->resno = cleanResno;
105 * create a new target list entry
107 tle = makeTargetEntry(cleanResdom, expr);
108 cleanTargetList = lappend(cleanTargetList, tle);
113 * Now calculate the tuple type for the cleaned tuple (we were already
114 * given the type for the original targetlist).
116 cleanTupType = ExecTypeFromTL(cleanTargetList, tupType->tdhasoid);
118 len = ExecTargetListLength(targetList);
119 cleanLength = ExecTargetListLength(cleanTargetList);
122 * Now calculate the "map" between the original tuple's attributes and
123 * the "clean" tuple's attributes.
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
132 cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
134 foreach(t, targetList)
136 TargetEntry *tle = lfirst(t);
138 resdom = tle->resdom;
139 resjunk = resdom->resjunk;
142 cleanMap[cleanResno - 1] = resdom->resno;
151 * Finally create and initialize the JunkFilter struct.
153 junkfilter = makeNode(JunkFilter);
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;
165 ExecSetSlotDescriptor(slot, cleanTupType, false);
170 /*-------------------------------------------------------------------------
171 * ExecGetJunkAttribute
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.
176 * It returns false iff no junk attribute with such name was found.
177 *-------------------------------------------------------------------------
180 ExecGetJunkAttribute(JunkFilter *junkfilter,
181 TupleTableSlot *slot,
193 * first look in the junkfilter's target list for an attribute with
196 resno = InvalidAttrNumber;
197 targetList = junkfilter->jf_targetList;
199 foreach(t, targetList)
201 TargetEntry *tle = lfirst(t);
202 Resdom *resdom = tle->resdom;
204 if (resdom->resjunk && resdom->resname &&
205 (strcmp(resdom->resname, attrName) == 0))
208 resno = resdom->resno;
213 if (resno == InvalidAttrNumber)
215 /* Ooops! We couldn't find this attribute... */
220 * Now extract the attribute value from the tuple.
223 tupType = junkfilter->jf_tupType;
225 *value = heap_getattr(tuple, resno, tupType, isNull);
230 /*-------------------------------------------------------------------------
233 * Construct and return a tuple with all the junk attributes removed.
235 * Note: for historical reasons, this does not store the constructed
236 * tuple into the junkfilter's resultSlot. The caller should do that
238 *-------------------------------------------------------------------------
241 ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
244 HeapTuple cleanTuple;
245 AttrNumber *cleanMap;
246 TupleDesc cleanTupType;
253 Datum values_array[64];
254 char nulls_array[64];
257 * get info from the slot and the junk filter
261 tupType = junkfilter->jf_tupType;
262 cleanTupType = junkfilter->jf_cleanTupType;
263 cleanLength = junkfilter->jf_cleanLength;
264 cleanMap = junkfilter->jf_cleanMap;
267 * Handle the trivial case first.
269 if (cleanLength == 0)
273 * Create the arrays that will hold the attribute values and the null
274 * information for the new "clean" tuple.
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
280 if (cleanLength > 64)
282 values = (Datum *) palloc(cleanLength * sizeof(Datum));
283 nulls = (char *) palloc(cleanLength * sizeof(char));
287 values = values_array;
292 * Exctract one by one all the values of the "clean" tuple.
294 for (i = 0; i < cleanLength; i++)
296 values[i] = heap_getattr(tuple, cleanMap[i], tupType, &isNull);
305 * Now form the new tuple.
307 cleanTuple = heap_formtuple(cleanTupType,
312 * We are done. Free any space allocated for 'values' and 'nulls' and
313 * return the new tuple.
315 if (cleanLength > 64)