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-2020, 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  TupleConversionMap *map;
106  AttrMap *attrMap;
107  int n = outdesc->natts;
108 
109  /* Verify compatibility and prepare attribute-number map */
110  attrMap = build_attrmap_by_name_if_req(indesc, outdesc);
111 
112  if (attrMap == NULL)
113  {
114  /* runtime conversion is not needed */
115  return NULL;
116  }
117 
118  /* Prepare the map structure */
119  map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
120  map->indesc = indesc;
121  map->outdesc = outdesc;
122  map->attrMap = attrMap;
123  /* preallocate workspace for Datum arrays */
124  map->outvalues = (Datum *) palloc(n * sizeof(Datum));
125  map->outisnull = (bool *) palloc(n * sizeof(bool));
126  n = indesc->natts + 1; /* +1 for NULL */
127  map->invalues = (Datum *) palloc(n * sizeof(Datum));
128  map->inisnull = (bool *) palloc(n * sizeof(bool));
129  map->invalues[0] = (Datum) 0; /* set up the NULL entry */
130  map->inisnull[0] = true;
131 
132  return map;
133 }
134 
135 /*
136  * Perform conversion of a tuple according to the map.
137  */
138 HeapTuple
140 {
141  AttrMap *attrMap = map->attrMap;
142  Datum *invalues = map->invalues;
143  bool *inisnull = map->inisnull;
144  Datum *outvalues = map->outvalues;
145  bool *outisnull = map->outisnull;
146  int i;
147 
148  /*
149  * Extract all the values of the old tuple, offsetting the arrays so that
150  * invalues[0] is left NULL and invalues[1] is the first source attribute;
151  * this exactly matches the numbering convention in attrMap.
152  */
153  heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);
154 
155  /*
156  * Transpose into proper fields of the new tuple.
157  */
158  Assert(attrMap->maplen == map->outdesc->natts);
159  for (i = 0; i < attrMap->maplen; i++)
160  {
161  int j = attrMap->attnums[i];
162 
163  outvalues[i] = invalues[j];
164  outisnull[i] = inisnull[j];
165  }
166 
167  /*
168  * Now form the new tuple.
169  */
170  return heap_form_tuple(map->outdesc, outvalues, outisnull);
171 }
172 
173 /*
174  * Perform conversion of a tuple slot according to the map.
175  */
178  TupleTableSlot *in_slot,
179  TupleTableSlot *out_slot)
180 {
181  Datum *invalues;
182  bool *inisnull;
183  Datum *outvalues;
184  bool *outisnull;
185  int outnatts;
186  int i;
187 
188  /* Sanity checks */
189  Assert(in_slot->tts_tupleDescriptor != NULL &&
190  out_slot->tts_tupleDescriptor != NULL);
191  Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL);
192 
193  outnatts = out_slot->tts_tupleDescriptor->natts;
194 
195  /* Extract all the values of the in slot. */
196  slot_getallattrs(in_slot);
197 
198  /* Before doing the mapping, clear any old contents from the out slot */
199  ExecClearTuple(out_slot);
200 
201  invalues = in_slot->tts_values;
202  inisnull = in_slot->tts_isnull;
203  outvalues = out_slot->tts_values;
204  outisnull = out_slot->tts_isnull;
205 
206  /* Transpose into proper fields of the out slot. */
207  for (i = 0; i < outnatts; i++)
208  {
209  int j = attrMap->attnums[i] - 1;
210 
211  /* attrMap->attnums[i] == 0 means it's a NULL datum. */
212  if (j == -1)
213  {
214  outvalues[i] = (Datum) 0;
215  outisnull[i] = true;
216  }
217  else
218  {
219  outvalues[i] = invalues[j];
220  outisnull[i] = inisnull[j];
221  }
222  }
223 
224  ExecStoreVirtualTuple(out_slot);
225 
226  return out_slot;
227 }
228 
229 /*
230  * Free a TupleConversionMap structure.
231  */
232 void
234 {
235  /* indesc and outdesc are not ours to free */
236  free_attrmap(map->attrMap);
237  pfree(map->invalues);
238  pfree(map->inisnull);
239  pfree(map->outvalues);
240  pfree(map->outisnull);
241  pfree(map);
242 }
TupleDesc indesc
Definition: tupconvert.h:25
TupleDesc outdesc
Definition: tupconvert.h:26
void free_attrmap(AttrMap *map)
Definition: attmap.c:57
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
TupleConversionMap * convert_tuples_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:59
int maplen
Definition: attmap.h:37
Datum * tts_values
Definition: tuptable.h:126
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
Definition: attmap.h:34
void pfree(void *pointer)
Definition: mcxt.c:1056
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc)
Definition: attmap.c:259
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
TupleConversionMap * convert_tuples_by_name(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:102
bool * tts_isnull
Definition: tuptable.h:128
void free_conversion_map(TupleConversionMap *map)
Definition: tupconvert.c:233
HeapTuple execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
Definition: tupconvert.c:139
AttrMap * attrMap
Definition: tupconvert.h:27
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
uintptr_t Datum
Definition: postgres.h:367
TupleTableSlot * execute_attr_map_slot(AttrMap *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
Definition: tupconvert.c:177
#define Assert(condition)
Definition: c.h:738
AttrNumber * attnums
Definition: attmap.h:36
AttrMap * build_attrmap_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: attmap.c:76
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
void * palloc(Size size)
Definition: mcxt.c:949
int i
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522