PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
tupconvert.h File Reference
#include "access/htup.h"
#include "access/tupdesc.h"
Include dependency graph for tupconvert.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  TupleConversionMap
 

Typedefs

typedef struct TupleConversionMap TupleConversionMap
 

Functions

TupleConversionMapconvert_tuples_by_position (TupleDesc indesc, TupleDesc outdesc, const char *msg)
 
TupleConversionMapconvert_tuples_by_name (TupleDesc indesc, TupleDesc outdesc, const char *msg)
 
AttrNumberconvert_tuples_by_name_map (TupleDesc indesc, TupleDesc outdesc, const char *msg)
 
HeapTuple do_convert_tuple (HeapTuple tuple, TupleConversionMap *map)
 
void free_conversion_map (TupleConversionMap *map)
 

Typedef Documentation

Function Documentation

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

Definition at line 210 of file tupconvert.c.

References TupleConversionMap::attrMap, convert_tuples_by_name_map(), i, TupleConversionMap::indesc, TupleConversionMap::inisnull, TupleConversionMap::invalues, tupleDesc::natts, TupleConversionMap::outdesc, TupleConversionMap::outisnull, TupleConversionMap::outvalues, palloc(), pfree(), tupleDesc::tdhasoid, and TupleDescAttr.

Referenced by acquire_inherited_sample_rows(), CopyFrom(), ExecConstraints(), ExecEvalConvertRowtype(), ExecPartitionCheck(), ExecSetupPartitionTupleRouting(), ExecSetupTransitionCaptureState(), ExecWithCheckOptions(), and get_partition_dispatch_recurse().

213 {
214  TupleConversionMap *map;
215  AttrNumber *attrMap;
216  int n = outdesc->natts;
217  int i;
218  bool same;
219 
220  /* Verify compatibility and prepare attribute-number map */
221  attrMap = convert_tuples_by_name_map(indesc, outdesc, msg);
222 
223  /*
224  * Check to see if the map is one-to-one, in which case we need not do a
225  * tuple conversion. We must also insist that both tupdescs either
226  * specify or don't specify an OID column, else we need a conversion to
227  * add/remove space for that. (For some callers, presence or absence of
228  * an OID column perhaps would not really matter, but let's be safe.)
229  */
230  if (indesc->natts == outdesc->natts &&
231  indesc->tdhasoid == outdesc->tdhasoid)
232  {
233  same = true;
234  for (i = 0; i < n; i++)
235  {
236  Form_pg_attribute inatt;
237  Form_pg_attribute outatt;
238 
239  if (attrMap[i] == (i + 1))
240  continue;
241 
242  /*
243  * If it's a dropped column and the corresponding input column is
244  * also dropped, we needn't convert. However, attlen and attalign
245  * must agree.
246  */
247  inatt = TupleDescAttr(indesc, i);
248  outatt = TupleDescAttr(outdesc, i);
249  if (attrMap[i] == 0 &&
250  inatt->attisdropped &&
251  inatt->attlen == outatt->attlen &&
252  inatt->attalign == outatt->attalign)
253  continue;
254 
255  same = false;
256  break;
257  }
258  }
259  else
260  same = false;
261 
262  if (same)
263  {
264  /* Runtime conversion is not needed */
265  pfree(attrMap);
266  return NULL;
267  }
268 
269  /* Prepare the map structure */
270  map = (TupleConversionMap *) palloc(sizeof(TupleConversionMap));
271  map->indesc = indesc;
272  map->outdesc = outdesc;
273  map->attrMap = attrMap;
274  /* preallocate workspace for Datum arrays */
275  map->outvalues = (Datum *) palloc(n * sizeof(Datum));
276  map->outisnull = (bool *) palloc(n * sizeof(bool));
277  n = indesc->natts + 1; /* +1 for NULL */
278  map->invalues = (Datum *) palloc(n * sizeof(Datum));
279  map->inisnull = (bool *) palloc(n * sizeof(bool));
280  map->invalues[0] = (Datum) 0; /* set up the NULL entry */
281  map->inisnull[0] = true;
282 
283  return map;
284 }
AttrNumber * attrMap
Definition: tupconvert.h:25
TupleDesc indesc
Definition: tupconvert.h:23
TupleDesc outdesc
Definition: tupconvert.h:24
bool tdhasoid
Definition: tupdesc.h:76
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:84
int natts
Definition: tupdesc.h:73
void pfree(void *pointer)
Definition: mcxt.c:949
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
AttrNumber * convert_tuples_by_name_map(TupleDesc indesc, TupleDesc outdesc, const char *msg)
Definition: tupconvert.c:293
uintptr_t Datum
Definition: postgres.h:372
void * palloc(Size size)
Definition: mcxt.c:848
int i
int16 AttrNumber
Definition: attnum.h:21
AttrNumber* convert_tuples_by_name_map ( TupleDesc  indesc,
TupleDesc  outdesc,
const char *  msg 
)

Definition at line 293 of file tupconvert.c.

References _, ereport, errcode(), errdetail(), errmsg_internal(), ERROR, format_type_be(), i, NameStr, tupleDesc::natts, palloc0(), tupleDesc::tdtypeid, and TupleDescAttr.

Referenced by ATPrepAlterColumnType(), convert_tuples_by_name(), and map_partition_varattnos().

