1 /*-------------------------------------------------------------------------
4 * Junk attribute support stuff....
6 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
13 *-------------------------------------------------------------------------
17 #include "executor/executor.h"
19 /*-------------------------------------------------------------------------
20 * XXX this stuff should be rewritten to take advantage
21 * of ExecProject() and the ProjectionInfo node.
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
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.
37 * When we initialize a plan we call ExecInitJunkFilter to create
38 * and store the appropriate information in the es_junkFilter attribute of
41 * We then execute the plan, treating the resjunk attributes like any others.
43 * Finally, when at the top level we get back a tuple, we can call
44 * ExecFindJunkAttribute/ExecGetJunkAttribute to retrieve the values of the
45 * junk attributes we are interested in, and ExecFilterJunk or ExecRemoveJunk
46 * to remove all the junk attributes from a tuple. This new "clean" tuple is
47 * then printed, replaced, deleted or inserted.
49 *-------------------------------------------------------------------------
55 * Initialize the Junk filter.
57 * The source targetlist is passed in. The output tuple descriptor is
58 * built from the non-junk tlist entries, plus the passed specification
59 * of whether to include room for an OID or not.
60 * An optional resultSlot can be passed as well.
63 ExecInitJunkFilter(List
*targetList
, bool hasoid
, TupleTableSlot
*slot
)
65 JunkFilter
*junkfilter
;
66 TupleDesc cleanTupType
;
70 AttrNumber cleanResno
;
73 * Compute the tuple descriptor for the cleaned tuple.
75 cleanTupType
= ExecCleanTypeFromTL(targetList
, hasoid
);
78 * Use the given slot, or make a new slot if we weren't given one.
81 ExecSetSlotDescriptor(slot
, cleanTupType
);
83 slot
= MakeSingleTupleTableSlot(cleanTupType
);
86 * Now calculate the mapping between the original tuple's attributes and
87 * the "clean" tuple's attributes.
89 * The "map" is an array of "cleanLength" attribute numbers, i.e. one
90 * entry for every attribute of the "clean" tuple. The value of this entry
91 * is the attribute number of the corresponding attribute of the
92 * "original" tuple. (Zero indicates a NULL output attribute, but we do
93 * not use that feature in this routine.)
95 cleanLength
= cleanTupType
->natts
;
98 cleanMap
= (AttrNumber
*) palloc(cleanLength
* sizeof(AttrNumber
));
100 foreach(t
, targetList
)
102 TargetEntry
*tle
= lfirst(t
);
106 cleanMap
[cleanResno
- 1] = tle
->resno
;
115 * Finally create and initialize the JunkFilter struct.
117 junkfilter
= makeNode(JunkFilter
);
119 junkfilter
->jf_targetList
= targetList
;
120 junkfilter
->jf_cleanTupType
= cleanTupType
;
121 junkfilter
->jf_cleanMap
= cleanMap
;
122 junkfilter
->jf_resultSlot
= slot
;
128 * ExecInitJunkFilterConversion
130 * Initialize a JunkFilter for rowtype conversions.
132 * Here, we are given the target "clean" tuple descriptor rather than
133 * inferring it from the targetlist. The target descriptor can contain
134 * deleted columns. It is assumed that the caller has checked that the
135 * non-deleted columns match up with the non-junk columns of the targetlist.
138 ExecInitJunkFilterConversion(List
*targetList
,
139 TupleDesc cleanTupType
,
140 TupleTableSlot
*slot
)
142 JunkFilter
*junkfilter
;
144 AttrNumber
*cleanMap
;
149 * Use the given slot, or make a new slot if we weren't given one.
152 ExecSetSlotDescriptor(slot
, cleanTupType
);
154 slot
= MakeSingleTupleTableSlot(cleanTupType
);
157 * Calculate the mapping between the original tuple's attributes and the
158 * "clean" tuple's attributes.
160 * The "map" is an array of "cleanLength" attribute numbers, i.e. one
161 * entry for every attribute of the "clean" tuple. The value of this entry
162 * is the attribute number of the corresponding attribute of the
163 * "original" tuple. We store zero for any deleted attributes, marking
164 * that a NULL is needed in the output tuple.
166 cleanLength
= cleanTupType
->natts
;
169 cleanMap
= (AttrNumber
*) palloc0(cleanLength
* sizeof(AttrNumber
));
170 t
= list_head(targetList
);
171 for (i
= 0; i
< cleanLength
; i
++)
173 if (cleanTupType
->attrs
[i
]->attisdropped
)
174 continue; /* map entry is already zero */
177 TargetEntry
*tle
= lfirst(t
);
182 cleanMap
[i
] = tle
->resno
;
192 * Finally create and initialize the JunkFilter struct.
194 junkfilter
= makeNode(JunkFilter
);
196 junkfilter
->jf_targetList
= targetList
;
197 junkfilter
->jf_cleanTupType
= cleanTupType
;
198 junkfilter
->jf_cleanMap
= cleanMap
;
199 junkfilter
->jf_resultSlot
= slot
;
205 * ExecFindJunkAttribute
207 * Locate the specified junk attribute in the junk filter's targetlist,
208 * and return its resno. Returns InvalidAttrNumber if not found.
211 ExecFindJunkAttribute(JunkFilter
*junkfilter
, const char *attrName
)
215 foreach(t
, junkfilter
->jf_targetList
)
217 TargetEntry
*tle
= lfirst(t
);
219 if (tle
->resjunk
&& tle
->resname
&&
220 (strcmp(tle
->resname
, attrName
) == 0))
227 return InvalidAttrNumber
;
231 * ExecGetJunkAttribute
233 * Given a junk filter's input tuple (slot) and a junk attribute's number
234 * previously found by ExecFindJunkAttribute, extract & return the value and
235 * isNull flag of the attribute.
238 ExecGetJunkAttribute(TupleTableSlot
*slot
, AttrNumber attno
,
243 return slot_getattr(slot
, attno
, isNull
);
249 * Construct and return a slot with all the junk attributes removed.
252 ExecFilterJunk(JunkFilter
*junkfilter
, TupleTableSlot
*slot
)
254 TupleTableSlot
*resultSlot
;
255 AttrNumber
*cleanMap
;
256 TupleDesc cleanTupType
;
265 * Extract all the values of the old tuple.
267 slot_getallattrs(slot
);
268 old_values
= slot
->tts_values
;
269 old_isnull
= slot
->tts_isnull
;
272 * get info from the junk filter
274 cleanTupType
= junkfilter
->jf_cleanTupType
;
275 cleanLength
= cleanTupType
->natts
;
276 cleanMap
= junkfilter
->jf_cleanMap
;
277 resultSlot
= junkfilter
->jf_resultSlot
;
280 * Prepare to build a virtual result tuple.
282 ExecClearTuple(resultSlot
);
283 values
= resultSlot
->tts_values
;
284 isnull
= resultSlot
->tts_isnull
;
287 * Transpose data into proper fields of the new tuple.
289 for (i
= 0; i
< cleanLength
; i
++)
295 values
[i
] = (Datum
) 0;
300 values
[i
] = old_values
[j
- 1];
301 isnull
[i
] = old_isnull
[j
- 1];
306 * And return the virtual tuple.
308 return ExecStoreVirtualTuple(resultSlot
);
314 * Convenience routine to generate a physical clean tuple,
315 * rather than just a virtual slot.
318 ExecRemoveJunk(JunkFilter
*junkfilter
, TupleTableSlot
*slot
)
320 return ExecCopySlotTuple(ExecFilterJunk(junkfilter
, slot
));