1/*-------------------------------------------------------------------------
4 * Attribute mapping support.
6 * This file provides utility routines to build and manage attribute
7 * mappings by comparing input and output TupleDescs. Such mappings
8 * are typically used by DDL operating on inheritance and partition trees
9 * to do a conversion between rowtypes logically equivalent but with
10 * columns in a different order, taking into account dropped columns.
11 * They are also used by the tuple conversion routines in tupconvert.c.
13 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
14 * Portions Copyright (c) 1994, Regents of the University of California
18 * src/backend/access/common/attmap.c
20 *-------------------------------------------------------------------------
36 * Utility routine to allocate an attribute map in the current memory
53 * Utility routine to release an attribute map.
63 * build_attrmap_by_position
65 * Return a palloc'd bare attribute map for tuple conversion, matching input
66 * and output columns by position. Dropped columns are ignored in both input
67 * and output, marked as 0. This is normally a subroutine for
68 * convert_tuples_by_position in tupconvert.c, but it can be used standalone.
70 * Note: the errdetail messages speak of indesc as the "returned" rowtype,
71 * outdesc as the "expected" rowtype. This is okay for current uses but
72 * might need generalization in future.
88 * The length is computed as the number of attributes of the expected
89 * rowtype as it includes dropped attributes in its count.
94 j = 0;
/* j is next physical input attribute */
95 nincols = noutcols = 0;
/* these count non-dropped attributes */
97 for (
i = 0;
i < n;
i++)
101 if (outatt->attisdropped)
102 continue;
/* attrMap->attnums[i] is already 0 */
108 if (inatt->attisdropped)
112 /* Found matching column, now check type */
113 if (outatt->atttypid != inatt->atttypid ||
114 (outatt->atttypmod != inatt->atttypmod && outatt->atttypmod >= 0))
116 (
errcode(ERRCODE_DATATYPE_MISMATCH),
118 errdetail(
"Returned type %s does not match expected type %s in column \"%s\" (position %d).",
130 same =
false;
/* we'll complain below */
133 /* Check for unused input columns */
139 same =
false;
/* we'll complain below */
142 /* Report column count mismatch using the non-dropped-column counts */
145 (
errcode(ERRCODE_DATATYPE_MISMATCH),
147 errdetail(
"Number of returned columns (%d) does not match "
148 "expected column count (%d).",
149 nincols, noutcols)));
151 /* Check if the map has a one-to-one match */
154 /* Runtime conversion is not needed */
163 * build_attrmap_by_name
165 * Return a palloc'd bare attribute map for tuple conversion, matching input
166 * and output columns by name. (Dropped columns are ignored in both input and
167 * output.) This is normally a subroutine for convert_tuples_by_name in
168 * tupconvert.c, but can be used standalone.
170 * If 'missing_ok' is true, a column from 'outdesc' not being present in
171 * 'indesc' is not flagged as an error; AttrMap.attnums[] entry for such an
172 * outdesc column will be 0 in that case.
185 outnatts = outdesc->
natts;
186 innatts = indesc->
natts;
189 for (
i = 0;
i < outnatts;
i++)
197 if (outatt->attisdropped)
198 continue;
/* attrMap->attnums[i] is already 0 */
200 atttypid = outatt->atttypid;
201 atttypmod = outatt->atttypmod;
204 * Now search for an attribute with the same name in the indesc. It
205 * seems likely that a partitioned table will have the attributes in
206 * the same order as the partition, so the search below is optimized
207 * for that case. It is possible that columns are dropped in one of
208 * the relations, but not the other, so we use the 'nextindesc'
209 * counter to track the starting point of the search. If the inner
210 * loop encounters dropped columns then it will have to skip over
211 * them, but it should leave 'nextindesc' at the correct position for
212 * the next outer loop.
214 for (
j = 0;
j < innatts;
j++)
219 if (nextindesc >= innatts)
223 if (inatt->attisdropped)
227 /* Found it, check type */
228 if (atttypid != inatt->atttypid || atttypmod != inatt->atttypmod)
230 (
errcode(ERRCODE_DATATYPE_MISMATCH),
231 errmsg(
"could not convert row type"),
232 errdetail(
"Attribute \"%s\" of type %s does not match corresponding attribute of type %s.",
236 attrMap->
attnums[
i] = inatt->attnum;
240 if (attrMap->
attnums[
i] == 0 && !missing_ok)
242 (
errcode(ERRCODE_DATATYPE_MISMATCH),
243 errmsg(
"could not convert row type"),
244 errdetail(
"Attribute \"%s\" of type %s does not exist in type %s.",
253 * build_attrmap_by_name_if_req
255 * Returns mapping created by build_attrmap_by_name, or NULL if no
256 * conversion is required. This is a convenience routine for
257 * convert_tuples_by_name() in tupconvert.c and other functions, but it
258 * can be used standalone.
267 /* Verify compatibility and prepare attribute-number map */
270 /* Check if the map has a one-to-one match */
273 /* Runtime conversion is not needed */
282 * check_attrmap_match
284 * Check to see if the map is a one-to-one match, in which case we need
285 * not to do a tuple conversion, and the attribute map is not necessary.
294 /* no match if attribute numbers are not the same */
304 * If the input column has a missing attribute, we need a conversion.
315 * If it's a dropped column and the corresponding input column is also
316 * dropped, we don't need a conversion. However, attlen and
317 * attalignby must agree.
void free_attrmap(AttrMap *map)
AttrMap * make_attrmap(int maplen)
AttrMap * build_attrmap_by_name(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
AttrMap * build_attrmap_by_name_if_req(TupleDesc indesc, TupleDesc outdesc, bool missing_ok)
static bool check_attrmap_match(TupleDesc indesc, TupleDesc outdesc, AttrMap *attrMap)
AttrMap * build_attrmap_by_position(TupleDesc indesc, TupleDesc outdesc, const char *msg)
int errmsg_internal(const char *fmt,...)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
void pfree(void *pointer)
void * palloc0(Size size)
FormData_pg_attribute * Form_pg_attribute
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)