LCOV - code coverage report
Current view: top level - src/backend/access/common - tupdesc.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19beta1 Lines: 91.7 % 457 419
Test Date: 2026-06-14 08:16:39 Functions: 92.3 % 26 24
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-2026, 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/catalog.h"
      26              : #include "catalog/pg_collation.h"
      27              : #include "catalog/pg_type.h"
      28              : #include "common/hashfn.h"
      29              : #include "utils/builtins.h"
      30              : #include "utils/datum.h"
      31              : #include "utils/resowner.h"
      32              : #include "utils/syscache.h"
      33              : 
      34              : /* ResourceOwner callbacks to hold tupledesc references  */
      35              : static void ResOwnerReleaseTupleDesc(Datum res);
      36              : static char *ResOwnerPrintTupleDesc(Datum res);
      37              : 
      38              : static const ResourceOwnerDesc tupdesc_resowner_desc =
      39              : {
      40              :     .name = "tupdesc reference",
      41              :     .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
      42              :     .release_priority = RELEASE_PRIO_TUPDESC_REFS,
      43              :     .ReleaseResource = ResOwnerReleaseTupleDesc,
      44              :     .DebugPrint = ResOwnerPrintTupleDesc
      45              : };
      46              : 
      47              : /* Convenience wrappers over ResourceOwnerRemember/Forget */
      48              : static inline void
      49     21302389 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
      50              : {
      51     21302389 :     ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
      52     21302389 : }
      53              : 
      54              : static inline void
      55     21290597 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
      56              : {
      57     21290597 :     ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
      58     21290597 : }
      59              : 
      60              : /*
      61              :  * populate_compact_attribute_internal
      62              :  *      Helper function for populate_compact_attribute()
      63              :  */
      64              : static inline void
      65     43234850 : populate_compact_attribute_internal(Form_pg_attribute src,
      66              :                                     CompactAttribute *dst)
      67              : {
      68     43234850 :     memset(dst, 0, sizeof(CompactAttribute));
      69              : 
      70     43234850 :     dst->attcacheoff = -1;
      71     43234850 :     dst->attlen = src->attlen;
      72              : 
      73     43234850 :     dst->attbyval = src->attbyval;
      74     43234850 :     dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
      75     43234850 :     dst->atthasmissing = src->atthasmissing;
      76     43234850 :     dst->attisdropped = src->attisdropped;
      77     43234850 :     dst->attgenerated = (src->attgenerated != '\0');
      78              : 
      79              :     /*
      80              :      * Assign nullability status for this column.  Assuming that a constraint
      81              :      * exists, at this point we don't know if a not-null constraint is valid,
      82              :      * so we assign UNKNOWN unless the table is a catalog, in which case we
      83              :      * know it's valid.
      84              :      */
      85     67490080 :     dst->attnullability = !src->attnotnull ? ATTNULLABLE_UNRESTRICTED :
      86     24255230 :         IsCatalogRelationOid(src->attrelid) ? ATTNULLABLE_VALID :
      87              :         ATTNULLABLE_UNKNOWN;
      88              : 
      89              :     /* Compute numeric alignment requirement, too */
      90     43234850 :     dst->attalignby = typalign_to_alignby(src->attalign);
      91     43234850 : }
      92              : 
      93              : /*
      94              :  * populate_compact_attribute
      95              :  *      Fill in the corresponding CompactAttribute element from the
      96              :  *      Form_pg_attribute for the given attribute number.  This must be called
      97              :  *      whenever a change is made to a Form_pg_attribute in the TupleDesc.
      98              :  */
      99              : void
     100     43234850 : populate_compact_attribute(TupleDesc tupdesc, int attnum)
     101              : {
     102     43234850 :     Form_pg_attribute src = TupleDescAttr(tupdesc, attnum);
     103              :     CompactAttribute *dst;
     104              : 
     105              :     /*
     106              :      * Don't use TupleDescCompactAttr to prevent infinite recursion in assert
     107              :      * builds.
     108              :      */
     109     43234850 :     dst = &tupdesc->compact_attrs[attnum];
     110              : 
     111     43234850 :     populate_compact_attribute_internal(src, dst);
     112     43234850 : }
     113              : 
     114              : /*
     115              :  * verify_compact_attribute
     116              :  *      In Assert enabled builds, we verify that the CompactAttribute is
     117              :  *      populated correctly.  This helps find bugs in places such as ALTER
     118              :  *      TABLE where code makes changes to the FormData_pg_attribute but
     119              :  *      forgets to call populate_compact_attribute().
     120              :  *
     121              :  * This is used in TupleDescCompactAttr(), but declared here to allow access
     122              :  * to populate_compact_attribute_internal().
     123              :  */
     124              : void
     125            0 : verify_compact_attribute(TupleDesc tupdesc, int attnum)
     126              : {
     127              : #ifdef USE_ASSERT_CHECKING
     128              :     CompactAttribute cattr;
     129              :     Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum);
     130              :     CompactAttribute tmp;
     131              : 
     132              :     /*
     133              :      * Make a temp copy of the TupleDesc's CompactAttribute.  This may be a
     134              :      * shared TupleDesc and the attcacheoff might get changed by another
     135              :      * backend.
     136              :      */
     137              :     memcpy(&cattr, &tupdesc->compact_attrs[attnum], sizeof(CompactAttribute));
     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.  Same with attnullability.
     148              :      */
     149              :     tmp.attcacheoff = cattr.attcacheoff;
     150              :     tmp.attnullability = cattr.attnullability;
     151              : 
     152              :     /* Check the freshly populated CompactAttribute matches the TupleDesc's */
     153              :     Assert(memcmp(&tmp, &cattr, sizeof(CompactAttribute)) == 0);
     154              : #endif
     155            0 : }
     156              : 
     157              : /*
     158              :  * CreateTemplateTupleDesc
     159              :  *      This function allocates an empty tuple descriptor structure.
     160              :  *
     161              :  * Tuple type ID information is initially set for an anonymous record type;
     162              :  * caller can overwrite this if needed.
     163              :  */
     164              : TupleDesc
     165      6566838 : CreateTemplateTupleDesc(int natts)
     166              : {
     167              :     TupleDesc   desc;
     168              : 
     169              :     /*
     170              :      * sanity checks
     171              :      */
     172              :     Assert(natts >= 0);
     173              : 
     174              :     /*
     175              :      * Allocate enough memory for the tuple descriptor, the CompactAttribute
     176              :      * array and also an array of FormData_pg_attribute.
     177              :      *
     178              :      * Note: the FormData_pg_attribute array stride is
     179              :      * sizeof(FormData_pg_attribute), since we declare the array elements as
     180              :      * FormData_pg_attribute for notational convenience.  However, we only
     181              :      * guarantee that the first ATTRIBUTE_FIXED_PART_SIZE bytes of each entry
     182              :      * are valid; most code that copies tupdesc entries around copies just
     183              :      * that much.  In principle that could be less due to trailing padding,
     184              :      * although with the current definition of pg_attribute there probably
     185              :      * isn't any padding.
     186              :      */
     187      6566838 :     desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
     188              :                               natts * sizeof(CompactAttribute) +
     189      6566838 :                               natts * sizeof(FormData_pg_attribute));
     190              : 
     191              :     /*
     192              :      * Initialize other fields of the tupdesc.
     193              :      */
     194      6566838 :     desc->natts = natts;
     195      6566838 :     desc->constr = NULL;
     196      6566838 :     desc->tdtypeid = RECORDOID;
     197      6566838 :     desc->tdtypmod = -1;
     198      6566838 :     desc->tdrefcount = -1;       /* assume not reference-counted */
     199              : 
     200              :     /* This will be set to the correct value by TupleDescFinalize() */
     201      6566838 :     desc->firstNonCachedOffsetAttr = -1;
     202      6566838 :     desc->firstNonGuaranteedAttr = -1;
     203              : 
     204      6566838 :     return desc;
     205              : }
     206              : 
     207              : /*
     208              :  * CreateTupleDesc
     209              :  *      This function allocates a new TupleDesc by copying a given
     210              :  *      Form_pg_attribute array.
     211              :  *
     212              :  * Tuple type ID information is initially set for an anonymous record type;
     213              :  * caller can overwrite this if needed.
     214              :  */
     215              : TupleDesc
     216       666672 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
     217              : {
     218              :     TupleDesc   desc;
     219              :     int         i;
     220              : 
     221       666672 :     desc = CreateTemplateTupleDesc(natts);
     222              : 
     223     10162074 :     for (i = 0; i < natts; ++i)
     224              :     {
     225      9495402 :         memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
     226      9495402 :         populate_compact_attribute(desc, i);
     227              :     }
     228              : 
     229       666672 :     TupleDescFinalize(desc);
     230              : 
     231       666672 :     return desc;
     232              : }
     233              : 
     234              : /*
     235              :  * CreateTupleDescCopy
     236              :  *      This function creates a new TupleDesc by copying from an existing
     237              :  *      TupleDesc.
     238              :  *
     239              :  * !!! Constraints and defaults are not copied !!!
     240              :  */
     241              : TupleDesc
     242       259571 : CreateTupleDescCopy(TupleDesc tupdesc)
     243              : {
     244              :     TupleDesc   desc;
     245              :     int         i;
     246              : 
     247       259571 :     desc = CreateTemplateTupleDesc(tupdesc->natts);
     248              : 
     249              :     /* Flat-copy the attribute array (unless there are no attributes) */
     250       259571 :     if (desc->natts > 0)
     251       257187 :         memcpy(TupleDescAttr(desc, 0),
     252       257187 :                TupleDescAttr(tupdesc, 0),
     253       257187 :                desc->natts * sizeof(FormData_pg_attribute));
     254              : 
     255              :     /*
     256              :      * Since we're not copying constraints and defaults, clear fields
     257              :      * associated with them.
     258              :      */
     259      1299146 :     for (i = 0; i < desc->natts; i++)
     260              :     {
     261      1039575 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     262              : 
     263      1039575 :         att->attnotnull = false;
     264      1039575 :         att->atthasdef = false;
     265      1039575 :         att->atthasmissing = false;
     266      1039575 :         att->attidentity = '\0';
     267      1039575 :         att->attgenerated = '\0';
     268              : 
     269      1039575 :         populate_compact_attribute(desc, i);
     270              :     }
     271              : 
     272              :     /* We can copy the tuple type identification, too */
     273       259571 :     desc->tdtypeid = tupdesc->tdtypeid;
     274       259571 :     desc->tdtypmod = tupdesc->tdtypmod;
     275              : 
     276       259571 :     TupleDescFinalize(desc);
     277              : 
     278       259571 :     return desc;
     279              : }
     280              : 
     281              : /*
     282              :  * CreateTupleDescTruncatedCopy
     283              :  *      This function creates a new TupleDesc with only the first 'natts'
     284              :  *      attributes from an existing TupleDesc
     285              :  *
     286              :  * !!! Constraints and defaults are not copied !!!
     287              :  */
     288              : TupleDesc
     289        25595 : CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
     290              : {
     291              :     TupleDesc   desc;
     292              :     int         i;
     293              : 
     294              :     Assert(natts <= tupdesc->natts);
     295              : 
     296        25595 :     desc = CreateTemplateTupleDesc(natts);
     297              : 
     298              :     /* Flat-copy the attribute array (unless there are no attributes) */
     299        25595 :     if (desc->natts > 0)
     300        25595 :         memcpy(TupleDescAttr(desc, 0),
     301        25595 :                TupleDescAttr(tupdesc, 0),
     302        25595 :                desc->natts * sizeof(FormData_pg_attribute));
     303              : 
     304              :     /*
     305              :      * Since we're not copying constraints and defaults, clear fields
     306              :      * associated with them.
     307              :      */
     308        62372 :     for (i = 0; i < desc->natts; i++)
     309              :     {
     310        36777 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     311              : 
     312        36777 :         att->attnotnull = false;
     313        36777 :         att->atthasdef = false;
     314        36777 :         att->atthasmissing = false;
     315        36777 :         att->attidentity = '\0';
     316        36777 :         att->attgenerated = '\0';
     317              : 
     318        36777 :         populate_compact_attribute(desc, i);
     319              :     }
     320              : 
     321              :     /* We can copy the tuple type identification, too */
     322        25595 :     desc->tdtypeid = tupdesc->tdtypeid;
     323        25595 :     desc->tdtypmod = tupdesc->tdtypmod;
     324              : 
     325        25595 :     TupleDescFinalize(desc);
     326              : 
     327        25595 :     return desc;
     328              : }
     329              : 
     330              : /*
     331              :  * CreateTupleDescCopyConstr
     332              :  *      This function creates a new TupleDesc by copying from an existing
     333              :  *      TupleDesc (including its constraints and defaults).
     334              :  */
     335              : TupleDesc
     336       528769 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
     337              : {
     338              :     TupleDesc   desc;
     339       528769 :     TupleConstr *constr = tupdesc->constr;
     340              :     int         i;
     341              : 
     342       528769 :     desc = CreateTemplateTupleDesc(tupdesc->natts);
     343              : 
     344              :     /* Flat-copy the attribute array (unless there are no attributes) */
     345       528769 :     if (desc->natts > 0)
     346       528707 :         memcpy(TupleDescAttr(desc, 0),
     347       528707 :                TupleDescAttr(tupdesc, 0),
     348       528707 :                desc->natts * sizeof(FormData_pg_attribute));
     349              : 
     350      7631792 :     for (i = 0; i < desc->natts; i++)
     351              :     {
     352      7103023 :         populate_compact_attribute(desc, i);
     353              : 
     354      7103023 :         TupleDescCompactAttr(desc, i)->attnullability =
     355     14206046 :             TupleDescCompactAttr(tupdesc, i)->attnullability;
     356              :     }
     357              : 
     358              :     /* Copy the TupleConstr data structure, if any */
     359       528769 :     if (constr)
     360              :     {
     361       483549 :         TupleConstr *cpy = palloc0_object(TupleConstr);
     362              : 
     363       483549 :         cpy->has_not_null = constr->has_not_null;
     364       483549 :         cpy->has_generated_stored = constr->has_generated_stored;
     365       483549 :         cpy->has_generated_virtual = constr->has_generated_virtual;
     366              : 
     367       483549 :         if ((cpy->num_defval = constr->num_defval) > 0)
     368              :         {
     369         2949 :             cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
     370         2949 :             memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
     371         7161 :             for (i = cpy->num_defval - 1; i >= 0; i--)
     372         4212 :                 cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
     373              :         }
     374              : 
     375       483549 :         if (constr->missing)
     376              :         {
     377          426 :             cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
     378          426 :             memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
     379         3278 :             for (i = tupdesc->natts - 1; i >= 0; i--)
     380              :             {
     381         2852 :                 if (constr->missing[i].am_present)
     382              :                 {
     383          762 :                     CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
     384              : 
     385          762 :                     cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
     386          762 :                                                          attr->attbyval,
     387          762 :                                                          attr->attlen);
     388              :                 }
     389              :             }
     390              :         }
     391              : 
     392       483549 :         if ((cpy->num_check = constr->num_check) > 0)
     393              :         {
     394         1787 :             cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
     395         1787 :             memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
     396         5319 :             for (i = cpy->num_check - 1; i >= 0; i--)
     397              :             {
     398         3532 :                 cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
     399         3532 :                 cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
     400         3532 :                 cpy->check[i].ccenforced = constr->check[i].ccenforced;
     401         3532 :                 cpy->check[i].ccvalid = constr->check[i].ccvalid;
     402         3532 :                 cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
     403              :             }
     404              :         }
     405              : 
     406       483549 :         desc->constr = cpy;
     407              :     }
     408              : 
     409              :     /* We can copy the tuple type identification, too */
     410       528769 :     desc->tdtypeid = tupdesc->tdtypeid;
     411       528769 :     desc->tdtypmod = tupdesc->tdtypmod;
     412              : 
     413       528769 :     TupleDescFinalize(desc);
     414              : 
     415       528769 :     return desc;
     416              : }
     417              : 
     418              : /*
     419              :  * TupleDescCopy
     420              :  *      Copy a tuple descriptor into caller-supplied memory.
     421              :  *      The memory may be shared memory mapped at any address, and must
     422              :  *      be sufficient to hold TupleDescSize(src) bytes.
     423              :  *
     424              :  * !!! Constraints and defaults are not copied !!!
     425              :  */
     426              : void
     427          236 : TupleDescCopy(TupleDesc dst, TupleDesc src)
     428              : {
     429              :     int         i;
     430              : 
     431              :     /* Flat-copy the header and attribute arrays */
     432          236 :     memcpy(dst, src, TupleDescSize(src));
     433              : 
     434              :     /*
     435              :      * Since we're not copying constraints and defaults, clear fields
     436              :      * associated with them.
     437              :      */
     438          933 :     for (i = 0; i < dst->natts; i++)
     439              :     {
     440          697 :         Form_pg_attribute att = TupleDescAttr(dst, i);
     441              : 
     442          697 :         att->attnotnull = false;
     443          697 :         att->atthasdef = false;
     444          697 :         att->atthasmissing = false;
     445          697 :         att->attidentity = '\0';
     446          697 :         att->attgenerated = '\0';
     447              : 
     448          697 :         populate_compact_attribute(dst, i);
     449              :     }
     450          236 :     dst->constr = NULL;
     451              : 
     452              :     /*
     453              :      * Also, assume the destination is not to be ref-counted.  (Copying the
     454              :      * source's refcount would be wrong in any case.)
     455              :      */
     456          236 :     dst->tdrefcount = -1;
     457              : 
     458          236 :     TupleDescFinalize(dst);
     459          236 : }
     460              : 
     461              : /*
     462              :  * TupleDescCopyEntry
     463              :  *      This function copies a single attribute structure from one tuple
     464              :  *      descriptor to another.
     465              :  *
     466              :  * !!! Constraints and defaults are not copied !!!
     467              :  *
     468              :  * The caller must take care of calling TupleDescFinalize() on 'dst' once all
     469              :  * TupleDesc changes have been made.
     470              :  */
     471              : void
     472         2864 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
     473              :                    TupleDesc src, AttrNumber srcAttno)
     474              : {
     475         2864 :     Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
     476         2864 :     Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
     477              : 
     478              :     /*
     479              :      * sanity checks
     480              :      */
     481              :     Assert(src);
     482              :     Assert(dst);
     483              :     Assert(srcAttno >= 1);
     484              :     Assert(srcAttno <= src->natts);
     485              :     Assert(dstAttno >= 1);
     486              :     Assert(dstAttno <= dst->natts);
     487              : 
     488         2864 :     memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
     489              : 
     490         2864 :     dstAtt->attnum = dstAttno;
     491              : 
     492              :     /* since we're not copying constraints or defaults, clear these */
     493         2864 :     dstAtt->attnotnull = false;
     494         2864 :     dstAtt->atthasdef = false;
     495         2864 :     dstAtt->atthasmissing = false;
     496         2864 :     dstAtt->attidentity = '\0';
     497         2864 :     dstAtt->attgenerated = '\0';
     498              : 
     499         2864 :     populate_compact_attribute(dst, dstAttno - 1);
     500         2864 : }
     501              : 
     502              : /*
     503              :  * TupleDescFinalize
     504              :  *      Finalize the given TupleDesc.  This must be called after the
     505              :  *      attributes arrays have been populated or adjusted by any code.
     506              :  *
     507              :  * Must be called after populate_compact_attribute() and before
     508              :  * BlessTupleDesc().
     509              :  */
     510              : void
     511      6701042 : TupleDescFinalize(TupleDesc tupdesc)
     512              : {
     513      6701042 :     int         firstNonCachedOffsetAttr = 0;
     514      6701042 :     int         firstNonGuaranteedAttr = tupdesc->natts;
     515      6701042 :     int         off = 0;
     516              : 
     517     37237353 :     for (int i = 0; i < tupdesc->natts; i++)
     518              :     {
     519     33926564 :         CompactAttribute *cattr = TupleDescCompactAttr(tupdesc, i);
     520     33926564 :         Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
     521              : 
     522              :         /*
     523              :          * Find the highest attnum which is guaranteed to exist in all tuples
     524              :          * in the table.  We currently only pay attention to byval attributes
     525              :          * to allow additional optimizations during tuple deformation.
     526              :          */
     527     33926564 :         if (firstNonGuaranteedAttr == tupdesc->natts &&
     528     14146559 :             (cattr->attnullability != ATTNULLABLE_VALID || !cattr->attbyval ||
     529      7988403 :              cattr->atthasmissing || cattr->attisdropped ||
     530      7988403 :              cattr->attlen <= 0 ||
     531      7988403 :              attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL))
     532      6158362 :             firstNonGuaranteedAttr = i;
     533              : 
     534              :         /*
     535              :          * Don't cache offsets beyond fixed-width attributes.  Virtual
     536              :          * generated attributes are stored as NULLs in the tuple, so we don't
     537              :          * cache offsets beyond these.
     538              :          */
     539     33926564 :         if (cattr->attlen <= 0 ||
     540     30541758 :             attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
     541              :             break;
     542              : 
     543     30536311 :         off = att_nominal_alignby(off, cattr->attalignby);
     544              : 
     545              :         /*
     546              :          * attcacheoff is an int16, so don't try to cache any offsets larger
     547              :          * than will fit in that type.  Any attributes which are offset more
     548              :          * than 2^15 are likely due to variable-length attributes.  Since we
     549              :          * don't cache offsets for or beyond variable-length attributes, using
     550              :          * an int16 rather than an int32 here is unlikely to cost us anything.
     551              :          */
     552     30536311 :         if (off > PG_INT16_MAX)
     553            0 :             break;
     554              : 
     555     30536311 :         cattr->attcacheoff = (int16) off;
     556              : 
     557     30536311 :         off += cattr->attlen;
     558     30536311 :         firstNonCachedOffsetAttr = i + 1;
     559              :     }
     560              : 
     561      6701042 :     tupdesc->firstNonCachedOffsetAttr = firstNonCachedOffsetAttr;
     562      6701042 :     tupdesc->firstNonGuaranteedAttr = firstNonGuaranteedAttr;
     563      6701042 : }
     564              : 
     565              : /*
     566              :  * Free a TupleDesc including all substructure
     567              :  */
     568              : void
     569       988531 : FreeTupleDesc(TupleDesc tupdesc)
     570              : {
     571              :     int         i;
     572              : 
     573              :     /*
     574              :      * Possibly this should assert tdrefcount == 0, to disallow explicit
     575              :      * freeing of un-refcounted tupdescs?
     576              :      */
     577              :     Assert(tupdesc->tdrefcount <= 0);
     578              : 
     579       988531 :     if (tupdesc->constr)
     580              :     {
     581       305747 :         if (tupdesc->constr->num_defval > 0)
     582              :         {
     583        23477 :             AttrDefault *attrdef = tupdesc->constr->defval;
     584              : 
     585        57295 :             for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
     586        33818 :                 pfree(attrdef[i].adbin);
     587        23477 :             pfree(attrdef);
     588              :         }
     589       305747 :         if (tupdesc->constr->missing)
     590              :         {
     591         2534 :             AttrMissing *attrmiss = tupdesc->constr->missing;
     592              : 
     593        17946 :             for (i = tupdesc->natts - 1; i >= 0; i--)
     594              :             {
     595        15412 :                 if (attrmiss[i].am_present
     596         5315 :                     && !TupleDescAttr(tupdesc, i)->attbyval)
     597         2021 :                     pfree(DatumGetPointer(attrmiss[i].am_value));
     598              :             }
     599         2534 :             pfree(attrmiss);
     600              :         }
     601       305747 :         if (tupdesc->constr->num_check > 0)
     602              :         {
     603         8440 :             ConstrCheck *check = tupdesc->constr->check;
     604              : 
     605        23500 :             for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
     606              :             {
     607        15060 :                 pfree(check[i].ccname);
     608        15060 :                 pfree(check[i].ccbin);
     609              :             }
     610         8440 :             pfree(check);
     611              :         }
     612       305747 :         pfree(tupdesc->constr);
     613              :     }
     614              : 
     615       988531 :     pfree(tupdesc);
     616       988531 : }
     617              : 
     618              : /*
     619              :  * Increment the reference count of a tupdesc, and log the reference in
     620              :  * CurrentResourceOwner.
     621              :  *
     622              :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     623              :  * macro PinTupleDesc for tupdescs of uncertain status.)
     624              :  */
     625              : void
     626     21302389 : IncrTupleDescRefCount(TupleDesc tupdesc)
     627              : {
     628              :     Assert(tupdesc->tdrefcount >= 0);
     629              : 
     630     21302389 :     ResourceOwnerEnlarge(CurrentResourceOwner);
     631     21302389 :     tupdesc->tdrefcount++;
     632     21302389 :     ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
     633     21302389 : }
     634              : 
     635              : /*
     636              :  * Decrement the reference count of a tupdesc, remove the corresponding
     637              :  * reference from CurrentResourceOwner, and free the tupdesc if no more
     638              :  * references remain.
     639              :  *
     640              :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     641              :  * macro ReleaseTupleDesc for tupdescs of uncertain status.)
     642              :  */
     643              : void
     644     21290597 : DecrTupleDescRefCount(TupleDesc tupdesc)
     645              : {
     646              :     Assert(tupdesc->tdrefcount > 0);
     647              : 
     648     21290597 :     ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
     649     21290597 :     if (--tupdesc->tdrefcount == 0)
     650            0 :         FreeTupleDesc(tupdesc);
     651     21290597 : }
     652              : 
     653              : /*
     654              :  * Compare two TupleDesc structures for logical equality
     655              :  */
     656              : bool
     657       282488 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
     658              : {
     659              :     int         i,
     660              :                 n;
     661              : 
     662       282488 :     if (tupdesc1->natts != tupdesc2->natts)
     663         1946 :         return false;
     664       280542 :     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     665            0 :         return false;
     666              : 
     667              :     /* tdtypmod and tdrefcount are not checked */
     668              : 
     669      1318079 :     for (i = 0; i < tupdesc1->natts; i++)
     670              :     {
     671      1047684 :         Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
     672      1047684 :         Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
     673              : 
     674              :         /*
     675              :          * We do not need to check every single field here: we can disregard
     676              :          * attrelid and attnum (which were used to place the row in the attrs
     677              :          * array in the first place).  It might look like we could dispense
     678              :          * with checking attlen/attbyval/attalign, since these are derived
     679              :          * from atttypid; but in the case of dropped columns we must check
     680              :          * them (since atttypid will be zero for all dropped columns) and in
     681              :          * general it seems safer to check them always.
     682              :          *
     683              :          * We intentionally ignore atthasmissing, since that's not very
     684              :          * relevant in tupdescs, which lack the attmissingval field.
     685              :          */
     686      1047684 :         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     687          926 :             return false;
     688      1046758 :         if (attr1->atttypid != attr2->atttypid)
     689          758 :             return false;
     690      1046000 :         if (attr1->attlen != attr2->attlen)
     691            6 :             return false;
     692      1045994 :         if (attr1->attndims != attr2->attndims)
     693            0 :             return false;
     694      1045994 :         if (attr1->atttypmod != attr2->atttypmod)
     695           28 :             return false;
     696      1045966 :         if (attr1->attbyval != attr2->attbyval)
     697           34 :             return false;
     698      1045932 :         if (attr1->attalign != attr2->attalign)
     699            0 :             return false;
     700      1045932 :         if (attr1->attstorage != attr2->attstorage)
     701          157 :             return false;
     702      1045775 :         if (attr1->attcompression != attr2->attcompression)
     703           44 :             return false;
     704      1045731 :         if (attr1->attnotnull != attr2->attnotnull)
     705         1166 :             return false;
     706              : 
     707              :         /*
     708              :          * When the column has a not-null constraint, we also need to consider
     709              :          * its validity aspect, which only manifests in CompactAttribute->
     710              :          * attnullability, so verify that.
     711              :          */
     712      1044565 :         if (attr1->attnotnull)
     713              :         {
     714       343083 :             CompactAttribute *cattr1 = TupleDescCompactAttr(tupdesc1, i);
     715       343083 :             CompactAttribute *cattr2 = TupleDescCompactAttr(tupdesc2, i);
     716              : 
     717              :             Assert(cattr1->attnullability != ATTNULLABLE_UNKNOWN);
     718              :             Assert((cattr1->attnullability == ATTNULLABLE_UNKNOWN) ==
     719              :                    (cattr2->attnullability == ATTNULLABLE_UNKNOWN));
     720              : 
     721       343083 :             if (cattr1->attnullability != cattr2->attnullability)
     722           70 :                 return false;
     723              :         }
     724      1044495 :         if (attr1->atthasdef != attr2->atthasdef)
     725         3682 :             return false;
     726      1040813 :         if (attr1->attidentity != attr2->attidentity)
     727          118 :             return false;
     728      1040695 :         if (attr1->attgenerated != attr2->attgenerated)
     729           13 :             return false;
     730      1040682 :         if (attr1->attisdropped != attr2->attisdropped)
     731            0 :             return false;
     732      1040682 :         if (attr1->attislocal != attr2->attislocal)
     733         2640 :             return false;
     734      1038042 :         if (attr1->attinhcount != attr2->attinhcount)
     735          505 :             return false;
     736      1037537 :         if (attr1->attcollation != attr2->attcollation)
     737            0 :             return false;
     738              :         /* variable-length fields are not even present... */
     739              :     }
     740              : 
     741       270395 :     if (tupdesc1->constr != NULL)
     742              :     {
     743        99695 :         TupleConstr *constr1 = tupdesc1->constr;
     744        99695 :         TupleConstr *constr2 = tupdesc2->constr;
     745              : 
     746        99695 :         if (constr2 == NULL)
     747          175 :             return false;
     748        99520 :         if (constr1->has_not_null != constr2->has_not_null)
     749            0 :             return false;
     750        99520 :         if (constr1->has_generated_stored != constr2->has_generated_stored)
     751          468 :             return false;
     752        99052 :         if (constr1->has_generated_virtual != constr2->has_generated_virtual)
     753          290 :             return false;
     754        98762 :         n = constr1->num_defval;
     755        98762 :         if (n != (int) constr2->num_defval)
     756            0 :             return false;
     757              :         /* We assume here that both AttrDefault arrays are in adnum order */
     758       112192 :         for (i = 0; i < n; i++)
     759              :         {
     760        13430 :             AttrDefault *defval1 = constr1->defval + i;
     761        13430 :             AttrDefault *defval2 = constr2->defval + i;
     762              : 
     763        13430 :             if (defval1->adnum != defval2->adnum)
     764            0 :                 return false;
     765        13430 :             if (strcmp(defval1->adbin, defval2->adbin) != 0)
     766            0 :                 return false;
     767              :         }
     768        98762 :         if (constr1->missing)
     769              :         {
     770          520 :             if (!constr2->missing)
     771           65 :                 return false;
     772         2670 :             for (i = 0; i < tupdesc1->natts; i++)
     773              :             {
     774         2316 :                 AttrMissing *missval1 = constr1->missing + i;
     775         2316 :                 AttrMissing *missval2 = constr2->missing + i;
     776              : 
     777         2316 :                 if (missval1->am_present != missval2->am_present)
     778          101 :                     return false;
     779         2215 :                 if (missval1->am_present)
     780              :                 {
     781          757 :                     CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
     782              : 
     783          757 :                     if (!datumIsEqual(missval1->am_value, missval2->am_value,
     784          757 :                                       missatt1->attbyval, missatt1->attlen))
     785            0 :                         return false;
     786              :                 }
     787              :             }
     788              :         }
     789        98242 :         else if (constr2->missing)
     790          251 :             return false;
     791        98345 :         n = constr1->num_check;
     792        98345 :         if (n != (int) constr2->num_check)
     793         1179 :             return false;
     794              : 
     795              :         /*
     796              :          * Similarly, we rely here on the ConstrCheck entries being sorted by
     797              :          * name.  If there are duplicate names, the outcome of the comparison
     798              :          * is uncertain, but that should not happen.
     799              :          */
     800       100000 :         for (i = 0; i < n; i++)
     801              :         {
     802         2978 :             ConstrCheck *check1 = constr1->check + i;
     803         2978 :             ConstrCheck *check2 = constr2->check + i;
     804              : 
     805         2978 :             if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
     806         2978 :                   strcmp(check1->ccbin, check2->ccbin) == 0 &&
     807         2978 :                   check1->ccenforced == check2->ccenforced &&
     808         2890 :                   check1->ccvalid == check2->ccvalid &&
     809         2834 :                   check1->ccnoinherit == check2->ccnoinherit))
     810          144 :                 return false;
     811              :         }
     812              :     }
     813       170700 :     else if (tupdesc2->constr != NULL)
     814         1321 :         return false;
     815       266401 :     return true;
     816              : }
     817              : 
     818              : /*
     819              :  * equalRowTypes
     820              :  *
     821              :  * This determines whether two tuple descriptors have equal row types.  This
     822              :  * only checks those fields in pg_attribute that are applicable for row types,
     823              :  * while ignoring those fields that define the physical row storage or those
     824              :  * that define table column metadata.
     825              :  *
     826              :  * Specifically, this checks:
     827              :  *
     828              :  * - same number of attributes
     829              :  * - same composite type ID (but could both be zero)
     830              :  * - corresponding attributes (in order) have same the name, type, typmod,
     831              :  *   collation
     832              :  *
     833              :  * This is used to check whether two record types are compatible, whether
     834              :  * function return row types are the same, and other similar situations.
     835              :  *
     836              :  * (XXX There was some discussion whether attndims should be checked here, but
     837              :  * for now it has been decided not to.)
     838              :  *
     839              :  * Note: We deliberately do not check the tdtypmod field.  This allows
     840              :  * typcache.c to use this routine to see if a cached record type matches a
     841              :  * requested type.
     842              :  */
     843              : bool
     844       270181 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
     845              : {
     846       270181 :     if (tupdesc1->natts != tupdesc2->natts)
     847          110 :         return false;
     848       270071 :     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     849         1283 :         return false;
     850              : 
     851      3626187 :     for (int i = 0; i < tupdesc1->natts; i++)
     852              :     {
     853      3363176 :         Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
     854      3363176 :         Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
     855              : 
     856      3363176 :         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     857         5761 :             return false;
     858      3357415 :         if (attr1->atttypid != attr2->atttypid)
     859           14 :             return false;
     860      3357401 :         if (attr1->atttypmod != attr2->atttypmod)
     861            2 :             return false;
     862      3357399 :         if (attr1->attcollation != attr2->attcollation)
     863            0 :             return false;
     864              : 
     865              :         /* Record types derived from tables could have dropped fields. */
     866      3357399 :         if (attr1->attisdropped != attr2->attisdropped)
     867            0 :             return false;
     868              :     }
     869              : 
     870       263011 :     return true;
     871              : }
     872              : 
     873              : /*
     874              :  * hashRowType
     875              :  *
     876              :  * If two tuple descriptors would be considered equal by equalRowTypes()
     877              :  * then their hash value will be equal according to this function.
     878              :  */
     879              : uint32
     880       278606 : hashRowType(TupleDesc desc)
     881              : {
     882              :     uint32      s;
     883              :     int         i;
     884              : 
     885       278606 :     s = hash_combine(0, hash_bytes_uint32(desc->natts));
     886       278606 :     s = hash_combine(s, hash_bytes_uint32(desc->tdtypeid));
     887      3803816 :     for (i = 0; i < desc->natts; ++i)
     888      3525210 :         s = hash_combine(s, hash_bytes_uint32(TupleDescAttr(desc, i)->atttypid));
     889              : 
     890       278606 :     return s;
     891              : }
     892              : 
     893              : /*
     894              :  * TupleDescInitEntry
     895              :  *      This function initializes a single attribute structure in
     896              :  *      a previously allocated tuple descriptor.
     897              :  *
     898              :  * If attributeName is NULL, the attname field is set to an empty string
     899              :  * (this is for cases where we don't know or need a name for the field).
     900              :  * Also, some callers use this function to change the datatype-related fields
     901              :  * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
     902              :  * to indicate that the attname field shouldn't be modified.
     903              :  *
     904              :  * Note that attcollation is set to the default for the specified datatype.
     905              :  * If a nondefault collation is needed, insert it afterwards using
     906              :  * TupleDescInitEntryCollation.
     907              :  */
     908              : void
     909      7873144 : TupleDescInitEntry(TupleDesc desc,
     910              :                    AttrNumber attributeNumber,
     911              :                    const char *attributeName,
     912              :                    Oid oidtypeid,
     913              :                    int32 typmod,
     914              :                    int attdim)
     915              : {
     916              :     HeapTuple   tuple;
     917              :     Form_pg_type typeForm;
     918              :     Form_pg_attribute att;
     919              : 
     920              :     /*
     921              :      * sanity checks
     922              :      */
     923              :     Assert(desc);
     924              :     Assert(attributeNumber >= 1);
     925              :     Assert(attributeNumber <= desc->natts);
     926              :     Assert(attdim >= 0);
     927              :     Assert(attdim <= PG_INT16_MAX);
     928              : 
     929              :     /*
     930              :      * initialize the attribute fields
     931              :      */
     932      7873144 :     att = TupleDescAttr(desc, attributeNumber - 1);
     933              : 
     934      7873144 :     att->attrelid = 0;           /* dummy value */
     935              : 
     936              :     /*
     937              :      * Note: attributeName can be NULL, because the planner doesn't always
     938              :      * fill in valid resname values in targetlists, particularly for resjunk
     939              :      * attributes. Also, do nothing if caller wants to re-use the old attname.
     940              :      */
     941      7873144 :     if (attributeName == NULL)
     942     12822353 :         MemSet(NameStr(att->attname), 0, NAMEDATALEN);
     943      5134511 :     else if (attributeName != NameStr(att->attname))
     944      5132086 :         namestrcpy(&(att->attname), attributeName);
     945              : 
     946      7873144 :     att->atttypmod = typmod;
     947              : 
     948      7873144 :     att->attnum = attributeNumber;
     949      7873144 :     att->attndims = attdim;
     950              : 
     951      7873144 :     att->attnotnull = false;
     952      7873144 :     att->atthasdef = false;
     953      7873144 :     att->atthasmissing = false;
     954      7873144 :     att->attidentity = '\0';
     955      7873144 :     att->attgenerated = '\0';
     956      7873144 :     att->attisdropped = false;
     957      7873144 :     att->attislocal = true;
     958      7873144 :     att->attinhcount = 0;
     959              :     /* variable-length fields are not present in tupledescs */
     960              : 
     961      7873144 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
     962      7873144 :     if (!HeapTupleIsValid(tuple))
     963            0 :         elog(ERROR, "cache lookup failed for type %u", oidtypeid);
     964      7873144 :     typeForm = (Form_pg_type) GETSTRUCT(tuple);
     965              : 
     966      7873144 :     att->atttypid = oidtypeid;
     967      7873144 :     att->attlen = typeForm->typlen;
     968      7873144 :     att->attbyval = typeForm->typbyval;
     969      7873144 :     att->attalign = typeForm->typalign;
     970      7873144 :     att->attstorage = typeForm->typstorage;
     971      7873144 :     att->attcompression = InvalidCompressionMethod;
     972      7873144 :     att->attcollation = typeForm->typcollation;
     973              : 
     974      7873144 :     populate_compact_attribute(desc, attributeNumber - 1);
     975              : 
     976      7873144 :     ReleaseSysCache(tuple);
     977      7873144 : }
     978              : 
     979              : /*
     980              :  * TupleDescInitBuiltinEntry
     981              :  *      Initialize a tuple descriptor without catalog access.  Only
     982              :  *      a limited range of builtin types are supported.
     983              :  */
     984              : void
     985         8339 : TupleDescInitBuiltinEntry(TupleDesc desc,
     986              :                           AttrNumber attributeNumber,
     987              :                           const char *attributeName,
     988              :                           Oid oidtypeid,
     989              :                           int32 typmod,
     990              :                           int attdim)
     991              : {
     992              :     Form_pg_attribute att;
     993              : 
     994              :     /* sanity checks */
     995              :     Assert(desc);
     996              :     Assert(attributeNumber >= 1);
     997              :     Assert(attributeNumber <= desc->natts);
     998              :     Assert(attdim >= 0);
     999              :     Assert(attdim <= PG_INT16_MAX);
    1000              : 
    1001              :     /* initialize the attribute fields */
    1002         8339 :     att = TupleDescAttr(desc, attributeNumber - 1);
    1003         8339 :     att->attrelid = 0;           /* dummy value */
    1004              : 
    1005              :     /* unlike TupleDescInitEntry, we require an attribute name */
    1006              :     Assert(attributeName != NULL);
    1007         8339 :     namestrcpy(&(att->attname), attributeName);
    1008              : 
    1009         8339 :     att->atttypmod = typmod;
    1010              : 
    1011         8339 :     att->attnum = attributeNumber;
    1012         8339 :     att->attndims = attdim;
    1013              : 
    1014         8339 :     att->attnotnull = false;
    1015         8339 :     att->atthasdef = false;
    1016         8339 :     att->atthasmissing = false;
    1017         8339 :     att->attidentity = '\0';
    1018         8339 :     att->attgenerated = '\0';
    1019         8339 :     att->attisdropped = false;
    1020         8339 :     att->attislocal = true;
    1021         8339 :     att->attinhcount = 0;
    1022              :     /* variable-length fields are not present in tupledescs */
    1023              : 
    1024         8339 :     att->atttypid = oidtypeid;
    1025              : 
    1026              :     /*
    1027              :      * Our goal here is to support just enough types to let basic builtin
    1028              :      * commands work without catalog access - e.g. so that we can do certain
    1029              :      * things even in processes that are not connected to a database.
    1030              :      */
    1031         8339 :     switch (oidtypeid)
    1032              :     {
    1033         6796 :         case TEXTOID:
    1034              :         case TEXTARRAYOID:
    1035         6796 :             att->attlen = -1;
    1036         6796 :             att->attbyval = false;
    1037         6796 :             att->attalign = TYPALIGN_INT;
    1038         6796 :             att->attstorage = TYPSTORAGE_EXTENDED;
    1039         6796 :             att->attcompression = InvalidCompressionMethod;
    1040         6796 :             att->attcollation = DEFAULT_COLLATION_OID;
    1041         6796 :             break;
    1042              : 
    1043            0 :         case BOOLOID:
    1044            0 :             att->attlen = 1;
    1045            0 :             att->attbyval = true;
    1046            0 :             att->attalign = TYPALIGN_CHAR;
    1047            0 :             att->attstorage = TYPSTORAGE_PLAIN;
    1048            0 :             att->attcompression = InvalidCompressionMethod;
    1049            0 :             att->attcollation = InvalidOid;
    1050            0 :             break;
    1051              : 
    1052            0 :         case INT4OID:
    1053            0 :             att->attlen = 4;
    1054            0 :             att->attbyval = true;
    1055            0 :             att->attalign = TYPALIGN_INT;
    1056            0 :             att->attstorage = TYPSTORAGE_PLAIN;
    1057            0 :             att->attcompression = InvalidCompressionMethod;
    1058            0 :             att->attcollation = InvalidOid;
    1059            0 :             break;
    1060              : 
    1061         1366 :         case INT8OID:
    1062         1366 :             att->attlen = 8;
    1063         1366 :             att->attbyval = true;
    1064         1366 :             att->attalign = TYPALIGN_DOUBLE;
    1065         1366 :             att->attstorage = TYPSTORAGE_PLAIN;
    1066         1366 :             att->attcompression = InvalidCompressionMethod;
    1067         1366 :             att->attcollation = InvalidOid;
    1068         1366 :             break;
    1069              : 
    1070          177 :         case OIDOID:
    1071          177 :             att->attlen = 4;
    1072          177 :             att->attbyval = true;
    1073          177 :             att->attalign = TYPALIGN_INT;
    1074          177 :             att->attstorage = TYPSTORAGE_PLAIN;
    1075          177 :             att->attcompression = InvalidCompressionMethod;
    1076          177 :             att->attcollation = InvalidOid;
    1077          177 :             break;
    1078              : 
    1079            0 :         default:
    1080            0 :             elog(ERROR, "unsupported type %u", oidtypeid);
    1081              :     }
    1082              : 
    1083         8339 :     populate_compact_attribute(desc, attributeNumber - 1);
    1084         8339 : }
    1085              : 
    1086              : /*
    1087              :  * TupleDescInitEntryCollation
    1088              :  *
    1089              :  * Assign a nondefault collation to a previously initialized tuple descriptor
    1090              :  * entry.
    1091              :  */
    1092              : void
    1093      4250500 : TupleDescInitEntryCollation(TupleDesc desc,
    1094              :                             AttrNumber attributeNumber,
    1095              :                             Oid collationid)
    1096              : {
    1097              :     /*
    1098              :      * sanity checks
    1099              :      */
    1100              :     Assert(desc);
    1101              :     Assert(attributeNumber >= 1);
    1102              :     Assert(attributeNumber <= desc->natts);
    1103              : 
    1104      4250500 :     TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
    1105      4250500 : }
    1106              : 
    1107              : /*
    1108              :  * BuildDescFromLists
    1109              :  *
    1110              :  * Build a TupleDesc given lists of column names (as String nodes),
    1111              :  * column type OIDs, typmods, and collation OIDs.
    1112              :  *
    1113              :  * No constraints are generated.
    1114              :  *
    1115              :  * This is for use with functions returning RECORD.
    1116              :  */
    1117              : TupleDesc
    1118          904 : BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
    1119              : {
    1120              :     int         natts;
    1121              :     AttrNumber  attnum;
    1122              :     ListCell   *l1;
    1123              :     ListCell   *l2;
    1124              :     ListCell   *l3;
    1125              :     ListCell   *l4;
    1126              :     TupleDesc   desc;
    1127              : 
    1128          904 :     natts = list_length(names);
    1129              :     Assert(natts == list_length(types));
    1130              :     Assert(natts == list_length(typmods));
    1131              :     Assert(natts == list_length(collations));
    1132              : 
    1133              :     /*
    1134              :      * allocate a new tuple descriptor
    1135              :      */
    1136          904 :     desc = CreateTemplateTupleDesc(natts);
    1137              : 
    1138          904 :     attnum = 0;
    1139         3169 :     forfour(l1, names, l2, types, l3, typmods, l4, collations)
    1140              :     {
    1141         2265 :         char       *attname = strVal(lfirst(l1));
    1142         2265 :         Oid         atttypid = lfirst_oid(l2);
    1143         2265 :         int32       atttypmod = lfirst_int(l3);
    1144         2265 :         Oid         attcollation = lfirst_oid(l4);
    1145              : 
    1146         2265 :         attnum++;
    1147              : 
    1148         2265 :         TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
    1149         2265 :         TupleDescInitEntryCollation(desc, attnum, attcollation);
    1150              :     }
    1151              : 
    1152          904 :     TupleDescFinalize(desc);
    1153              : 
    1154          904 :     return desc;
    1155              : }
    1156              : 
    1157              : /*
    1158              :  * Get default expression (or NULL if none) for the given attribute number.
    1159              :  */
    1160              : Node *
    1161        78729 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
    1162              : {
    1163        78729 :     Node       *result = NULL;
    1164              : 
    1165        78729 :     if (tupdesc->constr)
    1166              :     {
    1167        78729 :         AttrDefault *attrdef = tupdesc->constr->defval;
    1168              : 
    1169       119064 :         for (int i = 0; i < tupdesc->constr->num_defval; i++)
    1170              :         {
    1171       119064 :             if (attrdef[i].adnum == attnum)
    1172              :             {
    1173        78729 :                 result = stringToNode(attrdef[i].adbin);
    1174        78729 :                 break;
    1175              :             }
    1176              :         }
    1177              :     }
    1178              : 
    1179        78729 :     return result;
    1180              : }
    1181              : 
    1182              : /* ResourceOwner callbacks */
    1183              : 
    1184              : static void
    1185        11792 : ResOwnerReleaseTupleDesc(Datum res)
    1186              : {
    1187        11792 :     TupleDesc   tupdesc = (TupleDesc) DatumGetPointer(res);
    1188              : 
    1189              :     /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
    1190              :     Assert(tupdesc->tdrefcount > 0);
    1191        11792 :     if (--tupdesc->tdrefcount == 0)
    1192          395 :         FreeTupleDesc(tupdesc);
    1193        11792 : }
    1194              : 
    1195              : static char *
    1196            0 : ResOwnerPrintTupleDesc(Datum res)
    1197              : {
    1198            0 :     TupleDesc   tupdesc = (TupleDesc) DatumGetPointer(res);
    1199              : 
    1200            0 :     return psprintf("TupleDesc %p (%u,%d)",
    1201              :                     tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
    1202              : }
        

Generated by: LCOV version 2.0-1