LTP GCOV extension - code coverage report
Current view: directory - access/common - tupdesc.c
Test: unnamed
Date: 2008-07-03 Instrumented lines: 252
Code covered: 94.0 % Executed lines: 237
Legend: not executed executed

       1                 : /*-------------------------------------------------------------------------
       2                 :  *
       3                 :  * tupdesc.c
       4                 :  *        POSTGRES tuple descriptor support code
       5                 :  *
       6                 :  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
       7                 :  * Portions Copyright (c) 1994, Regents of the University of California
       8                 :  *
       9                 :  *
      10                 :  * IDENTIFICATION
      11                 :  *        $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.121 2007/11/11 19:22:48 tgl Exp $
      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 "catalog/pg_type.h"
      23                 : #include "parser/parse_type.h"
      24                 : #include "utils/builtins.h"
      25                 : #include "utils/resowner.h"
      26                 : #include "utils/syscache.h"
      27                 : 
      28                 : 
      29                 : /*
      30                 :  * CreateTemplateTupleDesc
      31                 :  *              This function allocates an empty tuple descriptor structure.
      32                 :  *
      33                 :  * Tuple type ID information is initially set for an anonymous record type;
      34                 :  * caller can overwrite this if needed.
      35                 :  */
      36                 : TupleDesc
      37                 : CreateTemplateTupleDesc(int natts, bool hasoid)
      38           55466 : {
      39                 :         TupleDesc       desc;
      40                 :         char       *stg;
      41                 :         int                     attroffset;
      42                 : 
      43                 :         /*
      44                 :          * sanity checks
      45                 :          */
      46                 :         AssertArg(natts >= 0);
      47                 : 
      48                 :         /*
      49                 :          * Allocate enough memory for the tuple descriptor, including the
      50                 :          * attribute rows, and set up the attribute row pointers.
      51                 :          *
      52                 :          * Note: we assume that sizeof(struct tupleDesc) is a multiple of the
      53                 :          * struct pointer alignment requirement, and hence we don't need to insert
      54                 :          * alignment padding between the struct and the array of attribute row
      55                 :          * pointers.
      56                 :          */
      57           55466 :         attroffset = sizeof(struct tupleDesc) + natts * sizeof(Form_pg_attribute);
      58           55466 :         attroffset = MAXALIGN(attroffset);
      59           55466 :         stg = palloc(attroffset + natts * MAXALIGN(ATTRIBUTE_TUPLE_SIZE));
      60           55466 :         desc = (TupleDesc) stg;
      61                 : 
      62           55466 :         if (natts > 0)
      63                 :         {
      64                 :                 Form_pg_attribute *attrs;
      65                 :                 int                     i;
      66                 : 
      67           55292 :                 attrs = (Form_pg_attribute *) (stg + sizeof(struct tupleDesc));
      68           55292 :                 desc->attrs = attrs;
      69           55292 :                 stg += attroffset;
      70          264843 :                 for (i = 0; i < natts; i++)
      71                 :                 {
      72          209551 :                         attrs[i] = (Form_pg_attribute) stg;
      73          209551 :                         stg += MAXALIGN(ATTRIBUTE_TUPLE_SIZE);
      74                 :                 }
      75                 :         }
      76                 :         else
      77             174 :                 desc->attrs = NULL;
      78                 : 
      79                 :         /*
      80                 :          * Initialize other fields of the tupdesc.
      81                 :          */
      82           55466 :         desc->natts = natts;
      83           55466 :         desc->constr = NULL;
      84           55466 :         desc->tdtypeid = RECORDOID;
      85           55466 :         desc->tdtypmod = -1;
      86           55466 :         desc->tdhasoid = hasoid;
      87           55466 :         desc->tdrefcount = -1;               /* assume not reference-counted */
      88                 : 
      89           55466 :         return desc;
      90                 : }
      91                 : 
      92                 : /*
      93                 :  * CreateTupleDesc
      94                 :  *              This function allocates a new TupleDesc pointing to a given
      95                 :  *              Form_pg_attribute array.
      96                 :  *
      97                 :  * Note: if the TupleDesc is ever freed, the Form_pg_attribute array
      98                 :  * will not be freed thereby.
      99                 :  *
     100                 :  * Tuple type ID information is initially set for an anonymous record type;
     101                 :  * caller can overwrite this if needed.
     102                 :  */
     103                 : TupleDesc
     104                 : CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
     105            4162 : {
     106                 :         TupleDesc       desc;
     107                 : 
     108                 :         /*
     109                 :          * sanity checks
     110                 :          */
     111                 :         AssertArg(natts >= 0);
     112                 : 
     113            4162 :         desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
     114            4162 :         desc->attrs = attrs;
     115            4162 :         desc->natts = natts;
     116            4162 :         desc->constr = NULL;
     117            4162 :         desc->tdtypeid = RECORDOID;
     118            4162 :         desc->tdtypmod = -1;
     119            4162 :         desc->tdhasoid = hasoid;
     120            4162 :         desc->tdrefcount = -1;               /* assume not reference-counted */
     121                 : 
     122            4162 :         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                 : CreateTupleDescCopy(TupleDesc tupdesc)
     134            4566 : {
     135                 :         TupleDesc       desc;
     136                 :         int                     i;
     137                 : 
     138            4566 :         desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
     139                 : 
     140           17937 :         for (i = 0; i < desc->natts; i++)
     141                 :         {
     142           13371 :                 memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
     143           13371 :                 desc->attrs[i]->attnotnull = false;
     144           13371 :                 desc->attrs[i]->atthasdef = false;
     145                 :         }
     146                 : 
     147            4566 :         desc->tdtypeid = tupdesc->tdtypeid;
     148            4566 :         desc->tdtypmod = tupdesc->tdtypmod;
     149                 : 
     150            4566 :         return desc;
     151                 : }
     152                 : 
     153                 : /*
     154                 :  * CreateTupleDescCopyConstr
     155                 :  *              This function creates a new TupleDesc by copying from an existing
     156                 :  *              TupleDesc (including its constraints and defaults).
     157                 :  */
     158                 : TupleDesc
     159                 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
     160            6608 : {
     161                 :         TupleDesc       desc;
     162            6608 :         TupleConstr *constr = tupdesc->constr;
     163                 :         int                     i;
     164                 : 
     165            6608 :         desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
     166                 : 
     167           73706 :         for (i = 0; i < desc->natts; i++)
     168                 :         {
     169           67098 :                 memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
     170                 :         }
     171                 : 
     172            6608 :         if (constr)
     173                 :         {
     174            6392 :                 TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
     175                 : 
     176            6392 :                 cpy->has_not_null = constr->has_not_null;
     177                 : 
     178            6392 :                 if ((cpy->num_defval = constr->num_defval) > 0)
     179                 :                 {
     180               7 :                         cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
     181               7 :                         memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
     182              18 :                         for (i = cpy->num_defval - 1; i >= 0; i--)
     183                 :                         {
     184              11 :                                 if (constr->defval[i].adbin)
     185              11 :                                         cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
     186                 :                         }
     187                 :                 }
     188                 : 
     189            6392 :                 if ((cpy->num_check = constr->num_check) > 0)
     190                 :                 {
     191               2 :                         cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
     192               2 :                         memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
     193               4 :                         for (i = cpy->num_check - 1; i >= 0; i--)
     194                 :                         {
     195               2 :                                 if (constr->check[i].ccname)
     196               2 :                                         cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
     197               2 :                                 if (constr->check[i].ccbin)
     198               2 :                                         cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
     199                 :                         }
     200                 :                 }
     201                 : 
     202            6392 :                 desc->constr = cpy;
     203                 :         }
     204                 : 
     205            6608 :         desc->tdtypeid = tupdesc->tdtypeid;
     206            6608 :         desc->tdtypmod = tupdesc->tdtypmod;
     207                 : 
     208            6608 :         return desc;
     209                 : }
     210                 : 
     211                 : /*
     212                 :  * Free a TupleDesc including all substructure
     213                 :  */
     214                 : void
     215                 : FreeTupleDesc(TupleDesc tupdesc)
     216            8215 : {
     217                 :         int                     i;
     218                 : 
     219                 :         /*
     220                 :          * Possibly this should assert tdrefcount == 0, to disallow explicit
     221                 :          * freeing of un-refcounted tupdescs?
     222                 :          */
     223                 :         Assert(tupdesc->tdrefcount <= 0);
     224                 : 
     225            8215 :         if (tupdesc->constr)
     226                 :         {
     227            1869 :                 if (tupdesc->constr->num_defval > 0)
     228                 :                 {
     229             390 :                         AttrDefault *attrdef = tupdesc->constr->defval;
     230                 : 
     231             917 :                         for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
     232                 :                         {
     233             527 :                                 if (attrdef[i].adbin)
     234             527 :                                         pfree(attrdef[i].adbin);
     235                 :                         }
     236             390 :                         pfree(attrdef);
     237                 :                 }
     238            1869 :                 if (tupdesc->constr->num_check > 0)
     239                 :                 {
     240              93 :                         ConstrCheck *check = tupdesc->constr->check;
     241                 : 
     242             200 :                         for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
     243                 :                         {
     244             107 :                                 if (check[i].ccname)
     245             107 :                                         pfree(check[i].ccname);
     246             107 :                                 if (check[i].ccbin)
     247             107 :                                         pfree(check[i].ccbin);
     248                 :                         }
     249              93 :                         pfree(check);
     250                 :                 }
     251            1869 :                 pfree(tupdesc->constr);
     252                 :         }
     253                 : 
     254            8215 :         pfree(tupdesc);
     255            8215 : }
     256                 : 
     257                 : /*
     258                 :  * Increment the reference count of a tupdesc, and log the reference in
     259                 :  * CurrentResourceOwner.
     260                 :  *
     261                 :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     262                 :  * macro PinTupleDesc for tupdescs of uncertain status.)
     263                 :  */
     264                 : void
     265                 : IncrTupleDescRefCount(TupleDesc tupdesc)
     266           37334 : {
     267                 :         Assert(tupdesc->tdrefcount >= 0);
     268                 : 
     269           37334 :         ResourceOwnerEnlargeTupleDescs(CurrentResourceOwner);
     270           37334 :         tupdesc->tdrefcount++;
     271           37334 :         ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
     272           37334 : }
     273                 : 
     274                 : /*
     275                 :  * Decrement the reference count of a tupdesc, remove the corresponding
     276                 :  * reference from CurrentResourceOwner, and free the tupdesc if no more
     277                 :  * references remain.
     278                 :  *
     279                 :  * Do not apply this to tupdescs that are not being refcounted.  (Use the
     280                 :  * macro ReleaseTupleDesc for tupdescs of uncertain status.)
     281                 :  */
     282                 : void
     283                 : DecrTupleDescRefCount(TupleDesc tupdesc)
     284           37334 : {
     285                 :         Assert(tupdesc->tdrefcount > 0);
     286                 : 
     287           37334 :         ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
     288           37334 :         if (--tupdesc->tdrefcount == 0)
     289               7 :                 FreeTupleDesc(tupdesc);
     290           37334 : }
     291                 : 
     292                 : /*
     293                 :  * Compare two TupleDesc structures for logical equality
     294                 :  *
     295                 :  * Note: we deliberately do not check the attrelid and tdtypmod fields.
     296                 :  * This allows typcache.c to use this routine to see if a cached record type
     297                 :  * matches a requested type, and is harmless for relcache.c's uses.
     298                 :  * We don't compare tdrefcount, either.
     299                 :  */
     300                 : bool
     301                 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
     302            3258 : {
     303                 :         int                     i,
     304                 :                                 j,
     305                 :                                 n;
     306                 : 
     307            3258 :         if (tupdesc1->natts != tupdesc2->natts)
     308              80 :                 return false;
     309            3178 :         if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
     310             460 :                 return false;
     311            2718 :         if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
     312               3 :                 return false;
     313                 : 
     314           11336 :         for (i = 0; i < tupdesc1->natts; i++)
     315                 :         {
     316            8834 :                 Form_pg_attribute attr1 = tupdesc1->attrs[i];
     317            8834 :                 Form_pg_attribute attr2 = tupdesc2->attrs[i];
     318                 : 
     319                 :                 /*
     320                 :                  * We do not need to check every single field here: we can disregard
     321                 :                  * attrelid and attnum (which were used to place the row in the attrs
     322                 :                  * array in the first place).  It might look like we could dispense
     323                 :                  * with checking attlen/attbyval/attalign, since these are derived
     324                 :                  * from atttypid; but in the case of dropped columns we must check
     325                 :                  * them (since atttypid will be zero for all dropped columns) and in
     326                 :                  * general it seems safer to check them always.
     327                 :                  *
     328                 :                  * attcacheoff must NOT be checked since it's possibly not set in both
     329                 :                  * copies.
     330                 :                  */
     331            8834 :                 if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
     332              96 :                         return false;
     333            8738 :                 if (attr1->atttypid != attr2->atttypid)
     334              15 :                         return false;
     335            8723 :                 if (attr1->attstattarget != attr2->attstattarget)
     336               0 :                         return false;
     337            8723 :                 if (attr1->attlen != attr2->attlen)
     338               0 :                         return false;
     339            8723 :                 if (attr1->attndims != attr2->attndims)
     340               0 :                         return false;
     341            8723 :                 if (attr1->atttypmod != attr2->atttypmod)
     342               0 :                         return false;
     343            8723 :                 if (attr1->attbyval != attr2->attbyval)
     344               0 :                         return false;
     345            8723 :                 if (attr1->attstorage != attr2->attstorage)
     346               2 :                         return false;
     347            8721 :                 if (attr1->attalign != attr2->attalign)
     348               0 :                         return false;
     349            8721 :                 if (attr1->attnotnull != attr2->attnotnull)
     350              18 :                         return false;
     351            8703 :                 if (attr1->atthasdef != attr2->atthasdef)
     352              72 :                         return false;
     353            8631 :                 if (attr1->attisdropped != attr2->attisdropped)
     354               0 :                         return false;
     355            8631 :                 if (attr1->attislocal != attr2->attislocal)
     356               4 :                         return false;
     357            8627 :                 if (attr1->attinhcount != attr2->attinhcount)
     358               6 :                         return false;
     359                 :         }
     360                 : 
     361            2502 :         if (tupdesc1->constr != NULL)
     362                 :         {
     363             525 :                 TupleConstr *constr1 = tupdesc1->constr;
     364             525 :                 TupleConstr *constr2 = tupdesc2->constr;
     365                 : 
     366             525 :                 if (constr2 == NULL)
     367               0 :                         return false;
     368             525 :                 if (constr1->has_not_null != constr2->has_not_null)
     369               0 :                         return false;
     370             525 :                 n = constr1->num_defval;
     371             525 :                 if (n != (int) constr2->num_defval)
     372               0 :                         return false;
     373             643 :                 for (i = 0; i < n; i++)
     374                 :                 {
     375             118 :                         AttrDefault *defval1 = constr1->defval + i;
     376             118 :                         AttrDefault *defval2 = constr2->defval;
     377                 : 
     378                 :                         /*
     379                 :                          * We can't assume that the items are always read from the system
     380                 :                          * catalogs in the same order; so use the adnum field to identify
     381                 :                          * the matching item to compare.
     382                 :                          */
     383             150 :                         for (j = 0; j < n; defval2++, j++)
     384                 :                         {
     385             150 :                                 if (defval1->adnum == defval2->adnum)
     386             118 :                                         break;
     387                 :                         }
     388             118 :                         if (j >= n)
     389               0 :                                 return false;
     390             118 :                         if (strcmp(defval1->adbin, defval2->adbin) != 0)
     391               0 :                                 return false;
     392                 :                 }
     393             525 :                 n = constr1->num_check;
     394             525 :                 if (n != (int) constr2->num_check)
     395              10 :                         return false;
     396             530 :                 for (i = 0; i < n; i++)
     397                 :                 {
     398              15 :                         ConstrCheck *check1 = constr1->check + i;
     399              15 :                         ConstrCheck *check2 = constr2->check;
     400                 : 
     401                 :                         /*
     402                 :                          * Similarly, don't assume that the checks are always read in the
     403                 :                          * same order; match them up by name and contents. (The name
     404                 :                          * *should* be unique, but...)
     405                 :                          */
     406              19 :                         for (j = 0; j < n; check2++, j++)
     407                 :                         {
     408              34 :                                 if (strcmp(check1->ccname, check2->ccname) == 0 &&
     409              15 :                                         strcmp(check1->ccbin, check2->ccbin) == 0)
     410              15 :                                         break;
     411                 :                         }
     412              15 :                         if (j >= n)
     413               0 :                                 return false;
     414                 :                 }
     415                 :         }
     416            1977 :         else if (tupdesc2->constr != NULL)
     417              14 :                 return false;
     418            2478 :         return true;
     419                 : }
     420                 : 
     421                 : /*
     422                 :  * TupleDescInitEntry
     423                 :  *              This function initializes a single attribute structure in
     424                 :  *              a previously allocated tuple descriptor.
     425                 :  */
     426                 : void
     427                 : TupleDescInitEntry(TupleDesc desc,
     428                 :                                    AttrNumber attributeNumber,
     429                 :                                    const char *attributeName,
     430                 :                                    Oid oidtypeid,
     431                 :                                    int32 typmod,
     432                 :                                    int attdim)
     433           46237 : {
     434                 :         HeapTuple       tuple;
     435                 :         Form_pg_type typeForm;
     436                 :         Form_pg_attribute att;
     437                 : 
     438                 :         /*
     439                 :          * sanity checks
     440                 :          */
     441                 :         AssertArg(PointerIsValid(desc));
     442                 :         AssertArg(attributeNumber >= 1);
     443                 :         AssertArg(attributeNumber <= desc->natts);
     444                 : 
     445                 :         /*
     446                 :          * initialize the attribute fields
     447                 :          */
     448           46237 :         att = desc->attrs[attributeNumber - 1];
     449                 : 
     450           46237 :         att->attrelid = 0;                   /* dummy value */
     451                 : 
     452                 :         /*
     453                 :          * Note: attributeName can be NULL, because the planner doesn't always
     454                 :          * fill in valid resname values in targetlists, particularly for resjunk
     455                 :          * attributes.
     456                 :          */
     457           46237 :         if (attributeName != NULL)
     458           39351 :                 namestrcpy(&(att->attname), attributeName);
     459                 :         else
     460            6886 :                 MemSet(NameStr(att->attname), 0, NAMEDATALEN);
     461                 : 
     462           46237 :         att->attstattarget = -1;
     463           46237 :         att->attcacheoff = -1;
     464           46237 :         att->atttypmod = typmod;
     465                 : 
     466           46237 :         att->attnum = attributeNumber;
     467           46237 :         att->attndims = attdim;
     468                 : 
     469           46237 :         att->attnotnull = false;
     470           46237 :         att->atthasdef = false;
     471           46237 :         att->attisdropped = false;
     472           46237 :         att->attislocal = true;
     473           46237 :         att->attinhcount = 0;
     474                 : 
     475           46237 :         tuple = SearchSysCache(TYPEOID,
     476                 :                                                    ObjectIdGetDatum(oidtypeid),
     477                 :                                                    0, 0, 0);
     478           46237 :         if (!HeapTupleIsValid(tuple))
     479               0 :                 elog(ERROR, "cache lookup failed for type %u", oidtypeid);
     480           46237 :         typeForm = (Form_pg_type) GETSTRUCT(tuple);
     481                 : 
     482           46237 :         att->atttypid = oidtypeid;
     483           46237 :         att->attlen = typeForm->typlen;
     484           46237 :         att->attbyval = typeForm->typbyval;
     485           46237 :         att->attalign = typeForm->typalign;
     486           46237 :         att->attstorage = typeForm->typstorage;
     487                 : 
     488           46237 :         ReleaseSysCache(tuple);
     489           46237 : }
     490                 : 
     491                 : 
     492                 : /*
     493                 :  * BuildDescForRelation
     494                 :  *
     495                 :  * Given a relation schema (list of ColumnDef nodes), build a TupleDesc.
     496                 :  *
     497                 :  * Note: the default assumption is no OIDs; caller may modify the returned
     498                 :  * TupleDesc if it wants OIDs.  Also, tdtypeid will need to be filled in
     499                 :  * later on.
     500                 :  */
     501                 : TupleDesc
     502                 : BuildDescForRelation(List *schema)
     503             769 : {
     504                 :         int                     natts;
     505                 :         AttrNumber      attnum;
     506                 :         ListCell   *l;
     507                 :         TupleDesc       desc;
     508             769 :         AttrDefault *attrdef = NULL;
     509             769 :         TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
     510                 :         char       *attname;
     511                 :         Oid                     atttypid;
     512                 :         int32           atttypmod;
     513                 :         int                     attdim;
     514             769 :         int                     ndef = 0;
     515                 : 
     516                 :         /*
     517                 :          * allocate a new tuple descriptor
     518                 :          */
     519             769 :         natts = list_length(schema);
     520             769 :         desc = CreateTemplateTupleDesc(natts, false);
     521             769 :         constr->has_not_null = false;
     522                 : 
     523             769 :         attnum = 0;
     524                 : 
     525            3358 :         foreach(l, schema)
     526                 :         {
     527            2589 :                 ColumnDef  *entry = lfirst(l);
     528                 : 
     529                 :                 /*
     530                 :                  * for each entry in the list, get the name and type information from
     531                 :                  * the list and have TupleDescInitEntry fill in the attribute
     532                 :                  * information we need.
     533                 :                  */
     534            2589 :                 attnum++;
     535                 : 
     536            2589 :                 attname = entry->colname;
     537            2589 :                 atttypid = typenameTypeId(NULL, entry->typename, &atttypmod);
     538            2589 :                 attdim = list_length(entry->typename->arrayBounds);
     539                 : 
     540            2589 :                 if (entry->typename->setof)
     541               0 :                         ereport(ERROR,
     542                 :                                         (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
     543                 :                                          errmsg("column \"%s\" cannot be declared SETOF",
     544                 :                                                         attname)));
     545                 : 
     546            2589 :                 TupleDescInitEntry(desc, attnum, attname,
     547                 :                                                    atttypid, atttypmod, attdim);
     548                 : 
     549                 :                 /* Fill in additional stuff not handled by TupleDescInitEntry */
     550            2589 :                 if (entry->is_not_null)
     551             502 :                         constr->has_not_null = true;
     552            2589 :                 desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
     553                 : 
     554                 :                 /*
     555                 :                  * Note we copy only pre-cooked default expressions. Digestion of raw
     556                 :                  * ones is someone else's problem.
     557                 :                  */
     558            2589 :                 if (entry->cooked_default != NULL)
     559                 :                 {
     560              10 :                         if (attrdef == NULL)
     561               7 :                                 attrdef = (AttrDefault *) palloc(natts * sizeof(AttrDefault));
     562              10 :                         attrdef[ndef].adnum = attnum;
     563              10 :                         attrdef[ndef].adbin = pstrdup(entry->cooked_default);
     564              10 :                         ndef++;
     565              10 :                         desc->attrs[attnum - 1]->atthasdef = true;
     566                 :                 }
     567                 : 
     568            2589 :                 desc->attrs[attnum - 1]->attislocal = entry->is_local;
     569            2589 :                 desc->attrs[attnum - 1]->attinhcount = entry->inhcount;
     570                 :         }
     571                 : 
     572             769 :         if (constr->has_not_null || ndef > 0)
     573                 :         {
     574             149 :                 desc->constr = constr;
     575                 : 
     576             149 :                 if (ndef > 0)                        /* DEFAULTs */
     577                 :                 {
     578               7 :                         if (ndef < natts)
     579               6 :                                 constr->defval = (AttrDefault *)
     580                 :                                         repalloc(attrdef, ndef * sizeof(AttrDefault));
     581                 :                         else
     582               1 :                                 constr->defval = attrdef;
     583               7 :                         constr->num_defval = ndef;
     584                 :                 }
     585                 :                 else
     586                 :                 {
     587             142 :                         constr->defval = NULL;
     588             142 :                         constr->num_defval = 0;
     589                 :                 }
     590             149 :                 constr->check = NULL;
     591             149 :                 constr->num_check = 0;
     592                 :         }
     593                 :         else
     594                 :         {
     595             620 :                 pfree(constr);
     596             620 :                 desc->constr = NULL;
     597                 :         }
     598                 : 
     599             769 :         return desc;
     600                 : }
     601                 : 
     602                 : /*
     603                 :  * BuildDescFromLists
     604                 :  *
     605                 :  * Build a TupleDesc given lists of column names (as String nodes),
     606                 :  * column type OIDs, and column typmods.  No constraints are generated.
     607                 :  *
     608                 :  * This is essentially a cut-down version of BuildDescForRelation for use
     609                 :  * with functions returning RECORD.
     610                 :  */
     611                 : TupleDesc
     612                 : BuildDescFromLists(List *names, List *types, List *typmods)
     613              51 : {
     614                 :         int                     natts;
     615                 :         AttrNumber      attnum;
     616                 :         ListCell   *l1;
     617                 :         ListCell   *l2;
     618                 :         ListCell   *l3;
     619                 :         TupleDesc       desc;
     620                 : 
     621              51 :         natts = list_length(names);
     622                 :         Assert(natts == list_length(types));
     623                 :         Assert(natts == list_length(typmods));
     624                 : 
     625                 :         /*
     626                 :          * allocate a new tuple descriptor
     627                 :          */
     628              51 :         desc = CreateTemplateTupleDesc(natts, false);
     629                 : 
     630              51 :         attnum = 0;
     631                 : 
     632              51 :         l2 = list_head(types);
     633              51 :         l3 = list_head(typmods);
     634             309 :         foreach(l1, names)
     635                 :         {
     636             258 :                 char       *attname = strVal(lfirst(l1));
     637                 :                 Oid                     atttypid;
     638                 :                 int32           atttypmod;
     639                 : 
     640             258 :                 atttypid = lfirst_oid(l2);
     641             258 :                 l2 = lnext(l2);
     642             258 :                 atttypmod = lfirst_int(l3);
     643             258 :                 l3 = lnext(l3);
     644                 : 
     645             258 :                 attnum++;
     646                 : 
     647             258 :                 TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
     648                 :         }
     649                 : 
     650              51 :         return desc;
     651                 : }

Generated by: LTP GCOV extension version 1.5