LCOV - code coverage report
Current view: top level - src/backend/access/common - tupdesc.c (source / functions) Coverage Total Hit
Test: Code coverage Lines: 89.6 % 530 475
Test Date: 2026-01-26 10:56:24 Functions: 96.0 % 25 24
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
Branches: 72.9 % 314 229

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

Generated by: LCOV version 2.3.2-1