PostgreSQL Source Code git master
tupconvert.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * tupconvert.c
4 * Tuple conversion support.
5 *
6 * These functions provide conversion between rowtypes that are logically
7 * equivalent but might have columns in a different order or different sets of
8 * dropped columns.
9 *
10 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
11 * Portions Copyright (c) 1994, Regents of the University of California
12 *
13 *
14 * IDENTIFICATION
15 * src/backend/access/common/tupconvert.c
16 *
17 *-------------------------------------------------------------------------
18 */
19#include "postgres.h"
20
21#include "access/tupconvert.h"
22#include "executor/tuptable.h"
23
24
25/*
26 * The conversion setup routines have the following common API:
27 *
28 * The setup routine checks using attmap.c whether the given source and
29 * destination tuple descriptors are logically compatible. If not, it throws
30 * an error. If so, it returns NULL if they are physically compatible (ie, no
31 * conversion is needed), else a TupleConversionMap that can be used by
32 * execute_attr_map_tuple or execute_attr_map_slot to perform the conversion.
33 *
34 * The TupleConversionMap, if needed, is palloc'd in the caller's memory
35 * context. Also, the given tuple descriptors are referenced by the map,
36 * so they must survive as long as the map is needed.
37 *
38 * The caller must supply a suitable primary error message to be used if
39 * a compatibility error is thrown. Recommended coding practice is to use
40 * gettext_noop() on this string, so that it is translatable but won't
41 * actually be translated unless the error gets thrown.
42 *
43 *
44 * Implementation notes:
45 *
46 * The key component of a TupleConversionMap is an attrMap[] array with
47 * one entry per output column. This entry contains the 1-based index of
48 * the corresponding input column, or zero to force a NULL value (for
49 * a dropped output column). The TupleConversionMap also contains workspace
50 * arrays.
51 */
52
53
54/*
55 * Set up for tuple conversion, matching input and output columns by
56 * position. (Dropped columns are ignored in both input and output.)
57 */
60 TupleDesc outdesc,
61 const char *msg)
62{
64 int n;
65 AttrMap *attrMap;
66
67 /* Verify compatibility and prepare attribute-number map */
68 attrMap = build_attrmap_by_position(indesc, outdesc, msg);
69
70 if (attrMap == NULL)
71 {
72 /* runtime conversion is not needed */
73 return NULL;
74 }
75
76 /* Prepare the map structure */
78 map->indesc = indesc;
79 map->outdesc = outdesc;
80 map->attrMap = attrMap;
81 /* preallocate workspace for Datum arrays */
82 n = outdesc->natts + 1; /* +1 for NULL */
83 map->outvalues = (Datum *) palloc(n * sizeof(Datum));
84 map->outisnull = (bool *) palloc(n * sizeof(bool));
85 n = indesc->natts + 1; /* +1 for NULL */
86 map->invalues = (Datum *) palloc(n * sizeof(Datum));
87 map->inisnull = (bool *) palloc(n * sizeof(bool));
88 map->invalues[0] = (Datum) 0; /* set up the NULL entry */
89 map->inisnull[0] = true;
90
91 return map;
92}
93
94/*
95 * Set up for tuple conversion, matching input and output columns by name.
96 * (Dropped columns are ignored in both input and output.) This is intended
97 * for use when the rowtypes are related by inheritance, so we expect an exact
98 * match of both type and typmod. The error messages will be a bit unhelpful
99 * unless both rowtypes are named composite types.
100 */
103 TupleDesc outdesc)
104{
105 AttrMap *attrMap;
106
107 /* Verify compatibility and prepare attribute-number map */
108 attrMap = build_attrmap_by_name_if_req(indesc, outdesc, false);
109
110 if (attrMap == NULL)
111 {
112 /* runtime conversion is not needed */
113 return NULL;
114 }
115
116 return convert_tuples_by_name_attrmap(indesc, outdesc, attrMap);
117}
118
119/*
120 * Set up tuple conversion for input and output TupleDescs using the given
121 * AttrMap.
122 */
125 TupleDesc outdesc,
126 AttrMap *attrMap)
127{
128 int n = outdesc->natts;
130
131 Assert(attrMap != NULL);
132
133 /* Prepare the map structure */
135 map->indesc = indesc;
136 map->outdesc = outdesc;
137 map->attrMap = attrMap;
138 /* preallocate workspace for Datum arrays */
139 map->outvalues = (Datum *) palloc(n * sizeof(Datum));
140 map->outisnull = (bool *) palloc(n * sizeof(bool));
141 n = indesc->natts + 1; /* +1 for NULL */
142 map->invalues = (Datum *) palloc(n * sizeof(Datum));
143 map->inisnull = (bool *) palloc(n * sizeof(bool));
144 map->invalues[0] = (Datum) 0; /* set up the NULL entry */
145 map->inisnull[0] = true;
146
147 return map;
148}
149
150/*
151 * Perform conversion of a tuple according to the map.
152 */
155{
156 AttrMap *attrMap = map->attrMap;
157 Datum *invalues = map->invalues;
158 bool *inisnull = map->inisnull;
159 Datum *outvalues = map->outvalues;
160 bool *outisnull = map->outisnull;
161 int i;
162
163 /*
164 * Extract all the values of the old tuple, offsetting the arrays so that
165 * invalues[0] is left NULL and invalues[1] is the first source attribute;
166 * this exactly matches the numbering convention in attrMap.
167 */
168 heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);
169
170 /*
171 * Transpose into proper fields of the new tuple.
172 */
173 Assert(attrMap->maplen == map->outdesc->natts);
174 for (i = 0; i < attrMap->maplen; i++)
175 {
176 int j = attrMap->attnums[i];
177
178 outvalues[i] = invalues[j];
179 outisnull[i] = inisnull[j];
180 }
181
182 /*
183 * Now form the new tuple.
184 */
185 return heap_form_tuple(map->outdesc, outvalues, outisnull);
186}
187
188/*
189 * Perform conversion of a tuple slot according to the map.
190 */
193 TupleTableSlot *in_slot,
194 TupleTableSlot *out_slot)
195{
196 Datum *invalues;
197 bool *inisnull;
198 Datum *outvalues;
199 bool *outisnull;
200 int outnatts;
201 int i;
202
203 /* Sanity checks */
204 Assert(in_slot->tts_tupleDescriptor != NULL &&
205 out_slot->tts_tupleDescriptor != NULL);
206 Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL);
207
208 outnatts = out_slot->tts_tupleDescriptor->natts;
209
210 /* Extract all the values of the in slot. */
211 slot_getallattrs(in_slot);
212
213 /* Before doing the mapping, clear any old contents from the out slot */
214 ExecClearTuple(out_slot);
215
216 invalues = in_slot->tts_values;
217 inisnull = in_slot->tts_isnull;
218 outvalues = out_slot->tts_values;
219 outisnull = out_slot->tts_isnull;
220
221 /* Transpose into proper fields of the out slot. */
222 for (i = 0; i < outnatts; i++)
223 {
224 int j = attrMap->attnums[i] - 1;
225
226 /* attrMap->attnums[i] == 0 means it's a NULL datum. */
227 if (j == -1)
228 {
229 outvalues[i] = (Datum) 0;
230 outisnull[i] = true;
231 }
232 else
233 {
234 outvalues[i] = invalues[j];
235 outisnull[i] = inisnull[j];
236 }
237 }
238
239 ExecStoreVirtualTuple(out_slot);
240
241 return out_slot;
242}
243
244/*
245 * Perform conversion of bitmap of columns according to the map.
246 *
247 * The input and output bitmaps are offset by
248 * FirstLowInvalidHeapAttributeNumber to accommodate system cols, like the
249 * column-bitmaps in RangeTblEntry.
250 */
251Bitmapset *
253{
254 Bitmapset *out_cols;
255 int out_attnum;
256
257 /* fast path for the common trivial case */
258 if (in_cols == NULL)
259 return NULL;
260
261 /*
262 * For each output column, check which input column it corresponds to.
263 */
264 out_cols = NULL;
265
266 for (out_attnum = FirstLowInvalidHeapAttributeNumber;
267 out_attnum <= attrMap->maplen;
268 out_attnum++)
269 {
270 int in_attnum;
271
272 if (out_attnum < 0)
273 {
274 /* System column. No mapping. */
275 in_attnum = out_attnum;
276 }
277 else if (out_attnum == 0)
278 continue;
279 else
280 {
281 /* normal user column */
282 in_attnum = attrMap->attnums[out_attnum - 1];
283
284 if (in_attnum == 0)
285 continue;
286 }
287
288 if (bms_is_member(in_attnum - FirstLowInvalidHeapAttributeNumber, in_cols))
289 out_cols = bms_add_member(out_cols, out_attnum - FirstLowInvalidHeapAttributeNumber);
290 }
291
292 return out_cols;
293}
294
295/*
296 * Free a TupleConversionMap structure.
297 */
298void
300{
301 /* indesc and outdesc are not ours to free */
302 free_attrmap(map->attrMap);
303 pfree(map->invalues);
304 pfree(map->inisnull);
305 pfree(map->outvalues);
306 pfree(map->outisnull);
307 pfree(map);
308}
void free_attrmap(AttrMap *map)
Definition: attmap.c:56
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:261
AttrMap * build_attrmap_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: attmap.c:75
bool bms_is_member(int x, const Bitmapset *a)
Definition: bitmapset.c:510
Bitmapset * bms_add_member(Bitmapset *a, int x)
Definition: bitmapset.c:815
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1739
Assert(PointerIsAligned(start, uint64))
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1117
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1346
int j
Definition: isn.c:75
int i
Definition: isn.c:74
void pfree(void *pointer)
Definition: mcxt.c:1524
void * palloc(Size size)
Definition: mcxt.c:1317
uintptr_t Datum
Definition: postgres.h:69
Definition: attmap.h:35
int maplen
Definition: attmap.h:37
AttrNumber * attnums
Definition: attmap.h:36
AttrMap * attrMap
Definition: tupconvert.h:28
TupleDesc outdesc
Definition: tupconvert.h:27
TupleDesc indesc
Definition: tupconvert.h:26
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:123
bool * tts_isnull
Definition: tuptable.h:127
Datum * tts_values
Definition: tuptable.h:125
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:27
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
void free_conversion_map(TupleConversionMap *map)
Definition: tupconvert.c:299
TupleConversionMap * convert_tuples_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:59
TupleConversionMap * convert_tuples_by_name_attrmap(TupleDesc indesc, TupleDesc outdesc, AttrMap *attrMap)
Definition: tupconvert.c:124
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:192
Bitmapset * execute_attr_map_cols(AttrMap *attrMap, Bitmapset *in_cols)
Definition: tupconvert.c:252
HeapTuple execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:154
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:454
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:368