LCOV - code coverage report
Current view: top level - src/backend/access/common - tupdesc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 390 429 90.9 %
Date: 2025-04-01 15:15:16 Functions: 23 25 92.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * tupdesc.c
       4             :  *    POSTGRES tuple descriptor support code
       5             :  *
       6             :  * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/access/common/tupdesc.c
      12             :  *
      13             :  * NOTES
      14             :  *    some of the executor utility code such as "ExecTypeFromTL" should be
      15             :  *    moved here.
      16             :  *
      17             :  *-------------------------------------------------------------------------
      18             :  */
      19             : 
      20             : #include "postgres.h"
      21             : 
      22             : #include "access/htup_details.h"
      23             : #include "access/toast_compression.h"
      24             : #include "access/tupdesc_details.h"
      25             : #include "catalog/pg_collation.h"
      26             : #include "catalog/pg_type.h"
      27             : #include "common/hashfn.h"
      28             : #include "utils/builtins.h"
      29             : #include "utils/datum.h"
      30             : #include "utils/resowner.h"
      31             : #include "utils/syscache.h"
      32             : 
      33             : /* ResourceOwner callbacks to hold tupledesc references  */
      34             : static void ResOwnerReleaseTupleDesc(Datum res);
      35             : static char *ResOwnerPrintTupleDesc(Datum res);
      36             : 
      37             : static const ResourceOwnerDesc tupdesc_resowner_desc =
      38             : {
      39             :     .name = "tupdesc reference",
      40             :     .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
      41             :     .release_priority = RELEASE_PRIO_TUPDESC_REFS,
      42             :     .ReleaseResource = ResOwnerReleaseTupleDesc,
      43             :     .DebugPrint = ResOwnerPrintTupleDesc
      44             : };
      45             : 
      46             : /* Convenience wrappers over ResourceOwnerRemember/Forget */
      47             : static inline void
      48    30525350 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
      49             : {
      50    30525350 :     ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
      51    30525350 : }
      52             : 
      53             : static inline void
      54    30510380 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
      55             : {
      56    30510380 :     ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
      57    30510380 : }
      58             : 
      59             : /*
      60             :  * populate_compact_attribute_internal
      61             :  *      Helper function for populate_compact_attribute()
      62             :  */
      63             : static inline void
      64    69762606 : populate_compact_attribute_internal(Form_pg_attribute src,
      65             :                                     CompactAttribute *dst)
      66             : {
      67    69762606 :     memset(dst, 0, sizeof(CompactAttribute));
      68             : 
      69    69762606 :     dst->attcacheoff = -1;
      70    69762606 :     dst->attlen = src->attlen;
      71             : 
      72    69762606 :     dst->attbyval = src->attbyval;
      73    69762606 :     dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
      74    69762606 :     dst->atthasmissing = src->atthasmissing;
      75    69762606 :     dst->attisdropped = src->attisdropped;
      76    69762606 :     dst->attgenerated = (src->attgenerated != '\0');
      77    69762606 :     dst->attnotnull = src->attnotnull;
      78             : 
      79    69762606 :     switch (src->attalign)
      80             :     {
      81    44235538 :         case TYPALIGN_INT:
      82    44235538 :             dst->attalignby = ALIGNOF_INT;
      83    44235538 :             break;
      84    17790670 :         case TYPALIGN_CHAR:
      85    17790670 :             dst->attalignby = sizeof(char);
      86    17790670 :             break;
      87     4327828 :         case TYPALIGN_DOUBLE:
      88     4327828 :             dst->attalignby = ALIGNOF_DOUBLE;
      89     4327828 :             break;
      90     3408570 :         case TYPALIGN_SHORT:
      91     3408570 :             dst->attalignby = ALIGNOF_SHORT;
      92     3408570 :             break;
      93           0 :         default:
      94           0 :             dst->attalignby = 0;
      95           0 :             elog(ERROR, "invalid attalign value: %c", src->attalign);
      96             :             break;
      97             :     }
      98    69762606 : }
      99             : 
     100             : /*
     101             :  * populate_compact_attribute
     102             :  *      Fill in the corresponding CompactAttribute element from the
     103             :  *      Form_pg_attribute for the given attribute number.  This must be called
     104             :  *      whenever a change is made to a Form_pg_attribute in the TupleDesc.
     105             :  */
     106             : void
     107    69762606 : populate_compact_attribute(TupleDesc tupdesc, int attnum)
     108             : {
     109    69762606 :     Form_pg_attribute src = TupleDescAttr(tupdesc, attnum);
     110             :     CompactAttribute *dst;
     111             : 
     112             :     /*
     113             :      * Don't use TupleDescCompactAttr to prevent infinite recursion in assert
     114             :      * builds.
     115             :      */
     116    69762606 :     dst = &tupdesc->compact_attrs[attnum];
     117             : 
     118    69762606 :     populate_compact_attribute_internal(src, dst);
     119    69762606 : }
     120             : 
     121             : /*
     122             :  * verify_compact_attribute
     123             :  *      In Assert enabled builds, we verify that the CompactAttribute is
     124             :  *      populated correctly.  This helps find bugs in places such as ALTER
     125             :  *      TABLE where code makes changes to the FormData_pg_attribute but
     126             :  *      forgets to call populate_compact_attribute().
     127             :  *
     128             :  * This is used in TupleDescCompactAttr(), but declared here to allow access
     129             :  * to populate_compact_attribute_internal().
     130             :  */
     131             : void
     132           0 : verify_compact_attribute(TupleDesc tupdesc, int attnum)
     133             : {
     134             : #ifdef USE_ASSERT_CHECKING
     135             :     CompactAttribute *cattr = &tupdesc->compact_attrs[attnum];
     136             :     Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum);
     137             :     CompactAttribute tmp;
     138             : 
     139             :     /*
     140             :      * Populate the temporary CompactAttribute from the corresponding
     141             :      * Form_pg_attribute
     142             :      */
     143             :     populate_compact_attribute_internal(attr, &tmp);
     144             : 
     145             :     /*
     146             :      * Make the attcacheoff match since it's been reset to -1 by
     147             :      * populate_compact_attribute_internal.
     148             :      */
     149             :     tmp.attcacheoff = cattr->attcacheoff;
     150             : 
     151             :     /* Check the freshly populated CompactAttribute matches the TupleDesc's */
     152             :     Assert(memcmp(&tmp, cattr, sizeof(CompactAttribute)) == 0);
     153             : #endif
     154           0 : }
     155             : 
     156             : /*
     157             :  * CreateTemplateTupleDesc
     158             :  *      This function allocates an empty tuple descriptor structure.
     159             :  *
     160             :  * Tuple type ID information is initially set for an anonymous record type;
     161             :  * caller can overwrite this if needed.
     162             :  */
     163             : TupleDesc
     164    10117376 : CreateTemplateTupleDesc(int natts)
     165             : {
     166             :     TupleDesc   desc;
     167             : 
     168             :     /*
     169             :      * sanity checks
     170             :      */
     171             :     Assert(natts >= 0);
     172             : 
     173             :     /*
     174             :      * Allocate enough memory for the tuple descriptor, the CompactAttribute
     175             :      * array and also an array of FormData_pg_attribute.
     176             :      *
     177             :      * Note: the FormData_pg_attribute array stride is
     178             :      * sizeof(FormData_pg_attribute), since we declare the array elements as
     179             :      * FormData_pg_attribute for notational convenience.  However, we only
     180             :      * guarantee that the first ATTRIBUTE_FIXED_PART_SIZE bytes of each entry
     181             :      * are valid; most code that copies tupdesc entries around copies just
     182             :      * that much.  In principle that could be less due to trailing padding,
     183             :      * although with the current definition of pg_attribute there probably
     184             :      * isn't any padding.
     185             :      */
     186    10117376 :     desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
     187    10117376 :                               natts * sizeof(CompactAttribute) +
     188             :                               natts * sizeof(FormData_pg_attribute));
     189             : 
     190             :     /*
     191             :      * Initialize other fields of the tupdesc.
     192             :      */
     193    10117376 :     desc->natts = natts;
     194    10117376 :     desc->constr = NULL;
     195    10117376 :     desc->tdtypeid = RECORDOID;
     196    10117376 :     desc->tdtypmod = -1;
     197    10117376 :     desc->tdrefcount = -1;       /* assume not reference-counted */
     198             : 
     199    10117376 :     return desc;
     200             : }
     201             : 
     202             : /*
     203             :  * CreateTupleDesc
     204             :  *      This function allocates a new TupleDesc by copying a given
     205             :  *      Form_pg_attribute array.
     206             :  *
     207             :  * Tuple type ID information is initially set for an anonymous record type;
     208             :  * caller can overwrite this if needed.
     209             :  */
     210             : TupleDesc
     211     1037444 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
     212             : {
     213             :     TupleDesc   desc;
     214             :     int         i;
     215             : 
     216     1037444 :     desc = CreateTemplateTupleDesc(natts);
     217             : 
     218    15836948 :     for (i = 0; i < natts; ++i)
     219             :     {
     220    14799504 :         memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
     221    14799504 :         populate_compact_attribute(desc, i);
     222             :     }
     223     1037444 :     return desc;
     224             : }
     225             : 
     226             : /*
     227             :  * CreateTupleDescCopy
     228             :  *      This function creates a new TupleDesc by copying from an existing
     229             :  *      TupleDesc.
     230             :  *
     231             :  * !!! Constraints and defaults are not copied !!!
     232             :  */
     233             : TupleDesc
     234      415424 : CreateTupleDescCopy(TupleDesc tupdesc)
     235             : {
     236             :     TupleDesc   desc;
     237             :     int         i;
     238             : 
     239      415424 :     desc = CreateTemplateTupleDesc(tupdesc->natts);
     240             : 
     241             :     /* Flat-copy the attribute array */
     242      415424 :     memcpy(TupleDescAttr(desc, 0),
     243      415424 :            TupleDescAttr(tupdesc, 0),
     244      415424 :            desc->natts * sizeof(FormData_pg_attribute));
     245             : 
     246             :     /*
     247             :      * Since we're not copying constraints and defaults, clear fields
     248             :      * associated with them.
     249             :      */
     250     2246066 :     for (i = 0; i < desc->natts; i++)
     251             :     {
     252     1830642 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     253             : 
     254     1830642 :         att->attnotnull = false;
     255     1830642 :         att->atthasdef = false;
     256     1830642 :         att->atthasmissing = false;
     257     1830642 :         att->attidentity = '\0';
     258     1830642 :         att->attgenerated = '\0';
     259             : 
     260     1830642 :         populate_compact_attribute(desc, i);
     261             :     }
     262             : 
     263             :     /* We can copy the tuple type identification, too */
     264      415424 :     desc->tdtypeid = tupdesc->tdtypeid;
     265      415424 :     desc->tdtypmod = tupdesc->tdtypmod;
     266             : 
     267      415424 :     return desc;
     268             : }
     269             : 
     270             : /*
     271             :  * CreateTupleDescTruncatedCopy
     272             :  *      This function creates a new TupleDesc with only the first 'natts'
     273             :  *      attributes from an existing TupleDesc
     274             :  *
     275             :  * !!! Constraints and defaults are not copied !!!
     276             :  */
     277             : TupleDesc
     278       34248 : CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
     279             : {
     280             :     TupleDesc   desc;
     281             :     int         i;
     282             : 
     283             :     Assert(natts <= tupdesc->natts);
     284             : 
     285       34248 :     desc = CreateTemplateTupleDesc(natts);
     286             : 
     287             :     /* Flat-copy the attribute array */
     288       34248 :     memcpy(TupleDescAttr(desc, 0),
     289       34248 :            TupleDescAttr(tupdesc, 0),
     290       34248 :            desc->natts * sizeof(FormData_pg_attribute));
     291             : 
     292             :     /*
     293             :      * Since we're not copying constraints and defaults, clear fields
     294             :      * associated with them.
     295             :      */
     296       79346 :     for (i = 0; i < desc->natts; i++)
     297             :     {
     298       45098 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     299             : 
     300       45098 :         att->attnotnull = false;
     301       45098 :         att->atthasdef = false;
     302       45098 :         att->atthasmissing = false;
     303       45098 :         att->attidentity = '\0';
     304       45098 :         att->attgenerated = '\0';
     305             : 
     306       45098 :         populate_compact_attribute(desc, i);
     307             :     }
     308             : 
     309             :     /* We can copy the tuple type identification, too */
     310       34248 :     desc->tdtypeid = tupdesc->tdtypeid;
     311       34248 :     desc->tdtypmod = tupdesc->tdtypmod;
     312             : 
     313       34248 :     return desc;
     314             : }
     315             : 
     316             : /*
     317             :  * CreateTupleDescCopyConstr
     318             :  *      This function creates a new TupleDesc by copying from an existing
     319             :  *      TupleDesc (including its constraints and defaults).
     320             :  */
     321             : TupleDesc
     322      863024 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
     323             : {
     324             :     TupleDesc   desc;
     325      863024 :     TupleConstr *constr = tupdesc->constr;
     326             :     int         i;
     327             : 
     328      863024 :     desc = CreateTemplateTupleDesc(tupdesc->natts);
     329             : 
     330             :     /* Flat-copy the attribute array */
     331      863024 :     memcpy(TupleDescAttr(desc, 0),
     332      863024 :            TupleDescAttr(tupdesc, 0),
     333      863024 :            desc->natts * sizeof(FormData_pg_attribute));
     334             : 
     335    12987304 :     for (i = 0; i < desc->natts; i++)
     336    12124280 :         populate_compact_attribute(desc, i);
     337             : 
     338             :     /* Copy the TupleConstr data structure, if any */
     339      863024 :     if (constr)
     340             :     {
     341      807394 :         TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
     342             : 
     343      807394 :         cpy->has_not_null = constr->has_not_null;
     344      807394 :         cpy->has_generated_stored = constr->has_generated_stored;
     345      807394 :         cpy->has_generated_virtual = constr->has_generated_virtual;
     346             : 
     347      807394 :         if ((cpy->num_defval = constr->num_defval) > 0)
     348             :         {
     349        3564 :             cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
     350        3564 :             memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
     351        8744 :             for (i = cpy->num_defval - 1; i >= 0; i--)
     352        5180 :                 cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
     353             :         }
     354             : 
     355      807394 :         if (constr->missing)
     356             :         {
     357         626 :             cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
     358         626 :             memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
     359        4862 :             for (i = tupdesc->natts - 1; i >= 0; i--)
     360             :             {
     361        4236 :                 if (constr->missing[i].am_present)
     362             :                 {
     363        1130 :                     CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
     364             : 
     365        1130 :                     cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
     366        1130 :                                                          attr->attbyval,
     367        1130 :                                                          attr->attlen);
     368             :                 }
     369             :             }
     370             :         }
     371             : 
     372      807394 :         if ((cpy->num_check = constr->num_check) > 0)
     373             :         {
     374        2122 :             cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
     375        2122 :             memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
     376        5520 :             for (i = cpy->num_check - 1; i >= 0; i--)
     377             :             {
     378        3398 :                 cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
     379        3398 :                 cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
     380        3398 :                 cpy->check[i].ccenforced = constr->check[i].ccenforced;
     381        3398 :                 cpy->check[i].ccvalid = constr->check[i].ccvalid;
     382        3398 :                 cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
     383             :             }
     384             :         }
     385             : 
     386      807394 :         desc->constr = cpy;
     387             :     }
     388             : 
     389             :     /* We can copy the tuple type identification, too */
     390      863024 :     desc->tdtypeid = tupdesc->tdtypeid;
     391      863024 :     desc->tdtypmod = tupdesc->tdtypmod;
     392             : 
     393      863024 :     return desc;
     394             : }
     395             : 
     396             : /*
     397             :  * TupleDescCopy
     398             :  *      Copy a tuple descriptor into caller-supplied memory.
     399             :  *      The memory may be shared memory mapped at any address, and must
     400             :  *      be sufficient to hold TupleDescSize(src) bytes.
     401             :  *
     402             :  * !!! Constraints and defaults are not copied !!!
     403             :  */
     404             : void
     405         174 : TupleDescCopy(TupleDesc dst, TupleDesc src)
     406             : {
     407             :     int         i;
     408             : 
     409             :     /* Flat-copy the header and attribute arrays */
     410         174 :     memcpy(dst, src, TupleDescSize(src));
     411             : 
     412             :     /*
     413             :      * Since we're not copying constraints and defaults, clear fields
     414             :      * associated with them.
     415             :      */
     416         704 :     for (i = 0; i < dst->natts; i++)
     417             :     {
     418         530 :         Form_pg_attribute att = TupleDescAttr(dst, i);
     419             : 
     420         530 :         att->attnotnull = false;
     421         530 :         att->atthasdef = false;
     422         530 :         att->atthasmissing = false;
     423         530 :         att->attidentity = '\0';
     424         530 :         att->attgenerated = '\0';
     425             : 
     426         530 :         populate_compact_attribute(dst, i);
     427             :     }
     428         174 :     dst->constr = NULL;
     429             : 
     430             :     /*
     431             :      * Also, assume the destination is not to be ref-counted.  (Copying the
     432             :      * source's refcount would be wrong in any case.)
     433             :      */
     434         174 :     dst->tdrefcount = -1;
     435         174 : }
     436             : 
     437             : /*
     438             :  * TupleDescCopyEntry
     439             :  *      This function copies a single attribute structure from one tuple
     440             :  *      descriptor to another.
     441             :  *
     442             :  * !!! Constraints and defaults are not copied !!!
     443             :  */
     444             : void
     445        3618 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
     446             :                    TupleDesc src, AttrNumber srcAttno)
     447             : {
     448        3618 :     Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
     449        3618 :     Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
     450             : 
     451             :     /*
     452             :      * sanity checks
     453             :      */
     454             :     Assert(PointerIsValid(src));
     455             :     Assert(PointerIsValid(dst));
     456             :     Assert(srcAttno >= 1);
     457             :     Assert(srcAttno <= src->natts);
     458             :     Assert(dstAttno >= 1);
     459             :     Assert(dstAttno <= dst->natts);
     460             : 
     461        3618 :     memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
     462             : 
     463        3618 :     dstAtt->attnum = dstAttno;
     464             : 
     465             :     /* since we're not copying constraints or defaults, clear these */
     466        3618 :     dstAtt->attnotnull = false;
     467        3618 :     dstAtt->atthasdef = false;
     468        3618 :     dstAtt->atthasmissing = false;
     469        3618 :     dstAtt->attidentity = '\0';
     470        3618 :     dstAtt->attgenerated = '\0';
     471             : 
     472        3618 :     populate_compact_attribute(dst, dstAttno - 1);
     473        3618 : }
     474             : 
     475             : /*
     476             :  * Free a TupleDesc including all substructure
     477             :  */
     478             : void
     479     1362100 : FreeTupleDesc(TupleDesc tupdesc)
     480             : {
     481             :     int         i;
     482             : 
     483             :     /*
     484             :      * Possibly this should assert tdrefcount == 0, to disallow explicit
     485             :      * freeing of un-refcounted tupdescs?
     486             :      */
     487             :     Assert(tupdesc->tdrefcount <= 0);
     488             : 
     489     1362100 :     if (tupdesc->constr)
     490             :     {
     491      407182 :         if (tupdesc->constr->num_defval > 0)
     492             :         {
     493       28526 :             AttrDefault *attrdef = tupdesc->constr->defval;
     494             : 
     495       69940 :             for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
     496       41414 :                 pfree(attrdef[i].adbin);
     497       28526 :             pfree(attrdef);
     498             :         }
     499      407182 :         if (tupdesc->constr->missing)
     500             :         {
     501        3586 :             AttrMissing *attrmiss = tupdesc->constr->missing;
     502             : 
     503       26176 :             for (i = tupdesc->natts - 1; i >= 0; i--)
     504             :             {
     505       22590 :                 if (attrmiss[i].am_present
     506        7726 :                     && !TupleDescAttr(tupdesc, i)->attbyval)
     507        2926 :                     pfree(DatumGetPointer(attrmiss[i].am_value));
     508             :             }
     509        3586 :             pfree(attrmiss);
     510             :         }
     511      407182 :         if (tupdesc->constr->num_check > 0)
     512             :         {
     513       10380 :             ConstrCheck *check = tupdesc->constr->check;
     514             : 
     515       25970 :             for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
     516             :             {
     517       15590 :                 pfree(check[i].ccname);
     518       15590 :                 pfree(check[i].ccbin);
     519             :             }
     520       10380 :             pfree(check);
     521             :         }
     522      407182 :         pfree(tupdesc->constr);
     523             :     }
     524             : 
     525     1362100 :     pfree(tupdesc);
     526     1362100 : }
     527             : 
     528             : /*
     529             :  * Increment the reference count of a tupdesc, and log the reference in
     530             :  * CurrentResourceOwner.
     531             :  *
     532             :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     533             :  * macro PinTupleDesc for tupdescs of uncertain status.)
     534             :  */
     535             : void
     536    30525350 : IncrTupleDescRefCount(TupleDesc tupdesc)
     537             : {
     538             :     Assert(tupdesc->tdrefcount >= 0);
     539             : 
     540    30525350 :     ResourceOwnerEnlarge(CurrentResourceOwner);
     541    30525350 :     tupdesc->tdrefcount++;
     542    30525350 :     ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
     543    30525350 : }
     544             : 
     545             : /*
     546             :  * Decrement the reference count of a tupdesc, remove the corresponding
     547             :  * reference from CurrentResourceOwner, and free the tupdesc if no more
     548             :  * references remain.
     549             :  *
     550             :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     551             :  * macro ReleaseTupleDesc for tupdescs of uncertain status.)
     552             :  */
     553             : void
     554    30510380 : DecrTupleDescRefCount(TupleDesc tupdesc)
     555             : {
     556             :     Assert(tupdesc->tdrefcount > 0);
     557             : 
     558    30510380 :     ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
     559    30510380 :     if (--tupdesc->tdrefcount == 0)
     560           4 :         FreeTupleDesc(tupdesc);
     561    30510380 : }
     562             : 
     563             : /*
     564             :  * Compare two TupleDesc structures for logical equality
     565             :  */
     566             : bool
     567      399166 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
     568             : {
     569             :     int         i,
     570             :                 n;
     571             : 
     572      399166 :     if (tupdesc1->natts != tupdesc2->natts)
     573        2654 :         return false;
     574      396512 :     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     575           0 :         return false;
     576             : 
     577             :     /* tdtypmod and tdrefcount are not checked */
     578             : 
     579     1898650 :     for (i = 0; i < tupdesc1->natts; i++)
     580             :     {
     581     1514914 :         Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
     582     1514914 :         Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
     583             : 
     584             :         /*
     585             :          * We do not need to check every single field here: we can disregard
     586             :          * attrelid and attnum (which were used to place the row in the attrs
     587             :          * array in the first place).  It might look like we could dispense
     588             :          * with checking attlen/attbyval/attalign, since these are derived
     589             :          * from atttypid; but in the case of dropped columns we must check
     590             :          * them (since atttypid will be zero for all dropped columns) and in
     591             :          * general it seems safer to check them always.
     592             :          *
     593             :          * We intentionally ignore atthasmissing, since that's not very
     594             :          * relevant in tupdescs, which lack the attmissingval field.
     595             :          */
     596     1514914 :         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     597        1290 :             return false;
     598     1513624 :         if (attr1->atttypid != attr2->atttypid)
     599        1044 :             return false;
     600     1512580 :         if (attr1->attlen != attr2->attlen)
     601          10 :             return false;
     602     1512570 :         if (attr1->attndims != attr2->attndims)
     603           0 :             return false;
     604     1512570 :         if (attr1->atttypmod != attr2->atttypmod)
     605          42 :             return false;
     606     1512528 :         if (attr1->attbyval != attr2->attbyval)
     607          68 :             return false;
     608     1512460 :         if (attr1->attalign != attr2->attalign)
     609           0 :             return false;
     610     1512460 :         if (attr1->attstorage != attr2->attstorage)
     611         214 :             return false;
     612     1512246 :         if (attr1->attcompression != attr2->attcompression)
     613          62 :             return false;
     614     1512184 :         if (attr1->attnotnull != attr2->attnotnull)
     615        1522 :             return false;
     616     1510662 :         if (attr1->atthasdef != attr2->atthasdef)
     617        4906 :             return false;
     618     1505756 :         if (attr1->attidentity != attr2->attidentity)
     619         178 :             return false;
     620     1505578 :         if (attr1->attgenerated != attr2->attgenerated)
     621          20 :             return false;
     622     1505558 :         if (attr1->attisdropped != attr2->attisdropped)
     623           0 :             return false;
     624     1505558 :         if (attr1->attislocal != attr2->attislocal)
     625        2638 :             return false;
     626     1502920 :         if (attr1->attinhcount != attr2->attinhcount)
     627         782 :             return false;
     628     1502138 :         if (attr1->attcollation != attr2->attcollation)
     629           0 :             return false;
     630             :         /* variable-length fields are not even present... */
     631             :     }
     632             : 
     633      383736 :     if (tupdesc1->constr != NULL)
     634             :     {
     635      133616 :         TupleConstr *constr1 = tupdesc1->constr;
     636      133616 :         TupleConstr *constr2 = tupdesc2->constr;
     637             : 
     638      133616 :         if (constr2 == NULL)
     639         212 :             return false;
     640      133404 :         if (constr1->has_not_null != constr2->has_not_null)
     641           0 :             return false;
     642      133404 :         if (constr1->has_generated_stored != constr2->has_generated_stored)
     643         552 :             return false;
     644      132852 :         if (constr1->has_generated_virtual != constr2->has_generated_virtual)
     645         386 :             return false;
     646      132466 :         n = constr1->num_defval;
     647      132466 :         if (n != (int) constr2->num_defval)
     648           0 :             return false;
     649             :         /* We assume here that both AttrDefault arrays are in adnum order */
     650      148152 :         for (i = 0; i < n; i++)
     651             :         {
     652       15686 :             AttrDefault *defval1 = constr1->defval + i;
     653       15686 :             AttrDefault *defval2 = constr2->defval + i;
     654             : 
     655       15686 :             if (defval1->adnum != defval2->adnum)
     656           0 :                 return false;
     657       15686 :             if (strcmp(defval1->adbin, defval2->adbin) != 0)
     658           0 :                 return false;
     659             :         }
     660      132466 :         if (constr1->missing)
     661             :         {
     662         702 :             if (!constr2->missing)
     663          84 :                 return false;
     664        3740 :             for (i = 0; i < tupdesc1->natts; i++)
     665             :             {
     666        3268 :                 AttrMissing *missval1 = constr1->missing + i;
     667        3268 :                 AttrMissing *missval2 = constr2->missing + i;
     668             : 
     669        3268 :                 if (missval1->am_present != missval2->am_present)
     670         146 :                     return false;
     671        3122 :                 if (missval1->am_present)
     672             :                 {
     673        1048 :                     CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
     674             : 
     675        1048 :                     if (!datumIsEqual(missval1->am_value, missval2->am_value,
     676        1048 :                                       missatt1->attbyval, missatt1->attlen))
     677           0 :                         return false;
     678             :                 }
     679             :             }
     680             :         }
     681      131764 :         else if (constr2->missing)
     682         320 :             return false;
     683      131916 :         n = constr1->num_check;
     684      131916 :         if (n != (int) constr2->num_check)
     685        1432 :             return false;
     686             : 
     687             :         /*
     688             :          * Similarly, we rely here on the ConstrCheck entries being sorted by
     689             :          * name.  If there are duplicate names, the outcome of the comparison
     690             :          * is uncertain, but that should not happen.
     691             :          */
     692      133546 :         for (i = 0; i < n; i++)
     693             :         {
     694        3158 :             ConstrCheck *check1 = constr1->check + i;
     695        3158 :             ConstrCheck *check2 = constr2->check + i;
     696             : 
     697        3158 :             if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
     698        3158 :                   strcmp(check1->ccbin, check2->ccbin) == 0 &&
     699        3158 :                   check1->ccenforced == check2->ccenforced &&
     700        3146 :                   check1->ccvalid == check2->ccvalid &&
     701        3062 :                   check1->ccnoinherit == check2->ccnoinherit))
     702          96 :                 return false;
     703             :         }
     704             :     }
     705      250120 :     else if (tupdesc2->constr != NULL)
     706        1748 :         return false;
     707      378760 :     return true;
     708             : }
     709             : 
     710             : /*
     711             :  * equalRowTypes
     712             :  *
     713             :  * This determines whether two tuple descriptors have equal row types.  This
     714             :  * only checks those fields in pg_attribute that are applicable for row types,
     715             :  * while ignoring those fields that define the physical row storage or those
     716             :  * that define table column metadata.
     717             :  *
     718             :  * Specifically, this checks:
     719             :  *
     720             :  * - same number of attributes
     721             :  * - same composite type ID (but could both be zero)
     722             :  * - corresponding attributes (in order) have same the name, type, typmod,
     723             :  *   collation
     724             :  *
     725             :  * This is used to check whether two record types are compatible, whether
     726             :  * function return row types are the same, and other similar situations.
     727             :  *
     728             :  * (XXX There was some discussion whether attndims should be checked here, but
     729             :  * for now it has been decided not to.)
     730             :  *
     731             :  * Note: We deliberately do not check the tdtypmod field.  This allows
     732             :  * typcache.c to use this routine to see if a cached record type matches a
     733             :  * requested type.
     734             :  */
     735             : bool
     736      335386 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
     737             : {
     738      335386 :     if (tupdesc1->natts != tupdesc2->natts)
     739         166 :         return false;
     740      335220 :     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     741        1758 :         return false;
     742             : 
     743     5228978 :     for (int i = 0; i < tupdesc1->natts; i++)
     744             :     {
     745     4899182 :         Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
     746     4899182 :         Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
     747             : 
     748     4899182 :         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     749        3640 :             return false;
     750     4895542 :         if (attr1->atttypid != attr2->atttypid)
     751          22 :             return false;
     752     4895520 :         if (attr1->atttypmod != attr2->atttypmod)
     753           4 :             return false;
     754     4895516 :         if (attr1->attcollation != attr2->attcollation)
     755           0 :             return false;
     756             : 
     757             :         /* Record types derived from tables could have dropped fields. */
     758     4895516 :         if (attr1->attisdropped != attr2->attisdropped)
     759           0 :             return false;
     760             :     }
     761             : 
     762      329796 :     return true;
     763             : }
     764             : 
     765             : /*
     766             :  * hashRowType
     767             :  *
     768             :  * If two tuple descriptors would be considered equal by equalRowTypes()
     769             :  * then their hash value will be equal according to this function.
     770             :  */
     771             : uint32
     772      354014 : hashRowType(TupleDesc desc)
     773             : {
     774             :     uint32      s;
     775             :     int         i;
     776             : 
     777      354014 :     s = hash_combine(0, hash_uint32(desc->natts));
     778      354014 :     s = hash_combine(s, hash_uint32(desc->tdtypeid));
     779     5522384 :     for (i = 0; i < desc->natts; ++i)
     780     5168370 :         s = hash_combine(s, hash_uint32(TupleDescAttr(desc, i)->atttypid));
     781             : 
     782      354014 :     return s;
     783             : }
     784             : 
     785             : /*
     786             :  * TupleDescInitEntry
     787             :  *      This function initializes a single attribute structure in
     788             :  *      a previously allocated tuple descriptor.
     789             :  *
     790             :  * If attributeName is NULL, the attname field is set to an empty string
     791             :  * (this is for cases where we don't know or need a name for the field).
     792             :  * Also, some callers use this function to change the datatype-related fields
     793             :  * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
     794             :  * to indicate that the attname field shouldn't be modified.
     795             :  *
     796             :  * Note that attcollation is set to the default for the specified datatype.
     797             :  * If a nondefault collation is needed, insert it afterwards using
     798             :  * TupleDescInitEntryCollation.
     799             :  */
     800             : void
     801    13455052 : TupleDescInitEntry(TupleDesc desc,
     802             :                    AttrNumber attributeNumber,
     803             :                    const char *attributeName,
     804             :                    Oid oidtypeid,
     805             :                    int32 typmod,
     806             :                    int attdim)
     807             : {
     808             :     HeapTuple   tuple;
     809             :     Form_pg_type typeForm;
     810             :     Form_pg_attribute att;
     811             : 
     812             :     /*
     813             :      * sanity checks
     814             :      */
     815             :     Assert(PointerIsValid(desc));
     816             :     Assert(attributeNumber >= 1);
     817             :     Assert(attributeNumber <= desc->natts);
     818             :     Assert(attdim >= 0);
     819             :     Assert(attdim <= PG_INT16_MAX);
     820             : 
     821             :     /*
     822             :      * initialize the attribute fields
     823             :      */
     824    13455052 :     att = TupleDescAttr(desc, attributeNumber - 1);
     825             : 
     826    13455052 :     att->attrelid = 0;           /* dummy value */
     827             : 
     828             :     /*
     829             :      * Note: attributeName can be NULL, because the planner doesn't always
     830             :      * fill in valid resname values in targetlists, particularly for resjunk
     831             :      * attributes. Also, do nothing if caller wants to re-use the old attname.
     832             :      */
     833    13455052 :     if (attributeName == NULL)
     834    25469202 :         MemSet(NameStr(att->attname), 0, NAMEDATALEN);
     835     8115146 :     else if (attributeName != NameStr(att->attname))
     836     8112206 :         namestrcpy(&(att->attname), attributeName);
     837             : 
     838    13455052 :     att->atttypmod = typmod;
     839             : 
     840    13455052 :     att->attnum = attributeNumber;
     841    13455052 :     att->attndims = attdim;
     842             : 
     843    13455052 :     att->attnotnull = false;
     844    13455052 :     att->atthasdef = false;
     845    13455052 :     att->atthasmissing = false;
     846    13455052 :     att->attidentity = '\0';
     847    13455052 :     att->attgenerated = '\0';
     848    13455052 :     att->attisdropped = false;
     849    13455052 :     att->attislocal = true;
     850    13455052 :     att->attinhcount = 0;
     851             :     /* variable-length fields are not present in tupledescs */
     852             : 
     853    13455052 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
     854    13455052 :     if (!HeapTupleIsValid(tuple))
     855           0 :         elog(ERROR, "cache lookup failed for type %u", oidtypeid);
     856    13455052 :     typeForm = (Form_pg_type) GETSTRUCT(tuple);
     857             : 
     858    13455052 :     att->atttypid = oidtypeid;
     859    13455052 :     att->attlen = typeForm->typlen;
     860    13455052 :     att->attbyval = typeForm->typbyval;
     861    13455052 :     att->attalign = typeForm->typalign;
     862    13455052 :     att->attstorage = typeForm->typstorage;
     863    13455052 :     att->attcompression = InvalidCompressionMethod;
     864    13455052 :     att->attcollation = typeForm->typcollation;
     865             : 
     866    13455052 :     populate_compact_attribute(desc, attributeNumber - 1);
     867             : 
     868    13455052 :     ReleaseSysCache(tuple);
     869    13455052 : }
     870             : 
     871             : /*
     872             :  * TupleDescInitBuiltinEntry
     873             :  *      Initialize a tuple descriptor without catalog access.  Only
     874             :  *      a limited range of builtin types are supported.
     875             :  */
     876             : void
     877       13244 : TupleDescInitBuiltinEntry(TupleDesc desc,
     878             :                           AttrNumber attributeNumber,
     879             :                           const char *attributeName,
     880             :                           Oid oidtypeid,
     881             :                           int32 typmod,
     882             :                           int attdim)
     883             : {
     884             :     Form_pg_attribute att;
     885             : 
     886             :     /* sanity checks */
     887             :     Assert(PointerIsValid(desc));
     888             :     Assert(attributeNumber >= 1);
     889             :     Assert(attributeNumber <= desc->natts);
     890             :     Assert(attdim >= 0);
     891             :     Assert(attdim <= PG_INT16_MAX);
     892             : 
     893             :     /* initialize the attribute fields */
     894       13244 :     att = TupleDescAttr(desc, attributeNumber - 1);
     895       13244 :     att->attrelid = 0;           /* dummy value */
     896             : 
     897             :     /* unlike TupleDescInitEntry, we require an attribute name */
     898             :     Assert(attributeName != NULL);
     899       13244 :     namestrcpy(&(att->attname), attributeName);
     900             : 
     901       13244 :     att->atttypmod = typmod;
     902             : 
     903       13244 :     att->attnum = attributeNumber;
     904       13244 :     att->attndims = attdim;
     905             : 
     906       13244 :     att->attnotnull = false;
     907       13244 :     att->atthasdef = false;
     908       13244 :     att->atthasmissing = false;
     909       13244 :     att->attidentity = '\0';
     910       13244 :     att->attgenerated = '\0';
     911       13244 :     att->attisdropped = false;
     912       13244 :     att->attislocal = true;
     913       13244 :     att->attinhcount = 0;
     914             :     /* variable-length fields are not present in tupledescs */
     915             : 
     916       13244 :     att->atttypid = oidtypeid;
     917             : 
     918             :     /*
     919             :      * Our goal here is to support just enough types to let basic builtin
     920             :      * commands work without catalog access - e.g. so that we can do certain
     921             :      * things even in processes that are not connected to a database.
     922             :      */
     923       13244 :     switch (oidtypeid)
     924             :     {
     925       10626 :         case TEXTOID:
     926             :         case TEXTARRAYOID:
     927       10626 :             att->attlen = -1;
     928       10626 :             att->attbyval = false;
     929       10626 :             att->attalign = TYPALIGN_INT;
     930       10626 :             att->attstorage = TYPSTORAGE_EXTENDED;
     931       10626 :             att->attcompression = InvalidCompressionMethod;
     932       10626 :             att->attcollation = DEFAULT_COLLATION_OID;
     933       10626 :             break;
     934             : 
     935           0 :         case BOOLOID:
     936           0 :             att->attlen = 1;
     937           0 :             att->attbyval = true;
     938           0 :             att->attalign = TYPALIGN_CHAR;
     939           0 :             att->attstorage = TYPSTORAGE_PLAIN;
     940           0 :             att->attcompression = InvalidCompressionMethod;
     941           0 :             att->attcollation = InvalidOid;
     942           0 :             break;
     943             : 
     944           0 :         case INT4OID:
     945           0 :             att->attlen = 4;
     946           0 :             att->attbyval = true;
     947           0 :             att->attalign = TYPALIGN_INT;
     948           0 :             att->attstorage = TYPSTORAGE_PLAIN;
     949           0 :             att->attcompression = InvalidCompressionMethod;
     950           0 :             att->attcollation = InvalidOid;
     951           0 :             break;
     952             : 
     953        2304 :         case INT8OID:
     954        2304 :             att->attlen = 8;
     955        2304 :             att->attbyval = FLOAT8PASSBYVAL;
     956        2304 :             att->attalign = TYPALIGN_DOUBLE;
     957        2304 :             att->attstorage = TYPSTORAGE_PLAIN;
     958        2304 :             att->attcompression = InvalidCompressionMethod;
     959        2304 :             att->attcollation = InvalidOid;
     960        2304 :             break;
     961             : 
     962         314 :         case OIDOID:
     963         314 :             att->attlen = 4;
     964         314 :             att->attbyval = true;
     965         314 :             att->attalign = TYPALIGN_INT;
     966         314 :             att->attstorage = TYPSTORAGE_PLAIN;
     967         314 :             att->attcompression = InvalidCompressionMethod;
     968         314 :             att->attcollation = InvalidOid;
     969         314 :             break;
     970             : 
     971           0 :         default:
     972           0 :             elog(ERROR, "unsupported type %u", oidtypeid);
     973             :     }
     974             : 
     975       13244 :     populate_compact_attribute(desc, attributeNumber - 1);
     976       13244 : }
     977             : 
     978             : /*
     979             :  * TupleDescInitEntryCollation
     980             :  *
     981             :  * Assign a nondefault collation to a previously initialized tuple descriptor
     982             :  * entry.
     983             :  */
     984             : void
     985     8143810 : TupleDescInitEntryCollation(TupleDesc desc,
     986             :                             AttrNumber attributeNumber,
     987             :                             Oid collationid)
     988             : {
     989             :     /*
     990             :      * sanity checks
     991             :      */
     992             :     Assert(PointerIsValid(desc));
     993             :     Assert(attributeNumber >= 1);
     994             :     Assert(attributeNumber <= desc->natts);
     995             : 
     996     8143810 :     TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
     997     8143810 : }
     998             : 
     999             : /*
    1000             :  * BuildDescFromLists
    1001             :  *
    1002             :  * Build a TupleDesc given lists of column names (as String nodes),
    1003             :  * column type OIDs, typmods, and collation OIDs.
    1004             :  *
    1005             :  * No constraints are generated.
    1006             :  *
    1007             :  * This is for use with functions returning RECORD.
    1008             :  */
    1009             : TupleDesc
    1010        1418 : BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
    1011             : {
    1012             :     int         natts;
    1013             :     AttrNumber  attnum;
    1014             :     ListCell   *l1;
    1015             :     ListCell   *l2;
    1016             :     ListCell   *l3;
    1017             :     ListCell   *l4;
    1018             :     TupleDesc   desc;
    1019             : 
    1020        1418 :     natts = list_length(names);
    1021             :     Assert(natts == list_length(types));
    1022             :     Assert(natts == list_length(typmods));
    1023             :     Assert(natts == list_length(collations));
    1024             : 
    1025             :     /*
    1026             :      * allocate a new tuple descriptor
    1027             :      */
    1028        1418 :     desc = CreateTemplateTupleDesc(natts);
    1029             : 
    1030        1418 :     attnum = 0;
    1031        4998 :     forfour(l1, names, l2, types, l3, typmods, l4, collations)
    1032             :     {
    1033        3580 :         char       *attname = strVal(lfirst(l1));
    1034        3580 :         Oid         atttypid = lfirst_oid(l2);
    1035        3580 :         int32       atttypmod = lfirst_int(l3);
    1036        3580 :         Oid         attcollation = lfirst_oid(l4);
    1037             : 
    1038        3580 :         attnum++;
    1039             : 
    1040        3580 :         TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
    1041        3580 :         TupleDescInitEntryCollation(desc, attnum, attcollation);
    1042             :     }
    1043             : 
    1044        1418 :     return desc;
    1045             : }
    1046             : 
    1047             : /*
    1048             :  * Get default expression (or NULL if none) for the given attribute number.
    1049             :  */
    1050             : Node *
    1051      151358 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
    1052             : {
    1053      151358 :     Node       *result = NULL;
    1054             : 
    1055      151358 :     if (tupdesc->constr)
    1056             :     {
    1057      151358 :         AttrDefault *attrdef = tupdesc->constr->defval;
    1058             : 
    1059      228350 :         for (int i = 0; i < tupdesc->constr->num_defval; i++)
    1060             :         {
    1061      228350 :             if (attrdef[i].adnum == attnum)
    1062             :             {
    1063      151358 :                 result = stringToNode(attrdef[i].adbin);
    1064      151358 :                 break;
    1065             :             }
    1066             :         }
    1067             :     }
    1068             : 
    1069      151358 :     return result;
    1070             : }
    1071             : 
    1072             : /* ResourceOwner callbacks */
    1073             : 
    1074             : static void
    1075       14970 : ResOwnerReleaseTupleDesc(Datum res)
    1076             : {
    1077       14970 :     TupleDesc   tupdesc = (TupleDesc) DatumGetPointer(res);
    1078             : 
    1079             :     /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
    1080             :     Assert(tupdesc->tdrefcount > 0);
    1081       14970 :     if (--tupdesc->tdrefcount == 0)
    1082         466 :         FreeTupleDesc(tupdesc);
    1083       14970 : }
    1084             : 
    1085             : static char *
    1086           0 : ResOwnerPrintTupleDesc(Datum res)
    1087             : {
    1088           0 :     TupleDesc   tupdesc = (TupleDesc) DatumGetPointer(res);
    1089             : 
    1090           0 :     return psprintf("TupleDesc %p (%u,%d)",
    1091             :                     tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
    1092             : }

Generated by: LCOV version 1.14