LCOV - code coverage report
Current view: top level - src/backend/access/common - tupdesc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 18devel Lines: 334 369 90.5 %
Date: 2024-11-21 08:14:44 Functions: 20 21 95.2 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * tupdesc.c
       4             :  *    POSTGRES tuple descriptor support code
       5             :  *
       6             :  * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
       7             :  * Portions Copyright (c) 1994, Regents of the University of California
       8             :  *
       9             :  *
      10             :  * IDENTIFICATION
      11             :  *    src/backend/access/common/tupdesc.c
      12             :  *
      13             :  * NOTES
      14             :  *    some of the executor utility code such as "ExecTypeFromTL" should be
      15             :  *    moved here.
      16             :  *
      17             :  *-------------------------------------------------------------------------
      18             :  */
      19             : 
      20             : #include "postgres.h"
      21             : 
      22             : #include "access/htup_details.h"
      23             : #include "access/toast_compression.h"
      24             : #include "access/tupdesc_details.h"
      25             : #include "catalog/pg_collation.h"
      26             : #include "catalog/pg_type.h"
      27             : #include "common/hashfn.h"
      28             : #include "utils/builtins.h"
      29             : #include "utils/datum.h"
      30             : #include "utils/resowner.h"
      31             : #include "utils/syscache.h"
      32             : 
      33             : /* ResourceOwner callbacks to hold tupledesc references  */
      34             : static void ResOwnerReleaseTupleDesc(Datum res);
      35             : static char *ResOwnerPrintTupleDesc(Datum res);
      36             : 
      37             : static const ResourceOwnerDesc tupdesc_resowner_desc =
      38             : {
      39             :     .name = "tupdesc reference",
      40             :     .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
      41             :     .release_priority = RELEASE_PRIO_TUPDESC_REFS,
      42             :     .ReleaseResource = ResOwnerReleaseTupleDesc,
      43             :     .DebugPrint = ResOwnerPrintTupleDesc
      44             : };
      45             : 
      46             : /* Convenience wrappers over ResourceOwnerRemember/Forget */
      47             : static inline void
      48    29195488 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
      49             : {
      50    29195488 :     ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
      51    29195488 : }
      52             : 
      53             : static inline void
      54    29182508 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
      55             : {
      56    29182508 :     ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
      57    29182508 : }
      58             : 
      59             : /*
      60             :  * CreateTemplateTupleDesc
      61             :  *      This function allocates an empty tuple descriptor structure.
      62             :  *
      63             :  * Tuple type ID information is initially set for an anonymous record type;
      64             :  * caller can overwrite this if needed.
      65             :  */
      66             : TupleDesc
      67     9244012 : CreateTemplateTupleDesc(int natts)
      68             : {
      69             :     TupleDesc   desc;
      70             : 
      71             :     /*
      72             :      * sanity checks
      73             :      */
      74             :     Assert(natts >= 0);
      75             : 
      76             :     /*
      77             :      * Allocate enough memory for the tuple descriptor, including the
      78             :      * attribute rows.
      79             :      *
      80             :      * Note: the attribute array stride is sizeof(FormData_pg_attribute),
      81             :      * since we declare the array elements as FormData_pg_attribute for
      82             :      * notational convenience.  However, we only guarantee that the first
      83             :      * ATTRIBUTE_FIXED_PART_SIZE bytes of each entry are valid; most code that
      84             :      * copies tupdesc entries around copies just that much.  In principle that
      85             :      * could be less due to trailing padding, although with the current
      86             :      * definition of pg_attribute there probably isn't any padding.
      87             :      */
      88     9244012 :     desc = (TupleDesc) palloc(offsetof(struct TupleDescData, attrs) +
      89     9244012 :                               natts * sizeof(FormData_pg_attribute));
      90             : 
      91             :     /*
      92             :      * Initialize other fields of the tupdesc.
      93             :      */
      94     9244012 :     desc->natts = natts;
      95     9244012 :     desc->constr = NULL;
      96     9244012 :     desc->tdtypeid = RECORDOID;
      97     9244012 :     desc->tdtypmod = -1;
      98     9244012 :     desc->tdrefcount = -1;       /* assume not reference-counted */
      99             : 
     100     9244012 :     return desc;
     101             : }
     102             : 
     103             : /*
     104             :  * CreateTupleDesc
     105             :  *      This function allocates a new TupleDesc by copying a given
     106             :  *      Form_pg_attribute array.
     107             :  *
     108             :  * Tuple type ID information is initially set for an anonymous record type;
     109             :  * caller can overwrite this if needed.
     110             :  */
     111             : TupleDesc
     112     1030308 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
     113             : {
     114             :     TupleDesc   desc;
     115             :     int         i;
     116             : 
     117     1030308 :     desc = CreateTemplateTupleDesc(natts);
     118             : 
     119    15751716 :     for (i = 0; i < natts; ++i)
     120    14721408 :         memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
     121             : 
     122     1030308 :     return desc;
     123             : }
     124             : 
     125             : /*
     126             :  * CreateTupleDescCopy
     127             :  *      This function creates a new TupleDesc by copying from an existing
     128             :  *      TupleDesc.
     129             :  *
     130             :  * !!! Constraints and defaults are not copied !!!
     131             :  */
     132             : TupleDesc
     133      383790 : CreateTupleDescCopy(TupleDesc tupdesc)
     134             : {
     135             :     TupleDesc   desc;
     136             :     int         i;
     137             : 
     138      383790 :     desc = CreateTemplateTupleDesc(tupdesc->natts);
     139             : 
     140             :     /* Flat-copy the attribute array */
     141      383790 :     memcpy(TupleDescAttr(desc, 0),
     142      383790 :            TupleDescAttr(tupdesc, 0),
     143      383790 :            desc->natts * sizeof(FormData_pg_attribute));
     144             : 
     145             :     /*
     146             :      * Since we're not copying constraints and defaults, clear fields
     147             :      * associated with them.
     148             :      */
     149     1943088 :     for (i = 0; i < desc->natts; i++)
     150             :     {
     151     1559298 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     152             : 
     153     1559298 :         att->attnotnull = false;
     154     1559298 :         att->atthasdef = false;
     155     1559298 :         att->atthasmissing = false;
     156     1559298 :         att->attidentity = '\0';
     157     1559298 :         att->attgenerated = '\0';
     158             :     }
     159             : 
     160             :     /* We can copy the tuple type identification, too */
     161      383790 :     desc->tdtypeid = tupdesc->tdtypeid;
     162      383790 :     desc->tdtypmod = tupdesc->tdtypmod;
     163             : 
     164      383790 :     return desc;
     165             : }
     166             : 
     167             : /*
     168             :  * CreateTupleDescCopyConstr
     169             :  *      This function creates a new TupleDesc by copying from an existing
     170             :  *      TupleDesc (including its constraints and defaults).
     171             :  */
     172             : TupleDesc
     173      784782 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
     174             : {
     175             :     TupleDesc   desc;
     176      784782 :     TupleConstr *constr = tupdesc->constr;
     177             :     int         i;
     178             : 
     179      784782 :     desc = CreateTemplateTupleDesc(tupdesc->natts);
     180             : 
     181             :     /* Flat-copy the attribute array */
     182      784782 :     memcpy(TupleDescAttr(desc, 0),
     183      784782 :            TupleDescAttr(tupdesc, 0),
     184      784782 :            desc->natts * sizeof(FormData_pg_attribute));
     185             : 
     186             :     /* Copy the TupleConstr data structure, if any */
     187      784782 :     if (constr)
     188             :     {
     189      720484 :         TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
     190             : 
     191      720484 :         cpy->has_not_null = constr->has_not_null;
     192      720484 :         cpy->has_generated_stored = constr->has_generated_stored;
     193             : 
     194      720484 :         if ((cpy->num_defval = constr->num_defval) > 0)
     195             :         {
     196        2834 :             cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
     197        2834 :             memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
     198        6980 :             for (i = cpy->num_defval - 1; i >= 0; i--)
     199        4146 :                 cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
     200             :         }
     201             : 
     202      720484 :         if (constr->missing)
     203             :         {
     204         578 :             cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
     205         578 :             memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
     206        4628 :             for (i = tupdesc->natts - 1; i >= 0; i--)
     207             :             {
     208        4050 :                 if (constr->missing[i].am_present)
     209             :                 {
     210        1076 :                     Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
     211             : 
     212        1076 :                     cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
     213        1076 :                                                          attr->attbyval,
     214        1076 :                                                          attr->attlen);
     215             :                 }
     216             :             }
     217             :         }
     218             : 
     219      720484 :         if ((cpy->num_check = constr->num_check) > 0)
     220             :         {
     221        1884 :             cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
     222        1884 :             memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
     223        4472 :             for (i = cpy->num_check - 1; i >= 0; i--)
     224             :             {
     225        2588 :                 cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
     226        2588 :                 cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
     227        2588 :                 cpy->check[i].ccvalid = constr->check[i].ccvalid;
     228        2588 :                 cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
     229             :             }
     230             :         }
     231             : 
     232      720484 :         desc->constr = cpy;
     233             :     }
     234             : 
     235             :     /* We can copy the tuple type identification, too */
     236      784782 :     desc->tdtypeid = tupdesc->tdtypeid;
     237      784782 :     desc->tdtypmod = tupdesc->tdtypmod;
     238             : 
     239      784782 :     return desc;
     240             : }
     241             : 
     242             : /*
     243             :  * TupleDescCopy
     244             :  *      Copy a tuple descriptor into caller-supplied memory.
     245             :  *      The memory may be shared memory mapped at any address, and must
     246             :  *      be sufficient to hold TupleDescSize(src) bytes.
     247             :  *
     248             :  * !!! Constraints and defaults are not copied !!!
     249             :  */
     250             : void
     251       25252 : TupleDescCopy(TupleDesc dst, TupleDesc src)
     252             : {
     253             :     int         i;
     254             : 
     255             :     /* Flat-copy the header and attribute array */
     256       25252 :     memcpy(dst, src, TupleDescSize(src));
     257             : 
     258             :     /*
     259             :      * Since we're not copying constraints and defaults, clear fields
     260             :      * associated with them.
     261             :      */
     262       96638 :     for (i = 0; i < dst->natts; i++)
     263             :     {
     264       71386 :         Form_pg_attribute att = TupleDescAttr(dst, i);
     265             : 
     266       71386 :         att->attnotnull = false;
     267       71386 :         att->atthasdef = false;
     268       71386 :         att->atthasmissing = false;
     269       71386 :         att->attidentity = '\0';
     270       71386 :         att->attgenerated = '\0';
     271             :     }
     272       25252 :     dst->constr = NULL;
     273             : 
     274             :     /*
     275             :      * Also, assume the destination is not to be ref-counted.  (Copying the
     276             :      * source's refcount would be wrong in any case.)
     277             :      */
     278       25252 :     dst->tdrefcount = -1;
     279       25252 : }
     280             : 
     281             : /*
     282             :  * TupleDescCopyEntry
     283             :  *      This function copies a single attribute structure from one tuple
     284             :  *      descriptor to another.
     285             :  *
     286             :  * !!! Constraints and defaults are not copied !!!
     287             :  */
     288             : void
     289        3618 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
     290             :                    TupleDesc src, AttrNumber srcAttno)
     291             : {
     292        3618 :     Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
     293        3618 :     Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
     294             : 
     295             :     /*
     296             :      * sanity checks
     297             :      */
     298             :     Assert(PointerIsValid(src));
     299             :     Assert(PointerIsValid(dst));
     300             :     Assert(srcAttno >= 1);
     301             :     Assert(srcAttno <= src->natts);
     302             :     Assert(dstAttno >= 1);
     303             :     Assert(dstAttno <= dst->natts);
     304             : 
     305        3618 :     memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
     306             : 
     307             :     /*
     308             :      * Aside from updating the attno, we'd better reset attcacheoff.
     309             :      *
     310             :      * XXX Actually, to be entirely safe we'd need to reset the attcacheoff of
     311             :      * all following columns in dst as well.  Current usage scenarios don't
     312             :      * require that though, because all following columns will get initialized
     313             :      * by other uses of this function or TupleDescInitEntry.  So we cheat a
     314             :      * bit to avoid a useless O(N^2) penalty.
     315             :      */
     316        3618 :     dstAtt->attnum = dstAttno;
     317        3618 :     dstAtt->attcacheoff = -1;
     318             : 
     319             :     /* since we're not copying constraints or defaults, clear these */
     320        3618 :     dstAtt->attnotnull = false;
     321        3618 :     dstAtt->atthasdef = false;
     322        3618 :     dstAtt->atthasmissing = false;
     323        3618 :     dstAtt->attidentity = '\0';
     324        3618 :     dstAtt->attgenerated = '\0';
     325        3618 : }
     326             : 
     327             : /*
     328             :  * Free a TupleDesc including all substructure
     329             :  */
     330             : void
     331     1305948 : FreeTupleDesc(TupleDesc tupdesc)
     332             : {
     333             :     int         i;
     334             : 
     335             :     /*
     336             :      * Possibly this should assert tdrefcount == 0, to disallow explicit
     337             :      * freeing of un-refcounted tupdescs?
     338             :      */
     339             :     Assert(tupdesc->tdrefcount <= 0);
     340             : 
     341     1305948 :     if (tupdesc->constr)
     342             :     {
     343      386478 :         if (tupdesc->constr->num_defval > 0)
     344             :         {
     345       24002 :             AttrDefault *attrdef = tupdesc->constr->defval;
     346             : 
     347       58000 :             for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
     348       33998 :                 pfree(attrdef[i].adbin);
     349       24002 :             pfree(attrdef);
     350             :         }
     351      386478 :         if (tupdesc->constr->missing)
     352             :         {
     353        3268 :             AttrMissing *attrmiss = tupdesc->constr->missing;
     354             : 
     355       24146 :             for (i = tupdesc->natts - 1; i >= 0; i--)
     356             :             {
     357       20878 :                 if (attrmiss[i].am_present
     358        7084 :                     && !TupleDescAttr(tupdesc, i)->attbyval)
     359        2684 :                     pfree(DatumGetPointer(attrmiss[i].am_value));
     360             :             }
     361        3268 :             pfree(attrmiss);
     362             :         }
     363      386478 :         if (tupdesc->constr->num_check > 0)
     364             :         {
     365        9392 :             ConstrCheck *check = tupdesc->constr->check;
     366             : 
     367       21416 :             for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
     368             :             {
     369       12024 :                 pfree(check[i].ccname);
     370       12024 :                 pfree(check[i].ccbin);
     371             :             }
     372        9392 :             pfree(check);
     373             :         }
     374      386478 :         pfree(tupdesc->constr);
     375             :     }
     376             : 
     377     1305948 :     pfree(tupdesc);
     378     1305948 : }
     379             : 
     380             : /*
     381             :  * Increment the reference count of a tupdesc, and log the reference in
     382             :  * CurrentResourceOwner.
     383             :  *
     384             :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     385             :  * macro PinTupleDesc for tupdescs of uncertain status.)
     386             :  */
     387             : void
     388    29195488 : IncrTupleDescRefCount(TupleDesc tupdesc)
     389             : {
     390             :     Assert(tupdesc->tdrefcount >= 0);
     391             : 
     392    29195488 :     ResourceOwnerEnlarge(CurrentResourceOwner);
     393    29195488 :     tupdesc->tdrefcount++;
     394    29195488 :     ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
     395    29195488 : }
     396             : 
     397             : /*
     398             :  * Decrement the reference count of a tupdesc, remove the corresponding
     399             :  * reference from CurrentResourceOwner, and free the tupdesc if no more
     400             :  * references remain.
     401             :  *
     402             :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     403             :  * macro ReleaseTupleDesc for tupdescs of uncertain status.)
     404             :  */
     405             : void
     406    29182508 : DecrTupleDescRefCount(TupleDesc tupdesc)
     407             : {
     408             :     Assert(tupdesc->tdrefcount > 0);
     409             : 
     410    29182508 :     ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
     411    29182508 :     if (--tupdesc->tdrefcount == 0)
     412           4 :         FreeTupleDesc(tupdesc);
     413    29182508 : }
     414             : 
     415             : /*
     416             :  * Compare two TupleDesc structures for logical equality
     417             :  */
     418             : bool
     419      381496 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
     420             : {
     421             :     int         i,
     422             :                 n;
     423             : 
     424      381496 :     if (tupdesc1->natts != tupdesc2->natts)
     425        2432 :         return false;
     426      379064 :     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     427           0 :         return false;
     428             : 
     429             :     /* tdtypmod and tdrefcount are not checked */
     430             : 
     431     1814020 :     for (i = 0; i < tupdesc1->natts; i++)
     432             :     {
     433     1446318 :         Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
     434     1446318 :         Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
     435             : 
     436             :         /*
     437             :          * We do not need to check every single field here: we can disregard
     438             :          * attrelid and attnum (which were used to place the row in the attrs
     439             :          * array in the first place).  It might look like we could dispense
     440             :          * with checking attlen/attbyval/attalign, since these are derived
     441             :          * from atttypid; but in the case of dropped columns we must check
     442             :          * them (since atttypid will be zero for all dropped columns) and in
     443             :          * general it seems safer to check them always.
     444             :          *
     445             :          * attcacheoff must NOT be checked since it's possibly not set in both
     446             :          * copies.  We also intentionally ignore atthasmissing, since that's
     447             :          * not very relevant in tupdescs, which lack the attmissingval field.
     448             :          */
     449     1446318 :         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     450        1248 :             return false;
     451     1445070 :         if (attr1->atttypid != attr2->atttypid)
     452         974 :             return false;
     453     1444096 :         if (attr1->attlen != attr2->attlen)
     454           8 :             return false;
     455     1444088 :         if (attr1->attndims != attr2->attndims)
     456           0 :             return false;
     457     1444088 :         if (attr1->atttypmod != attr2->atttypmod)
     458          42 :             return false;
     459     1444046 :         if (attr1->attbyval != attr2->attbyval)
     460          62 :             return false;
     461     1443984 :         if (attr1->attalign != attr2->attalign)
     462           0 :             return false;
     463     1443984 :         if (attr1->attstorage != attr2->attstorage)
     464         208 :             return false;
     465     1443776 :         if (attr1->attcompression != attr2->attcompression)
     466          62 :             return false;
     467     1443714 :         if (attr1->attnotnull != attr2->attnotnull)
     468        1426 :             return false;
     469     1442288 :         if (attr1->atthasdef != attr2->atthasdef)
     470        3880 :             return false;
     471     1438408 :         if (attr1->attidentity != attr2->attidentity)
     472         178 :             return false;
     473     1438230 :         if (attr1->attgenerated != attr2->attgenerated)
     474          20 :             return false;
     475     1438210 :         if (attr1->attisdropped != attr2->attisdropped)
     476           0 :             return false;
     477     1438210 :         if (attr1->attislocal != attr2->attislocal)
     478        2540 :             return false;
     479     1435670 :         if (attr1->attinhcount != attr2->attinhcount)
     480         714 :             return false;
     481     1434956 :         if (attr1->attcollation != attr2->attcollation)
     482           0 :             return false;
     483             :         /* variable-length fields are not even present... */
     484             :     }
     485             : 
     486      367702 :     if (tupdesc1->constr != NULL)
     487             :     {
     488      126682 :         TupleConstr *constr1 = tupdesc1->constr;
     489      126682 :         TupleConstr *constr2 = tupdesc2->constr;
     490             : 
     491      126682 :         if (constr2 == NULL)
     492         212 :             return false;
     493      126470 :         if (constr1->has_not_null != constr2->has_not_null)
     494           0 :             return false;
     495      126470 :         if (constr1->has_generated_stored != constr2->has_generated_stored)
     496         500 :             return false;
     497      125970 :         n = constr1->num_defval;
     498      125970 :         if (n != (int) constr2->num_defval)
     499           0 :             return false;
     500             :         /* We assume here that both AttrDefault arrays are in adnum order */
     501      138204 :         for (i = 0; i < n; i++)
     502             :         {
     503       12234 :             AttrDefault *defval1 = constr1->defval + i;
     504       12234 :             AttrDefault *defval2 = constr2->defval + i;
     505             : 
     506       12234 :             if (defval1->adnum != defval2->adnum)
     507           0 :                 return false;
     508       12234 :             if (strcmp(defval1->adbin, defval2->adbin) != 0)
     509           0 :                 return false;
     510             :         }
     511      125970 :         if (constr1->missing)
     512             :         {
     513         490 :             if (!constr2->missing)
     514          66 :                 return false;
     515        2450 :             for (i = 0; i < tupdesc1->natts; i++)
     516             :             {
     517        2026 :                 AttrMissing *missval1 = constr1->missing + i;
     518        2026 :                 AttrMissing *missval2 = constr2->missing + i;
     519             : 
     520        2026 :                 if (missval1->am_present != missval2->am_present)
     521           0 :                     return false;
     522        2026 :                 if (missval1->am_present)
     523             :                 {
     524         542 :                     Form_pg_attribute missatt1 = TupleDescAttr(tupdesc1, i);
     525             : 
     526         542 :                     if (!datumIsEqual(missval1->am_value, missval2->am_value,
     527         542 :                                       missatt1->attbyval, missatt1->attlen))
     528           0 :                         return false;
     529             :                 }
     530             :             }
     531             :         }
     532      125480 :         else if (constr2->missing)
     533           4 :             return false;
     534      125900 :         n = constr1->num_check;
     535      125900 :         if (n != (int) constr2->num_check)
     536        1238 :             return false;
     537             : 
     538             :         /*
     539             :          * Similarly, we rely here on the ConstrCheck entries being sorted by
     540             :          * name.  If there are duplicate names, the outcome of the comparison
     541             :          * is uncertain, but that should not happen.
     542             :          */
     543      127160 :         for (i = 0; i < n; i++)
     544             :         {
     545        2576 :             ConstrCheck *check1 = constr1->check + i;
     546        2576 :             ConstrCheck *check2 = constr2->check + i;
     547             : 
     548        2576 :             if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
     549        2576 :                   strcmp(check1->ccbin, check2->ccbin) == 0 &&
     550        2576 :                   check1->ccvalid == check2->ccvalid &&
     551        2498 :                   check1->ccnoinherit == check2->ccnoinherit))
     552          78 :                 return false;
     553             :         }
     554             :     }
     555      241020 :     else if (tupdesc2->constr != NULL)
     556        1456 :         return false;
     557      364148 :     return true;
     558             : }
     559             : 
     560             : /*
     561             :  * equalRowTypes
     562             :  *
     563             :  * This determines whether two tuple descriptors have equal row types.  This
     564             :  * only checks those fields in pg_attribute that are applicable for row types,
     565             :  * while ignoring those fields that define the physical row storage or those
     566             :  * that define table column metadata.
     567             :  *
     568             :  * Specifically, this checks:
     569             :  *
     570             :  * - same number of attributes
     571             :  * - same composite type ID (but could both be zero)
     572             :  * - corresponding attributes (in order) have same the name, type, typmod,
     573             :  *   collation
     574             :  *
     575             :  * This is used to check whether two record types are compatible, whether
     576             :  * function return row types are the same, and other similar situations.
     577             :  *
     578             :  * (XXX There was some discussion whether attndims should be checked here, but
     579             :  * for now it has been decided not to.)
     580             :  *
     581             :  * Note: We deliberately do not check the tdtypmod field.  This allows
     582             :  * typcache.c to use this routine to see if a cached record type matches a
     583             :  * requested type.
     584             :  */
     585             : bool
     586      323394 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
     587             : {
     588      323394 :     if (tupdesc1->natts != tupdesc2->natts)
     589         164 :         return false;
     590      323230 :     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     591        1728 :         return false;
     592             : 
     593     5147536 :     for (int i = 0; i < tupdesc1->natts; i++)
     594             :     {
     595     4829716 :         Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
     596     4829716 :         Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
     597             : 
     598     4829716 :         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     599        3656 :             return false;
     600     4826060 :         if (attr1->atttypid != attr2->atttypid)
     601          22 :             return false;
     602     4826038 :         if (attr1->atttypmod != attr2->atttypmod)
     603           4 :             return false;
     604     4826034 :         if (attr1->attcollation != attr2->attcollation)
     605           0 :             return false;
     606             : 
     607             :         /* Record types derived from tables could have dropped fields. */
     608     4826034 :         if (attr1->attisdropped != attr2->attisdropped)
     609           0 :             return false;
     610             :     }
     611             : 
     612      317820 :     return true;
     613             : }
     614             : 
     615             : /*
     616             :  * hashRowType
     617             :  *
     618             :  * If two tuple descriptors would be considered equal by equalRowTypes()
     619             :  * then their hash value will be equal according to this function.
     620             :  */
     621             : uint32
     622      340846 : hashRowType(TupleDesc desc)
     623             : {
     624             :     uint32      s;
     625             :     int         i;
     626             : 
     627      340846 :     s = hash_combine(0, hash_uint32(desc->natts));
     628      340846 :     s = hash_combine(s, hash_uint32(desc->tdtypeid));
     629     5432922 :     for (i = 0; i < desc->natts; ++i)
     630     5092076 :         s = hash_combine(s, hash_uint32(TupleDescAttr(desc, i)->atttypid));
     631             : 
     632      340846 :     return s;
     633             : }
     634             : 
     635             : /*
     636             :  * TupleDescInitEntry
     637             :  *      This function initializes a single attribute structure in
     638             :  *      a previously allocated tuple descriptor.
     639             :  *
     640             :  * If attributeName is NULL, the attname field is set to an empty string
     641             :  * (this is for cases where we don't know or need a name for the field).
     642             :  * Also, some callers use this function to change the datatype-related fields
     643             :  * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
     644             :  * to indicate that the attname field shouldn't be modified.
     645             :  *
     646             :  * Note that attcollation is set to the default for the specified datatype.
     647             :  * If a nondefault collation is needed, insert it afterwards using
     648             :  * TupleDescInitEntryCollation.
     649             :  */
     650             : void
     651    10862744 : TupleDescInitEntry(TupleDesc desc,
     652             :                    AttrNumber attributeNumber,
     653             :                    const char *attributeName,
     654             :                    Oid oidtypeid,
     655             :                    int32 typmod,
     656             :                    int attdim)
     657             : {
     658             :     HeapTuple   tuple;
     659             :     Form_pg_type typeForm;
     660             :     Form_pg_attribute att;
     661             : 
     662             :     /*
     663             :      * sanity checks
     664             :      */
     665             :     Assert(PointerIsValid(desc));
     666             :     Assert(attributeNumber >= 1);
     667             :     Assert(attributeNumber <= desc->natts);
     668             :     Assert(attdim >= 0);
     669             :     Assert(attdim <= PG_INT16_MAX);
     670             : 
     671             :     /*
     672             :      * initialize the attribute fields
     673             :      */
     674    10862744 :     att = TupleDescAttr(desc, attributeNumber - 1);
     675             : 
     676    10862744 :     att->attrelid = 0;           /* dummy value */
     677             : 
     678             :     /*
     679             :      * Note: attributeName can be NULL, because the planner doesn't always
     680             :      * fill in valid resname values in targetlists, particularly for resjunk
     681             :      * attributes. Also, do nothing if caller wants to re-use the old attname.
     682             :      */
     683    10862744 :     if (attributeName == NULL)
     684     3501272 :         MemSet(NameStr(att->attname), 0, NAMEDATALEN);
     685     7361472 :     else if (attributeName != NameStr(att->attname))
     686     7358532 :         namestrcpy(&(att->attname), attributeName);
     687             : 
     688    10862744 :     att->attcacheoff = -1;
     689    10862744 :     att->atttypmod = typmod;
     690             : 
     691    10862744 :     att->attnum = attributeNumber;
     692    10862744 :     att->attndims = attdim;
     693             : 
     694    10862744 :     att->attnotnull = false;
     695    10862744 :     att->atthasdef = false;
     696    10862744 :     att->atthasmissing = false;
     697    10862744 :     att->attidentity = '\0';
     698    10862744 :     att->attgenerated = '\0';
     699    10862744 :     att->attisdropped = false;
     700    10862744 :     att->attislocal = true;
     701    10862744 :     att->attinhcount = 0;
     702             :     /* variable-length fields are not present in tupledescs */
     703             : 
     704    10862744 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
     705    10862744 :     if (!HeapTupleIsValid(tuple))
     706           0 :         elog(ERROR, "cache lookup failed for type %u", oidtypeid);
     707    10862744 :     typeForm = (Form_pg_type) GETSTRUCT(tuple);
     708             : 
     709    10862744 :     att->atttypid = oidtypeid;
     710    10862744 :     att->attlen = typeForm->typlen;
     711    10862744 :     att->attbyval = typeForm->typbyval;
     712    10862744 :     att->attalign = typeForm->typalign;
     713    10862744 :     att->attstorage = typeForm->typstorage;
     714    10862744 :     att->attcompression = InvalidCompressionMethod;
     715    10862744 :     att->attcollation = typeForm->typcollation;
     716             : 
     717    10862744 :     ReleaseSysCache(tuple);
     718    10862744 : }
     719             : 
     720             : /*
     721             :  * TupleDescInitBuiltinEntry
     722             :  *      Initialize a tuple descriptor without catalog access.  Only
     723             :  *      a limited range of builtin types are supported.
     724             :  */
     725             : void
     726       12776 : TupleDescInitBuiltinEntry(TupleDesc desc,
     727             :                           AttrNumber attributeNumber,
     728             :                           const char *attributeName,
     729             :                           Oid oidtypeid,
     730             :                           int32 typmod,
     731             :                           int attdim)
     732             : {
     733             :     Form_pg_attribute att;
     734             : 
     735             :     /* sanity checks */
     736             :     Assert(PointerIsValid(desc));
     737             :     Assert(attributeNumber >= 1);
     738             :     Assert(attributeNumber <= desc->natts);
     739             :     Assert(attdim >= 0);
     740             :     Assert(attdim <= PG_INT16_MAX);
     741             : 
     742             :     /* initialize the attribute fields */
     743       12776 :     att = TupleDescAttr(desc, attributeNumber - 1);
     744       12776 :     att->attrelid = 0;           /* dummy value */
     745             : 
     746             :     /* unlike TupleDescInitEntry, we require an attribute name */
     747             :     Assert(attributeName != NULL);
     748       12776 :     namestrcpy(&(att->attname), attributeName);
     749             : 
     750       12776 :     att->attcacheoff = -1;
     751       12776 :     att->atttypmod = typmod;
     752             : 
     753       12776 :     att->attnum = attributeNumber;
     754       12776 :     att->attndims = attdim;
     755             : 
     756       12776 :     att->attnotnull = false;
     757       12776 :     att->atthasdef = false;
     758       12776 :     att->atthasmissing = false;
     759       12776 :     att->attidentity = '\0';
     760       12776 :     att->attgenerated = '\0';
     761       12776 :     att->attisdropped = false;
     762       12776 :     att->attislocal = true;
     763       12776 :     att->attinhcount = 0;
     764             :     /* variable-length fields are not present in tupledescs */
     765             : 
     766       12776 :     att->atttypid = oidtypeid;
     767             : 
     768             :     /*
     769             :      * Our goal here is to support just enough types to let basic builtin
     770             :      * commands work without catalog access - e.g. so that we can do certain
     771             :      * things even in processes that are not connected to a database.
     772             :      */
     773       12776 :     switch (oidtypeid)
     774             :     {
     775       10216 :         case TEXTOID:
     776             :         case TEXTARRAYOID:
     777       10216 :             att->attlen = -1;
     778       10216 :             att->attbyval = false;
     779       10216 :             att->attalign = TYPALIGN_INT;
     780       10216 :             att->attstorage = TYPSTORAGE_EXTENDED;
     781       10216 :             att->attcompression = InvalidCompressionMethod;
     782       10216 :             att->attcollation = DEFAULT_COLLATION_OID;
     783       10216 :             break;
     784             : 
     785           0 :         case BOOLOID:
     786           0 :             att->attlen = 1;
     787           0 :             att->attbyval = true;
     788           0 :             att->attalign = TYPALIGN_CHAR;
     789           0 :             att->attstorage = TYPSTORAGE_PLAIN;
     790           0 :             att->attcompression = InvalidCompressionMethod;
     791           0 :             att->attcollation = InvalidOid;
     792           0 :             break;
     793             : 
     794           0 :         case INT4OID:
     795           0 :             att->attlen = 4;
     796           0 :             att->attbyval = true;
     797           0 :             att->attalign = TYPALIGN_INT;
     798           0 :             att->attstorage = TYPSTORAGE_PLAIN;
     799           0 :             att->attcompression = InvalidCompressionMethod;
     800           0 :             att->attcollation = InvalidOid;
     801           0 :             break;
     802             : 
     803        2250 :         case INT8OID:
     804        2250 :             att->attlen = 8;
     805        2250 :             att->attbyval = FLOAT8PASSBYVAL;
     806        2250 :             att->attalign = TYPALIGN_DOUBLE;
     807        2250 :             att->attstorage = TYPSTORAGE_PLAIN;
     808        2250 :             att->attcompression = InvalidCompressionMethod;
     809        2250 :             att->attcollation = InvalidOid;
     810        2250 :             break;
     811             : 
     812         310 :         case OIDOID:
     813         310 :             att->attlen = 4;
     814         310 :             att->attbyval = true;
     815         310 :             att->attalign = TYPALIGN_INT;
     816         310 :             att->attstorage = TYPSTORAGE_PLAIN;
     817         310 :             att->attcompression = InvalidCompressionMethod;
     818         310 :             att->attcollation = InvalidOid;
     819         310 :             break;
     820             : 
     821           0 :         default:
     822           0 :             elog(ERROR, "unsupported type %u", oidtypeid);
     823             :     }
     824       12776 : }
     825             : 
     826             : /*
     827             :  * TupleDescInitEntryCollation
     828             :  *
     829             :  * Assign a nondefault collation to a previously initialized tuple descriptor
     830             :  * entry.
     831             :  */
     832             : void
     833     5634448 : TupleDescInitEntryCollation(TupleDesc desc,
     834             :                             AttrNumber attributeNumber,
     835             :                             Oid collationid)
     836             : {
     837             :     /*
     838             :      * sanity checks
     839             :      */
     840             :     Assert(PointerIsValid(desc));
     841             :     Assert(attributeNumber >= 1);
     842             :     Assert(attributeNumber <= desc->natts);
     843             : 
     844     5634448 :     TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
     845     5634448 : }
     846             : 
     847             : /*
     848             :  * BuildDescFromLists
     849             :  *
     850             :  * Build a TupleDesc given lists of column names (as String nodes),
     851             :  * column type OIDs, typmods, and collation OIDs.
     852             :  *
     853             :  * No constraints are generated.
     854             :  *
     855             :  * This is for use with functions returning RECORD.
     856             :  */
     857             : TupleDesc
     858        1410 : BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
     859             : {
     860             :     int         natts;
     861             :     AttrNumber  attnum;
     862             :     ListCell   *l1;
     863             :     ListCell   *l2;
     864             :     ListCell   *l3;
     865             :     ListCell   *l4;
     866             :     TupleDesc   desc;
     867             : 
     868        1410 :     natts = list_length(names);
     869             :     Assert(natts == list_length(types));
     870             :     Assert(natts == list_length(typmods));
     871             :     Assert(natts == list_length(collations));
     872             : 
     873             :     /*
     874             :      * allocate a new tuple descriptor
     875             :      */
     876        1410 :     desc = CreateTemplateTupleDesc(natts);
     877             : 
     878        1410 :     attnum = 0;
     879        4974 :     forfour(l1, names, l2, types, l3, typmods, l4, collations)
     880             :     {
     881        3564 :         char       *attname = strVal(lfirst(l1));
     882        3564 :         Oid         atttypid = lfirst_oid(l2);
     883        3564 :         int32       atttypmod = lfirst_int(l3);
     884        3564 :         Oid         attcollation = lfirst_oid(l4);
     885             : 
     886        3564 :         attnum++;
     887             : 
     888        3564 :         TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
     889        3564 :         TupleDescInitEntryCollation(desc, attnum, attcollation);
     890             :     }
     891             : 
     892        1410 :     return desc;
     893             : }
     894             : 
     895             : /*
     896             :  * Get default expression (or NULL if none) for the given attribute number.
     897             :  */
     898             : Node *
     899      149064 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
     900             : {
     901      149064 :     Node       *result = NULL;
     902             : 
     903      149064 :     if (tupdesc->constr)
     904             :     {
     905      149064 :         AttrDefault *attrdef = tupdesc->constr->defval;
     906             : 
     907      225008 :         for (int i = 0; i < tupdesc->constr->num_defval; i++)
     908             :         {
     909      225008 :             if (attrdef[i].adnum == attnum)
     910             :             {
     911      149064 :                 result = stringToNode(attrdef[i].adbin);
     912      149064 :                 break;
     913             :             }
     914             :         }
     915             :     }
     916             : 
     917      149064 :     return result;
     918             : }
     919             : 
     920             : /* ResourceOwner callbacks */
     921             : 
     922             : static void
     923       12980 : ResOwnerReleaseTupleDesc(Datum res)
     924             : {
     925       12980 :     TupleDesc   tupdesc = (TupleDesc) DatumGetPointer(res);
     926             : 
     927             :     /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
     928             :     Assert(tupdesc->tdrefcount > 0);
     929       12980 :     if (--tupdesc->tdrefcount == 0)
     930         424 :         FreeTupleDesc(tupdesc);
     931       12980 : }
     932             : 
     933             : static char *
     934           0 : ResOwnerPrintTupleDesc(Datum res)
     935             : {
     936           0 :     TupleDesc   tupdesc = (TupleDesc) DatumGetPointer(res);
     937             : 
     938           0 :     return psprintf("TupleDesc %p (%u,%d)",
     939             :                     tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
     940             : }

Generated by: LCOV version 1.14