PostgreSQL Source Code  git master
tupconvert.c File Reference
#include "postgres.h"
#include "access/htup_details.h"
#include "access/tupconvert.h"
#include "executor/tuptable.h"
#include "utils/builtins.h"
Include dependency graph for tupconvert.c:

Go to the source code of this file.

Functions

TupleConversionMapconvert_tuples_by_position (TupleDesc indesc, TupleDesc outdesc, const char *msg)
 
TupleConversionMapconvert_tuples_by_name (TupleDesc indesc, TupleDesc outdesc)
 
AttrNumberconvert_tuples_by_name_map (TupleDesc indesc, TupleDesc outdesc)
 
AttrNumberconvert_tuples_by_name_map_if_req (TupleDesc indesc, TupleDesc outdesc)
 
HeapTuple execute_attr_map_tuple (HeapTuple tuple, TupleConversionMap *map)
 
TupleTableSlotexecute_attr_map_slot (AttrNumber *attrMap, TupleTableSlot *in_slot, TupleTableSlot *out_slot)
 
void free_conversion_map (TupleConversionMap *map)
 

Function Documentation

◆ convert_tuples_by_name()

TupleConversionMap* convert_tuples_by_name ( TupleDesc  indesc,
TupleDesc  outdesc 
)

Definition at line 205 of file tupconvert.c.

References TupleConversionMap::attrMap, convert_tuples_by_name_map_if_req(), TupleConversionMap::indesc, TupleConversionMap::inisnull, TupleConversionMap::invalues, TupleDescData::natts, TupleConversionMap::outdesc, TupleConversionMap::outisnull, TupleConversionMap::outvalues, and palloc().

Referenced by acquire_inherited_sample_rows(), ExecEvalConvertRowtype(), ExecInitRoutingInfo(), and ExecSetupChildParentMapForSubplan().