296 {
297  AttrNumber *attrMap;
298  int n;
299  int i;
300 
301  n = outdesc->natts;
302  attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber));
303  for (i = 0; i < n; i++)
304  {
305  Form_pg_attribute outatt = TupleDescAttr(outdesc, i);
306  char *attname;
307  Oid atttypid;
308  int32 atttypmod;
309  int j;
310 
311  if (outatt->attisdropped)
312  continue; /* attrMap[i] is already 0 */
313  attname = NameStr(outatt->attname);
314  atttypid = outatt->atttypid;
315  atttypmod = outatt->atttypmod;
316  for (j = 0; j < indesc->natts; j++)
317  {
318  Form_pg_attribute inatt = TupleDescAttr(indesc, j);
319 
320  if (inatt->attisdropped)
321  continue;
322  if (strcmp(attname, NameStr(inatt->attname)) == 0)
323  {
324  /* Found it, check type */
325  if (atttypid != inatt->atttypid || atttypmod != inatt->atttypmod)
326  ereport(ERROR,
327  (errcode(ERRCODE_DATATYPE_MISMATCH),
328  errmsg_internal("%s", _(msg)),
329  errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.",
330  attname,
331  format_type_be(outdesc->tdtypeid),
332  format_type_be(indesc->tdtypeid))));
333  attrMap[i] = (AttrNumber) (j + 1);
334  break;
335  }
336  }
337  if (attrMap[i] == 0)
338  ereport(ERROR,
339  (errcode(ERRCODE_DATATYPE_MISMATCH),
340  errmsg_internal("%s", _(msg)),
341  errdetail("Attribute \"%s\" of type %s does not exist in type %s.",
342  attname,
343  format_type_be(outdesc->tdtypeid),
344  format_type_be(indesc->tdtypeid))));
345  }
346 
347  return attrMap;
348 }
Oid tdtypeid
Definition: tupdesc.h:74
#define TupleDescAttr(tupdesc, i)
Definition: tupdesc.h:84
int errcode(int sqlerrcode)
Definition: elog.c:575
char * format_type_be(Oid type_oid)
Definition: format_type.c:94
unsigned int Oid
Definition: postgres_ext.h:31
int natts
Definition: tupdesc.h:73
signed int int32
Definition: c.h:246
#define ERROR
Definition: elog.h:43
int errdetail(const char *fmt,...)
Definition: elog.c:873
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:187
#define ereport(elevel, rest)
Definition: elog.h:122
void * palloc0(Size size)
Definition: mcxt.c:877
int errmsg_internal(const char *fmt,...)
Definition: elog.c:827
int i
#define NameStr(name)
Definition: c.h:493
int16 AttrNumber
Definition: attnum.h:21
#define _(x)
Definition: elog.c:84
TupleConversionMap* convert_tuples_by_position ( TupleDesc  indesc,
TupleDesc  outdesc,
const char *  msg 
)

Definition at line 66 of file tupconvert.c.

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

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

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

Definition at line 354 of file tupconvert.c.

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

Referenced by acquire_inherited_sample_rows(), AfterTriggerSaveEvent(), CopyFrom(), exec_stmt_return_next(), exec_stmt_return_query(), ExecConstraints(), ExecEvalConvertRowtype(), ExecInsert(), ExecPartitionCheck(), ExecWithCheckOptions(), get_partition_for_tuple(), plpgsql_exec_function(), and plpgsql_exec_trigger().

355 {
356  AttrNumber *attrMap = map->attrMap;
357  Datum *invalues = map->invalues;
358  bool *inisnull = map->inisnull;
359  Datum *outvalues = map->outvalues;
360  bool *outisnull = map->outisnull;
361  int outnatts = map->outdesc->natts;
362  int i;
363 
364  /*
365  * Extract all the values of the old tuple, offsetting the arrays so that
366  * invalues[0] is left NULL and invalues[1] is the first source attribute;
367  * this exactly matches the numbering convention in attrMap.
368  */
369  heap_deform_tuple(tuple, map->indesc, invalues + 1, inisnull + 1);
370 
371  /*
372  * Transpose into proper fields of the new tuple.
373  */
374  for (i = 0; i < outnatts; i++)
375  {
376  int j = attrMap[i];
377 
378  outvalues[i] = invalues[j];
379  outisnull[i] = inisnull[j];
380  }
381 
382  /*
383  * Now form the new tuple.
384  */
385  return heap_form_tuple(map->outdesc, outvalues, outisnull);
386 }
AttrNumber * attrMap
Definition: tupconvert.h:25
TupleDesc indesc
Definition: tupconvert.h:23
TupleDesc outdesc
Definition: tupconvert.h:24
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:695
int natts
Definition: tupdesc.h:73
uintptr_t Datum
Definition: postgres.h:372
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:936
int i
int16 AttrNumber
Definition: attnum.h:21
void free_conversion_map ( TupleConversionMap map)

Definition at line 392 of file tupconvert.c.

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

Referenced by acquire_inherited_sample_rows().

393 {
394  /* indesc and outdesc are not ours to free */
395  pfree(map->attrMap);
396  pfree(map->invalues);
397  pfree(map->inisnull);
398  pfree(map->outvalues);
399  pfree(map->outisnull);
400  pfree(map);
401 }
AttrNumber * attrMap
Definition: tupconvert.h:25
void pfree(void *pointer)
Definition: mcxt.c:949