Refactor attribute mappings used in logical tuple conversion

Tuple conversion support in tupconvert.c is able to convert rowtypes
between two relations, inner and outer, which are logically equivalent
but have a different ordering or even dropped columns (used mainly for
inheritance tree and partitions).  This makes use of attribute mappings,
which are simple arrays made of AttrNumber elements with a length
matching the number of attributes of the outer relation.  The length of
the attribute mapping has been treated as completely independent of the
mapping itself until now, making it easy to pass down an incorrect
mapping length.

This commit refactors the code related to attribute mappings and moves
it into an independent facility called attmap.c, extracted from
tupconvert.c.  This merges the attribute mapping with its length,
avoiding to try to guess what is the length of a mapping to use as this
is computed once, when the map is built.

This will avoid mistakes like what has been fixed in dc816e58, which has
used an incorrect mapping length by matching it with the number of
attributes of an inner relation (a child partition) instead of an outer
relation (a partitioned table).

Author: Michael Paquier
Reviewed-by: Amit Langote
Discussion: https://postgr.es/m/20191121042556.GD153437@paquier.xyz
This commit is contained in:
Michael Paquier 2019-12-18 16:23:02 +09:00
parent 04c8a69c0c
commit e1551f96e6
22 changed files with 534 additions and 420 deletions

View File

@ -13,6 +13,7 @@ top_builddir = ../../../..
include $(top_builddir)/src/Makefile.global include $(top_builddir)/src/Makefile.global
OBJS = \ OBJS = \
attmap.o \
bufmask.o \ bufmask.o \
detoast.o \ detoast.o \
heaptuple.o \ heaptuple.o \

View File

@ -0,0 +1,320 @@
/*-------------------------------------------------------------------------
*
* attmap.c
* Attribute mapping support.
*
* This file provides utility routines to build and manage attribute
* mappings by comparing input and output TupleDescs. Such mappings
* are typically used by DDL operating on inheritance and partition trees
* to do a conversion between rowtypes logically equivalent but with
* columns in a different order, taking into account dropped columns.
* They are also used by the tuple conversion routines in tupconvert.c.
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* src/backend/access/common/attmap.c
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "access/attmap.h"
#include "access/htup_details.h"
#include "utils/builtins.h"
static bool check_attrmap_match(TupleDesc indesc,
TupleDesc outdesc,
AttrMap *attrMap);
/*
* make_attrmap
*
* Utility routine to allocate an attribute map in the current memory
* context.
*/
AttrMap *
make_attrmap(int maplen)
{
AttrMap *res;
res = (AttrMap *) palloc0(sizeof(AttrMap));
res->maplen = maplen;
res->attnums = (AttrNumber *) palloc0(sizeof(AttrNumber) * maplen);
return res;
}
/*
* free_attrmap
*
* Utility routine to release an attribute map.
*/
void
free_attrmap(AttrMap *map)
{
pfree(map->attnums);
pfree(map);
}
/*
* build_attrmap_by_position
*
* Return a palloc'd bare attribute map for tuple conversion, matching input
* and output columns by position. Dropped columns are ignored in both input
* and output, marked as 0. This is normally a subroutine for
* convert_tuples_by_position in tupconvert.c, but it can be used standalone.
*
* Note: the errdetail messages speak of indesc as the "returned" rowtype,
* outdesc as the "expected" rowtype. This is okay for current uses but
* might need generalization in future.
*/
AttrMap *
build_attrmap_by_position(TupleDesc indesc,
TupleDesc outdesc,
const char *msg)
{
AttrMap *attrMap;
int nincols;
int noutcols;
int n;
int i;
int j;
bool same;
/*
* The length is computed as the number of attributes of the expected
* rowtype as it includes dropped attributes in its count.
*/
n = outdesc->natts;
attrMap = make_attrmap(n);
j = 0; /* j is next physical input attribute */
nincols = noutcols = 0; /* these count non-dropped attributes */
same = true;
for (i = 0; i < n; i++)
{
Form_pg_attribute att = TupleDescAttr(outdesc, i);
Oid atttypid;
int32 atttypmod;
if (att->attisdropped)
continue; /* attrMap->attnums[i] is already 0 */
noutcols++;
atttypid = att->atttypid;
atttypmod = att->atttypmod;
for (; j < indesc->natts; j++)
{
att = TupleDescAttr(indesc, j);
if (att->attisdropped)
continue;
nincols++;
/* Found matching column, now check type */
if (atttypid != att->atttypid ||
(atttypmod != att->atttypmod && atttypmod >= 0))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg_internal("%s", _(msg)),
errdetail("Returned type %s does not match expected type %s in column %d.",
format_type_with_typemod(att->atttypid,
att->atttypmod),
format_type_with_typemod(atttypid,
atttypmod),
noutcols)));
attrMap->attnums[i] = (AttrNumber) (j + 1);
j++;
break;
}
if (attrMap->attnums[i] == 0)
same = false; /* we'll complain below */
}
/* Check for unused input columns */
for (; j < indesc->natts; j++)
{
if (TupleDescAttr(indesc, j)->attisdropped)
continue;
nincols++;
same = false; /* we'll complain below */
}
/* Report column count mismatch using the non-dropped-column counts */
if (!same)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg_internal("%s", _(msg)),
errdetail("Number of returned columns (%d) does not match "
"expected column count (%d).",
nincols, noutcols)));
/* Check if the map has a one-to-one match */
if (check_attrmap_match(indesc, outdesc, attrMap))
{
/* Runtime conversion is not needed */
free_attrmap(attrMap);
return NULL;
}
return attrMap;
}
/*
* build_attrmap_by_name
*
* Return a palloc'd bare attribute map for tuple conversion, matching input
* and output columns by name. (Dropped columns are ignored in both input and
* output.) This is normally a subroutine for convert_tuples_by_name in
* tupconvert.c, but can be used standalone.
*/
AttrMap *
build_attrmap_by_name(TupleDesc indesc,
TupleDesc outdesc)
{
AttrMap *attrMap;
int outnatts;
int innatts;
int i;
int nextindesc = -1;
outnatts = outdesc->natts;
innatts = indesc->natts;
attrMap = make_attrmap(outnatts);
for (i = 0; i < outnatts; i++)
{
Form_pg_attribute outatt = TupleDescAttr(outdesc, i);
char *attname;
Oid atttypid;
int32 atttypmod;
int j;
if (outatt->attisdropped)
continue; /* attrMap->attnums[i] is already 0 */
attname = NameStr(outatt->attname);
atttypid = outatt->atttypid;
atttypmod = outatt->atttypmod;
/*
* Now search for an attribute with the same name in the indesc. It
* seems likely that a partitioned table will have the attributes in
* the same order as the partition, so the search below is optimized
* for that case. It is possible that columns are dropped in one of
* the relations, but not the other, so we use the 'nextindesc'
* counter to track the starting point of the search. If the inner
* loop encounters dropped columns then it will have to skip over
* them, but it should leave 'nextindesc' at the correct position for
* the next outer loop.
*/
for (j = 0; j < innatts; j++)
{
Form_pg_attribute inatt;
nextindesc++;
if (nextindesc >= innatts)
nextindesc = 0;
inatt = TupleDescAttr(indesc, nextindesc);
if (inatt->attisdropped)
continue;
if (strcmp(attname, NameStr(inatt->attname)) == 0)
{
/* Found it, check type */
if (atttypid != inatt->atttypid || atttypmod != inatt->atttypmod)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not convert row type"),
errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.",
attname,
format_type_be(outdesc->tdtypeid),
format_type_be(indesc->tdtypeid))));
attrMap->attnums[i] = inatt->attnum;
break;
}
}
if (attrMap->attnums[i] == 0)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not convert row type"),
errdetail("Attribute \"%s\" of type %s does not exist in type %s.",
attname,
format_type_be(outdesc->tdtypeid),
format_type_be(indesc->tdtypeid))));
}
return attrMap;
}
/*
* build_attrmap_by_name_if_req
*
* Returns mapping created by build_attrmap_by_name, or NULL if no
* conversion is required. This is a convenience routine for
* convert_tuples_by_name() in tupconvert.c and other functions, but it
* can be used standalone.
*/
AttrMap *
build_attrmap_by_name_if_req(TupleDesc indesc,
TupleDesc outdesc)
{
AttrMap *attrMap;
/* Verify compatibility and prepare attribute-number map */
attrMap = build_attrmap_by_name(indesc, outdesc);
/* Check if the map has a one-to-one match */
if (check_attrmap_match(indesc, outdesc, attrMap))
{
/* Runtime conversion is not needed */
free_attrmap(attrMap);
return NULL;
}
return attrMap;
}
/*
* check_attrmap_match
*
* Check to see if the map is a one-to-one match, in which case we need
* not to do a tuple conversion, and the attribute map is not necessary.
*/
static bool
check_attrmap_match(TupleDesc indesc,
TupleDesc outdesc,
AttrMap *attrMap)
{
int i;
/* no match if attribute numbers are not the same */
if (indesc->natts != outdesc->natts)
return false;
for (i = 0; i < attrMap->maplen; i++)
{
Form_pg_attribute inatt;
Form_pg_attribute outatt;
if (attrMap->attnums[i] == (i + 1))
continue;
/*
* If it's a dropped column and the corresponding input column is also
* dropped, we don't need a conversion. However, attlen and attalign
* must agree.
*/
inatt = TupleDescAttr(indesc, i);
outatt = TupleDescAttr(outdesc, i);
if (attrMap->attnums[i] == 0 &&
inatt->attisdropped &&
inatt->attlen == outatt->attlen &&
inatt->attalign == outatt->attalign)
continue;
return false;
}
return true;
}