207 {
208  TupleConversionMap *map;
209  AttrNumber *attrMap;
210  int n = outdesc->natts;
211 
212  /* Verify compatibility and prepare attribute-number map */
213  attrMap = convert_tuples_by_name_map_if_req(indesc, outdesc);
214 
215  if (attrMap == NULL)
216  {
217  /* runtime conversion is not needed */
218  return NULL;
219  }
220 
221  /* Prepare the map structure */
222  map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
223  map->indesc = indesc;
224  map->outdesc = outdesc;
225  map->attrMap = attrMap;
226  /* preallocate workspace for Datum arrays */
227  map->outvalues = (Datum *) palloc(n * sizeof(Datum));
228  map->outisnull = (bool *) palloc(n * sizeof(bool));
229  n = indesc->natts + 1; /* +1 for NULL */
230  map->invalues = (Datum *) palloc(n * sizeof(Datum));
231  map->inisnull = (bool *) palloc(n * sizeof(bool));
232  map->invalues[0] = (Datum) 0; /* set up the NULL entry */
233  map->inisnull[0] = true;
234 
235  return map;
236 }
AttrNumber * attrMap
Definition: tupconvert.h:26
TupleDesc indesc
Definition: tupconvert.h:24
TupleDesc outdesc
Definition: tupconvert.h:25
AttrNumber * convert_tuples_by_name_map_if_req(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:327
uintptr_t Datum
Definition: postgres.h:367
void * palloc(Size size)
Definition: mcxt.c:949
int16 AttrNumber
Definition: attnum.h:21

◆ convert_tuples_by_name_map()

AttrNumber* convert_tuples_by_name_map ( TupleDesc  indesc,
TupleDesc  outdesc 
)

Definition at line 245 of file tupconvert.c.

References attname, atttypid, ereport, errcode(), errdetail(), errmsg(), ERROR, format_type_be(), i, NameStr, TupleDescData::natts, palloc0(), TupleDescData::tdtypeid, and TupleDescAttr.

Referenced by addFkRecurseReferencing(), ATExecAttachPartitionIdx(), ATPrepAlterColumnType(), AttachPartitionEnsureIndexes(), CloneFkReferenced(), CloneFkReferencing(), convert_tuples_by_name_map_if_req(), DefineIndex(), DefineRelation(), ExecInitPartitionInfo(), and map_partition_varattnos().

247 {
248  AttrNumber *attrMap;
249  int outnatts;
250  int innatts;
251  int i;
252  int nextindesc = -1;
253 
254  outnatts = outdesc->natts;
255  innatts = indesc->natts;
256 
257  attrMap = (AttrNumber *) palloc0(outnatts * sizeof(AttrNumber));
258  for (i = 0; i < outnatts; i++)
259  {
260  Form_pg_attribute outatt = TupleDescAttr(outdesc, i);
261  char *attname;
262  Oid atttypid;
263  int32 atttypmod;
264  int j;
265 
266  if (outatt->attisdropped)
267  continue; /* attrMap[i] is already 0 */
268  attname = NameStr(outatt->attname);
269  atttypid = outatt->atttypid;
270  atttypmod = outatt->atttypmod;
271 
272  /*
273  * Now search for an attribute with the same name in the indesc. It
274  * seems likely that a partitioned table will have the attributes in
275  * the same order as the partition, so the search below is optimized
276  * for that case. It is possible that columns are dropped in one of
277  * the relations, but not the other, so we use the 'nextindesc'
278  * counter to track the starting point of the search. If the inner
279  * loop encounters dropped columns then it will have to skip over
280  * them, but it should leave 'nextindesc' at the correct position for
281  * the next outer loop.
282  */
283  for (j = 0; j < innatts; j++)
284  {
285  Form_pg_attribute inatt;
286 
287  nextindesc++;
288  if (nextindesc >= innatts)
289  nextindesc = 0;
290 
291  inatt = TupleDescAttr(indesc, nextindesc);
292  if (inatt->attisdropped)
293  continue;
294  if (strcmp(attname, NameStr(inatt->attname)) == 0)
295  {
296  /* Found it, check type */
297  if (atttypid != inatt->atttypid || atttypmod != inatt->atttypmod)
298  ereport(ERROR,
299  (errcode(ERRCODE_DATATYPE_MISMATCH),
300  errmsg("could not convert row type"),
301  errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.",
302  attname,
303  format_type_be(outdesc->tdtypeid),
304  format_type_be(indesc->tdtypeid))));
305  attrMap[i] = inatt->attnum;
306  break;
307  }
308  }
309  if (attrMap[i] == 0)
310  ereport(ERROR,
311  (errcode(ERRCODE_DATATYPE_MISMATCH),
312  errmsg("could not convert row type"),
313  errdetail("Attribute \"%s\" of type %s does not exist in type %s.",
314  attname,
315  format_type_be(outdesc->tdtypeid),
316  format_type_be(indesc->tdtypeid))));
317  }
318  return attrMap;
319 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:608
char * format_type_be(Oid type_oid)
Definition: format_type.c:326
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:347
#define ERROR
Definition: elog.h:43
NameData attname
Definition: pg_attribute.h:40
int errdetail(const char *fmt,...)
Definition: elog.c:955
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
Oid atttypid
Definition: pg_attribute.h:49
#define ereport(elevel, rest)
Definition: elog.h:141
void * palloc0(Size size)
Definition: mcxt.c:980
Oid tdtypeid
Definition: tupdesc.h:82
int errmsg(const char *fmt,...)
Definition: elog.c:822
int i
#define NameStr(name)
Definition: c.h:616
int16 AttrNumber
Definition: attnum.h:21

◆ convert_tuples_by_name_map_if_req()

AttrNumber* convert_tuples_by_name_map_if_req ( TupleDesc  indesc,
TupleDesc  outdesc 
)

Definition at line 327 of file tupconvert.c.

References convert_tuples_by_name_map(), i, TupleDescData::natts, pfree(), and TupleDescAttr.

Referenced by addFkRecurseReferenced(), convert_tuples_by_name(), ExecConstraints(), ExecInitPartitionDispatchInfo(), ExecPartitionCheckEmitError(), and ExecWithCheckOptions().

329 {
330  AttrNumber *attrMap;
331  int n = outdesc->natts;
332  int i;
333  bool same;
334 
335  /* Verify compatibility and prepare attribute-number map */
336  attrMap = convert_tuples_by_name_map(indesc, outdesc);
337 
338  /*
339  * Check to see if the map is one-to-one, in which case we need not do a
340  * tuple conversion.
341  */
342  if (indesc->natts == outdesc->natts)
343  {
344  same = true;
345  for (i = 0; i < n; i++)
346  {
347  Form_pg_attribute inatt;
348  Form_pg_attribute outatt;
349 
350  if (attrMap[i] == (i + 1))
351  continue;
352 
353  /*
354  * If it's a dropped column and the corresponding input column is
355  * also dropped, we needn't convert. However, attlen and attalign
356  * must agree.
357  */
358  inatt = TupleDescAttr(indesc, i);
359  outatt = TupleDescAttr(outdesc, i);
360  if (attrMap[i] == 0 &&
361  inatt->attisdropped &&
362  inatt->attlen == outatt->attlen &&
363  inatt->attalign == outatt->attalign)
364  continue;
365 
366  same = false;
367  break;
368  }
369  }
370  else
371  same = false;
372 
373  if (same)
374  {
375  /* Runtime conversion is not needed */
376  pfree(attrMap);
377  return NULL;
378  }
379  else
380  return attrMap;
381 }
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
void pfree(void *pointer)
Definition: mcxt.c:1056
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
int i
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc)
Definition: tupconvert.c:245
int16 AttrNumber
Definition: attnum.h:21

