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