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-2024, 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 {
63  TupleConversionMap *map;
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 */
77  map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
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;
129  TupleConversionMap *map;
130 
131  Assert(attrMap != NULL);
132 
133  /* Prepare the map structure */
134  map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
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  */
153 HeapTuple
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  */
251 Bitmapset *
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  */
298 void
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_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: attmap.c:75
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
Definition: attmap.c:263
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
#define Assert(condition)
Definition: c.h:858
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1639
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
Definition: heaptuple.c:1116
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1345
int j
Definition: isn.c:74
int i
Definition: isn.c:73
void pfree(void *pointer)
Definition: mcxt.c:1520
void * palloc(Size size)
Definition: mcxt.c:1316
uintptr_t Datum
Definition: postgres.h:64
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
Bitmapset * execute_attr_map_cols(AttrMap *attrMap, Bitmapset *in_cols)
Definition: tupconvert.c:252
TupleConversionMap * convert_tuples_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:59
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:192
void free_conversion_map(TupleConversionMap *map)
Definition: tupconvert.c:299
TupleConversionMap * convert_tuples_by_name_attrmap(TupleDesc indesc, TupleDesc outdesc, AttrMap *attrMap)
Definition: tupconvert.c:124
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
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