Age Owner Branch data 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-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 : : */
58 : : TupleConversionMap *
5365 tgl@sss.pgh.pa.us 59 :CBC 4761 : 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 */
1579 michael@paquier.xyz 68 : 4761 : attrMap = build_attrmap_by_position(indesc, outdesc, msg);
69 : :
70 [ + + ]: 4745 : if (attrMap == NULL)
71 : : {
72 : : /* runtime conversion is not needed */
5365 tgl@sss.pgh.pa.us 73 : 4698 : 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 */
1579 michael@paquier.xyz 82 : 47 : n = outdesc->natts + 1; /* +1 for NULL */
5365 tgl@sss.pgh.pa.us 83 : 47 : map->outvalues = (Datum *) palloc(n * sizeof(Datum));
84 : 47 : map->outisnull = (bool *) palloc(n * sizeof(bool));
5161 bruce@momjian.us 85 : 47 : n = indesc->natts + 1; /* +1 for NULL */
5365 tgl@sss.pgh.pa.us 86 : 47 : map->invalues = (Datum *) palloc(n * sizeof(Datum));
87 : 47 : map->inisnull = (bool *) palloc(n * sizeof(bool));
2489 88 : 47 : map->invalues[0] = (Datum) 0; /* set up the NULL entry */
5365 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 : 1785 : convert_tuples_by_name(TupleDesc indesc,
103 : : TupleDesc outdesc)
104 : : {
105 : : AttrMap *attrMap;
106 : :
107 : : /* Verify compatibility and prepare attribute-number map */
502 alvherre@alvh.no-ip. 108 : 1785 : attrMap = build_attrmap_by_name_if_req(indesc, outdesc, false);
109 : :
2021 andres@anarazel.de 110 [ + + ]: 1785 : if (attrMap == NULL)
111 : : {
112 : : /* runtime conversion is not needed */
5365 tgl@sss.pgh.pa.us 113 : 1388 : return NULL;
114 : : }
115 : :
499 alvherre@alvh.no-ip. 116 : 397 : 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 : 1115 : convert_tuples_by_name_attrmap(TupleDesc indesc,
125 : : TupleDesc outdesc,
126 : : AttrMap *attrMap)
127 : : {
128 : 1115 : int n = outdesc->natts;
129 : : TupleConversionMap *map;
130 : :
131 [ - + ]: 1115 : Assert(attrMap != NULL);
132 : :
133 : : /* Prepare the map structure */
5365 tgl@sss.pgh.pa.us 134 : 1115 : map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
135 : 1115 : map->indesc = indesc;
136 : 1115 : map->outdesc = outdesc;
137 : 1115 : map->attrMap = attrMap;
138 : : /* preallocate workspace for Datum arrays */
139 : 1115 : map->outvalues = (Datum *) palloc(n * sizeof(Datum));
140 : 1115 : map->outisnull = (bool *) palloc(n * sizeof(bool));
5161 bruce@momjian.us 141 : 1115 : n = indesc->natts + 1; /* +1 for NULL */
5365 tgl@sss.pgh.pa.us 142 : 1115 : map->invalues = (Datum *) palloc(n * sizeof(Datum));
143 : 1115 : map->inisnull = (bool *) palloc(n * sizeof(bool));
2489 144 : 1115 : map->invalues[0] = (Datum) 0; /* set up the NULL entry */
5365 145 : 1115 : map->inisnull[0] = true;
146 : :
147 : 1115 : return map;
148 : : }
149 : :
150 : : /*
151 : : * Perform conversion of a tuple according to the map.
152 : : */
153 : : HeapTuple
2021 andres@anarazel.de 154 : 53367 : execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
155 : : {
1579 michael@paquier.xyz 156 : 53367 : AttrMap *attrMap = map->attrMap;
5365 tgl@sss.pgh.pa.us 157 : 53367 : Datum *invalues = map->invalues;
158 : 53367 : bool *inisnull = map->inisnull;
159 : 53367 : Datum *outvalues = map->outvalues;
160 : 53367 : 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 : 53367 : heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);
169 : :
170 : : /*
171 : : * Transpose into proper fields of the new tuple.
172 : : */
1579 michael@paquier.xyz 173 [ - + ]: 53367 : Assert(attrMap->maplen == map->outdesc->natts);
174 [ + + ]: 212326 : for (i = 0; i < attrMap->maplen; i++)
175 : : {
176 : 158959 : int j = attrMap->attnums[i];
177 : :
5365 tgl@sss.pgh.pa.us 178 : 158959 : outvalues[i] = invalues[j];
179 : 158959 : outisnull[i] = inisnull[j];
180 : : }
181 : :
182 : : /*
183 : : * Now form the new tuple.
184 : : */
185 : 53367 : return heap_form_tuple(map->outdesc, outvalues, outisnull);
186 : : }
187 : :
188 : : /*
189 : : * Perform conversion of a tuple slot according to the map.
190 : : */
191 : : TupleTableSlot *
1579 michael@paquier.xyz 192 : 71866 : execute_attr_map_slot(AttrMap *attrMap,
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 */
2021 andres@anarazel.de 204 [ + - - + ]: 71866 : Assert(in_slot->tts_tupleDescriptor != NULL &&
205 : : out_slot->tts_tupleDescriptor != NULL);
206 [ + - - + ]: 71866 : Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL);
207 : :
208 : 71866 : outnatts = out_slot->tts_tupleDescriptor->natts;
209 : :
210 : : /* Extract all the values of the in slot. */
211 : 71866 : slot_getallattrs(in_slot);
212 : :
213 : : /* Before doing the mapping, clear any old contents from the out slot */
214 : 71866 : ExecClearTuple(out_slot);
215 : :
216 : 71866 : invalues = in_slot->tts_values;
217 : 71866 : inisnull = in_slot->tts_isnull;
218 : 71866 : outvalues = out_slot->tts_values;
219 : 71866 : outisnull = out_slot->tts_isnull;
220 : :
221 : : /* Transpose into proper fields of the out slot. */
222 [ + + ]: 289796 : for (i = 0; i < outnatts; i++)
223 : : {
1579 michael@paquier.xyz 224 : 217930 : int j = attrMap->attnums[i] - 1;
225 : :
226 : : /* attrMap->attnums[i] == 0 means it's a NULL datum. */
2021 andres@anarazel.de 227 [ + + ]: 217930 : if (j == -1)
228 : : {
229 : 1326 : outvalues[i] = (Datum) 0;
230 : 1326 : outisnull[i] = true;
231 : : }
232 : : else
233 : : {
234 : 216604 : outvalues[i] = invalues[j];
235 : 216604 : outisnull[i] = inisnull[j];
236 : : }
237 : : }
238 : :
239 : 71866 : ExecStoreVirtualTuple(out_slot);
240 : :
241 : 71866 : 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 *
1161 heikki.linnakangas@i 252 : 243 : execute_attr_map_cols(AttrMap *attrMap, Bitmapset *in_cols)
253 : : {
254 : : Bitmapset *out_cols;
255 : : int out_attnum;
256 : :
257 : : /* fast path for the common trivial case */
258 [ - + ]: 243 : if (in_cols == NULL)
1161 heikki.linnakangas@i 259 :UBC 0 : return NULL;
260 : :
261 : : /*
262 : : * For each output column, check which input column it corresponds to.
263 : : */
1161 heikki.linnakangas@i 264 :CBC 243 : out_cols = NULL;
265 : :
266 : 243 : for (out_attnum = FirstLowInvalidHeapAttributeNumber;
267 [ + + ]: 3100 : out_attnum <= attrMap->maplen;
268 : 2857 : out_attnum++)
269 : : {
270 : : int in_attnum;
271 : :
272 [ + + ]: 2857 : if (out_attnum < 0)
273 : : {
274 : : /* System column. No mapping. */
275 : 1701 : in_attnum = out_attnum;
276 : : }
277 [ + + ]: 1156 : else if (out_attnum == 0)
278 : 243 : continue;
279 : : else
280 : : {
281 : : /* normal user column */
282 : 913 : in_attnum = attrMap->attnums[out_attnum - 1];
283 : :
284 [ + + ]: 913 : if (in_attnum == 0)
285 : 71 : continue;
286 : : }
287 : :
288 [ + + ]: 2543 : if (bms_is_member(in_attnum - FirstLowInvalidHeapAttributeNumber, in_cols))
289 : 260 : out_cols = bms_add_member(out_cols, out_attnum - FirstLowInvalidHeapAttributeNumber);
290 : : }
291 : :
292 : 243 : return out_cols;
293 : : }
294 : :
295 : : /*
296 : : * Free a TupleConversionMap structure.
297 : : */
298 : : void
5365 tgl@sss.pgh.pa.us 299 : 79 : free_conversion_map(TupleConversionMap *map)
300 : : {
301 : : /* indesc and outdesc are not ours to free */
1579 michael@paquier.xyz 302 : 79 : free_attrmap(map->attrMap);
5365 tgl@sss.pgh.pa.us 303 : 79 : pfree(map->invalues);
304 : 79 : pfree(map->inisnull);
305 : 79 : pfree(map->outvalues);
306 : 79 : pfree(map->outisnull);
307 : 79 : pfree(map);
308 : 79 : }
|