◆ convert_tuples_by_position()

TupleConversionMap* convert_tuples_by_position ( TupleDesc  indesc,
TupleDesc  outdesc,
const char *  msg 
)

Definition at line 65 of file tupconvert.c.

References _, TupleConversionMap::attrMap, atttypid, ereport, errcode(), errdetail(), errmsg_internal(), ERROR, format_type_with_typemod(), i, TupleConversionMap::indesc, TupleConversionMap::inisnull, TupleConversionMap::invalues, TupleDescData::natts, TupleConversionMap::outdesc, TupleConversionMap::outisnull, TupleConversionMap::outvalues, palloc(), palloc0(), pfree(), and TupleDescAttr.

Referenced by coerce_function_result_tuple(), exec_stmt_return_next(), exec_stmt_return_query(), and plpgsql_exec_trigger().

68 {
69  TupleConversionMap *map;
70  AttrNumber *attrMap;
71  int nincols;
72  int noutcols;
73  int n;
74  int i;
75  int j;
76  bool same;
77 
78  /* Verify compatibility and prepare attribute-number map */
79  n = outdesc->natts;
80  attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber));
81  j = 0; /* j is next physical input attribute */
82  nincols = noutcols = 0; /* these count non-dropped attributes */
83  same = true;
84  for (i = 0; i < n; i++)
85  {
86  Form_pg_attribute att = TupleDescAttr(outdesc, i);
87  Oid atttypid;
88  int32 atttypmod;
89 
90  if (att->attisdropped)
91  continue; /* attrMap[i] is already 0 */
92  noutcols++;
93  atttypid = att->atttypid;
94  atttypmod = att->atttypmod;
95  for (; j < indesc->natts; j++)
96  {
97  att = TupleDescAttr(indesc, j);
98  if (att->attisdropped)
99  continue;
100  nincols++;
101  /* Found matching column, check type */
102  if (atttypid != att->atttypid ||
103  (atttypmod != att->atttypmod && atttypmod >= 0))
104  ereport(ERROR,
105  (errcode(ERRCODE_DATATYPE_MISMATCH),
106  errmsg_internal("%s", _(msg)),
107  errdetail("Returned type %s does not match expected type %s in column %d.",
108  format_type_with_typemod(att->atttypid,
109  att->atttypmod),
110  format_type_with_typemod(atttypid,
111  atttypmod),
112  noutcols)));
113  attrMap[i] = (AttrNumber) (j + 1);
114  j++;
115  break;
116  }
117  if (attrMap[i] == 0)
118  same = false; /* we'll complain below */
119  }
120 
121  /* Check for unused input columns */
122  for (; j < indesc->natts; j++)
123  {
124  if (TupleDescAttr(indesc, j)->attisdropped)
125  continue;
126  nincols++;
127  same = false; /* we'll complain below */
128  }
129 
130  /* Report column count mismatch using the non-dropped-column counts */
131  if (!same)
132  ereport(ERROR,
133  (errcode(ERRCODE_DATATYPE_MISMATCH),
134  errmsg_internal("%s", _(msg)),
135  errdetail("Number of returned columns (%d) does not match "
136  "expected column count (%d).",
137  nincols, noutcols)));
138 
139  /*
140  * Check to see if the map is one-to-one, in which case we need not do a
141  * tuple conversion.
142  */
143  if (indesc->natts == outdesc->natts)
144  {
145  for (i = 0; i < n; i++)
146  {
147  Form_pg_attribute inatt;
148  Form_pg_attribute outatt;
149 
150  if (attrMap[i] == (i + 1))
151  continue;
152 
153  /*
154  * If it's a dropped column and the corresponding input column is
155  * also dropped, we needn't convert. However, attlen and attalign
156  * must agree.
157  */
158  inatt = TupleDescAttr(indesc, i);
159  outatt = TupleDescAttr(outdesc, i);
160  if (attrMap[i] == 0 &&
161  inatt->attisdropped &&
162  inatt->attlen == outatt->attlen &&
163  inatt->attalign == outatt->attalign)
164  continue;
165 
166  same = false;
167  break;
168  }
169  }
170  else
171  same = false;
172 
173  if (same)
174  {
175  /* Runtime conversion is not needed */
176  pfree(attrMap);
177  return NULL;
178  }
179 
180  /* Prepare the map structure */
181  map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
182  map->indesc = indesc;
183  map->outdesc = outdesc;
184  map->attrMap = attrMap;
185  /* preallocate workspace for Datum arrays */
186  map->outvalues = (Datum *) palloc(n * sizeof(Datum));
187  map->outisnull = (bool *) palloc(n * sizeof(bool));
188  n = indesc->natts + 1; /* +1 for NULL */
189  map->invalues = (Datum *) palloc(n * sizeof(Datum));
190  map->inisnull = (bool *) palloc(n * sizeof(bool));
191  map->invalues[0] = (Datum) 0; /* set up the NULL entry */
192  map->inisnull[0] = true;
193 
194  return map;
195 }
AttrNumber * attrMap
Definition: tupconvert.h:26
TupleDesc indesc
Definition: tupconvert.h:24
TupleDesc outdesc
Definition: tupconvert.h:25
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:92
int errcode(int sqlerrcode)
Definition: elog.c:608
unsigned int Oid
Definition: postgres_ext.h:31
signed int int32
Definition: c.h:347
void pfree(void *pointer)
Definition: mcxt.c:1056
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:955
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:200
Oid atttypid
Definition: pg_attribute.h:49
#define ereport(elevel, rest)
Definition: elog.h:141
char * format_type_with_typemod(Oid type_oid, int32 typemod)
Definition: format_type.c:345
void * palloc0(Size size)
Definition: mcxt.c:980
uintptr_t Datum
Definition: postgres.h:367
int errmsg_internal(const char *fmt,...)
Definition: elog.c:909
void * palloc(Size size)
Definition: mcxt.c:949
int i
int16 AttrNumber
Definition: attnum.h:21
#define _(x)
Definition: elog.c:87

