LCOV - code coverage report
Current view: top level - src/backend/access/common - tupdesc.c (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 91.7 % 457 419
Test Date: 2026-07-03 19:57:34 Functions: 92.3 % 26 24
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 83.9 % 248 208

             Branch data     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                 :    21272706 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
      50                 :             : {
      51                 :    21272706 :     ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
      52                 :    21272706 : }
      53                 :             : 
      54                 :             : static inline void
      55                 :    21260917 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
      56                 :             : {
      57                 :    21260917 :     ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
      58                 :    21260917 : }
      59                 :             : 
      60                 :             : /*
      61                 :             :  * populate_compact_attribute_internal
      62                 :             :  *      Helper function for populate_compact_attribute()
      63                 :             :  */
      64                 :             : static inline void
      65                 :    43385383 : populate_compact_attribute_internal(Form_pg_attribute src,
      66                 :             :                                     CompactAttribute *dst)
      67                 :             : {
      68                 :    43385383 :     memset(dst, 0, sizeof(CompactAttribute));
      69                 :             : 
      70                 :    43385383 :     dst->attcacheoff = -1;
      71                 :    43385383 :     dst->attlen = src->attlen;
      72                 :             : 
      73                 :    43385383 :     dst->attbyval = src->attbyval;
      74                 :    43385383 :     dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
      75                 :    43385383 :     dst->atthasmissing = src->atthasmissing;
      76                 :    43385383 :     dst->attisdropped = src->attisdropped;
      77                 :    43385383 :     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   [ +  +  +  + ]:    67782529 :     dst->attnullability = !src->attnotnull ? ATTNULLABLE_UNRESTRICTED :
      86                 :    24397146 :         IsCatalogRelationOid(src->attrelid) ? ATTNULLABLE_VALID :
      87                 :             :         ATTNULLABLE_UNKNOWN;
      88                 :             : 
      89                 :             :     /* Compute numeric alignment requirement, too */
      90                 :    43385383 :     dst->attalignby = typalign_to_alignby(src->attalign);
      91                 :    43385383 : }
      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                 :    43385383 : populate_compact_attribute(TupleDesc tupdesc, int attnum)
     101                 :             : {
     102                 :    43385383 :     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                 :    43385383 :     dst = &tupdesc->compact_attrs[attnum];
     110                 :             : 
     111                 :    43385383 :     populate_compact_attribute_internal(src, dst);
     112                 :    43385383 : }
     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                 :     6560434 : 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                 :     6560434 :     desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
     188                 :             :                               natts * sizeof(CompactAttribute) +
     189                 :     6560434 :                               natts * sizeof(FormData_pg_attribute));
     190                 :             : 
     191                 :             :     /*
     192                 :             :      * Initialize other fields of the tupdesc.
     193                 :             :      */
     194                 :     6560434 :     desc->natts = natts;
     195                 :     6560434 :     desc->constr = NULL;
     196                 :     6560434 :     desc->tdtypeid = RECORDOID;
     197                 :     6560434 :     desc->tdtypmod = -1;
     198                 :     6560434 :     desc->tdrefcount = -1;       /* assume not reference-counted */
     199                 :             : 
     200                 :             :     /* This will be set to the correct value by TupleDescFinalize() */
     201                 :     6560434 :     desc->firstNonCachedOffsetAttr = -1;
     202                 :     6560434 :     desc->firstNonGuaranteedAttr = -1;
     203                 :             : 
     204                 :     6560434 :     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                 :      667893 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
     217                 :             : {
     218                 :             :     TupleDesc   desc;
     219                 :             :     int         i;
     220                 :             : 
     221                 :      667893 :     desc = CreateTemplateTupleDesc(natts);
     222                 :             : 
     223         [ +  + ]:    10179855 :     for (i = 0; i < natts; ++i)
     224                 :             :     {
     225                 :     9511962 :         memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
     226                 :     9511962 :         populate_compact_attribute(desc, i);
     227                 :             :     }
     228                 :             : 
     229                 :      667893 :     TupleDescFinalize(desc);
     230                 :             : 
     231                 :      667893 :     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                 :      259097 : CreateTupleDescCopy(TupleDesc tupdesc)
     243                 :             : {
     244                 :             :     TupleDesc   desc;
     245                 :             :     int         i;
     246                 :             : 
     247                 :      259097 :     desc = CreateTemplateTupleDesc(tupdesc->natts);
     248                 :             : 
     249                 :             :     /* Flat-copy the attribute array (unless there are no attributes) */
     250         [ +  + ]:      259097 :     if (desc->natts > 0)
     251                 :      256713 :         memcpy(TupleDescAttr(desc, 0),
     252                 :      256713 :                TupleDescAttr(tupdesc, 0),
     253                 :      256713 :                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         [ +  + ]:     1306286 :     for (i = 0; i < desc->natts; i++)
     260                 :             :     {
     261                 :     1047189 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     262                 :             : 
     263                 :     1047189 :         att->attnotnull = false;
     264                 :     1047189 :         att->atthasdef = false;
     265                 :     1047189 :         att->atthasmissing = false;
     266                 :     1047189 :         att->attidentity = '\0';
     267                 :     1047189 :         att->attgenerated = '\0';
     268                 :             : 
     269                 :     1047189 :         populate_compact_attribute(desc, i);
     270                 :             :     }
     271                 :             : 
     272                 :             :     /* We can copy the tuple type identification, too */
     273                 :      259097 :     desc->tdtypeid = tupdesc->tdtypeid;
     274                 :      259097 :     desc->tdtypmod = tupdesc->tdtypmod;
     275                 :             : 
     276                 :      259097 :     TupleDescFinalize(desc);
     277                 :             : 
     278                 :      259097 :     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                 :       25719 : CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
     290                 :             : {
     291                 :             :     TupleDesc   desc;
     292                 :             :     int         i;
     293                 :             : 
     294                 :             :     Assert(natts <= tupdesc->natts);
     295                 :             : 
     296                 :       25719 :     desc = CreateTemplateTupleDesc(natts);
     297                 :             : 
     298                 :             :     /* Flat-copy the attribute array (unless there are no attributes) */
     299         [ +  - ]:       25719 :     if (desc->natts > 0)
     300                 :       25719 :         memcpy(TupleDescAttr(desc, 0),
     301                 :       25719 :                TupleDescAttr(tupdesc, 0),
     302                 :       25719 :                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         [ +  + ]:       62697 :     for (i = 0; i < desc->natts; i++)
     309                 :             :     {
     310                 :       36978 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     311                 :             : 
     312                 :       36978 :         att->attnotnull = false;
     313                 :       36978 :         att->atthasdef = false;
     314                 :       36978 :         att->atthasmissing = false;
     315                 :       36978 :         att->attidentity = '\0';
     316                 :       36978 :         att->attgenerated = '\0';
     317                 :             : 
     318                 :       36978 :         populate_compact_attribute(desc, i);
     319                 :             :     }
     320                 :             : 
     321                 :             :     /* We can copy the tuple type identification, too */
     322                 :       25719 :     desc->tdtypeid = tupdesc->tdtypeid;
     323                 :       25719 :     desc->tdtypmod = tupdesc->tdtypmod;
     324                 :             : 
     325                 :       25719 :     TupleDescFinalize(desc);
     326                 :             : 
     327                 :       25719 :     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                 :      534332 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
     337                 :             : {
     338                 :             :     TupleDesc   desc;
     339                 :      534332 :     TupleConstr *constr = tupdesc->constr;
     340                 :             :     int         i;
     341                 :             : 
     342                 :      534332 :     desc = CreateTemplateTupleDesc(tupdesc->natts);
     343                 :             : 
     344                 :             :     /* Flat-copy the attribute array (unless there are no attributes) */
     345         [ +  + ]:      534332 :     if (desc->natts > 0)
     346                 :      534270 :         memcpy(TupleDescAttr(desc, 0),
     347                 :      534270 :                TupleDescAttr(tupdesc, 0),
     348                 :      534270 :                desc->natts * sizeof(FormData_pg_attribute));
     349                 :             : 
     350         [ +  + ]:     7703110 :     for (i = 0; i < desc->natts; i++)
     351                 :             :     {
     352                 :     7168778 :         populate_compact_attribute(desc, i);
     353                 :             : 
     354                 :     7168778 :         TupleDescCompactAttr(desc, i)->attnullability =
     355                 :    14337556 :             TupleDescCompactAttr(tupdesc, i)->attnullability;
     356                 :             :     }
     357                 :             : 
     358                 :             :     /* Copy the TupleConstr data structure, if any */
     359         [ +  + ]:      534332 :     if (constr)
     360                 :             :     {
     361                 :      488998 :         TupleConstr *cpy = palloc0_object(TupleConstr);
     362                 :             : 
     363                 :      488998 :         cpy->has_not_null = constr->has_not_null;
     364                 :      488998 :         cpy->has_generated_stored = constr->has_generated_stored;
     365                 :      488998 :         cpy->has_generated_virtual = constr->has_generated_virtual;
     366                 :             : 
     367         [ +  + ]:      488998 :         if ((cpy->num_defval = constr->num_defval) > 0)
     368                 :             :         {
     369                 :        2960 :             cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
     370                 :        2960 :             memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
     371         [ +  + ]:        7187 :             for (i = cpy->num_defval - 1; i >= 0; i--)
     372                 :        4227 :                 cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
     373                 :             :         }
     374                 :             : 
     375         [ +  + ]:      488998 :         if (constr->missing)
     376                 :             :         {
     377                 :         430 :             cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
     378                 :         430 :             memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
     379         [ +  + ]:        3294 :             for (i = tupdesc->natts - 1; i >= 0; i--)
     380                 :             :             {
     381         [ +  + ]:        2864 :                 if (constr->missing[i].am_present)
     382                 :             :                 {
     383                 :         766 :                     CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
     384                 :             : 
     385                 :         766 :                     cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
     386                 :         766 :                                                          attr->attbyval,
     387                 :         766 :                                                          attr->attlen);
     388                 :             :                 }
     389                 :             :             }
     390                 :             :         }
     391                 :             : 
     392         [ +  + ]:      488998 :         if ((cpy->num_check = constr->num_check) > 0)
     393                 :             :         {
     394                 :        1835 :             cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
     395                 :        1835 :             memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
     396         [ +  + ]:        5423 :             for (i = cpy->num_check - 1; i >= 0; i--)
     397                 :             :             {
     398                 :        3588 :                 cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
     399                 :        3588 :                 cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
     400                 :        3588 :                 cpy->check[i].ccenforced = constr->check[i].ccenforced;
     401                 :        3588 :                 cpy->check[i].ccvalid = constr->check[i].ccvalid;
     402                 :        3588 :                 cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
     403                 :             :             }
     404                 :             :         }
     405                 :             : 
     406                 :      488998 :         desc->constr = cpy;
     407                 :             :     }
     408                 :             : 
     409                 :             :     /* We can copy the tuple type identification, too */
     410                 :      534332 :     desc->tdtypeid = tupdesc->tdtypeid;
     411                 :      534332 :     desc->tdtypmod = tupdesc->tdtypmod;
     412                 :             : 
     413                 :      534332 :     TupleDescFinalize(desc);
     414                 :             : 
     415                 :      534332 :     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                 :        2874 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
     473                 :             :                    TupleDesc src, AttrNumber srcAttno)
     474                 :             : {
     475                 :        2874 :     Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
     476                 :        2874 :     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                 :        2874 :     memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
     489                 :             : 
     490                 :        2874 :     dstAtt->attnum = dstAttno;
     491                 :             : 
     492                 :             :     /* since we're not copying constraints or defaults, clear these */
     493                 :        2874 :     dstAtt->attnotnull = false;
     494                 :        2874 :     dstAtt->atthasdef = false;
     495                 :        2874 :     dstAtt->atthasmissing = false;
     496                 :        2874 :     dstAtt->attidentity = '\0';
     497                 :        2874 :     dstAtt->attgenerated = '\0';
     498                 :             : 
     499                 :        2874 :     populate_compact_attribute(dst, dstAttno - 1);
     500                 :        2874 : }
     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                 :     6695279 : TupleDescFinalize(TupleDesc tupdesc)
     512                 :             : {
     513                 :     6695279 :     int         firstNonCachedOffsetAttr = 0;
     514                 :     6695279 :     int         firstNonGuaranteedAttr = tupdesc->natts;
     515                 :     6695279 :     int         off = 0;
     516                 :             : 
     517         [ +  + ]:    37276581 :     for (int i = 0; i < tupdesc->natts; i++)
     518                 :             :     {
     519                 :    33972851 :         CompactAttribute *cattr = TupleDescCompactAttr(tupdesc, i);
     520                 :    33972851 :         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         [ +  + ]:    33972851 :         if (firstNonGuaranteedAttr == tupdesc->natts &&
     528   [ +  +  +  +  :    14175183 :             (cattr->attnullability != ATTNULLABLE_VALID || !cattr->attbyval ||
                   +  + ]
     529         [ +  - ]:     8021507 :              cattr->atthasmissing || cattr->attisdropped ||
     530         [ +  - ]:     8021507 :              cattr->attlen <= 0 ||
     531         [ +  + ]:     8021507 :              attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL))
     532                 :     6153978 :             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         [ +  + ]:    33972851 :         if (cattr->attlen <= 0 ||
     540         [ +  + ]:    30586852 :             attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
     541                 :             :             break;
     542                 :             : 
     543                 :    30581302 :         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         [ -  + ]:    30581302 :         if (off > PG_INT16_MAX)
     553                 :           0 :             break;
     554                 :             : 
     555                 :    30581302 :         cattr->attcacheoff = (int16) off;
     556                 :             : 
     557                 :    30581302 :         off += cattr->attlen;
     558                 :    30581302 :         firstNonCachedOffsetAttr = i + 1;
     559                 :             :     }
     560                 :             : 
     561                 :     6695279 :     tupdesc->firstNonCachedOffsetAttr = firstNonCachedOffsetAttr;
     562                 :     6695279 :     tupdesc->firstNonGuaranteedAttr = firstNonGuaranteedAttr;
     563                 :     6695279 : }
     564                 :             : 
     565                 :             : /*
     566                 :             :  * Free a TupleDesc including all substructure
     567                 :             :  */
     568                 :             : void
     569                 :      987327 : 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         [ +  + ]:      987327 :     if (tupdesc->constr)
     580                 :             :     {
     581         [ +  + ]:      304595 :         if (tupdesc->constr->num_defval > 0)
     582                 :             :         {
     583                 :       23546 :             AttrDefault *attrdef = tupdesc->constr->defval;
     584                 :             : 
     585         [ +  + ]:       57459 :             for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
     586                 :       33913 :                 pfree(attrdef[i].adbin);
     587                 :       23546 :             pfree(attrdef);
     588                 :             :         }
     589         [ +  + ]:      304595 :         if (tupdesc->constr->missing)
     590                 :             :         {
     591                 :        2562 :             AttrMissing *attrmiss = tupdesc->constr->missing;
     592                 :             : 
     593         [ +  + ]:       18074 :             for (i = tupdesc->natts - 1; i >= 0; i--)
     594                 :             :             {
     595         [ +  + ]:       15512 :                 if (attrmiss[i].am_present
     596         [ +  + ]:        5343 :                     && !TupleDescAttr(tupdesc, i)->attbyval)
     597                 :        2021 :                     pfree(DatumGetPointer(attrmiss[i].am_value));
     598                 :             :             }
     599                 :        2562 :             pfree(attrmiss);
     600                 :             :         }
     601         [ +  + ]:      304595 :         if (tupdesc->constr->num_check > 0)
     602                 :             :         {
     603                 :        8695 :             ConstrCheck *check = tupdesc->constr->check;
     604                 :             : 
     605         [ +  + ]:       23977 :             for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
     606                 :             :             {
     607                 :       15282 :                 pfree(check[i].ccname);
     608                 :       15282 :                 pfree(check[i].ccbin);
     609                 :             :             }
     610                 :        8695 :             pfree(check);
     611                 :             :         }
     612                 :      304595 :         pfree(tupdesc->constr);
     613                 :             :     }
     614                 :             : 
     615                 :      987327 :     pfree(tupdesc);
     616                 :      987327 : }
     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                 :    21272706 : IncrTupleDescRefCount(TupleDesc tupdesc)
     627                 :             : {
     628                 :             :     Assert(tupdesc->tdrefcount >= 0);
     629                 :             : 
     630                 :    21272706 :     ResourceOwnerEnlarge(CurrentResourceOwner);
     631                 :    21272706 :     tupdesc->tdrefcount++;
     632                 :    21272706 :     ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
     633                 :    21272706 : }
     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                 :    21260917 : DecrTupleDescRefCount(TupleDesc tupdesc)
     645                 :             : {
     646                 :             :     Assert(tupdesc->tdrefcount > 0);
     647                 :             : 
     648                 :    21260917 :     ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
     649         [ -  + ]:    21260917 :     if (--tupdesc->tdrefcount == 0)
     650                 :           0 :         FreeTupleDesc(tupdesc);
     651                 :    21260917 : }
     652                 :             : 
     653                 :             : /*
     654                 :             :  * Compare two TupleDesc structures for logical equality
     655                 :             :  */
     656                 :             : bool
     657                 :      283726 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
     658                 :             : {
     659                 :             :     int         i,
     660                 :             :                 n;
     661                 :             : 
     662         [ +  + ]:      283726 :     if (tupdesc1->natts != tupdesc2->natts)
     663                 :        1958 :         return false;
     664         [ -  + ]:      281768 :     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     665                 :           0 :         return false;
     666                 :             : 
     667                 :             :     /* tdtypmod and tdrefcount are not checked */
     668                 :             : 
     669         [ +  + ]:     1323290 :     for (i = 0; i < tupdesc1->natts; i++)
     670                 :             :     {
     671                 :     1051807 :         Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
     672                 :     1051807 :         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         [ +  + ]:     1051807 :         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     687                 :         926 :             return false;
     688         [ +  + ]:     1050881 :         if (attr1->atttypid != attr2->atttypid)
     689                 :         758 :             return false;
     690         [ +  + ]:     1050123 :         if (attr1->attlen != attr2->attlen)
     691                 :           6 :             return false;
     692         [ -  + ]:     1050117 :         if (attr1->attndims != attr2->attndims)
     693                 :           0 :             return false;
     694         [ +  + ]:     1050117 :         if (attr1->atttypmod != attr2->atttypmod)
     695                 :          28 :             return false;
     696         [ +  + ]:     1050089 :         if (attr1->attbyval != attr2->attbyval)
     697                 :          34 :             return false;
     698         [ -  + ]:     1050055 :         if (attr1->attalign != attr2->attalign)
     699                 :           0 :             return false;
     700         [ +  + ]:     1050055 :         if (attr1->attstorage != attr2->attstorage)
     701                 :         165 :             return false;
     702         [ +  + ]:     1049890 :         if (attr1->attcompression != attr2->attcompression)
     703                 :          44 :             return false;
     704         [ +  + ]:     1049846 :         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         [ +  + ]:     1048680 :         if (attr1->attnotnull)
     713                 :             :         {
     714                 :      344847 :             CompactAttribute *cattr1 = TupleDescCompactAttr(tupdesc1, i);
     715                 :      344847 :             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         [ +  + ]:      344847 :             if (cattr1->attnullability != cattr2->attnullability)
     722                 :          70 :                 return false;
     723                 :             :         }
     724         [ +  + ]:     1048610 :         if (attr1->atthasdef != attr2->atthasdef)
     725                 :        3696 :             return false;
     726         [ +  + ]:     1044914 :         if (attr1->attidentity != attr2->attidentity)
     727                 :         118 :             return false;
     728         [ +  + ]:     1044796 :         if (attr1->attgenerated != attr2->attgenerated)
     729                 :          13 :             return false;
     730         [ -  + ]:     1044783 :         if (attr1->attisdropped != attr2->attisdropped)
     731                 :           0 :             return false;
     732         [ +  + ]:     1044783 :         if (attr1->attislocal != attr2->attislocal)
     733                 :        2748 :             return false;
     734         [ +  + ]:     1042035 :         if (attr1->attinhcount != attr2->attinhcount)
     735                 :         513 :             return false;
     736         [ -  + ]:     1041522 :         if (attr1->attcollation != attr2->attcollation)
     737                 :           0 :             return false;
     738                 :             :         /* variable-length fields are not even present... */
     739                 :             :     }
     740                 :             : 
     741         [ +  + ]:      271483 :     if (tupdesc1->constr != NULL)
     742                 :             :     {
     743                 :       99657 :         TupleConstr *constr1 = tupdesc1->constr;
     744                 :       99657 :         TupleConstr *constr2 = tupdesc2->constr;
     745                 :             : 
     746         [ +  + ]:       99657 :         if (constr2 == NULL)
     747                 :         175 :             return false;
     748         [ -  + ]:       99482 :         if (constr1->has_not_null != constr2->has_not_null)
     749                 :           0 :             return false;
     750         [ +  + ]:       99482 :         if (constr1->has_generated_stored != constr2->has_generated_stored)
     751                 :         470 :             return false;
     752         [ +  + ]:       99012 :         if (constr1->has_generated_virtual != constr2->has_generated_virtual)
     753                 :         294 :             return false;
     754                 :       98718 :         n = constr1->num_defval;
     755         [ -  + ]:       98718 :         if (n != (int) constr2->num_defval)
     756                 :           0 :             return false;
     757                 :             :         /* We assume here that both AttrDefault arrays are in adnum order */
     758         [ +  + ]:      112179 :         for (i = 0; i < n; i++)
     759                 :             :         {
     760                 :       13461 :             AttrDefault *defval1 = constr1->defval + i;
     761                 :       13461 :             AttrDefault *defval2 = constr2->defval + i;
     762                 :             : 
     763         [ -  + ]:       13461 :             if (defval1->adnum != defval2->adnum)
     764                 :           0 :                 return false;
     765         [ -  + ]:       13461 :             if (strcmp(defval1->adbin, defval2->adbin) != 0)
     766                 :           0 :                 return false;
     767                 :             :         }
     768         [ +  + ]:       98718 :         if (constr1->missing)
     769                 :             :         {
     770         [ +  + ]:         524 :             if (!constr2->missing)
     771                 :          65 :                 return false;
     772         [ +  + ]:        2686 :             for (i = 0; i < tupdesc1->natts; i++)
     773                 :             :             {
     774                 :        2328 :                 AttrMissing *missval1 = constr1->missing + i;
     775                 :        2328 :                 AttrMissing *missval2 = constr2->missing + i;
     776                 :             : 
     777         [ +  + ]:        2328 :                 if (missval1->am_present != missval2->am_present)
     778                 :         101 :                     return false;
     779         [ +  + ]:        2227 :                 if (missval1->am_present)
     780                 :             :                 {
     781                 :         761 :                     CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
     782                 :             : 
     783         [ -  + ]:         761 :                     if (!datumIsEqual(missval1->am_value, missval2->am_value,
     784                 :         761 :                                       missatt1->attbyval, missatt1->attlen))
     785                 :           0 :                         return false;
     786                 :             :                 }
     787                 :             :             }
     788                 :             :         }
     789         [ +  + ]:       98194 :         else if (constr2->missing)
     790                 :         255 :             return false;
     791                 :       98297 :         n = constr1->num_check;
     792         [ +  + ]:       98297 :         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         [ +  + ]:       99948 :         for (i = 0; i < n; i++)
     801                 :             :         {
     802                 :        2986 :             ConstrCheck *check1 = constr1->check + i;
     803                 :        2986 :             ConstrCheck *check2 = constr2->check + i;
     804                 :             : 
     805         [ +  - ]:        2986 :             if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
     806         [ +  - ]:        2986 :                   strcmp(check1->ccbin, check2->ccbin) == 0 &&
     807         [ +  + ]:        2986 :                   check1->ccenforced == check2->ccenforced &&
     808         [ +  + ]:        2886 :                   check1->ccvalid == check2->ccvalid &&
     809         [ -  + ]:        2830 :                   check1->ccnoinherit == check2->ccnoinherit))
     810                 :         156 :                 return false;
     811                 :             :         }
     812                 :             :     }
     813         [ +  + ]:      171826 :     else if (tupdesc2->constr != NULL)
     814                 :        1381 :         return false;
     815                 :      267407 :     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                 :      274411 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
     845                 :             : {
     846         [ +  + ]:      274411 :     if (tupdesc1->natts != tupdesc2->natts)
     847                 :         111 :         return false;
     848         [ +  + ]:      274300 :     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     849                 :        1284 :         return false;
     850                 :             : 
     851         [ +  + ]:     3736174 :     for (int i = 0; i < tupdesc1->natts; i++)
     852                 :             :     {
     853                 :     3468976 :         Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
     854                 :     3468976 :         Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
     855                 :             : 
     856         [ +  + ]:     3468976 :         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     857                 :        5800 :             return false;
     858         [ +  + ]:     3463176 :         if (attr1->atttypid != attr2->atttypid)
     859                 :          14 :             return false;
     860         [ +  + ]:     3463162 :         if (attr1->atttypmod != attr2->atttypmod)
     861                 :           4 :             return false;
     862         [ -  + ]:     3463158 :         if (attr1->attcollation != attr2->attcollation)
     863                 :           0 :             return false;
     864                 :             : 
     865                 :             :         /* Record types derived from tables could have dropped fields. */
     866         [ -  + ]:     3463158 :         if (attr1->attisdropped != attr2->attisdropped)
     867                 :           0 :             return false;
     868                 :             :     }
     869                 :             : 
     870                 :      267198 :     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                 :      283033 : hashRowType(TupleDesc desc)
     881                 :             : {
     882                 :             :     uint32      s;
     883                 :             :     int         i;
     884                 :             : 
     885                 :      283033 :     s = hash_combine(0, hash_bytes_uint32(desc->natts));
     886                 :      283033 :     s = hash_combine(s, hash_bytes_uint32(desc->tdtypeid));
     887         [ +  + ]:     3917651 :     for (i = 0; i < desc->natts; ++i)
     888                 :     3634618 :         s = hash_combine(s, hash_bytes_uint32(TupleDescAttr(desc, i)->atttypid));
     889                 :             : 
     890                 :      283033 :     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                 :     7849010 : 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                 :     7849010 :     att = TupleDescAttr(desc, attributeNumber - 1);
     933                 :             : 
     934                 :     7849010 :     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         [ +  + ]:     7849010 :     if (attributeName == NULL)
     942   [ +  +  +  -  :    12461846 :         MemSet(NameStr(att->attname), 0, NAMEDATALEN);
          +  -  +  -  +  
                      + ]
     943         [ +  + ]:     5187332 :     else if (attributeName != NameStr(att->attname))
     944                 :     5184907 :         namestrcpy(&(att->attname), attributeName);
     945                 :             : 
     946                 :     7849010 :     att->atttypmod = typmod;
     947                 :             : 
     948                 :     7849010 :     att->attnum = attributeNumber;
     949                 :     7849010 :     att->attndims = attdim;
     950                 :             : 
     951                 :     7849010 :     att->attnotnull = false;
     952                 :     7849010 :     att->atthasdef = false;
     953                 :     7849010 :     att->atthasmissing = false;
     954                 :     7849010 :     att->attidentity = '\0';
     955                 :     7849010 :     att->attgenerated = '\0';
     956                 :     7849010 :     att->attisdropped = false;
     957                 :     7849010 :     att->attislocal = true;
     958                 :     7849010 :     att->attinhcount = 0;
     959                 :             :     /* variable-length fields are not present in tupledescs */
     960                 :             : 
     961                 :     7849010 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
     962         [ -  + ]:     7849010 :     if (!HeapTupleIsValid(tuple))
     963         [ #  # ]:           0 :         elog(ERROR, "cache lookup failed for type %u", oidtypeid);
     964                 :     7849010 :     typeForm = (Form_pg_type) GETSTRUCT(tuple);
     965                 :             : 
     966                 :     7849010 :     att->atttypid = oidtypeid;
     967                 :     7849010 :     att->attlen = typeForm->typlen;
     968                 :     7849010 :     att->attbyval = typeForm->typbyval;
     969                 :     7849010 :     att->attalign = typeForm->typalign;
     970                 :     7849010 :     att->attstorage = typeForm->typstorage;
     971                 :     7849010 :     att->attcompression = InvalidCompressionMethod;
     972                 :     7849010 :     att->attcollation = typeForm->typcollation;
     973                 :             : 
     974                 :     7849010 :     populate_compact_attribute(desc, attributeNumber - 1);
     975                 :             : 
     976                 :     7849010 :     ReleaseSysCache(tuple);
     977                 :     7849010 : }
     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                 :        8121 : 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                 :        8121 :     att = TupleDescAttr(desc, attributeNumber - 1);
    1003                 :        8121 :     att->attrelid = 0;           /* dummy value */
    1004                 :             : 
    1005                 :             :     /* unlike TupleDescInitEntry, we require an attribute name */
    1006                 :             :     Assert(attributeName != NULL);
    1007                 :        8121 :     namestrcpy(&(att->attname), attributeName);
    1008                 :             : 
    1009                 :        8121 :     att->atttypmod = typmod;
    1010                 :             : 
    1011                 :        8121 :     att->attnum = attributeNumber;
    1012                 :        8121 :     att->attndims = attdim;
    1013                 :             : 
    1014                 :        8121 :     att->attnotnull = false;
    1015                 :        8121 :     att->atthasdef = false;
    1016                 :        8121 :     att->atthasmissing = false;
    1017                 :        8121 :     att->attidentity = '\0';
    1018                 :        8121 :     att->attgenerated = '\0';
    1019                 :        8121 :     att->attisdropped = false;
    1020                 :        8121 :     att->attislocal = true;
    1021                 :        8121 :     att->attinhcount = 0;
    1022                 :             :     /* variable-length fields are not present in tupledescs */
    1023                 :             : 
    1024                 :        8121 :     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   [ +  -  -  +  :        8121 :     switch (oidtypeid)
                   +  - ]
    1032                 :             :     {
    1033                 :        6634 :         case TEXTOID:
    1034                 :             :         case TEXTARRAYOID:
    1035                 :        6634 :             att->attlen = -1;
    1036                 :        6634 :             att->attbyval = false;
    1037                 :        6634 :             att->attalign = TYPALIGN_INT;
    1038                 :        6634 :             att->attstorage = TYPSTORAGE_EXTENDED;
    1039                 :        6634 :             att->attcompression = InvalidCompressionMethod;
    1040                 :        6634 :             att->attcollation = DEFAULT_COLLATION_OID;
    1041                 :        6634 :             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                 :        1314 :         case INT8OID:
    1062                 :        1314 :             att->attlen = 8;
    1063                 :        1314 :             att->attbyval = true;
    1064                 :        1314 :             att->attalign = TYPALIGN_DOUBLE;
    1065                 :        1314 :             att->attstorage = TYPSTORAGE_PLAIN;
    1066                 :        1314 :             att->attcompression = InvalidCompressionMethod;
    1067                 :        1314 :             att->attcollation = InvalidOid;
    1068                 :        1314 :             break;
    1069                 :             : 
    1070                 :         173 :         case OIDOID:
    1071                 :         173 :             att->attlen = 4;
    1072                 :         173 :             att->attbyval = true;
    1073                 :         173 :             att->attalign = TYPALIGN_INT;
    1074                 :         173 :             att->attstorage = TYPSTORAGE_PLAIN;
    1075                 :         173 :             att->attcompression = InvalidCompressionMethod;
    1076                 :         173 :             att->attcollation = InvalidOid;
    1077                 :         173 :             break;
    1078                 :             : 
    1079                 :           0 :         default:
    1080         [ #  # ]:           0 :             elog(ERROR, "unsupported type %u", oidtypeid);
    1081                 :             :     }
    1082                 :             : 
    1083                 :        8121 :     populate_compact_attribute(desc, attributeNumber - 1);
    1084                 :        8121 : }
    1085                 :             : 
    1086                 :             : /*
    1087                 :             :  * TupleDescInitEntryCollation
    1088                 :             :  *
    1089                 :             :  * Assign a nondefault collation to a previously initialized tuple descriptor
    1090                 :             :  * entry.
    1091                 :             :  */
    1092                 :             : void
    1093                 :     4118682 : 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                 :     4118682 :     TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
    1105                 :     4118682 : }
    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                 :       78797 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
    1162                 :             : {
    1163                 :       78797 :     Node       *result = NULL;
    1164                 :             : 
    1165         [ +  - ]:       78797 :     if (tupdesc->constr)
    1166                 :             :     {
    1167                 :       78797 :         AttrDefault *attrdef = tupdesc->constr->defval;
    1168                 :             : 
    1169         [ +  - ]:      119136 :         for (int i = 0; i < tupdesc->constr->num_defval; i++)
    1170                 :             :         {
    1171         [ +  + ]:      119136 :             if (attrdef[i].adnum == attnum)
    1172                 :             :             {
    1173                 :       78797 :                 result = stringToNode(attrdef[i].adbin);
    1174                 :       78797 :                 break;
    1175                 :             :             }
    1176                 :             :         }
    1177                 :             :     }
    1178                 :             : 
    1179                 :       78797 :     return result;
    1180                 :             : }
    1181                 :             : 
    1182                 :             : /* ResourceOwner callbacks */
    1183                 :             : 
    1184                 :             : static void
    1185                 :       11789 : ResOwnerReleaseTupleDesc(Datum res)
    1186                 :             : {
    1187                 :       11789 :     TupleDesc   tupdesc = (TupleDesc) DatumGetPointer(res);
    1188                 :             : 
    1189                 :             :     /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
    1190                 :             :     Assert(tupdesc->tdrefcount > 0);
    1191         [ +  + ]:       11789 :     if (--tupdesc->tdrefcount == 0)
    1192                 :         395 :         FreeTupleDesc(tupdesc);
    1193                 :       11789 : }
    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