View File

@ -18,20 +18,18 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/htup_details.h"
#include "access/tupconvert.h" #include "access/tupconvert.h"
#include "executor/tuptable.h" #include "executor/tuptable.h"
#include "utils/builtins.h"
/* /*
* The conversion setup routines have the following common API: * The conversion setup routines have the following common API:
* *
* The setup routine checks whether the given source and destination tuple * The setup routine checks using attmap.c whether the given source and
* descriptors are logically compatible. If not, it throws an error. * destination tuple descriptors are logically compatible. If not, it throws
* If so, it returns NULL if they are physically compatible (ie, no conversion * an error. If so, it returns NULL if they are physically compatible (ie, no
* is needed), else a TupleConversionMap that can be used by execute_attr_map_tuple * conversion is needed), else a TupleConversionMap that can be used by
* to perform the conversion. * execute_attr_map_tuple or execute_attr_map_slot to perform the conversion.
* *
* The TupleConversionMap, if needed, is palloc'd in the caller's memory * The TupleConversionMap, if needed, is palloc'd in the caller's memory
* context. Also, the given tuple descriptors are referenced by the map, * context. Also, the given tuple descriptors are referenced by the map,
@ -56,10 +54,6 @@
/* /*
* Set up for tuple conversion, matching input and output columns by * Set up for tuple conversion, matching input and output columns by
* position. (Dropped columns are ignored in both input and output.) * position. (Dropped columns are ignored in both input and output.)
*
* Note: the errdetail messages speak of indesc as the "returned" rowtype,
* outdesc as the "expected" rowtype. This is okay for current uses but
* might need generalization in future.
*/ */
TupleConversionMap * TupleConversionMap *
convert_tuples_by_position(TupleDesc indesc, convert_tuples_by_position(TupleDesc indesc,
@ -67,113 +61,15 @@ convert_tuples_by_position(TupleDesc indesc,
const char *msg) const char *msg)
{ {
TupleConversionMap *map; TupleConversionMap *map;
AttrNumber *attrMap;
int nincols;
int noutcols;
int n; int n;
int i; AttrMap *attrMap;
int j;
bool same;
/* Verify compatibility and prepare attribute-number map */ /* Verify compatibility and prepare attribute-number map */
n = outdesc->natts; attrMap = build_attrmap_by_position(indesc, outdesc, msg);
attrMap = (AttrNumber *) palloc0(n * sizeof(AttrNumber));
j = 0; /* j is next physical input attribute */ if (attrMap == NULL)
nincols = noutcols = 0; /* these count non-dropped attributes */
same = true;
for (i = 0; i < n; i++)
{ {
Form_pg_attribute att = TupleDescAttr(outdesc, i); /* runtime conversion is not needed */
Oid atttypid;
int32 atttypmod;
if (att->attisdropped)
continue; /* attrMap[i] is already 0 */
noutcols++;
atttypid = att->atttypid;
atttypmod = att->atttypmod;
for (; j < indesc->natts; j++)
{
att = TupleDescAttr(indesc, j);
if (att->attisdropped)
continue;
nincols++;
/* Found matching column, check type */
if (atttypid != att->atttypid ||
(atttypmod != att->atttypmod && atttypmod >= 0))
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg_internal("%s", _(msg)),
errdetail("Returned type %s does not match expected type %s in column %d.",
format_type_with_typemod(att->atttypid,
att->atttypmod),
format_type_with_typemod(atttypid,
atttypmod),
noutcols)));
attrMap[i] = (AttrNumber) (j + 1);
j++;
break;
}
if (attrMap[i] == 0)
same = false; /* we'll complain below */
}
/* Check for unused input columns */
for (; j < indesc->natts; j++)
{
if (TupleDescAttr(indesc, j)->attisdropped)
continue;
nincols++;
same = false; /* we'll complain below */
}
/* Report column count mismatch using the non-dropped-column counts */
if (!same)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg_internal("%s", _(msg)),
errdetail("Number of returned columns (%d) does not match "
"expected column count (%d).",
nincols, noutcols)));
/*
* Check to see if the map is one-to-one, in which case we need not do a
* tuple conversion.
*/
if (indesc->natts == outdesc->natts)
{
for (i = 0; i < n; i++)
{
Form_pg_attribute inatt;
Form_pg_attribute outatt;
if (attrMap[i] == (i + 1))
continue;
/*
* If it's a dropped column and the corresponding input column is
* also dropped, we needn't convert. However, attlen and attalign
* must agree.
*/
inatt = TupleDescAttr(indesc, i);
outatt = TupleDescAttr(outdesc, i);
if (attrMap[i] == 0 &&
inatt->attisdropped &&
inatt->attlen == outatt->attlen &&
inatt->attalign == outatt->attalign)
continue;
same = false;
break;
}
}
else
same = false;
if (same)
{
/* Runtime conversion is not needed */
pfree(attrMap);
return NULL; return NULL;
} }
@ -183,6 +79,7 @@ convert_tuples_by_position(TupleDesc indesc,
map->outdesc = outdesc; map->outdesc = outdesc;
map->attrMap = attrMap; map->attrMap = attrMap;
/* preallocate workspace for Datum arrays */ /* preallocate workspace for Datum arrays */
n = outdesc->natts + 1; /* +1 for NULL */
map->outvalues = (Datum *) palloc(n * sizeof(Datum)); map->outvalues = (Datum *) palloc(n * sizeof(Datum));
map->outisnull = (bool *) palloc(n * sizeof(bool)); map->outisnull = (bool *) palloc(n * sizeof(bool));
n = indesc->natts + 1; /* +1 for NULL */ n = indesc->natts + 1; /* +1 for NULL */
@ -206,11 +103,11 @@ convert_tuples_by_name(TupleDesc indesc,
TupleDesc outdesc) TupleDesc outdesc)
{ {
TupleConversionMap *map; TupleConversionMap *map;
AttrNumber *attrMap; AttrMap *attrMap;
int n = outdesc->natts; int n = outdesc->natts;
/* Verify compatibility and prepare attribute-number map */ /* Verify compatibility and prepare attribute-number map */
attrMap = convert_tuples_by_name_map_if_req(indesc, outdesc); attrMap = build_attrmap_by_name_if_req(indesc, outdesc);
if (attrMap == NULL) if (attrMap == NULL)
{ {
@ -235,158 +132,13 @@ convert_tuples_by_name(TupleDesc indesc,
return map; return map;
} }
/*
* Return a palloc'd bare attribute map for tuple conversion, matching input
* and output columns by name. (Dropped columns are ignored in both input and
* output.) This is normally a subroutine for convert_tuples_by_name, but can
* be used standalone.
*/
AttrNumber *
convert_tuples_by_name_map(TupleDesc indesc,
TupleDesc outdesc)
{
AttrNumber *attrMap;
int outnatts;
int innatts;
int i;
int nextindesc = -1;
outnatts = outdesc->natts;
innatts = indesc->natts;
attrMap = (AttrNumber *) palloc0(outnatts * sizeof(AttrNumber));
for (i = 0; i < outnatts; i++)
{
Form_pg_attribute outatt = TupleDescAttr(outdesc, i);
char *attname;
Oid atttypid;
int32 atttypmod;
int j;
if (outatt->attisdropped)
continue; /* attrMap[i] is already 0 */
attname = NameStr(outatt->attname);
atttypid = outatt->atttypid;
atttypmod = outatt->atttypmod;
/*
* Now search for an attribute with the same name in the indesc. It
* seems likely that a partitioned table will have the attributes in
* the same order as the partition, so the search below is optimized
* for that case. It is possible that columns are dropped in one of
* the relations, but not the other, so we use the 'nextindesc'
* counter to track the starting point of the search. If the inner
* loop encounters dropped columns then it will have to skip over
* them, but it should leave 'nextindesc' at the correct position for
* the next outer loop.
*/
for (j = 0; j < innatts; j++)
{
Form_pg_attribute inatt;
nextindesc++;
if (nextindesc >= innatts)
nextindesc = 0;
inatt = TupleDescAttr(indesc, nextindesc);
if (inatt->attisdropped)
continue;
if (strcmp(attname, NameStr(inatt->attname)) == 0)
{
/* Found it, check type */
if (atttypid != inatt->atttypid || atttypmod != inatt->atttypmod)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not convert row type"),
errdetail("Attribute \"%s\" of type %s does not match corresponding attribute of type %s.",
attname,
format_type_be(outdesc->tdtypeid),
format_type_be(indesc->tdtypeid))));
attrMap[i] = inatt->attnum;
break;
}
}
if (attrMap[i] == 0)
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("could not convert row type"),
errdetail("Attribute \"%s\" of type %s does not exist in type %s.",
attname,
format_type_be(outdesc->tdtypeid),
format_type_be(indesc->tdtypeid))));
}
return attrMap;
}
/*
* Returns mapping created by convert_tuples_by_name_map, or NULL if no
* conversion not required. This is a convenience routine for
* convert_tuples_by_name() and other functions.
*/
AttrNumber *
convert_tuples_by_name_map_if_req(TupleDesc indesc,
TupleDesc outdesc)
{
AttrNumber *attrMap;
int n = outdesc->natts;
int i;
bool same;
/* Verify compatibility and prepare attribute-number map */
attrMap = convert_tuples_by_name_map(indesc, outdesc);
/*
* Check to see if the map is one-to-one, in which case we need not do a
* tuple conversion.
*/
if (indesc->natts == outdesc->natts)
{
same = true;
for (i = 0; i < n; i++)
{
Form_pg_attribute inatt;
Form_pg_attribute outatt;
if (attrMap[i] == (i + 1))
continue;
/*
* If it's a dropped column and the corresponding input column is
* also dropped, we needn't convert. However, attlen and attalign
* must agree.
*/
inatt = TupleDescAttr(indesc, i);
outatt = TupleDescAttr(outdesc, i);
if (attrMap[i] == 0 &&
inatt->attisdropped &&
inatt->attlen == outatt->attlen &&
inatt->attalign == outatt->attalign)
continue;
same = false;
break;
}
}
else
same = false;
if (same)
{
/* Runtime conversion is not needed */
pfree(attrMap);
return NULL;
}
else
return attrMap;
}
/* /*
* Perform conversion of a tuple according to the map. * Perform conversion of a tuple according to the map.
*/ */
HeapTuple HeapTuple
execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map) execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
{ {
AttrNumber *attrMap = map->attrMap; AttrMap *attrMap = map->attrMap;
Datum *invalues = map->invalues; Datum *invalues = map->invalues;
bool *inisnull = map->inisnull; bool *inisnull = map->inisnull;
Datum *outvalues = map->outvalues; Datum *outvalues = map->outvalues;
@ -404,9 +156,10 @@ execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
/* /*
* Transpose into proper fields of the new tuple. * Transpose into proper fields of the new tuple.
*/ */
for (i = 0; i < outnatts; i++) Assert(attrMap->maplen == outnatts);
for (i = 0; i < attrMap->maplen; i++)
{ {
int j = attrMap[i]; int j = attrMap->attnums[i];
outvalues[i] = invalues[j]; outvalues[i] = invalues[j];
outisnull[i] = inisnull[j]; outisnull[i] = inisnull[j];
@ -422,7 +175,7 @@ execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map)
* Perform conversion of a tuple slot according to the map. * Perform conversion of a tuple slot according to the map.
*/ */
TupleTableSlot * TupleTableSlot *
execute_attr_map_slot(AttrNumber *attrMap, execute_attr_map_slot(AttrMap *attrMap,
TupleTableSlot *in_slot, TupleTableSlot *in_slot,
TupleTableSlot *out_slot) TupleTableSlot *out_slot)
{ {
@ -454,9 +207,9 @@ execute_attr_map_slot(AttrNumber *attrMap,
/* Transpose into proper fields of the out slot. */ /* Transpose into proper fields of the out slot. */
for (i = 0; i < outnatts; i++) for (i = 0; i < outnatts; i++)
{ {
int j = attrMap[i] - 1; int j = attrMap->attnums[i] - 1;
/* attrMap[i] == 0 means it's a NULL datum. */ /* attrMap->attnums[i] == 0 means it's a NULL datum. */
if (j == -1) if (j == -1)
{ {
outvalues[i] = (Datum) 0; outvalues[i] = (Datum) 0;
@ -481,7 +234,7 @@ void
free_conversion_map(TupleConversionMap *map) free_conversion_map(TupleConversionMap *map)
{ {
/* indesc and outdesc are not ours to free */ /* indesc and outdesc are not ours to free */
pfree(map->attrMap); free_attrmap(map->attrMap);
pfree(map->invalues); pfree(map->invalues);
pfree(map->inisnull); pfree(map->inisnull);
pfree(map->outvalues); pfree(map->outvalues);

View File

@ -2381,13 +2381,13 @@ BuildDummyIndexInfo(Relation index)
* Note: passing collations and opfamilies separately is a kludge. Adding * Note: passing collations and opfamilies separately is a kludge. Adding
* them to IndexInfo may result in better coding here and elsewhere. * them to IndexInfo may result in better coding here and elsewhere.
* *
* Use convert_tuples_by_name_map(index2, index1) to build the attmap. * Use build_attrmap_by_name(index2, index1) to build the attmap.
*/ */
bool bool
CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
Oid *collations1, Oid *collations2, Oid *collations1, Oid *collations2,
Oid *opfamilies1, Oid *opfamilies2, Oid *opfamilies1, Oid *opfamilies2,
AttrNumber *attmap, int maplen) AttrMap *attmap)
{ {
int i; int i;
@ -2414,12 +2414,12 @@ CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
*/ */
for (i = 0; i < info1->ii_NumIndexAttrs; i++) for (i = 0; i < info1->ii_NumIndexAttrs; i++)
{ {
if (maplen < info2->ii_IndexAttrNumbers[i]) if (attmap->maplen < info2->ii_IndexAttrNumbers[i])
elog(ERROR, "incorrect attribute map"); elog(ERROR, "incorrect attribute map");
/* ignore expressions at this stage */ /* ignore expressions at this stage */
if ((info1->ii_IndexAttrNumbers[i] != InvalidAttrNumber) && if ((info1->ii_IndexAttrNumbers[i] != InvalidAttrNumber) &&
(attmap[info2->ii_IndexAttrNumbers[i] - 1] != (attmap->attnums[info2->ii_IndexAttrNumbers[i] - 1] !=
info1->ii_IndexAttrNumbers[i])) info1->ii_IndexAttrNumbers[i]))
return false; return false;
@ -2445,7 +2445,7 @@ CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
Node *mapped; Node *mapped;
mapped = map_variable_attnos((Node *) info2->ii_Expressions, mapped = map_variable_attnos((Node *) info2->ii_Expressions,
1, 0, attmap, maplen, 1, 0, attmap,
InvalidOid, &found_whole_row); InvalidOid, &found_whole_row);
if (found_whole_row) if (found_whole_row)
{ {
@ -2469,7 +2469,7 @@ CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
Node *mapped; Node *mapped;
mapped = map_variable_attnos((Node *) info2->ii_Predicate, mapped = map_variable_attnos((Node *) info2->ii_Predicate,
1, 0, attmap, maplen, 1, 0, attmap,
InvalidOid, &found_whole_row); InvalidOid, &found_whole_row);
if (found_whole_row) if (found_whole_row)
{ {

View File

@ -14,11 +14,11 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/attmap.h"
#include "access/genam.h" #include "access/genam.h"
#include "access/htup_details.h" #include "access/htup_details.h"
#include "access/sysattr.h" #include "access/sysattr.h"
#include "access/table.h" #include "access/table.h"
#include "access/tupconvert.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "catalog/partition.h" #include "catalog/partition.h"
#include "catalog/pg_inherits.h" #include "catalog/pg_inherits.h"
@ -206,14 +206,13 @@ map_partition_varattnos(List *expr, int fromrel_varno,
if (expr != NIL) if (expr != NIL)
{ {
AttrNumber *part_attnos; AttrMap *part_attmap;
part_attnos = convert_tuples_by_name_map(RelationGetDescr(to_rel), part_attmap = build_attrmap_by_name(RelationGetDescr(to_rel),
RelationGetDescr(from_rel)); RelationGetDescr(from_rel));
expr = (List *) map_variable_attnos((Node *) expr, expr = (List *) map_variable_attnos((Node *) expr,
fromrel_varno, 0, fromrel_varno, 0,
part_attnos, part_attmap,
RelationGetDescr(from_rel)->natts,
RelationGetForm(to_rel)->reltype, RelationGetForm(to_rel)->reltype,
&my_found_whole_row); &my_found_whole_row);
} }

View File

@ -18,7 +18,6 @@
#include "access/htup_details.h" #include "access/htup_details.h"
#include "access/sysattr.h" #include "access/sysattr.h"
#include "access/table.h" #include "access/table.h"
#include "access/tupconvert.h"
#include "access/xact.h" #include "access/xact.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/dependency.h" #include "catalog/dependency.h"

View File

@ -1060,9 +1060,8 @@ DefineIndex(Oid relationId,
Relation childrel; Relation childrel;
List *childidxs; List *childidxs;
ListCell *cell; ListCell *cell;
AttrNumber *attmap; AttrMap *attmap;
bool found = false; bool found = false;
int maplen;
childrel = table_open(childRelid, lockmode); childrel = table_open(childRelid, lockmode);
@ -1087,9 +1086,8 @@ DefineIndex(Oid relationId,
childidxs = RelationGetIndexList(childrel); childidxs = RelationGetIndexList(childrel);
attmap = attmap =
convert_tuples_by_name_map(RelationGetDescr(childrel), build_attrmap_by_name(RelationGetDescr(childrel),
parentDesc); parentDesc);
maplen = parentDesc->natts;
foreach(cell, childidxs) foreach(cell, childidxs)
{ {
@ -1108,7 +1106,7 @@ DefineIndex(Oid relationId,
collationObjectId, collationObjectId,
cldidx->rd_opfamily, cldidx->rd_opfamily,
opfamOids, opfamOids,
attmap, maplen)) attmap))
{ {
Oid cldConstrOid = InvalidOid; Oid cldConstrOid = InvalidOid;
@ -1193,7 +1191,7 @@ DefineIndex(Oid relationId,
{ {
ielem->expr = ielem->expr =
map_variable_attnos((Node *) ielem->expr, map_variable_attnos((Node *) ielem->expr,
1, 0, attmap, maplen, 1, 0, attmap,
InvalidOid, InvalidOid,
&found_whole_row); &found_whole_row);
if (found_whole_row) if (found_whole_row)
@ -1202,7 +1200,7 @@ DefineIndex(Oid relationId,
} }
childStmt->whereClause = childStmt->whereClause =
map_variable_attnos(stmt->whereClause, 1, 0, map_variable_attnos(stmt->whereClause, 1, 0,
attmap, maplen, attmap,
InvalidOid, &found_whole_row); InvalidOid, &found_whole_row);
if (found_whole_row) if (found_whole_row)
elog(ERROR, "cannot convert whole-row table reference"); elog(ERROR, "cannot convert whole-row table reference");
@ -1217,7 +1215,7 @@ DefineIndex(Oid relationId,
pgstat_progress_update_param(PROGRESS_CREATEIDX_PARTITIONS_DONE, pgstat_progress_update_param(PROGRESS_CREATEIDX_PARTITIONS_DONE,
i + 1); i + 1);
pfree(attmap); free_attrmap(attmap);
} }
/* /*

View File

@ -14,6 +14,7 @@
*/ */
#include "postgres.h" #include "postgres.h"
#include "access/attmap.h"
#include "access/genam.h" #include "access/genam.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "access/heapam_xlog.h" #include "access/heapam_xlog.h"
@ -22,7 +23,6 @@
#include "access/relscan.h" #include "access/relscan.h"
#include "access/sysattr.h" #include "access/sysattr.h"
#include "access/tableam.h" #include "access/tableam.h"
#include "access/tupconvert.h"
#include "access/xact.h" #include "access/xact.h"
#include "access/xlog.h" #include "access/xlog.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
@ -1070,7 +1070,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
foreach(cell, idxlist) foreach(cell, idxlist)
{ {
Relation idxRel = index_open(lfirst_oid(cell), AccessShareLock); Relation idxRel = index_open(lfirst_oid(cell), AccessShareLock);
AttrNumber *attmap; AttrMap *attmap;
IndexStmt *idxstmt; IndexStmt *idxstmt;
Oid constraintOid; Oid constraintOid;
@ -1090,12 +1090,11 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
} }
} }
attmap = convert_tuples_by_name_map(RelationGetDescr(rel), attmap = build_attrmap_by_name(RelationGetDescr(rel),
RelationGetDescr(parent)); RelationGetDescr(parent));
idxstmt = idxstmt =
generateClonedIndexStmt(NULL, idxRel, generateClonedIndexStmt(NULL, idxRel,
attmap, RelationGetDescr(parent)->natts, attmap, &constraintOid);
&constraintOid);
DefineIndex(RelationGetRelid(rel), DefineIndex(RelationGetRelid(rel),
idxstmt, idxstmt,
InvalidOid, InvalidOid,
@ -2156,7 +2155,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
Relation relation; Relation relation;
TupleDesc tupleDesc; TupleDesc tupleDesc;
TupleConstr *constr; TupleConstr *constr;
AttrNumber *newattno; AttrMap *newattmap;
AttrNumber parent_attno; AttrNumber parent_attno;
/* caller already got lock */ /* caller already got lock */
@ -2237,12 +2236,11 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
constr = tupleDesc->constr; constr = tupleDesc->constr;
/* /*
* newattno[] will contain the child-table attribute numbers for the * newattmap->attnums[] will contain the child-table attribute numbers
* attributes of this parent table. (They are not the same for * for the attributes of this parent table. (They are not the same
* parents after the first one, nor if we have dropped columns.) * for parents after the first one, nor if we have dropped columns.)
*/ */
newattno = (AttrNumber *) newattmap = make_attrmap(tupleDesc->natts);
palloc0(tupleDesc->natts * sizeof(AttrNumber));
for (parent_attno = 1; parent_attno <= tupleDesc->natts; for (parent_attno = 1; parent_attno <= tupleDesc->natts;
parent_attno++) parent_attno++)
@ -2257,7 +2255,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
* Ignore dropped columns in the parent. * Ignore dropped columns in the parent.
*/ */
if (attribute->attisdropped) if (attribute->attisdropped)
continue; /* leave newattno entry as zero */ continue; /* leave newattmap->attnums entry as zero */
/* /*
* Does it conflict with some previously inherited column? * Does it conflict with some previously inherited column?
@ -2315,7 +2313,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
/* Merge of NOT NULL constraints = OR 'em together */ /* Merge of NOT NULL constraints = OR 'em together */
def->is_not_null |= attribute->attnotnull; def->is_not_null |= attribute->attnotnull;
/* Default and other constraints are handled below */ /* Default and other constraints are handled below */
newattno[parent_attno - 1] = exist_attno; newattmap->attnums[parent_attno - 1] = exist_attno;
/* Check for GENERATED conflicts */ /* Check for GENERATED conflicts */
if (def->generated != attribute->attgenerated) if (def->generated != attribute->attgenerated)
@ -2346,7 +2344,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
def->constraints = NIL; def->constraints = NIL;
def->location = -1; def->location = -1;
inhSchema = lappend(inhSchema, def); inhSchema = lappend(inhSchema, def);
newattno[parent_attno - 1] = ++child_attno; newattmap->attnums[parent_attno - 1] = ++child_attno;
} }
/* /*
@ -2394,7 +2392,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
/* /*
* Now copy the CHECK constraints of this parent, adjusting attnos * Now copy the CHECK constraints of this parent, adjusting attnos
* using the completed newattno[] map. Identically named constraints * using the completed newattmap map. Identically named constraints
* are merged if possible, else we throw error. * are merged if possible, else we throw error.
*/ */
if (constr && constr->num_check > 0) if (constr && constr->num_check > 0)
@ -2415,7 +2413,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
/* Adjust Vars to match new table's column numbering */ /* Adjust Vars to match new table's column numbering */
expr = map_variable_attnos(stringToNode(check[i].ccbin), expr = map_variable_attnos(stringToNode(check[i].ccbin),
1, 0, 1, 0,
newattno, tupleDesc->natts, newattmap,
InvalidOid, &found_whole_row); InvalidOid, &found_whole_row);
/* /*
@ -2452,7 +2450,7 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
} }
} }
pfree(newattno); free_attrmap(newattmap);
/* /*
* Close the parent rel, but keep our lock on it until xact commit. * Close the parent rel, but keep our lock on it until xact commit.
@ -8168,7 +8166,7 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
for (int i = 0; i < pd->nparts; i++) for (int i = 0; i < pd->nparts; i++)
{ {
Relation partRel; Relation partRel;
AttrNumber *map; AttrMap *map;
AttrNumber *mapped_pkattnum; AttrNumber *mapped_pkattnum;
Oid partIndexId; Oid partIndexId;
@ -8178,13 +8176,13 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
* Map the attribute numbers in the referenced side of the FK * Map the attribute numbers in the referenced side of the FK
* definition to match the partition's column layout. * definition to match the partition's column layout.
*/ */
map = convert_tuples_by_name_map_if_req(RelationGetDescr(partRel), map = build_attrmap_by_name_if_req(RelationGetDescr(partRel),
RelationGetDescr(pkrel)); RelationGetDescr(pkrel));
if (map) if (map)
{ {
mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks); mapped_pkattnum = palloc(sizeof(AttrNumber) * numfks);
for (int j = 0; j < numfks; j++) for (int j = 0; j < numfks; j++)
mapped_pkattnum[j] = map[pkattnum[j] - 1]; mapped_pkattnum[j] = map->attnums[pkattnum[j] - 1];
} }
else else
mapped_pkattnum = pkattnum; mapped_pkattnum = pkattnum;
@ -8205,7 +8203,7 @@ addFkRecurseReferenced(List **wqueue, Constraint *fkconstraint, Relation rel,
if (map) if (map)
{ {
pfree(mapped_pkattnum); pfree(mapped_pkattnum);
pfree(map); free_attrmap(map);
} }
} }
} }
@ -8309,7 +8307,7 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
Oid partitionId = pd->oids[i]; Oid partitionId = pd->oids[i];
Relation partition = table_open(partitionId, lockmode); Relation partition = table_open(partitionId, lockmode);
List *partFKs; List *partFKs;
AttrNumber *attmap; AttrMap *attmap;
AttrNumber mapped_fkattnum[INDEX_MAX_KEYS]; AttrNumber mapped_fkattnum[INDEX_MAX_KEYS];
bool attached; bool attached;
char *conname; char *conname;
@ -8320,10 +8318,10 @@ addFkRecurseReferencing(List **wqueue, Constraint *fkconstraint, Relation rel,
CheckTableNotInUse(partition, "ALTER TABLE"); CheckTableNotInUse(partition, "ALTER TABLE");
attmap = convert_tuples_by_name_map(RelationGetDescr(partition), attmap = build_attrmap_by_name(RelationGetDescr(partition),
RelationGetDescr(rel)); RelationGetDescr(rel));
for (int j = 0; j < numfks; j++) for (int j = 0; j < numfks; j++)
mapped_fkattnum[j] = attmap[fkattnum[j] - 1]; mapped_fkattnum[j] = attmap->attnums[fkattnum[j] - 1];
/* Check whether an existing constraint can be repurposed */ /* Check whether an existing constraint can be repurposed */
partFKs = copyObject(RelationGetFKeyList(partition)); partFKs = copyObject(RelationGetFKeyList(partition));
@ -8471,7 +8469,7 @@ static void
CloneFkReferenced(Relation parentRel, Relation partitionRel) CloneFkReferenced(Relation parentRel, Relation partitionRel)
{ {
Relation pg_constraint; Relation pg_constraint;
AttrNumber *attmap; AttrMap *attmap;
ListCell *cell; ListCell *cell;
SysScanDesc scan; SysScanDesc scan;
ScanKeyData key[2]; ScanKeyData key[2];
@ -8510,8 +8508,8 @@ CloneFkReferenced(Relation parentRel, Relation partitionRel)
systable_endscan(scan); systable_endscan(scan);
table_close(pg_constraint, RowShareLock); table_close(pg_constraint, RowShareLock);
attmap = convert_tuples_by_name_map(RelationGetDescr(partitionRel), attmap = build_attrmap_by_name(RelationGetDescr(partitionRel),
RelationGetDescr(parentRel)); RelationGetDescr(parentRel));
foreach(cell, clone) foreach(cell, clone)
{ {
Oid constrOid = lfirst_oid(cell); Oid constrOid = lfirst_oid(cell);
@ -8549,8 +8547,9 @@ CloneFkReferenced(Relation parentRel, Relation partitionRel)
conpfeqop, conpfeqop,
conppeqop, conppeqop,
conffeqop); conffeqop);
Assert(numfks == attmap->maplen);
for (int i = 0; i < numfks; i++) for (int i = 0; i < numfks; i++)
mapped_confkey[i] = attmap[confkey[i] - 1]; mapped_confkey[i] = attmap->attnums[confkey[i] - 1];
fkconstraint = makeNode(Constraint); fkconstraint = makeNode(Constraint);
/* for now this is all we need */ /* for now this is all we need */
@ -8617,7 +8616,7 @@ CloneFkReferenced(Relation parentRel, Relation partitionRel)
static void static void
CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel) CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
{ {
AttrNumber *attmap; AttrMap *attmap;
List *partFKs; List *partFKs;
List *clone = NIL; List *clone = NIL;
ListCell *cell; ListCell *cell;
@ -8646,8 +8645,8 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
* The constraint key may differ, if the columns in the partition are * The constraint key may differ, if the columns in the partition are
* different. This map is used to convert them. * different. This map is used to convert them.
*/ */
attmap = convert_tuples_by_name_map(RelationGetDescr(partRel), attmap = build_attrmap_by_name(RelationGetDescr(partRel),
RelationGetDescr(parentRel)); RelationGetDescr(parentRel));
partFKs = copyObject(RelationGetFKeyList(partRel)); partFKs = copyObject(RelationGetFKeyList(partRel));
@ -8697,7 +8696,7 @@ CloneFkReferencing(List **wqueue, Relation parentRel, Relation partRel)
DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey, DeconstructFkConstraintRow(tuple, &numfks, conkey, confkey,
conpfeqop, conppeqop, conffeqop); conpfeqop, conppeqop, conffeqop);
for (int i = 0; i < numfks; i++) for (int i = 0; i < numfks; i++)
mapped_conkey[i] = attmap[conkey[i] - 1]; mapped_conkey[i] = attmap->attnums[conkey[i] - 1];
/* /*
* Before creating a new constraint, see whether any existing FKs are * Before creating a new constraint, see whether any existing FKs are
@ -10470,18 +10469,18 @@ ATPrepAlterColumnType(List **wqueue,
*/ */
if (def->cooked_default) if (def->cooked_default)
{ {
AttrNumber *attmap; AttrMap *attmap;
bool found_whole_row; bool found_whole_row;
/* create a copy to scribble on */ /* create a copy to scribble on */
cmd = copyObject(cmd); cmd = copyObject(cmd);
attmap = convert_tuples_by_name_map(RelationGetDescr(childrel), attmap = build_attrmap_by_name(RelationGetDescr(childrel),
RelationGetDescr(rel)); RelationGetDescr(rel));
((ColumnDef *) cmd->def)->cooked_default = ((ColumnDef *) cmd->def)->cooked_default =
map_variable_attnos(def->cooked_default, map_variable_attnos(def->cooked_default,
1, 0, 1, 0,
attmap, RelationGetDescr(rel)->natts, attmap,
InvalidOid, &found_whole_row); InvalidOid, &found_whole_row);
if (found_whole_row) if (found_whole_row)
ereport(ERROR, ereport(ERROR,
@ -15833,7 +15832,7 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
Oid idx = lfirst_oid(cell); Oid idx = lfirst_oid(cell);
Relation idxRel = index_open(idx, AccessShareLock); Relation idxRel = index_open(idx, AccessShareLock);
IndexInfo *info; IndexInfo *info;
AttrNumber *attmap; AttrMap *attmap;
bool found = false; bool found = false;
Oid constraintOid; Oid constraintOid;
@ -15849,8 +15848,8 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
/* construct an indexinfo to compare existing indexes against */ /* construct an indexinfo to compare existing indexes against */
info = BuildIndexInfo(idxRel); info = BuildIndexInfo(idxRel);
attmap = convert_tuples_by_name_map(RelationGetDescr(attachrel), attmap = build_attrmap_by_name(RelationGetDescr(attachrel),
RelationGetDescr(rel)); RelationGetDescr(rel));
constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx); constraintOid = get_relation_idx_constraint_oid(RelationGetRelid(rel), idx);
/* /*
@ -15872,8 +15871,7 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
idxRel->rd_indcollation, idxRel->rd_indcollation,
attachrelIdxRels[i]->rd_opfamily, attachrelIdxRels[i]->rd_opfamily,
idxRel->rd_opfamily, idxRel->rd_opfamily,
attmap, attmap))
RelationGetDescr(rel)->natts))
{ {
/* /*
* If this index is being created in the parent because of a * If this index is being created in the parent because of a
@ -15914,7 +15912,6 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
stmt = generateClonedIndexStmt(NULL, stmt = generateClonedIndexStmt(NULL,
idxRel, attmap, idxRel, attmap,
RelationGetDescr(rel)->natts,
&constraintOid); &constraintOid);
DefineIndex(RelationGetRelid(attachrel), stmt, InvalidOid, DefineIndex(RelationGetRelid(attachrel), stmt, InvalidOid,
RelationGetRelid(idxRel), RelationGetRelid(idxRel),
@ -16380,7 +16377,7 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
{ {
IndexInfo *childInfo; IndexInfo *childInfo;
IndexInfo *parentInfo; IndexInfo *parentInfo;
AttrNumber *attmap; AttrMap *attmap;
bool found; bool found;
int i; int i;
PartitionDesc partDesc; PartitionDesc partDesc;
@ -16425,15 +16422,14 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
/* Ensure the indexes are compatible */ /* Ensure the indexes are compatible */
childInfo = BuildIndexInfo(partIdx); childInfo = BuildIndexInfo(partIdx);
parentInfo = BuildIndexInfo(parentIdx); parentInfo = BuildIndexInfo(parentIdx);
attmap = convert_tuples_by_name_map(RelationGetDescr(partTbl), attmap = build_attrmap_by_name(RelationGetDescr(partTbl),
RelationGetDescr(parentTbl)); RelationGetDescr(parentTbl));
if (!CompareIndexInfo(childInfo, parentInfo, if (!CompareIndexInfo(childInfo, parentInfo,
partIdx->rd_indcollation, partIdx->rd_indcollation,
parentIdx->rd_indcollation, parentIdx->rd_indcollation,
partIdx->rd_opfamily, partIdx->rd_opfamily,
parentIdx->rd_opfamily, parentIdx->rd_opfamily,
attmap, attmap))
RelationGetDescr(parentTbl)->natts))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION), (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("cannot attach index \"%s\" as a partition of index \"%s\"", errmsg("cannot attach index \"%s\" as a partition of index \"%s\"",
@ -16470,7 +16466,7 @@ ATExecAttachPartitionIdx(List **wqueue, Relation parentIdx, RangeVar *name)
ConstraintSetParentConstraint(cldConstrId, constraintOid, ConstraintSetParentConstraint(cldConstrId, constraintOid,
RelationGetRelid(partTbl)); RelationGetRelid(partTbl));
pfree(attmap); free_attrmap(attmap);
validatePartitionedIndex(parentIdx, parentTbl); validatePartitionedIndex(parentIdx, parentTbl);
} }

View File

@ -1843,14 +1843,14 @@ ExecPartitionCheckEmitError(ResultRelInfo *resultRelInfo,
if (resultRelInfo->ri_PartitionRoot) if (resultRelInfo->ri_PartitionRoot)
{ {
TupleDesc old_tupdesc; TupleDesc old_tupdesc;
AttrNumber *map; AttrMap *map;
root_relid = RelationGetRelid(resultRelInfo->ri_PartitionRoot); root_relid = RelationGetRelid(resultRelInfo->ri_PartitionRoot);
tupdesc = RelationGetDescr(resultRelInfo->ri_PartitionRoot); tupdesc = RelationGetDescr(resultRelInfo->ri_PartitionRoot);
old_tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc); old_tupdesc = RelationGetDescr(resultRelInfo->ri_RelationDesc);
/* a reverse map */ /* a reverse map */
map = convert_tuples_by_name_map_if_req(old_tupdesc, tupdesc); map = build_attrmap_by_name_if_req(old_tupdesc, tupdesc);
/* /*
* Partition-specific slot's tupdesc can't be changed, so allocate a * Partition-specific slot's tupdesc can't be changed, so allocate a
@ -1929,13 +1929,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
*/ */
if (resultRelInfo->ri_PartitionRoot) if (resultRelInfo->ri_PartitionRoot)
{ {
AttrNumber *map; AttrMap *map;
rel = resultRelInfo->ri_PartitionRoot; rel = resultRelInfo->ri_PartitionRoot;
tupdesc = RelationGetDescr(rel); tupdesc = RelationGetDescr(rel);
/* a reverse map */ /* a reverse map */
map = convert_tuples_by_name_map_if_req(orig_tupdesc, map = build_attrmap_by_name_if_req(orig_tupdesc,
tupdesc); tupdesc);
/* /*
* Partition-specific slot's tupdesc can't be changed, so * Partition-specific slot's tupdesc can't be changed, so
@ -1978,13 +1978,13 @@ ExecConstraints(ResultRelInfo *resultRelInfo,
if (resultRelInfo->ri_PartitionRoot) if (resultRelInfo->ri_PartitionRoot)
{ {
TupleDesc old_tupdesc = RelationGetDescr(rel); TupleDesc old_tupdesc = RelationGetDescr(rel);
AttrNumber *map; AttrMap *map;
rel = resultRelInfo->ri_PartitionRoot; rel = resultRelInfo->ri_PartitionRoot;
tupdesc = RelationGetDescr(rel); tupdesc = RelationGetDescr(rel);
/* a reverse map */ /* a reverse map */
map = convert_tuples_by_name_map_if_req(old_tupdesc, map = build_attrmap_by_name_if_req(old_tupdesc,
tupdesc); tupdesc);
/* /*
* Partition-specific slot's tupdesc can't be changed, so * Partition-specific slot's tupdesc can't be changed, so
@ -2085,13 +2085,13 @@ ExecWithCheckOptions(WCOKind kind, ResultRelInfo *resultRelInfo,
if (resultRelInfo->ri_PartitionRoot) if (resultRelInfo->ri_PartitionRoot)
{ {
TupleDesc old_tupdesc = RelationGetDescr(rel); TupleDesc old_tupdesc = RelationGetDescr(rel);
AttrNumber *map; AttrMap *map;
rel = resultRelInfo->ri_PartitionRoot; rel = resultRelInfo->ri_PartitionRoot;
tupdesc = RelationGetDescr(rel); tupdesc = RelationGetDescr(rel);
/* a reverse map */ /* a reverse map */
map = convert_tuples_by_name_map_if_req(old_tupdesc, map = build_attrmap_by_name_if_req(old_tupdesc,
tupdesc); tupdesc);
/* /*
* Partition-specific slot's tupdesc can't be changed, * Partition-specific slot's tupdesc can't be changed,

View File

@ -143,7 +143,7 @@ typedef struct PartitionDispatchData
List *keystate; /* list of ExprState */ List *keystate; /* list of ExprState */
PartitionDesc partdesc; PartitionDesc partdesc;
TupleTableSlot *tupslot; TupleTableSlot *tupslot;
AttrNumber *tupmap; AttrMap *tupmap;
int indexes[FLEXIBLE_ARRAY_MEMBER]; int indexes[FLEXIBLE_ARRAY_MEMBER];
} PartitionDispatchData; } PartitionDispatchData;
@ -298,7 +298,7 @@ ExecFindPartition(ModifyTableState *mtstate,
dispatch = pd[0]; dispatch = pd[0];
while (true) while (true)
{ {
AttrNumber *map = dispatch->tupmap; AttrMap *map = dispatch->tupmap;
int partidx = -1; int partidx = -1;
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
@ -511,7 +511,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc; Relation firstResultRel = mtstate->resultRelInfo[0].ri_RelationDesc;
ResultRelInfo *leaf_part_rri; ResultRelInfo *leaf_part_rri;
MemoryContext oldcxt; MemoryContext oldcxt;
AttrNumber *part_attnos = NULL; AttrMap *part_attmap = NULL;
bool found_whole_row; bool found_whole_row;
oldcxt = MemoryContextSwitchTo(proute->memcxt); oldcxt = MemoryContextSwitchTo(proute->memcxt);
@ -584,14 +584,13 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
/* /*
* Convert Vars in it to contain this partition's attribute numbers. * Convert Vars in it to contain this partition's attribute numbers.
*/ */
part_attnos = part_attmap =
convert_tuples_by_name_map(RelationGetDescr(partrel), build_attrmap_by_name(RelationGetDescr(partrel),
RelationGetDescr(firstResultRel)); RelationGetDescr(firstResultRel));
wcoList = (List *) wcoList = (List *)
map_variable_attnos((Node *) wcoList, map_variable_attnos((Node *) wcoList,
firstVarno, 0, firstVarno, 0,
part_attnos, part_attmap,
RelationGetDescr(firstResultRel)->natts,
RelationGetForm(partrel)->reltype, RelationGetForm(partrel)->reltype,
&found_whole_row); &found_whole_row);
/* We ignore the value of found_whole_row. */ /* We ignore the value of found_whole_row. */
@ -642,15 +641,14 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
/* /*
* Convert Vars in it to contain this partition's attribute numbers. * Convert Vars in it to contain this partition's attribute numbers.
*/ */
if (part_attnos == NULL) if (part_attmap == NULL)
part_attnos = part_attmap =
convert_tuples_by_name_map(RelationGetDescr(partrel), build_attrmap_by_name(RelationGetDescr(partrel),
RelationGetDescr(firstResultRel)); RelationGetDescr(firstResultRel));
returningList = (List *) returningList = (List *)
map_variable_attnos((Node *) returningList, map_variable_attnos((Node *) returningList,
firstVarno, 0, firstVarno, 0,
part_attnos, part_attmap,
RelationGetDescr(firstResultRel)->natts,
RelationGetForm(partrel)->reltype, RelationGetForm(partrel)->reltype,
&found_whole_row); &found_whole_row);
/* We ignore the value of found_whole_row. */ /* We ignore the value of found_whole_row. */
@ -785,23 +783,21 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
* target relation (firstVarno). * target relation (firstVarno).
*/ */
onconflset = (List *) copyObject((Node *) node->onConflictSet); onconflset = (List *) copyObject((Node *) node->onConflictSet);
if (part_attnos == NULL) if (part_attmap == NULL)
part_attnos = part_attmap =
convert_tuples_by_name_map(RelationGetDescr(partrel), build_attrmap_by_name(RelationGetDescr(partrel),
RelationGetDescr(firstResultRel)); RelationGetDescr(firstResultRel));
onconflset = (List *) onconflset = (List *)
map_variable_attnos((Node *) onconflset, map_variable_attnos((Node *) onconflset,
INNER_VAR, 0, INNER_VAR, 0,
part_attnos, part_attmap,
RelationGetDescr(firstResultRel)->natts,
RelationGetForm(partrel)->reltype, RelationGetForm(partrel)->reltype,
&found_whole_row); &found_whole_row);
/* We ignore the value of found_whole_row. */ /* We ignore the value of found_whole_row. */
onconflset = (List *) onconflset = (List *)
map_variable_attnos((Node *) onconflset, map_variable_attnos((Node *) onconflset,
firstVarno, 0, firstVarno, 0,
part_attnos, part_attmap,
RelationGetDescr(firstResultRel)->natts,
RelationGetForm(partrel)->reltype, RelationGetForm(partrel)->reltype,
&found_whole_row); &found_whole_row);
/* We ignore the value of found_whole_row. */ /* We ignore the value of found_whole_row. */
@ -835,16 +831,14 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate,
clause = (List *) clause = (List *)
map_variable_attnos((Node *) clause, map_variable_attnos((Node *) clause,
INNER_VAR, 0, INNER_VAR, 0,
part_attnos, part_attmap,
RelationGetDescr(firstResultRel)->natts,
RelationGetForm(partrel)->reltype, RelationGetForm(partrel)->reltype,
&found_whole_row); &found_whole_row);
/* We ignore the value of found_whole_row. */ /* We ignore the value of found_whole_row. */
clause = (List *) clause = (List *)
map_variable_attnos((Node *) clause, map_variable_attnos((Node *) clause,
firstVarno, 0, firstVarno, 0,
part_attnos, part_attmap,
RelationGetDescr(firstResultRel)->natts,
RelationGetForm(partrel)->reltype, RelationGetForm(partrel)->reltype,
&found_whole_row); &found_whole_row);
/* We ignore the value of found_whole_row. */ /* We ignore the value of found_whole_row. */
@ -1036,8 +1030,8 @@ ExecInitPartitionDispatchInfo(EState *estate,
* tuple descriptor when computing its partition key for tuple * tuple descriptor when computing its partition key for tuple
* routing. * routing.
*/ */
pd->tupmap = convert_tuples_by_name_map_if_req(RelationGetDescr(parent_pd->reldesc), pd->tupmap = build_attrmap_by_name_if_req(RelationGetDescr(parent_pd->reldesc),
tupdesc); tupdesc);
pd->tupslot = pd->tupmap ? pd->tupslot = pd->tupmap ?
MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual) : NULL; MakeSingleTupleTableSlot(tupdesc, &TTSOpsVirtual) : NULL;
} }
@ -1434,15 +1428,16 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
{ {
List *new_tlist = NIL; List *new_tlist = NIL;
TupleDesc tupdesc = map->outdesc; TupleDesc tupdesc = map->outdesc;
AttrNumber *attrMap = map->attrMap; AttrMap *attrMap = map->attrMap;
AttrNumber attrno; AttrNumber attrno;
Assert(tupdesc->natts == attrMap->maplen);
for (attrno = 1; attrno <= tupdesc->natts; attrno++) for (attrno = 1; attrno <= tupdesc->natts; attrno++)
{ {
Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1); Form_pg_attribute att_tup = TupleDescAttr(tupdesc, attrno - 1);
TargetEntry *tle; TargetEntry *tle;
if (attrMap[attrno - 1] != InvalidAttrNumber) if (attrMap->attnums[attrno - 1] != InvalidAttrNumber)
{ {
Assert(!att_tup->attisdropped); Assert(!att_tup->attisdropped);
@ -1450,7 +1445,7 @@ adjust_partition_tlist(List *tlist, TupleConversionMap *map)
* Use the corresponding entry from the parent's tlist, adjusting * Use the corresponding entry from the parent's tlist, adjusting
* the resno the match the partition's attno. * the resno the match the partition's attno.
*/ */
tle = (TargetEntry *) list_nth(tlist, attrMap[attrno - 1] - 1); tle = (TargetEntry *) list_nth(tlist, attrMap->attnums[attrno - 1] - 1);
tle->resno = attrno; tle->resno = attrno;
} }
else else

View File

@ -20,7 +20,6 @@
#include "access/htup_details.h" #include "access/htup_details.h"
#include "access/nbtree.h" #include "access/nbtree.h"
#include "access/tupconvert.h"
#include "catalog/objectaccess.h" #include "catalog/objectaccess.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "executor/execExpr.h" #include "executor/execExpr.h"

View File

@ -917,7 +917,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
Relation relation; Relation relation;
TupleDesc tupleDesc; TupleDesc tupleDesc;
TupleConstr *constr; TupleConstr *constr;
AttrNumber *attmap; AttrMap *attmap;
AclResult aclresult; AclResult aclresult;
char *comment; char *comment;
ParseCallbackState pcbstate; ParseCallbackState pcbstate;
@ -974,7 +974,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
* since dropped columns in the source table aren't copied, so the new * since dropped columns in the source table aren't copied, so the new
* table can have different column numbers. * table can have different column numbers.
*/ */
attmap = (AttrNumber *) palloc0(sizeof(AttrNumber) * tupleDesc->natts); attmap = make_attrmap(tupleDesc->natts);
/* /*
* Insert the copied attributes into the cxt for the new table definition. * Insert the copied attributes into the cxt for the new table definition.
@ -1020,7 +1020,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
*/ */
cxt->columns = lappend(cxt->columns, def); cxt->columns = lappend(cxt->columns, def);
attmap[parent_attno - 1] = list_length(cxt->columns); attmap->attnums[parent_attno - 1] = list_length(cxt->columns);
/* /*
* Copy default, if present and it should be copied. We have separate * Copy default, if present and it should be copied. We have separate
@ -1051,7 +1051,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
def->cooked_default = map_variable_attnos(this_default, def->cooked_default = map_variable_attnos(this_default,
1, 0, 1, 0,
attmap, tupleDesc->natts, attmap,
InvalidOid, &found_whole_row); InvalidOid, &found_whole_row);
/* /*
@ -1134,7 +1134,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
ccbin_node = map_variable_attnos(stringToNode(ccbin), ccbin_node = map_variable_attnos(stringToNode(ccbin),
1, 0, 1, 0,
attmap, tupleDesc->natts, attmap,
InvalidOid, &found_whole_row); InvalidOid, &found_whole_row);
/* /*
@ -1200,7 +1200,7 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
/* Build CREATE INDEX statement to recreate the parent_index */ /* Build CREATE INDEX statement to recreate the parent_index */
index_stmt = generateClonedIndexStmt(cxt->relation, index_stmt = generateClonedIndexStmt(cxt->relation,
parent_index, parent_index,
attmap, tupleDesc->natts, attmap,
NULL); NULL);
/* Copy comment on index, if requested */ /* Copy comment on index, if requested */
@ -1332,7 +1332,7 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
*/ */
IndexStmt * IndexStmt *
generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx, generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx,
const AttrNumber *attmap, int attmap_length, const AttrMap *attmap,
Oid *constraintOid) Oid *constraintOid)
{ {
Oid source_relid = RelationGetRelid(source_idx); Oid source_relid = RelationGetRelid(source_idx);
@ -1552,7 +1552,7 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx,
/* Adjust Vars to match new table's column numbering */ /* Adjust Vars to match new table's column numbering */
indexkey = map_variable_attnos(indexkey, indexkey = map_variable_attnos(indexkey,
1, 0, 1, 0,
attmap, attmap_length, attmap,
InvalidOid, &found_whole_row); InvalidOid, &found_whole_row);
/* As in transformTableLikeClause, reject whole-row variables */ /* As in transformTableLikeClause, reject whole-row variables */
@ -1659,7 +1659,7 @@ generateClonedIndexStmt(RangeVar *heapRel, Relation source_idx,
/* Adjust Vars to match new table's column numbering */ /* Adjust Vars to match new table's column numbering */
pred_tree = map_variable_attnos(pred_tree, pred_tree = map_variable_attnos(pred_tree,
1, 0, 1, 0,
attmap, attmap_length, attmap,
InvalidOid, &found_whole_row); InvalidOid, &found_whole_row);
/* As in transformTableLikeClause, reject whole-row variables */ /* As in transformTableLikeClause, reject whole-row variables */

View File

@ -281,7 +281,7 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
*/ */
desc = RelationGetDescr(entry->localrel); desc = RelationGetDescr(entry->localrel);
oldctx = MemoryContextSwitchTo(LogicalRepRelMapContext); oldctx = MemoryContextSwitchTo(LogicalRepRelMapContext);
entry->attrmap = palloc(desc->natts * sizeof(AttrNumber)); entry->attrmap = make_attrmap(desc->natts);
MemoryContextSwitchTo(oldctx); MemoryContextSwitchTo(oldctx);
found = 0; found = 0;
@ -292,14 +292,14 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
if (attr->attisdropped || attr->attgenerated) if (attr->attisdropped || attr->attgenerated)
{ {
entry->attrmap[i] = -1; entry->attrmap->attnums[i] = -1;
continue; continue;
} }
attnum = logicalrep_rel_att_by_name(remoterel, attnum = logicalrep_rel_att_by_name(remoterel,
NameStr(attr->attname)); NameStr(attr->attname));
entry->attrmap[i] = attnum; entry->attrmap->attnums[i] = attnum;
if (attnum >= 0) if (attnum >= 0)
found++; found++;
} }
@ -354,8 +354,8 @@ logicalrep_rel_open(LogicalRepRelId remoteid, LOCKMODE lockmode)
attnum = AttrNumberGetAttrOffset(attnum); attnum = AttrNumberGetAttrOffset(attnum);
if (entry->attrmap[attnum] < 0 || if (entry->attrmap->attnums[attnum] < 0 ||
!bms_is_member(entry->attrmap[attnum], remoterel->attkeys)) !bms_is_member(entry->attrmap->attnums[attnum], remoterel->attkeys))
{ {
entry->updatable = false; entry->updatable = false;
break; break;

View File

@ -230,6 +230,7 @@ slot_fill_defaults(LogicalRepRelMapEntry *rel, EState *estate,
defmap = (int *) palloc(num_phys_attrs * sizeof(int)); defmap = (int *) palloc(num_phys_attrs * sizeof(int));
defexprs = (ExprState **) palloc(num_phys_attrs * sizeof(ExprState *)); defexprs = (ExprState **) palloc(num_phys_attrs * sizeof(ExprState *));
Assert(rel->attrmap->maplen == num_phys_attrs);
for (attnum = 0; attnum < num_phys_attrs; attnum++) for (attnum = 0; attnum < num_phys_attrs; attnum++)
{ {
Expr *defexpr; Expr *defexpr;
@ -237,7 +238,7 @@ slot_fill_defaults(LogicalRepRelMapEntry *rel, EState *estate,
if (TupleDescAttr(desc, attnum)->attisdropped || TupleDescAttr(desc, attnum)->attgenerated) if (TupleDescAttr(desc, attnum)->attisdropped || TupleDescAttr(desc, attnum)->attgenerated)
continue; continue;
if (rel->attrmap[attnum] >= 0) if (rel->attrmap->attnums[attnum] >= 0)
continue; continue;
defexpr = (Expr *) build_column_default(rel->localrel, attnum + 1); defexpr = (Expr *) build_column_default(rel->localrel, attnum + 1);
@ -319,10 +320,11 @@ slot_store_cstrings(TupleTableSlot *slot, LogicalRepRelMapEntry *rel,
error_context_stack = &errcallback; error_context_stack = &errcallback;
/* Call the "in" function for each non-dropped attribute */ /* Call the "in" function for each non-dropped attribute */
Assert(natts == rel->attrmap->maplen);
for (i = 0; i < natts; i++) for (i = 0; i < natts; i++)
{ {
Form_pg_attribute att = TupleDescAttr(slot->tts_tupleDescriptor, i); Form_pg_attribute att = TupleDescAttr(slot->tts_tupleDescriptor, i);
int remoteattnum = rel->attrmap[i]; int remoteattnum = rel->attrmap->attnums[i];
if (!att->attisdropped && remoteattnum >= 0 && if (!att->attisdropped && remoteattnum >= 0 &&
values[remoteattnum] != NULL) values[remoteattnum] != NULL)
@ -403,10 +405,11 @@ slot_modify_cstrings(TupleTableSlot *slot, TupleTableSlot *srcslot,
error_context_stack = &errcallback; error_context_stack = &errcallback;
/* Call the "in" function for each replaced attribute */ /* Call the "in" function for each replaced attribute */
Assert(natts == rel->attrmap->maplen);
for (i = 0; i < natts; i++) for (i = 0; i < natts; i++)
{ {
Form_pg_attribute att = TupleDescAttr(slot->tts_tupleDescriptor, i); Form_pg_attribute att = TupleDescAttr(slot->tts_tupleDescriptor, i);
int remoteattnum = rel->attrmap[i]; int remoteattnum = rel->attrmap->attnums[i];
if (remoteattnum < 0) if (remoteattnum < 0)
continue; continue;

View File

@ -1221,8 +1221,7 @@ typedef struct
{ {
int target_varno; /* RTE index to search for */ int target_varno; /* RTE index to search for */
int sublevels_up; /* (current) nesting depth */ int sublevels_up; /* (current) nesting depth */
const AttrNumber *attno_map; /* map array for user attnos */ const AttrMap *attno_map; /* map array for user attnos */
int map_length; /* number of entries in attno_map[] */
Oid to_rowtype; /* change whole-row Vars to this type */ Oid to_rowtype; /* change whole-row Vars to this type */
bool *found_whole_row; /* output flag */ bool *found_whole_row; /* output flag */
} map_variable_attnos_context; } map_variable_attnos_context;
@ -1249,11 +1248,11 @@ map_variable_attnos_mutator(Node *node,
if (attno > 0) if (attno > 0)
{ {
/* user-defined column, replace attno */ /* user-defined column, replace attno */
if (attno > context->map_length || if (attno > context->attno_map->maplen ||
context->attno_map[attno - 1] == 0) context->attno_map->attnums[attno - 1] == 0)
elog(ERROR, "unexpected varattno %d in expression to be mapped", elog(ERROR, "unexpected varattno %d in expression to be mapped",
attno); attno);
newvar->varattno = newvar->varoattno = context->attno_map[attno - 1]; newvar->varattno = newvar->varoattno = context->attno_map->attnums[attno - 1];
} }
else if (attno == 0) else if (attno == 0)
{ {
@ -1350,7 +1349,7 @@ map_variable_attnos_mutator(Node *node,
Node * Node *
map_variable_attnos(Node *node, map_variable_attnos(Node *node,
int target_varno, int sublevels_up, int target_varno, int sublevels_up,
const AttrNumber *attno_map, int map_length, const AttrMap *attno_map,
Oid to_rowtype, bool *found_whole_row) Oid to_rowtype, bool *found_whole_row)
{ {
map_variable_attnos_context context; map_variable_attnos_context context;
@ -1358,7 +1357,6 @@ map_variable_attnos(Node *node,
context.target_varno = target_varno; context.target_varno = target_varno;
context.sublevels_up = sublevels_up; context.sublevels_up = sublevels_up;
context.attno_map = attno_map; context.attno_map = attno_map;
context.map_length = map_length;
context.to_rowtype = to_rowtype; context.to_rowtype = to_rowtype;
context.found_whole_row = found_whole_row; context.found_whole_row = found_whole_row;

View File

@ -0,0 +1,52 @@
/*-------------------------------------------------------------------------
*
* attmap.h
* Definitions for PostgreSQL attribute mappings
*
*
* Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* src/include/access/attmap.h
*
*-------------------------------------------------------------------------
*/
#ifndef ATTMAP_H
#define ATTMAP_H
#include "access/attnum.h"
#include "access/tupdesc.h"
/*
* Attribute mapping structure
*
* This maps attribute numbers between a pair of relations, designated
* 'input' and 'output' (most typically inheritance parent and child
* relations), whose common columns may have different attribute numbers.
* Such difference may arise due to the columns being ordered differently
* in the two relations or the two relations having dropped columns at
* different positions.
*
* 'maplen' is set to the number of attributes of the 'output' relation,
* taking into account any of its dropped attributes, with the corresponding
* elements of the 'attnums' array set to 0.
*/
typedef struct AttrMap
{
AttrNumber *attnums;
int maplen;
} AttrMap;
extern AttrMap *make_attrmap(int maplen);
extern void free_attrmap(AttrMap *map);
/* Convertion routines to build mappings */
extern AttrMap *build_attrmap_by_name(TupleDesc indesc,
TupleDesc outdesc);
extern AttrMap *build_attrmap_by_name_if_req(TupleDesc indesc,
TupleDesc outdesc);
extern AttrMap *build_attrmap_by_position(TupleDesc indesc,
TupleDesc outdesc,
const char *msg);
#endif /* ATTMAP_H */

View File

@ -14,6 +14,7 @@
#ifndef TUPCONVERT_H #ifndef TUPCONVERT_H
#define TUPCONVERT_H #define TUPCONVERT_H
#include "access/attmap.h"
#include "access/htup.h" #include "access/htup.h"
#include "access/tupdesc.h" #include "access/tupdesc.h"
#include "executor/tuptable.h" #include "executor/tuptable.h"
@ -23,7 +24,7 @@ typedef struct TupleConversionMap
{ {
TupleDesc indesc; /* tupdesc for source rowtype */ TupleDesc indesc; /* tupdesc for source rowtype */
TupleDesc outdesc; /* tupdesc for result rowtype */ TupleDesc outdesc; /* tupdesc for result rowtype */
AttrNumber *attrMap; /* indexes of input fields, or 0 for null */ AttrMap *attrMap; /* indexes of input fields, or 0 for null */
Datum *invalues; /* workspace for deconstructing source */ Datum *invalues; /* workspace for deconstructing source */
bool *inisnull; bool *inisnull;
Datum *outvalues; /* workspace for constructing result */ Datum *outvalues; /* workspace for constructing result */
@ -38,14 +39,10 @@ extern TupleConversionMap *convert_tuples_by_position(TupleDesc indesc,
extern TupleConversionMap *convert_tuples_by_name(TupleDesc indesc, extern TupleConversionMap *convert_tuples_by_name(TupleDesc indesc,
TupleDesc outdesc); TupleDesc outdesc);
extern AttrNumber *convert_tuples_by_name_map(TupleDesc indesc,
TupleDesc outdesc);
extern AttrNumber *convert_tuples_by_name_map_if_req(TupleDesc indesc,
TupleDesc outdesc);
extern HeapTuple execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map); extern HeapTuple execute_attr_map_tuple(HeapTuple tuple, TupleConversionMap *map);
extern TupleTableSlot *execute_attr_map_slot(AttrNumber *attrMap, extern TupleTableSlot *execute_attr_map_slot(AttrMap *attrMap,
TupleTableSlot *in_slot, TupleTableSlot *out_slot); TupleTableSlot *in_slot,
TupleTableSlot *out_slot);
extern void free_conversion_map(TupleConversionMap *map); extern void free_conversion_map(TupleConversionMap *map);

View File

@ -111,7 +111,7 @@ extern IndexInfo *BuildDummyIndexInfo(Relation index);
extern bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2, extern bool CompareIndexInfo(IndexInfo *info1, IndexInfo *info2,
Oid *collations1, Oid *collations2, Oid *collations1, Oid *collations2,
Oid *opfamilies1, Oid *opfamilies2, Oid *opfamilies1, Oid *opfamilies2,
AttrNumber *attmap, int maplen); AttrMap *attmap);
extern void BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii); extern void BuildSpeculativeIndexInfo(Relation index, IndexInfo *ii);

View File

@ -16,6 +16,7 @@
#include "parser/parse_node.h" #include "parser/parse_node.h"
typedef struct AttrMap AttrMap;
extern List *transformCreateStmt(CreateStmt *stmt, const char *queryString); extern List *transformCreateStmt(CreateStmt *stmt, const char *queryString);
extern List *transformAlterTableStmt(Oid relid, AlterTableStmt *stmt, extern List *transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
@ -29,7 +30,7 @@ extern PartitionBoundSpec *transformPartitionBound(ParseState *pstate, Relation
PartitionBoundSpec *spec); PartitionBoundSpec *spec);
extern IndexStmt *generateClonedIndexStmt(RangeVar *heapRel, extern IndexStmt *generateClonedIndexStmt(RangeVar *heapRel,
Relation source_idx, Relation source_idx,
const AttrNumber *attmap, int attmap_length, const AttrMap *attmap,
Oid *constraintOid); Oid *constraintOid);
#endif /* PARSE_UTILCMD_H */ #endif /* PARSE_UTILCMD_H */

View File

@ -12,6 +12,7 @@
#ifndef LOGICALRELATION_H #ifndef LOGICALRELATION_H
#define LOGICALRELATION_H #define LOGICALRELATION_H
#include "access/attmap.h"
#include "replication/logicalproto.h" #include "replication/logicalproto.h"
typedef struct LogicalRepRelMapEntry typedef struct LogicalRepRelMapEntry
@ -21,7 +22,7 @@ typedef struct LogicalRepRelMapEntry
/* Mapping to local relation, filled as needed. */ /* Mapping to local relation, filled as needed. */
Oid localreloid; /* local relation id */ Oid localreloid; /* local relation id */
Relation localrel; /* relcache entry */ Relation localrel; /* relcache entry */
AttrNumber *attrmap; /* map of local attributes to remote ones */ AttrMap *attrmap; /* map of local attributes to remote ones */
bool updatable; /* Can apply updates/deletes? */ bool updatable; /* Can apply updates/deletes? */
/* Sync state. */ /* Sync state. */

View File

@ -17,6 +17,7 @@
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
typedef struct AttrMap AttrMap;
typedef struct replace_rte_variables_context replace_rte_variables_context; typedef struct replace_rte_variables_context replace_rte_variables_context;
typedef Node *(*replace_rte_variables_callback) (Var *var, typedef Node *(*replace_rte_variables_callback) (Var *var,
@ -71,7 +72,7 @@ extern Node *replace_rte_variables_mutator(Node *node,
extern Node *map_variable_attnos(Node *node, extern Node *map_variable_attnos(Node *node,
int target_varno, int sublevels_up, int target_varno, int sublevels_up,
const AttrNumber *attno_map, int map_length, const AttrMap *attno_map,
Oid to_rowtype, bool *found_whole_row); Oid to_rowtype, bool *found_whole_row);
extern Node *ReplaceVarsFromTargetList(Node *node, extern Node *ReplaceVarsFromTargetList(Node *node,

View File

@ -137,6 +137,7 @@ AttoptCacheEntry
AttoptCacheKey AttoptCacheKey
AttrDefInfo AttrDefInfo
AttrDefault AttrDefault
AttrMap
AttrMissing AttrMissing
AttrNumber AttrNumber
AttributeOpts AttributeOpts