LCOV - code coverage report
Current view: top level - src/backend/access/common - tupdesc.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 303 333 91.0 %
Date: 2017-09-29 13:40:31 Functions: 15 15 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * tupdesc.c
       4             :  *    POSTGRES tuple descriptor support code
       5             :  *
       6             :  * Portions Copyright (c) 1996-2017, 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/hash.h"
      23             : #include "access/htup_details.h"
      24             : #include "catalog/pg_collation.h"
      25             : #include "catalog/pg_type.h"
      26             : #include "miscadmin.h"
      27             : #include "parser/parse_type.h"
      28             : #include "utils/acl.h"
      29             : #include "utils/builtins.h"
      30             : #include "utils/hashutils.h"
      31             : #include "utils/resowner_private.h"
      32             : #include "utils/syscache.h"
      33             : 
      34             : 
      35             : /*
      36             :  * CreateTemplateTupleDesc
      37             :  *      This function allocates an empty tuple descriptor structure.
      38             :  *
      39             :  * Tuple type ID information is initially set for an anonymous record type;
      40             :  * caller can overwrite this if needed.
      41             :  */
      42             : TupleDesc
      43      183041 : CreateTemplateTupleDesc(int natts, bool hasoid)
      44             : {
      45             :     TupleDesc   desc;
      46             : 
      47             :     /*
      48             :      * sanity checks
      49             :      */
      50      183041 :     AssertArg(natts >= 0);
      51             : 
      52             :     /*
      53             :      * Allocate enough memory for the tuple descriptor, including the
      54             :      * attribute rows.
      55             :      */
      56      183041 :     desc = (TupleDesc) palloc(offsetof(struct tupleDesc, attrs) +
      57      183041 :                               natts * sizeof(FormData_pg_attribute));
      58             : 
      59             :     /*
      60             :      * Initialize other fields of the tupdesc.
      61             :      */
      62      183041 :     desc->natts = natts;
      63      183041 :     desc->constr = NULL;
      64      183041 :     desc->tdtypeid = RECORDOID;
      65      183041 :     desc->tdtypmod = -1;
      66      183041 :     desc->tdhasoid = hasoid;
      67      183041 :     desc->tdrefcount = -1;       /* assume not reference-counted */
      68             : 
      69      183041 :     return desc;
      70             : }
      71             : 
      72             : /*
      73             :  * CreateTupleDesc
      74             :  *      This function allocates a new TupleDesc by copying a given
      75             :  *      Form_pg_attribute array.
      76             :  *
      77             :  * Tuple type ID information is initially set for an anonymous record type;
      78             :  * caller can overwrite this if needed.
      79             :  */
      80             : TupleDesc
      81        5805 : CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
      82             : {
      83             :     TupleDesc   desc;
      84             :     int         i;
      85             : 
      86        5805 :     desc = CreateTemplateTupleDesc(natts, hasoid);
      87             : 
      88      120859 :     for (i = 0; i < natts; ++i)
      89      115054 :         memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
      90             : 
      91        5805 :     return desc;
      92             : }
      93             : 
      94             : /*
      95             :  * CreateTupleDescCopy
      96             :  *      This function creates a new TupleDesc by copying from an existing
      97             :  *      TupleDesc.
      98             :  *
      99             :  * !!! Constraints and defaults are not copied !!!
     100             :  */
     101             : TupleDesc
     102       16807 : CreateTupleDescCopy(TupleDesc tupdesc)
     103             : {
     104             :     TupleDesc   desc;
     105             :     int         i;
     106             : 
     107       16807 :     desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
     108             : 
     109       65997 :     for (i = 0; i < desc->natts; i++)
     110             :     {
     111       49190 :         Form_pg_attribute att = TupleDescAttr(desc, i);
     112             : 
     113       49190 :         memcpy(att, &tupdesc->attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
     114       49190 :         att->attnotnull = false;
     115       49190 :         att->atthasdef = false;
     116       49190 :         att->attidentity = '\0';
     117             :     }
     118             : 
     119       16807 :     desc->tdtypeid = tupdesc->tdtypeid;
     120       16807 :     desc->tdtypmod = tupdesc->tdtypmod;
     121             : 
     122       16807 :     return desc;
     123             : }
     124             : 
     125             : /*
     126             :  * CreateTupleDescCopyConstr
     127             :  *      This function creates a new TupleDesc by copying from an existing
     128             :  *      TupleDesc (including its constraints and defaults).
     129             :  */
     130             : TupleDesc
     131        9541 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
     132             : {
     133             :     TupleDesc   desc;
     134        9541 :     TupleConstr *constr = tupdesc->constr;
     135             :     int         i;
     136             : 
     137        9541 :     desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
     138             : 
     139      126895 :     for (i = 0; i < desc->natts; i++)
     140             :     {
     141      117354 :         memcpy(TupleDescAttr(desc, i),
     142      117354 :                TupleDescAttr(tupdesc, i),
     143             :                ATTRIBUTE_FIXED_PART_SIZE);
     144             :     }
     145             : 
     146        9541 :     if (constr)
     147             :     {
     148        7816 :         TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
     149             : 
     150        7816 :         cpy->has_not_null = constr->has_not_null;
     151             : 
     152        7816 :         if ((cpy->num_defval = constr->num_defval) > 0)
     153             :         {
     154           4 :             cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
     155           4 :             memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
     156           8 :             for (i = cpy->num_defval - 1; i >= 0; i--)
     157             :             {
     158           4 :                 if (constr->defval[i].adbin)
     159           4 :                     cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
     160             :             }
     161             :         }
     162             : 
     163        7816 :         if ((cpy->num_check = constr->num_check) > 0)
     164             :         {
     165           2 :             cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
     166           2 :             memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
     167           4 :             for (i = cpy->num_check - 1; i >= 0; i--)
     168             :             {
     169           2 :                 if (constr->check[i].ccname)
     170           2 :                     cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
     171           2 :                 if (constr->check[i].ccbin)
     172           2 :                     cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
     173           2 :                 cpy->check[i].ccvalid = constr->check[i].ccvalid;
     174           2 :                 cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
     175             :             }
     176             :         }
     177             : 
     178        7816 :         desc->constr = cpy;
     179             :     }
     180             : 
     181        9541 :     desc->tdtypeid = tupdesc->tdtypeid;
     182        9541 :     desc->tdtypmod = tupdesc->tdtypmod;
     183             : 
     184        9541 :     return desc;
     185             : }
     186             : 
     187             : /*
     188             :  * TupleDescCopyEntry
     189             :  *      This function copies a single attribute structure from one tuple
     190             :  *      descriptor to another.
     191             :  *
     192             :  * !!! Constraints and defaults are not copied !!!
     193             :  */
     194             : void
     195         440 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
     196             :                    TupleDesc src, AttrNumber srcAttno)
     197             : {
     198         440 :     Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
     199         440 :     Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
     200             : 
     201             :     /*
     202             :      * sanity checks
     203             :      */
     204         440 :     AssertArg(PointerIsValid(src));
     205         440 :     AssertArg(PointerIsValid(dst));
     206         440 :     AssertArg(srcAttno >= 1);
     207         440 :     AssertArg(srcAttno <= src->natts);
     208         440 :     AssertArg(dstAttno >= 1);
     209         440 :     AssertArg(dstAttno <= dst->natts);
     210             : 
     211         440 :     memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
     212             : 
     213             :     /*
     214             :      * Aside from updating the attno, we'd better reset attcacheoff.
     215             :      *
     216             :      * XXX Actually, to be entirely safe we'd need to reset the attcacheoff of
     217             :      * all following columns in dst as well.  Current usage scenarios don't
     218             :      * require that though, because all following columns will get initialized
     219             :      * by other uses of this function or TupleDescInitEntry.  So we cheat a
     220             :      * bit to avoid a useless O(N^2) penalty.
     221             :      */
     222         440 :     dstAtt->attnum = dstAttno;
     223         440 :     dstAtt->attcacheoff = -1;
     224             : 
     225             :     /* since we're not copying constraints or defaults, clear these */
     226         440 :     dstAtt->attnotnull = false;
     227         440 :     dstAtt->atthasdef = false;
     228         440 :     dstAtt->attidentity = '\0';
     229         440 : }
     230             : 
     231             : /*
     232             :  * Free a TupleDesc including all substructure
     233             :  */
     234             : void
     235       45628 : FreeTupleDesc(TupleDesc tupdesc)
     236             : {
     237             :     int         i;
     238             : 
     239             :     /*
     240             :      * Possibly this should assert tdrefcount == 0, to disallow explicit
     241             :      * freeing of un-refcounted tupdescs?
     242             :      */
     243       45628 :     Assert(tupdesc->tdrefcount <= 0);
     244             : 
     245       45628 :     if (tupdesc->constr)
     246             :     {
     247       10503 :         if (tupdesc->constr->num_defval > 0)
     248             :         {
     249        1098 :             AttrDefault *attrdef = tupdesc->constr->defval;
     250             : 
     251        2452 :             for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
     252             :             {
     253        1354 :                 if (attrdef[i].adbin)
     254        1354 :                     pfree(attrdef[i].adbin);
     255             :             }
     256        1098 :             pfree(attrdef);
     257             :         }
     258       10503 :         if (tupdesc->constr->num_check > 0)
     259             :         {
     260         786 :             ConstrCheck *check = tupdesc->constr->check;
     261             : 
     262        1847 :             for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
     263             :             {
     264        1061 :                 if (check[i].ccname)
     265        1061 :                     pfree(check[i].ccname);
     266        1061 :                 if (check[i].ccbin)
     267        1061 :                     pfree(check[i].ccbin);
     268             :             }
     269         786 :             pfree(check);
     270             :         }
     271       10503 :         pfree(tupdesc->constr);
     272             :     }
     273             : 
     274       45628 :     pfree(tupdesc);
     275       45628 : }
     276             : 
     277             : /*
     278             :  * Increment the reference count of a tupdesc, and log the reference in
     279             :  * CurrentResourceOwner.
     280             :  *
     281             :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     282             :  * macro PinTupleDesc for tupdescs of uncertain status.)
     283             :  */
     284             : void
     285       88284 : IncrTupleDescRefCount(TupleDesc tupdesc)
     286             : {
     287       88284 :     Assert(tupdesc->tdrefcount >= 0);
     288             : 
     289       88284 :     ResourceOwnerEnlargeTupleDescs(CurrentResourceOwner);
     290       88284 :     tupdesc->tdrefcount++;
     291       88284 :     ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
     292       88284 : }
     293             : 
     294             : /*
     295             :  * Decrement the reference count of a tupdesc, remove the corresponding
     296             :  * reference from CurrentResourceOwner, and free the tupdesc if no more
     297             :  * references remain.
     298             :  *
     299             :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     300             :  * macro ReleaseTupleDesc for tupdescs of uncertain status.)
     301             :  */
     302             : void
     303       88284 : DecrTupleDescRefCount(TupleDesc tupdesc)
     304             : {
     305       88284 :     Assert(tupdesc->tdrefcount > 0);
     306             : 
     307       88284 :     ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
     308       88284 :     if (--tupdesc->tdrefcount == 0)
     309          19 :         FreeTupleDesc(tupdesc);
     310       88284 : }
     311             : 
     312             : /*
     313             :  * Compare two TupleDesc structures for logical equality
     314             :  *
     315             :  * Note: we deliberately do not check the attrelid and tdtypmod fields.
     316             :  * This allows typcache.c to use this routine to see if a cached record type
     317             :  * matches a requested type, and is harmless for relcache.c's uses.
     318             :  * We don't compare tdrefcount, either.
     319             :  */
     320             : bool
     321       13255 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
     322             : {
     323             :     int         i,
     324             :                 j,
     325             :                 n;
     326             : 
     327       13255 :     if (tupdesc1->natts != tupdesc2->natts)
     328         179 :         return false;
     329       13076 :     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     330        1241 :         return false;
     331       11835 :     if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
     332          20 :         return false;
     333             : 
     334       46380 :     for (i = 0; i < tupdesc1->natts; i++)
     335             :     {
     336       35119 :         Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
     337       35119 :         Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
     338             : 
     339             :         /*
     340             :          * We do not need to check every single field here: we can disregard
     341             :          * attrelid and attnum (which were used to place the row in the attrs
     342             :          * array in the first place).  It might look like we could dispense
     343             :          * with checking attlen/attbyval/attalign, since these are derived
     344             :          * from atttypid; but in the case of dropped columns we must check
     345             :          * them (since atttypid will be zero for all dropped columns) and in
     346             :          * general it seems safer to check them always.
     347             :          *
     348             :          * attcacheoff must NOT be checked since it's possibly not set in both
     349             :          * copies.
     350             :          */
     351       35119 :         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     352         225 :             return false;
     353       34894 :         if (attr1->atttypid != attr2->atttypid)
     354          59 :             return false;
     355       34835 :         if (attr1->attstattarget != attr2->attstattarget)
     356           8 :             return false;
     357       34827 :         if (attr1->attlen != attr2->attlen)
     358           0 :             return false;
     359       34827 :         if (attr1->attndims != attr2->attndims)
     360           0 :             return false;
     361       34827 :         if (attr1->atttypmod != attr2->atttypmod)
     362           2 :             return false;
     363       34825 :         if (attr1->attbyval != attr2->attbyval)
     364           0 :             return false;
     365       34825 :         if (attr1->attstorage != attr2->attstorage)
     366          14 :             return false;
     367       34811 :         if (attr1->attalign != attr2->attalign)
     368           0 :             return false;
     369       34811 :         if (attr1->attnotnull != attr2->attnotnull)
     370          53 :             return false;
     371       34758 :         if (attr1->atthasdef != attr2->atthasdef)
     372         166 :             return false;
     373       34592 :         if (attr1->attidentity != attr2->attidentity)
     374           6 :             return false;
     375       34586 :         if (attr1->attisdropped != attr2->attisdropped)
     376           0 :             return false;
     377       34586 :         if (attr1->attislocal != attr2->attislocal)
     378           7 :             return false;
     379       34579 :         if (attr1->attinhcount != attr2->attinhcount)
     380          14 :             return false;
     381       34565 :         if (attr1->attcollation != attr2->attcollation)
     382           0 :             return false;
     383             :         /* attacl, attoptions and attfdwoptions are not even present... */
     384             :     }
     385             : 
     386       11261 :     if (tupdesc1->constr != NULL)
     387             :     {
     388        1789 :         TupleConstr *constr1 = tupdesc1->constr;
     389        1789 :         TupleConstr *constr2 = tupdesc2->constr;
     390             : 
     391        1789 :         if (constr2 == NULL)
     392          16 :             return false;
     393        1773 :         if (constr1->has_not_null != constr2->has_not_null)
     394           0 :             return false;
     395        1773 :         n = constr1->num_defval;
     396        1773 :         if (n != (int) constr2->num_defval)
     397           0 :             return false;
     398        2134 :         for (i = 0; i < n; i++)
     399             :         {
     400         361 :             AttrDefault *defval1 = constr1->defval + i;
     401         361 :             AttrDefault *defval2 = constr2->defval;
     402             : 
     403             :             /*
     404             :              * We can't assume that the items are always read from the system
     405             :              * catalogs in the same order; so use the adnum field to identify
     406             :              * the matching item to compare.
     407             :              */
     408         453 :             for (j = 0; j < n; defval2++, j++)
     409             :             {
     410         453 :                 if (defval1->adnum == defval2->adnum)
     411         361 :                     break;
     412             :             }
     413         361 :             if (j >= n)
     414           0 :                 return false;
     415         361 :             if (strcmp(defval1->adbin, defval2->adbin) != 0)
     416           0 :                 return false;
     417             :         }
     418        1773 :         n = constr1->num_check;
     419        1773 :         if (n != (int) constr2->num_check)
     420         107 :             return false;
     421        1822 :         for (i = 0; i < n; i++)
     422             :         {
     423         163 :             ConstrCheck *check1 = constr1->check + i;
     424         163 :             ConstrCheck *check2 = constr2->check;
     425             : 
     426             :             /*
     427             :              * Similarly, don't assume that the checks are always read in the
     428             :              * same order; match them up by name and contents. (The name
     429             :              * *should* be unique, but...)
     430             :              */
     431         213 :             for (j = 0; j < n; check2++, j++)
     432             :             {
     433         369 :                 if (strcmp(check1->ccname, check2->ccname) == 0 &&
     434         326 :                     strcmp(check1->ccbin, check2->ccbin) == 0 &&
     435         319 :                     check1->ccvalid == check2->ccvalid &&
     436         156 :                     check1->ccnoinherit == check2->ccnoinherit)
     437         156 :                     break;
     438             :             }
     439         163 :             if (j >= n)
     440           7 :                 return false;
     441             :         }
     442             :     }
     443        9472 :     else if (tupdesc2->constr != NULL)
     444          86 :         return false;
     445       11045 :     return true;
     446             : }
     447             : 
     448             : /*
     449             :  * hashTupleDesc
     450             :  *      Compute a hash value for a tuple descriptor.
     451             :  *
     452             :  * If two tuple descriptors would be considered equal by equalTupleDescs()
     453             :  * then their hash value will be equal according to this function.
     454             :  *
     455             :  * Note that currently contents of constraint are not hashed - it'd be a bit
     456             :  * painful to do so, and conflicts just due to constraints are unlikely.
     457             :  */
     458             : uint32
     459        4343 : hashTupleDesc(TupleDesc desc)
     460             : {
     461             :     uint32      s;
     462             :     int         i;
     463             : 
     464        4343 :     s = hash_combine(0, hash_uint32(desc->natts));
     465        4343 :     s = hash_combine(s, hash_uint32(desc->tdtypeid));
     466        4343 :     s = hash_combine(s, hash_uint32(desc->tdhasoid));
     467       20360 :     for (i = 0; i < desc->natts; ++i)
     468       16017 :         s = hash_combine(s, hash_uint32(TupleDescAttr(desc, i)->atttypid));
     469             : 
     470        4343 :     return s;
     471             : }
     472             : 
     473             : /*
     474             :  * TupleDescInitEntry
     475             :  *      This function initializes a single attribute structure in
     476             :  *      a previously allocated tuple descriptor.
     477             :  *
     478             :  * If attributeName is NULL, the attname field is set to an empty string
     479             :  * (this is for cases where we don't know or need a name for the field).
     480             :  * Also, some callers use this function to change the datatype-related fields
     481             :  * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
     482             :  * to indicate that the attname field shouldn't be modified.
     483             :  *
     484             :  * Note that attcollation is set to the default for the specified datatype.
     485             :  * If a nondefault collation is needed, insert it afterwards using
     486             :  * TupleDescInitEntryCollation.
     487             :  */
     488             : void
     489      191730 : TupleDescInitEntry(TupleDesc desc,
     490             :                    AttrNumber attributeNumber,
     491             :                    const char *attributeName,
     492             :                    Oid oidtypeid,
     493             :                    int32 typmod,
     494             :                    int attdim)
     495             : {
     496             :     HeapTuple   tuple;
     497             :     Form_pg_type typeForm;
     498             :     Form_pg_attribute att;
     499             : 
     500             :     /*
     501             :      * sanity checks
     502             :      */
     503      191730 :     AssertArg(PointerIsValid(desc));
     504      191730 :     AssertArg(attributeNumber >= 1);
     505      191730 :     AssertArg(attributeNumber <= desc->natts);
     506             : 
     507             :     /*
     508             :      * initialize the attribute fields
     509             :      */
     510      191730 :     att = TupleDescAttr(desc, attributeNumber - 1);
     511             : 
     512      191730 :     att->attrelid = 0;           /* dummy value */
     513             : 
     514             :     /*
     515             :      * Note: attributeName can be NULL, because the planner doesn't always
     516             :      * fill in valid resname values in targetlists, particularly for resjunk
     517             :      * attributes. Also, do nothing if caller wants to re-use the old attname.
     518             :      */
     519      191730 :     if (attributeName == NULL)
     520       79643 :         MemSet(NameStr(att->attname), 0, NAMEDATALEN);
     521      112087 :     else if (attributeName != NameStr(att->attname))
     522      112030 :         namestrcpy(&(att->attname), attributeName);
     523             : 
     524      191730 :     att->attstattarget = -1;
     525      191730 :     att->attcacheoff = -1;
     526      191730 :     att->atttypmod = typmod;
     527             : 
     528      191730 :     att->attnum = attributeNumber;
     529      191730 :     att->attndims = attdim;
     530             : 
     531      191730 :     att->attnotnull = false;
     532      191730 :     att->atthasdef = false;
     533      191730 :     att->attidentity = '\0';
     534      191730 :     att->attisdropped = false;
     535      191730 :     att->attislocal = true;
     536      191730 :     att->attinhcount = 0;
     537             :     /* attacl, attoptions and attfdwoptions are not present in tupledescs */
     538             : 
     539      191730 :     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
     540      191730 :     if (!HeapTupleIsValid(tuple))
     541           0 :         elog(ERROR, "cache lookup failed for type %u", oidtypeid);
     542      191730 :     typeForm = (Form_pg_type) GETSTRUCT(tuple);
     543             : 
     544      191730 :     att->atttypid = oidtypeid;
     545      191730 :     att->attlen = typeForm->typlen;
     546      191730 :     att->attbyval = typeForm->typbyval;
     547      191730 :     att->attalign = typeForm->typalign;
     548      191730 :     att->attstorage = typeForm->typstorage;
     549      191730 :     att->attcollation = typeForm->typcollation;
     550             : 
     551      191730 :     ReleaseSysCache(tuple);
     552      191730 : }
     553             : 
     554             : /*
     555             :  * TupleDescInitBuiltinEntry
     556             :  *      Initialize a tuple descriptor without catalog access.  Only
     557             :  *      a limited range of builtin types are supported.
     558             :  */
     559             : void
     560          64 : TupleDescInitBuiltinEntry(TupleDesc desc,
     561             :                           AttrNumber attributeNumber,
     562             :                           const char *attributeName,
     563             :                           Oid oidtypeid,
     564             :                           int32 typmod,
     565             :                           int attdim)
     566             : {
     567             :     Form_pg_attribute att;
     568             : 
     569             :     /* sanity checks */
     570          64 :     AssertArg(PointerIsValid(desc));
     571          64 :     AssertArg(attributeNumber >= 1);
     572          64 :     AssertArg(attributeNumber <= desc->natts);
     573             : 
     574             :     /* initialize the attribute fields */
     575          64 :     att = TupleDescAttr(desc, attributeNumber - 1);
     576          64 :     att->attrelid = 0;           /* dummy value */
     577             : 
     578             :     /* unlike TupleDescInitEntry, we require an attribute name */
     579          64 :     Assert(attributeName != NULL);
     580          64 :     namestrcpy(&(att->attname), attributeName);
     581             : 
     582          64 :     att->attstattarget = -1;
     583          64 :     att->attcacheoff = -1;
     584          64 :     att->atttypmod = typmod;
     585             : 
     586          64 :     att->attnum = attributeNumber;
     587          64 :     att->attndims = attdim;
     588             : 
     589          64 :     att->attnotnull = false;
     590          64 :     att->atthasdef = false;
     591          64 :     att->attidentity = '\0';
     592          64 :     att->attisdropped = false;
     593          64 :     att->attislocal = true;
     594          64 :     att->attinhcount = 0;
     595             :     /* attacl, attoptions and attfdwoptions are not present in tupledescs */
     596             : 
     597          64 :     att->atttypid = oidtypeid;
     598             : 
     599             :     /*
     600             :      * Our goal here is to support just enough types to let basic builtin
     601             :      * commands work without catalog access - e.g. so that we can do certain
     602             :      * things even in processes that are not connected to a database.
     603             :      */
     604          64 :     switch (oidtypeid)
     605             :     {
     606             :         case TEXTOID:
     607             :         case TEXTARRAYOID:
     608          64 :             att->attlen = -1;
     609          64 :             att->attbyval = false;
     610          64 :             att->attalign = 'i';
     611          64 :             att->attstorage = 'x';
     612          64 :             att->attcollation = DEFAULT_COLLATION_OID;
     613          64 :             break;
     614             : 
     615             :         case BOOLOID:
     616           0 :             att->attlen = 1;
     617           0 :             att->attbyval = true;
     618           0 :             att->attalign = 'c';
     619           0 :             att->attstorage = 'p';
     620           0 :             att->attcollation = InvalidOid;
     621           0 :             break;
     622             : 
     623             :         case INT4OID:
     624           0 :             att->attlen = 4;
     625           0 :             att->attbyval = true;
     626           0 :             att->attalign = 'i';
     627           0 :             att->attstorage = 'p';
     628           0 :             att->attcollation = InvalidOid;
     629           0 :             break;
     630             : 
     631             :         case INT8OID:
     632           0 :             att->attlen = 8;
     633           0 :             att->attbyval = FLOAT8PASSBYVAL;
     634           0 :             att->attalign = 'd';
     635           0 :             att->attstorage = 'p';
     636           0 :             att->attcollation = InvalidOid;
     637           0 :             break;
     638             :     }
     639          64 : }
     640             : 
     641             : /*
     642             :  * TupleDescInitEntryCollation
     643             :  *
     644             :  * Assign a nondefault collation to a previously initialized tuple descriptor
     645             :  * entry.
     646             :  */
     647             : void
     648      147202 : TupleDescInitEntryCollation(TupleDesc desc,
     649             :                             AttrNumber attributeNumber,
     650             :                             Oid collationid)
     651             : {
     652             :     /*
     653             :      * sanity checks
     654             :      */
     655      147202 :     AssertArg(PointerIsValid(desc));
     656      147202 :     AssertArg(attributeNumber >= 1);
     657      147202 :     AssertArg(attributeNumber <= desc->natts);
     658             : 
     659      147202 :     TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
     660      147202 : }
     661             : 
     662             : 
     663             : /*
     664             :  * BuildDescForRelation
     665             :  *
     666             :  * Given a relation schema (list of ColumnDef nodes), build a TupleDesc.
     667             :  *
     668             :  * Note: the default assumption is no OIDs; caller may modify the returned
     669             :  * TupleDesc if it wants OIDs.  Also, tdtypeid will need to be filled in
     670             :  * later on.
     671             :  */
     672             : TupleDesc
     673        2158 : BuildDescForRelation(List *schema)
     674             : {
     675             :     int         natts;
     676             :     AttrNumber  attnum;
     677             :     ListCell   *l;
     678             :     TupleDesc   desc;
     679             :     bool        has_not_null;
     680             :     char       *attname;
     681             :     Oid         atttypid;
     682             :     int32       atttypmod;
     683             :     Oid         attcollation;
     684             :     int         attdim;
     685             : 
     686             :     /*
     687             :      * allocate a new tuple descriptor
     688             :      */
     689        2158 :     natts = list_length(schema);
     690        2158 :     desc = CreateTemplateTupleDesc(natts, false);
     691        2158 :     has_not_null = false;
     692             : 
     693        2158 :     attnum = 0;
     694             : 
     695        7998 :     foreach(l, schema)
     696             :     {
     697        5844 :         ColumnDef  *entry = lfirst(l);
     698             :         AclResult   aclresult;
     699             :         Form_pg_attribute att;
     700             : 
     701             :         /*
     702             :          * for each entry in the list, get the name and type information from
     703             :          * the list and have TupleDescInitEntry fill in the attribute
     704             :          * information we need.
     705             :          */
     706        5844 :         attnum++;
     707             : 
     708        5844 :         attname = entry->colname;
     709        5844 :         typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
     710             : 
     711        5844 :         aclresult = pg_type_aclcheck(atttypid, GetUserId(), ACL_USAGE);
     712        5844 :         if (aclresult != ACLCHECK_OK)
     713           4 :             aclcheck_error_type(aclresult, atttypid);
     714             : 
     715        5840 :         attcollation = GetColumnDefCollation(NULL, entry, atttypid);
     716        5840 :         attdim = list_length(entry->typeName->arrayBounds);
     717             : 
     718        5840 :         if (entry->typeName->setof)
     719           0 :             ereport(ERROR,
     720             :                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     721             :                      errmsg("column \"%s\" cannot be declared SETOF",
     722             :                             attname)));
     723             : 
     724        5840 :         TupleDescInitEntry(desc, attnum, attname,
     725             :                            atttypid, atttypmod, attdim);
     726        5840 :         att = TupleDescAttr(desc, attnum - 1);
     727             : 
     728             :         /* Override TupleDescInitEntry's settings as requested */
     729        5840 :         TupleDescInitEntryCollation(desc, attnum, attcollation);
     730        5840 :         if (entry->storage)
     731         537 :             att->attstorage = entry->storage;
     732             : 
     733             :         /* Fill in additional stuff not handled by TupleDescInitEntry */
     734        5840 :         att->attnotnull = entry->is_not_null;
     735        5840 :         has_not_null |= entry->is_not_null;
     736        5840 :         att->attislocal = entry->is_local;
     737        5840 :         att->attinhcount = entry->inhcount;
     738             :     }
     739             : 
     740        2154 :     if (has_not_null)
     741             :     {
     742         466 :         TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
     743             : 
     744         466 :         constr->has_not_null = true;
     745         466 :         constr->defval = NULL;
     746         466 :         constr->num_defval = 0;
     747         466 :         constr->check = NULL;
     748         466 :         constr->num_check = 0;
     749         466 :         desc->constr = constr;
     750             :     }
     751             :     else
     752             :     {
     753        1688 :         desc->constr = NULL;
     754             :     }
     755             : 
     756        2154 :     return desc;
     757             : }
     758             : 
     759             : /*
     760             :  * BuildDescFromLists
     761             :  *
     762             :  * Build a TupleDesc given lists of column names (as String nodes),
     763             :  * column type OIDs, typmods, and collation OIDs.
     764             :  *
     765             :  * No constraints are generated.
     766             :  *
     767             :  * This is essentially a cut-down version of BuildDescForRelation for use
     768             :  * with functions returning RECORD.
     769             :  */
     770             : TupleDesc
     771          69 : BuildDescFromLists(List *names, List *types, List *typmods, List *collations)
     772             : {
     773             :     int         natts;
     774             :     AttrNumber  attnum;
     775             :     ListCell   *l1;
     776             :     ListCell   *l2;
     777             :     ListCell   *l3;
     778             :     ListCell   *l4;
     779             :     TupleDesc   desc;
     780             : 
     781          69 :     natts = list_length(names);
     782          69 :     Assert(natts == list_length(types));
     783          69 :     Assert(natts == list_length(typmods));
     784          69 :     Assert(natts == list_length(collations));
     785             : 
     786             :     /*
     787             :      * allocate a new tuple descriptor
     788             :      */
     789          69 :     desc = CreateTemplateTupleDesc(natts, false);
     790             : 
     791          69 :     attnum = 0;
     792             : 
     793          69 :     l2 = list_head(types);
     794          69 :     l3 = list_head(typmods);
     795          69 :     l4 = list_head(collations);
     796         286 :     foreach(l1, names)
     797             :     {
     798         217 :         char       *attname = strVal(lfirst(l1));
     799             :         Oid         atttypid;
     800             :         int32       atttypmod;
     801             :         Oid         attcollation;
     802             : 
     803         217 :         atttypid = lfirst_oid(l2);
     804         217 :         l2 = lnext(l2);
     805         217 :         atttypmod = lfirst_int(l3);
     806         217 :         l3 = lnext(l3);
     807         217 :         attcollation = lfirst_oid(l4);
     808         217 :         l4 = lnext(l4);
     809             : 
     810         217 :         attnum++;
     811             : 
     812         217 :         TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
     813         217 :         TupleDescInitEntryCollation(desc, attnum, attcollation);
     814             :     }
     815             : 
     816          69 :     return desc;
     817             : }

Generated by: LCOV version 1.11