PostgreSQL Source Code git master
execJunk.c
Go to the documentation of this file.
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 */
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 cleanTupType = ExecCleanTypeFromTL(targetList);
71
72 /*
73 * Use the given slot, or make a new slot if we weren't given one.
74 */
75 if (slot)
76 ExecSetSlotDescriptor(slot, cleanTupType);
77 else
78 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 */
90 cleanLength = cleanTupType->natts;
91 if (cleanLength > 0)
92 {
93 AttrNumber cleanResno;
94 ListCell *t;
95
96 cleanMap = (AttrNumber *) palloc(cleanLength * sizeof(AttrNumber));
97 cleanResno = 0;
98 foreach(t, targetList)
99 {
100 TargetEntry *tle = lfirst(t);
101
102 if (!tle->resjunk)
103 {
104 cleanMap[cleanResno] = tle->resno;
105 cleanResno++;
106 }
107 }
108 Assert(cleanResno == cleanLength);
109 }
110 else
111 cleanMap = NULL;
112
113 /*
114 * Finally create and initialize the JunkFilter struct.
115 */
116 junkfilter = makeNode(JunkFilter);
117
118 junkfilter->jf_targetList = targetList;
119 junkfilter->jf_cleanTupType = cleanTupType;
120 junkfilter->jf_cleanMap = cleanMap;
121 junkfilter->jf_resultSlot = slot;
122
123 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 */
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 */
150 if (slot)
151 ExecSetSlotDescriptor(slot, cleanTupType);
152 else
153 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 */
165 cleanLength = cleanTupType->natts;
166 if (cleanLength > 0)
167 {
168 cleanMap = (AttrNumber *) palloc0(cleanLength * sizeof(AttrNumber));
169 t = list_head(targetList);
170 for (i = 0; i < cleanLength; i++)
171 {
172 if (TupleDescCompactAttr(cleanTupType, i)->attisdropped)
173 continue; /* map entry is already zero */
174 for (;;)
175 {
176 TargetEntry *tle = lfirst(t);
177
178 t = lnext(targetList, t);
179 if (!tle->resjunk)
180 {
181 cleanMap[i] = tle->resno;
182 break;
183 }
184 }
185 }
186 }
187 else
188 cleanMap = NULL;
189
190 /*
191 * Finally create and initialize the JunkFilter struct.
192 */
193 junkfilter = makeNode(JunkFilter);
194
195 junkfilter->jf_targetList = targetList;
196 junkfilter->jf_cleanTupType = cleanTupType;
197 junkfilter->jf_cleanMap = cleanMap;
198 junkfilter->jf_resultSlot = slot;
199
200 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 */
210ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
211{
212 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 */
222ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
223{
224 ListCell *t;
225
226 foreach(t, targetlist)
227 {
228 TargetEntry *tle = lfirst(t);
229
230 if (tle->resjunk && tle->resname &&
231 (strcmp(tle->resname, attrName) == 0))
232 {
233 /* We found it ! */
234 return tle->resno;
235 }
236 }
237
238 return InvalidAttrNumber;
239}
240
241/*
242 * ExecFilterJunk
243 *
244 * Construct and return a slot with all the junk attributes removed.
245 */
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 slot_getallattrs(slot);
263 old_values = slot->tts_values;
264 old_isnull = slot->tts_isnull;
265
266 /*
267 * get info from the junk filter
268 */
269 cleanTupType = junkfilter->jf_cleanTupType;
270 cleanLength = cleanTupType->natts;
271 cleanMap = junkfilter->jf_cleanMap;
272 resultSlot = junkfilter->jf_resultSlot;
273
274 /*
275 * Prepare to build a virtual result tuple.
276 */
277 ExecClearTuple(resultSlot);
278 values = resultSlot->tts_values;
279 isnull = resultSlot->tts_isnull;
280
281 /*
282 * Transpose data into proper fields of the new tuple.
283 */
284 for (i = 0; i < cleanLength; i++)
285 {
286 int j = cleanMap[i];
287
288 if (j == 0)
289 {
290 values[i] = (Datum) 0;
291 isnull[i] = true;
292 }
293 else
294 {
295 values[i] = old_values[j - 1];
296 isnull[i] = old_isnull[j - 1];
297 }
298 }
299
300 /*
301 * And return the virtual tuple.
302 */
303 return ExecStoreVirtualTuple(resultSlot);
304}
int16 AttrNumber
Definition: attnum.h:21
#define InvalidAttrNumber
Definition: attnum.h:23
static Datum values[MAXATTR]
Definition: bootstrap.c:151
JunkFilter * ExecInitJunkFilterConversion(List *targetList, TupleDesc cleanTupType, TupleTableSlot *slot)
Definition: execJunk.c:137
TupleTableSlot * ExecFilterJunk(JunkFilter *junkfilter, TupleTableSlot *slot)
Definition: execJunk.c:247
AttrNumber ExecFindJunkAttributeInTlist(List *targetlist, const char *attrName)
Definition: execJunk.c:222
JunkFilter * ExecInitJunkFilter(List *targetList, TupleTableSlot *slot)
Definition: execJunk.c:60
AttrNumber ExecFindJunkAttribute(JunkFilter *junkfilter, const char *attrName)
Definition: execJunk.c:210
TupleTableSlot * MakeSingleTupleTableSlot(TupleDesc tupdesc, const TupleTableSlotOps *tts_ops)
Definition: execTuples.c:1425
const TupleTableSlotOps TTSOpsVirtual
Definition: execTuples.c:84
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1739
TupleDesc ExecCleanTypeFromTL(List *targetList)
Definition: execTuples.c:2137
void ExecSetSlotDescriptor(TupleTableSlot *slot, TupleDesc tupdesc)
Definition: execTuples.c:1476
Assert(PointerIsAligned(start, uint64))
int j
Definition: isn.c:75
int i
Definition: isn.c:74
void * palloc0(Size size)
Definition: mcxt.c:1347
void * palloc(Size size)
Definition: mcxt.c:1317
#define makeNode(_type_)
Definition: nodes.h:157
#define lfirst(lc)
Definition: pg_list.h:172
static ListCell * list_head(const List *l)
Definition: pg_list.h:128
static ListCell * lnext(const List *l, const ListCell *c)
Definition: pg_list.h:343
uintptr_t Datum
Definition: postgres.h:69
TupleDesc jf_cleanTupType
Definition: execnodes.h:414
TupleTableSlot * jf_resultSlot
Definition: execnodes.h:416
AttrNumber * jf_cleanMap
Definition: execnodes.h:415
List * jf_targetList
Definition: execnodes.h:413
Definition: pg_list.h:54
AttrNumber resno
Definition: primnodes.h:2221
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:169
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:368