◆ execute_attr_map_slot()

TupleTableSlot* execute_attr_map_slot ( AttrNumber attrMap,
TupleTableSlot in_slot,
TupleTableSlot out_slot 
)

Definition at line 425 of file tupconvert.c.

References Assert, ExecClearTuple(), ExecStoreVirtualTuple(), i, TupleDescData::natts, slot_getallattrs(), TupleTableSlot::tts_isnull, TupleTableSlot::tts_tupleDescriptor, and TupleTableSlot::tts_values.

Referenced by AfterTriggerSaveEvent(), CopyFrom(), ExecConstraints(), ExecFindPartition(), ExecPartitionCheckEmitError(), ExecPrepareTupleRouting(), ExecUpdate(), and ExecWithCheckOptions().

428 {
429  Datum *invalues;
430  bool *inisnull;
431  Datum *outvalues;
432  bool *outisnull;
433  int outnatts;
434  int i;
435 
436  /* Sanity checks */
437  Assert(in_slot->tts_tupleDescriptor != NULL &&
438  out_slot->tts_tupleDescriptor != NULL);
439  Assert(in_slot->tts_values != NULL && out_slot->tts_values != NULL);
440 
441  outnatts = out_slot->tts_tupleDescriptor->natts;
442 
443  /* Extract all the values of the in slot. */
444  slot_getallattrs(in_slot);
445 
446  /* Before doing the mapping, clear any old contents from the out slot */
447  ExecClearTuple(out_slot);
448 
449  invalues = in_slot->tts_values;
450  inisnull = in_slot->tts_isnull;
451  outvalues = out_slot->tts_values;
452  outisnull = out_slot->tts_isnull;
453 
454  /* Transpose into proper fields of the out slot. */
455  for (i = 0; i < outnatts; i++)
456  {
457  int j = attrMap[i] - 1;
458 
459  /* attrMap[i] == 0 means it's a NULL datum. */
460  if (j == -1)
461  {
462  outvalues[i] = (Datum) 0;
463  outisnull[i] = true;
464  }
465  else
466  {
467  outvalues[i] = invalues[j];
468  outisnull[i] = inisnull[j];
469  }
470  }
471 
472  ExecStoreVirtualTuple(out_slot);
473 
474  return out_slot;
475 }
static TupleTableSlot * ExecClearTuple(TupleTableSlot *slot)
Definition: tuptable.h:425
Datum * tts_values
Definition: tuptable.h:126
static void slot_getallattrs(TupleTableSlot *slot)
Definition: tuptable.h:354
bool * tts_isnull
Definition: tuptable.h:128
TupleDesc tts_tupleDescriptor
Definition: tuptable.h:124
uintptr_t Datum
Definition: postgres.h:367
#define Assert(condition)
Definition: c.h:739
int i
TupleTableSlot * ExecStoreVirtualTuple(TupleTableSlot *slot)
Definition: execTuples.c:1522

