TLA Line data Source code
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-2023, 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 : */
58 : TupleConversionMap *
59 CBC 4750 : convert_tuples_by_position(TupleDesc indesc,
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 4750 : attrMap = build_attrmap_by_position(indesc, outdesc, msg);
69 :
70 4734 : if (attrMap == NULL)
71 : {
72 : /* runtime conversion is not needed */
73 4687 : return NULL;
74 : }
75 :
76 : /* Prepare the map structure */
77 47 : map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
78 47 : map->indesc = indesc;
79 47 : map->outdesc = outdesc;
80 47 : map->attrMap = attrMap;
81 : /* preallocate workspace for Datum arrays */
82 47 : n = outdesc->natts + 1; /* +1 for NULL */
83 47 : map->outvalues = (Datum *) palloc(n * sizeof(Datum));
84 47 : map->outisnull = (bool *) palloc(n * sizeof(bool));
85 47 : n = indesc->natts + 1; /* +1 for NULL */
86 47 : map->invalues = (Datum *) palloc(n * sizeof(Datum));
87 47 : map->inisnull = (bool *) palloc(n * sizeof(bool));
88 47 : map->invalues[0] = (Datum) 0; /* set up the NULL entry */
89 47 : map->inisnull[0] = true;
90 :
91 47 : 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 : */
101 : TupleConversionMap *
102 1595 : convert_tuples_by_name(TupleDesc indesc,
103 : TupleDesc outdesc)
104 : {
105 : AttrMap *attrMap;
106 ECB :
107 : /* Verify compatibility and prepare attribute-number map */
108 GNC 1595 : attrMap = build_attrmap_by_name_if_req(indesc, outdesc, false);
109 :
110 GIC 1595 : if (attrMap == NULL)
111 ECB : {
112 : /* runtime conversion is not needed */
113 GIC 1216 : return NULL;
114 ECB : }
115 :
116 GNC 379 : 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 : */
123 : TupleConversionMap *
124 1068 : convert_tuples_by_name_attrmap(TupleDesc indesc,
125 : TupleDesc outdesc,
126 : AttrMap *attrMap)
127 : {
128 1068 : int n = outdesc->natts;
129 : TupleConversionMap *map;
130 :
131 1068 : Assert(attrMap != NULL);
132 :
133 : /* Prepare the map structure */
134 GIC 1068 : map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
135 1068 : map->indesc = indesc;
136 1068 : map->outdesc = outdesc;
137 1068 : map->attrMap = attrMap;
138 : /* preallocate workspace for Datum arrays */
139 CBC 1068 : map->outvalues = (Datum *) palloc(n * sizeof(Datum));
140 GIC 1068 : map->outisnull = (bool *) palloc(n * sizeof(bool));
141 1068 : n = indesc->natts + 1; /* +1 for NULL */
142 1068 : map->invalues = (Datum *) palloc(n * sizeof(Datum));
143 CBC 1068 : map->inisnull = (bool *) palloc(n * sizeof(bool));
144 GIC 1068 : map->invalues[0] = (Datum) 0; /* set up the NULL entry */
145 1068 : map->inisnull[0] = true;
146 ECB :
147 GIC 1068 : return map;
148 : }
149 ECB :
150 : /*
151 : * Perform conversion of a tuple according to the map.
152 : */
153 : HeapTuple
154 CBC 53290 : execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
155 ECB : {
156 CBC 53290 : AttrMap *attrMap = map->attrMap;
157 53290 : Datum *invalues = map->invalues;
158 53290 : bool *inisnull = map->inisnull;
159 53290 : Datum *outvalues = map->outvalues;
160 53290 : bool *outisnull = map->outisnull;
161 : int i;
162 ECB :
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 GIC 53290 : heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);
169 ECB :
170 : /*
171 : * Transpose into proper fields of the new tuple.
172 : */
173 CBC 53290 : Assert(attrMap->maplen == map->outdesc->natts);
174 212095 : for (i = 0; i < attrMap->maplen; i++)
175 ECB : {
176 GIC 158805 : int j = attrMap->attnums[i];
177 :
178 158805 : outvalues[i] = invalues[j];
179 158805 : outisnull[i] = inisnull[j];
180 : }
181 :
182 : /*
183 ECB : * Now form the new tuple.
184 : */
185 GIC 53290 : return heap_form_tuple(map->outdesc, outvalues, outisnull);
186 : }
187 :
188 ECB : /*
189 : * Perform conversion of a tuple slot according to the map.
190 : */
191 : TupleTableSlot *
192 GIC 71709 : execute_attr_map_slot(AttrMap *attrMap,
193 ECB : 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 GIC 71709 : Assert(in_slot->tts_tupleDescriptor != NULL &&
205 : out_slot->tts_tupleDescriptor != NULL);
206 71709 : Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL);
207 ECB :
208 GIC 71709 : outnatts = out_slot->tts_tupleDescriptor->natts;
209 :
210 : /* Extract all the values of the in slot. */
211 71709 : slot_getallattrs(in_slot);
212 :
213 : /* Before doing the mapping, clear any old contents from the out slot */
214 71709 : ExecClearTuple(out_slot);
215 :
216 71709 : invalues = in_slot->tts_values;
217 71709 : inisnull = in_slot->tts_isnull;
218 71709 : outvalues = out_slot->tts_values;
219 CBC 71709 : outisnull = out_slot->tts_isnull;
220 :
221 ECB : /* Transpose into proper fields of the out slot. */
222 GIC 289145 : for (i = 0; i < outnatts; i++)
223 ECB : {
224 GIC 217436 : int j = attrMap->attnums[i] - 1;
225 :
226 ECB : /* attrMap->attnums[i] == 0 means it's a NULL datum. */
227 GIC 217436 : if (j == -1)
228 : {
229 CBC 1236 : outvalues[i] = (Datum) 0;
230 GIC 1236 : outisnull[i] = true;
231 ECB : }
232 : else
233 : {
234 CBC 216200 : outvalues[i] = invalues[j];
235 GIC 216200 : outisnull[i] = inisnull[j];
236 : }
237 ECB : }
238 :
239 CBC 71709 : ExecStoreVirtualTuple(out_slot);
240 :
241 GIC 71709 : return out_slot;
242 ECB : }
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 *
252 GIC 243 : execute_attr_map_cols(AttrMap *attrMap, Bitmapset *in_cols)
253 : {
254 ECB : Bitmapset *out_cols;
255 : int out_attnum;
256 :
257 : /* fast path for the common trivial case */
258 GIC 243 : if (in_cols == NULL)
259 UIC 0 : return NULL;
260 :
261 : /*
262 : * For each output column, check which input column it corresponds to.
263 : */
264 GIC 243 : out_cols = NULL;
265 :
266 243 : for (out_attnum = FirstLowInvalidHeapAttributeNumber;
267 CBC 3100 : out_attnum <= attrMap->maplen;
268 GIC 2857 : out_attnum++)
269 : {
270 : int in_attnum;
271 :
272 2857 : if (out_attnum < 0)
273 ECB : {
274 EUB : /* System column. No mapping. */
275 GIC 1701 : in_attnum = out_attnum;
276 : }
277 1156 : else if (out_attnum == 0)
278 243 : continue;
279 ECB : else
280 : {
281 : /* normal user column */
282 CBC 913 : in_attnum = attrMap->attnums[out_attnum - 1];
283 ECB :
284 GIC 913 : if (in_attnum == 0)
285 71 : continue;
286 : }
287 ECB :
288 GIC 2543 : if (bms_is_member(in_attnum - FirstLowInvalidHeapAttributeNumber, in_cols))
289 260 : out_cols = bms_add_member(out_cols, out_attnum - FirstLowInvalidHeapAttributeNumber);
290 ECB : }
291 :
292 CBC 243 : return out_cols;
293 ECB : }
294 :
295 : /*
296 : * Free a TupleConversionMap structure.
297 : */
298 : void
299 CBC 66 : free_conversion_map(TupleConversionMap *map)
300 ECB : {
301 : /* indesc and outdesc are not ours to free */
302 GIC 66 : free_attrmap(map->attrMap);
303 CBC 66 : pfree(map->invalues);
304 66 : pfree(map->inisnull);
305 GIC 66 : pfree(map->outvalues);
306 66 : pfree(map->outisnull);
307 CBC 66 : pfree(map);
308 GIC 66 : }
|