◆ execute_attr_map_tuple()

HeapTuple execute_attr_map_tuple ( HeapTuple  tuple,
TupleConversionMap map 
)

Definition at line 387 of file tupconvert.c.

References TupleConversionMap::attrMap, heap_deform_tuple(), heap_form_tuple(), i, TupleConversionMap::indesc, TupleConversionMap::inisnull, TupleConversionMap::invalues, TupleDescData::natts, TupleConversionMap::outdesc, TupleConversionMap::outisnull, and TupleConversionMap::outvalues.

Referenced by acquire_inherited_sample_rows(), coerce_function_result_tuple(), exec_stmt_return_next(), exec_stmt_return_query(), ExecEvalConvertRowtype(), and plpgsql_exec_trigger().

388 {
389  AttrNumber *attrMap = map->attrMap;
390  Datum *invalues = map->invalues;
391  bool *inisnull = map->inisnull;
392  Datum *outvalues = map->outvalues;
393  bool *outisnull = map->outisnull;
394  int outnatts = map->outdesc->natts;
395  int i;
396 
397  /*
398  * Extract all the values of the old tuple, offsetting the arrays so that
399  * invalues[0] is left NULL and invalues[1] is the first source attribute;
400  * this exactly matches the numbering convention in attrMap.
401  */
402  heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);
403 
404  /*
405  * Transpose into proper fields of the new tuple.
406  */
407  for (i = 0; i < outnatts; i++)
408  {
409  int j = attrMap[i];
410 
411  outvalues[i] = invalues[j];
412  outisnull[i] = inisnull[j];
413  }
414 
415  /*
416  * Now form the new tuple.
417  */
418  return heap_form_tuple(map->outdesc, outvalues, outisnull);
419 }
AttrNumber * attrMap
Definition: tupconvert.h:26
TupleDesc indesc
Definition: tupconvert.h:24
TupleDesc outdesc
Definition: tupconvert.h:25
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:1020
uintptr_t Datum
Definition: postgres.h:367
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:1249
int i
int16 AttrNumber
Definition: attnum.h:21

◆ free_conversion_map()

void free_conversion_map ( TupleConversionMap map)

Definition at line 481 of file tupconvert.c.

References TupleConversionMap::attrMap, TupleConversionMap::inisnull, TupleConversionMap::invalues, TupleConversionMap::outisnull, TupleConversionMap::outvalues, and pfree().

Referenced by acquire_inherited_sample_rows().

482 {
483  /* indesc and outdesc are not ours to free */
484  pfree(map->attrMap);
485  pfree(map->invalues);
486  pfree(map->inisnull);
487  pfree(map->outvalues);
488  pfree(map->outisnull);
489  pfree(map);
490 }
AttrNumber * attrMap
Definition: tupconvert.h:26
void pfree(void *pointer)
Definition: mcxt.c:1056