Header And Logo

PostgreSQL
| The world's most advanced open source database.

tupdesc.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * tupdesc.c
00004  *    POSTGRES tuple descriptor support code
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/access/common/tupdesc.c
00012  *
00013  * NOTES
00014  *    some of the executor utility code such as "ExecTypeFromTL" should be
00015  *    moved here.
00016  *
00017  *-------------------------------------------------------------------------
00018  */
00019 
00020 #include "postgres.h"
00021 
00022 #include "access/htup_details.h"
00023 #include "catalog/pg_type.h"
00024 #include "miscadmin.h"
00025 #include "parser/parse_type.h"
00026 #include "utils/acl.h"
00027 #include "utils/builtins.h"
00028 #include "utils/resowner_private.h"
00029 #include "utils/syscache.h"
00030 
00031 
00032 /*
00033  * CreateTemplateTupleDesc
00034  *      This function allocates an empty tuple descriptor structure.
00035  *
00036  * Tuple type ID information is initially set for an anonymous record type;
00037  * caller can overwrite this if needed.
00038  */
00039 TupleDesc
00040 CreateTemplateTupleDesc(int natts, bool hasoid)
00041 {
00042     TupleDesc   desc;
00043     char       *stg;
00044     int         attroffset;
00045 
00046     /*
00047      * sanity checks
00048      */
00049     AssertArg(natts >= 0);
00050 
00051     /*
00052      * Allocate enough memory for the tuple descriptor, including the
00053      * attribute rows, and set up the attribute row pointers.
00054      *
00055      * Note: we assume that sizeof(struct tupleDesc) is a multiple of the
00056      * struct pointer alignment requirement, and hence we don't need to insert
00057      * alignment padding between the struct and the array of attribute row
00058      * pointers.
00059      *
00060      * Note: Only the fixed part of pg_attribute rows is included in tuple
00061      * descriptors, so we only need ATTRIBUTE_FIXED_PART_SIZE space per attr.
00062      * That might need alignment padding, however.
00063      */
00064     attroffset = sizeof(struct tupleDesc) + natts * sizeof(Form_pg_attribute);
00065     attroffset = MAXALIGN(attroffset);
00066     stg = palloc(attroffset + natts * MAXALIGN(ATTRIBUTE_FIXED_PART_SIZE));
00067     desc = (TupleDesc) stg;
00068 
00069     if (natts > 0)
00070     {
00071         Form_pg_attribute *attrs;
00072         int         i;
00073 
00074         attrs = (Form_pg_attribute *) (stg + sizeof(struct tupleDesc));
00075         desc->attrs = attrs;
00076         stg += attroffset;
00077         for (i = 0; i < natts; i++)
00078         {
00079             attrs[i] = (Form_pg_attribute) stg;
00080             stg += MAXALIGN(ATTRIBUTE_FIXED_PART_SIZE);
00081         }
00082     }
00083     else
00084         desc->attrs = NULL;
00085 
00086     /*
00087      * Initialize other fields of the tupdesc.
00088      */
00089     desc->natts = natts;
00090     desc->constr = NULL;
00091     desc->tdtypeid = RECORDOID;
00092     desc->tdtypmod = -1;
00093     desc->tdhasoid = hasoid;
00094     desc->tdrefcount = -1;      /* assume not reference-counted */
00095 
00096     return desc;
00097 }
00098 
00099 /*
00100  * CreateTupleDesc
00101  *      This function allocates a new TupleDesc pointing to a given
00102  *      Form_pg_attribute array.
00103  *
00104  * Note: if the TupleDesc is ever freed, the Form_pg_attribute array
00105  * will not be freed thereby.
00106  *
00107  * Tuple type ID information is initially set for an anonymous record type;
00108  * caller can overwrite this if needed.
00109  */
00110 TupleDesc
00111 CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
00112 {
00113     TupleDesc   desc;
00114 
00115     /*
00116      * sanity checks
00117      */
00118     AssertArg(natts >= 0);
00119 
00120     desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
00121     desc->attrs = attrs;
00122     desc->natts = natts;
00123     desc->constr = NULL;
00124     desc->tdtypeid = RECORDOID;
00125     desc->tdtypmod = -1;
00126     desc->tdhasoid = hasoid;
00127     desc->tdrefcount = -1;      /* assume not reference-counted */
00128 
00129     return desc;
00130 }
00131 
00132 /*
00133  * CreateTupleDescCopy
00134  *      This function creates a new TupleDesc by copying from an existing
00135  *      TupleDesc.
00136  *
00137  * !!! Constraints and defaults are not copied !!!
00138  */
00139 TupleDesc
00140 CreateTupleDescCopy(TupleDesc tupdesc)
00141 {
00142     TupleDesc   desc;
00143     int         i;
00144 
00145     desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
00146 
00147     for (i = 0; i < desc->natts; i++)
00148     {
00149         memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
00150         desc->attrs[i]->attnotnull = false;
00151         desc->attrs[i]->atthasdef = false;
00152     }
00153 
00154     desc->tdtypeid = tupdesc->tdtypeid;
00155     desc->tdtypmod = tupdesc->tdtypmod;
00156 
00157     return desc;
00158 }
00159 
00160 /*
00161  * CreateTupleDescCopyConstr
00162  *      This function creates a new TupleDesc by copying from an existing
00163  *      TupleDesc (including its constraints and defaults).
00164  */
00165 TupleDesc
00166 CreateTupleDescCopyConstr(TupleDesc tupdesc)
00167 {
00168     TupleDesc   desc;
00169     TupleConstr *constr = tupdesc->constr;
00170     int         i;
00171 
00172     desc = CreateTemplateTupleDesc(tupdesc->natts, tupdesc->tdhasoid);
00173 
00174     for (i = 0; i < desc->natts; i++)
00175     {
00176         memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
00177     }
00178 
00179     if (constr)
00180     {
00181         TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
00182 
00183         cpy->has_not_null = constr->has_not_null;
00184 
00185         if ((cpy->num_defval = constr->num_defval) > 0)
00186         {
00187             cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
00188             memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
00189             for (i = cpy->num_defval - 1; i >= 0; i--)
00190             {
00191                 if (constr->defval[i].adbin)
00192                     cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
00193             }
00194         }
00195 
00196         if ((cpy->num_check = constr->num_check) > 0)
00197         {
00198             cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
00199             memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
00200             for (i = cpy->num_check - 1; i >= 0; i--)
00201             {
00202                 if (constr->check[i].ccname)
00203                     cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
00204                 if (constr->check[i].ccbin)
00205                     cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
00206                 cpy->check[i].ccvalid = constr->check[i].ccvalid;
00207             }
00208         }
00209 
00210         desc->constr = cpy;
00211     }
00212 
00213     desc->tdtypeid = tupdesc->tdtypeid;
00214     desc->tdtypmod = tupdesc->tdtypmod;
00215 
00216     return desc;
00217 }
00218 
00219 /*
00220  * Free a TupleDesc including all substructure
00221  */
00222 void
00223 FreeTupleDesc(TupleDesc tupdesc)
00224 {
00225     int         i;
00226 
00227     /*
00228      * Possibly this should assert tdrefcount == 0, to disallow explicit
00229      * freeing of un-refcounted tupdescs?
00230      */
00231     Assert(tupdesc->tdrefcount <= 0);
00232 
00233     if (tupdesc->constr)
00234     {
00235         if (tupdesc->constr->num_defval > 0)
00236         {
00237             AttrDefault *attrdef = tupdesc->constr->defval;
00238 
00239             for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
00240             {
00241                 if (attrdef[i].adbin)
00242                     pfree(attrdef[i].adbin);
00243             }
00244             pfree(attrdef);
00245         }
00246         if (tupdesc->constr->num_check > 0)
00247         {
00248             ConstrCheck *check = tupdesc->constr->check;
00249 
00250             for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
00251             {
00252                 if (check[i].ccname)
00253                     pfree(check[i].ccname);
00254                 if (check[i].ccbin)
00255                     pfree(check[i].ccbin);
00256             }
00257             pfree(check);
00258         }
00259         pfree(tupdesc->constr);
00260     }
00261 
00262     pfree(tupdesc);
00263 }
00264 
00265 /*
00266  * Increment the reference count of a tupdesc, and log the reference in
00267  * CurrentResourceOwner.
00268  *
00269  * Do not apply this to tupdescs that are not being refcounted.  (Use the
00270  * macro PinTupleDesc for tupdescs of uncertain status.)
00271  */
00272 void
00273 IncrTupleDescRefCount(TupleDesc tupdesc)
00274 {
00275     Assert(tupdesc->tdrefcount >= 0);
00276 
00277     ResourceOwnerEnlargeTupleDescs(CurrentResourceOwner);
00278     tupdesc->tdrefcount++;
00279     ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
00280 }
00281 
00282 /*
00283  * Decrement the reference count of a tupdesc, remove the corresponding
00284  * reference from CurrentResourceOwner, and free the tupdesc if no more
00285  * references remain.
00286  *
00287  * Do not apply this to tupdescs that are not being refcounted.  (Use the
00288  * macro ReleaseTupleDesc for tupdescs of uncertain status.)
00289  */
00290 void
00291 DecrTupleDescRefCount(TupleDesc tupdesc)
00292 {
00293     Assert(tupdesc->tdrefcount > 0);
00294 
00295     ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
00296     if (--tupdesc->tdrefcount == 0)
00297         FreeTupleDesc(tupdesc);
00298 }
00299 
00300 /*
00301  * Compare two TupleDesc structures for logical equality
00302  *
00303  * Note: we deliberately do not check the attrelid and tdtypmod fields.
00304  * This allows typcache.c to use this routine to see if a cached record type
00305  * matches a requested type, and is harmless for relcache.c's uses.
00306  * We don't compare tdrefcount, either.
00307  */
00308 bool
00309 equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
00310 {
00311     int         i,
00312                 j,
00313                 n;
00314 
00315     if (tupdesc1->natts != tupdesc2->natts)
00316         return false;
00317     if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
00318         return false;
00319     if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
00320         return false;
00321 
00322     for (i = 0; i < tupdesc1->natts; i++)
00323     {
00324         Form_pg_attribute attr1 = tupdesc1->attrs[i];
00325         Form_pg_attribute attr2 = tupdesc2->attrs[i];
00326 
00327         /*
00328          * We do not need to check every single field here: we can disregard
00329          * attrelid and attnum (which were used to place the row in the attrs
00330          * array in the first place).  It might look like we could dispense
00331          * with checking attlen/attbyval/attalign, since these are derived
00332          * from atttypid; but in the case of dropped columns we must check
00333          * them (since atttypid will be zero for all dropped columns) and in
00334          * general it seems safer to check them always.
00335          *
00336          * attcacheoff must NOT be checked since it's possibly not set in both
00337          * copies.
00338          */
00339         if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
00340             return false;
00341         if (attr1->atttypid != attr2->atttypid)
00342             return false;
00343         if (attr1->attstattarget != attr2->attstattarget)
00344             return false;
00345         if (attr1->attlen != attr2->attlen)
00346             return false;
00347         if (attr1->attndims != attr2->attndims)
00348             return false;
00349         if (attr1->atttypmod != attr2->atttypmod)
00350             return false;
00351         if (attr1->attbyval != attr2->attbyval)
00352             return false;
00353         if (attr1->attstorage != attr2->attstorage)
00354             return false;
00355         if (attr1->attalign != attr2->attalign)
00356             return false;
00357         if (attr1->attnotnull != attr2->attnotnull)
00358             return false;
00359         if (attr1->atthasdef != attr2->atthasdef)
00360             return false;
00361         if (attr1->attisdropped != attr2->attisdropped)
00362             return false;
00363         if (attr1->attislocal != attr2->attislocal)
00364             return false;
00365         if (attr1->attinhcount != attr2->attinhcount)
00366             return false;
00367         if (attr1->attcollation != attr2->attcollation)
00368             return false;
00369         /* attacl, attoptions and attfdwoptions are not even present... */
00370     }
00371 
00372     if (tupdesc1->constr != NULL)
00373     {
00374         TupleConstr *constr1 = tupdesc1->constr;
00375         TupleConstr *constr2 = tupdesc2->constr;
00376 
00377         if (constr2 == NULL)
00378             return false;
00379         if (constr1->has_not_null != constr2->has_not_null)
00380             return false;
00381         n = constr1->num_defval;
00382         if (n != (int) constr2->num_defval)
00383             return false;
00384         for (i = 0; i < n; i++)
00385         {
00386             AttrDefault *defval1 = constr1->defval + i;
00387             AttrDefault *defval2 = constr2->defval;
00388 
00389             /*
00390              * We can't assume that the items are always read from the system
00391              * catalogs in the same order; so use the adnum field to identify
00392              * the matching item to compare.
00393              */
00394             for (j = 0; j < n; defval2++, j++)
00395             {
00396                 if (defval1->adnum == defval2->adnum)
00397                     break;
00398             }
00399             if (j >= n)
00400                 return false;
00401             if (strcmp(defval1->adbin, defval2->adbin) != 0)
00402                 return false;
00403         }
00404         n = constr1->num_check;
00405         if (n != (int) constr2->num_check)
00406             return false;
00407         for (i = 0; i < n; i++)
00408         {
00409             ConstrCheck *check1 = constr1->check + i;
00410             ConstrCheck *check2 = constr2->check;
00411 
00412             /*
00413              * Similarly, don't assume that the checks are always read in the
00414              * same order; match them up by name and contents. (The name
00415              * *should* be unique, but...)
00416              */
00417             for (j = 0; j < n; check2++, j++)
00418             {
00419                 if (strcmp(check1->ccname, check2->ccname) == 0 &&
00420                     strcmp(check1->ccbin, check2->ccbin) == 0)
00421                     break;
00422             }
00423             if (j >= n)
00424                 return false;
00425         }
00426     }
00427     else if (tupdesc2->constr != NULL)
00428         return false;
00429     return true;
00430 }
00431 
00432 /*
00433  * TupleDescInitEntry
00434  *      This function initializes a single attribute structure in
00435  *      a previously allocated tuple descriptor.
00436  *
00437  * Note that attcollation is set to the default for the specified datatype.
00438  * If a nondefault collation is needed, insert it afterwards using
00439  * TupleDescInitEntryCollation.
00440  */
00441 void
00442 TupleDescInitEntry(TupleDesc desc,
00443                    AttrNumber attributeNumber,
00444                    const char *attributeName,
00445                    Oid oidtypeid,
00446                    int32 typmod,
00447                    int attdim)
00448 {
00449     HeapTuple   tuple;
00450     Form_pg_type typeForm;
00451     Form_pg_attribute att;
00452 
00453     /*
00454      * sanity checks
00455      */
00456     AssertArg(PointerIsValid(desc));
00457     AssertArg(attributeNumber >= 1);
00458     AssertArg(attributeNumber <= desc->natts);
00459 
00460     /*
00461      * initialize the attribute fields
00462      */
00463     att = desc->attrs[attributeNumber - 1];
00464 
00465     att->attrelid = 0;          /* dummy value */
00466 
00467     /*
00468      * Note: attributeName can be NULL, because the planner doesn't always
00469      * fill in valid resname values in targetlists, particularly for resjunk
00470      * attributes.
00471      */
00472     if (attributeName != NULL)
00473         namestrcpy(&(att->attname), attributeName);
00474     else
00475         MemSet(NameStr(att->attname), 0, NAMEDATALEN);
00476 
00477     att->attstattarget = -1;
00478     att->attcacheoff = -1;
00479     att->atttypmod = typmod;
00480 
00481     att->attnum = attributeNumber;
00482     att->attndims = attdim;
00483 
00484     att->attnotnull = false;
00485     att->atthasdef = false;
00486     att->attisdropped = false;
00487     att->attislocal = true;
00488     att->attinhcount = 0;
00489     /* attacl, attoptions and attfdwoptions are not present in tupledescs */
00490 
00491     tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
00492     if (!HeapTupleIsValid(tuple))
00493         elog(ERROR, "cache lookup failed for type %u", oidtypeid);
00494     typeForm = (Form_pg_type) GETSTRUCT(tuple);
00495 
00496     att->atttypid = oidtypeid;
00497     att->attlen = typeForm->typlen;
00498     att->attbyval = typeForm->typbyval;
00499     att->attalign = typeForm->typalign;
00500     att->attstorage = typeForm->typstorage;
00501     att->attcollation = typeForm->typcollation;
00502 
00503     ReleaseSysCache(tuple);
00504 }
00505 
00506 /*
00507  * TupleDescInitEntryCollation
00508  *
00509  * Assign a nondefault collation to a previously initialized tuple descriptor
00510  * entry.
00511  */
00512 void
00513 TupleDescInitEntryCollation(TupleDesc desc,
00514                             AttrNumber attributeNumber,
00515                             Oid collationid)
00516 {
00517     /*
00518      * sanity checks
00519      */
00520     AssertArg(PointerIsValid(desc));
00521     AssertArg(attributeNumber >= 1);
00522     AssertArg(attributeNumber <= desc->natts);
00523 
00524     desc->attrs[attributeNumber - 1]->attcollation = collationid;
00525 }
00526 
00527 
00528 /*
00529  * BuildDescForRelation
00530  *
00531  * Given a relation schema (list of ColumnDef nodes), build a TupleDesc.
00532  *
00533  * Note: the default assumption is no OIDs; caller may modify the returned
00534  * TupleDesc if it wants OIDs.  Also, tdtypeid will need to be filled in
00535  * later on.
00536  */
00537 TupleDesc
00538 BuildDescForRelation(List *schema)
00539 {
00540     int         natts;
00541     AttrNumber  attnum;
00542     ListCell   *l;
00543     TupleDesc   desc;
00544     bool        has_not_null;
00545     char       *attname;
00546     Oid         atttypid;
00547     int32       atttypmod;
00548     Oid         attcollation;
00549     int         attdim;
00550 
00551     /*
00552      * allocate a new tuple descriptor
00553      */
00554     natts = list_length(schema);
00555     desc = CreateTemplateTupleDesc(natts, false);
00556     has_not_null = false;
00557 
00558     attnum = 0;
00559 
00560     foreach(l, schema)
00561     {
00562         ColumnDef  *entry = lfirst(l);
00563         AclResult   aclresult;
00564 
00565         /*
00566          * for each entry in the list, get the name and type information from
00567          * the list and have TupleDescInitEntry fill in the attribute
00568          * information we need.
00569          */
00570         attnum++;
00571 
00572         attname = entry->colname;
00573         typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod);
00574 
00575         aclresult = pg_type_aclcheck(atttypid, GetUserId(), ACL_USAGE);
00576         if (aclresult != ACLCHECK_OK)
00577             aclcheck_error_type(aclresult, atttypid);
00578 
00579         attcollation = GetColumnDefCollation(NULL, entry, atttypid);
00580         attdim = list_length(entry->typeName->arrayBounds);
00581 
00582         if (entry->typeName->setof)
00583             ereport(ERROR,
00584                     (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
00585                      errmsg("column \"%s\" cannot be declared SETOF",
00586                             attname)));
00587 
00588         TupleDescInitEntry(desc, attnum, attname,
00589                            atttypid, atttypmod, attdim);
00590 
00591         /* Override TupleDescInitEntry's settings as requested */
00592         TupleDescInitEntryCollation(desc, attnum, attcollation);
00593         if (entry->storage)
00594             desc->attrs[attnum - 1]->attstorage = entry->storage;
00595 
00596         /* Fill in additional stuff not handled by TupleDescInitEntry */
00597         desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
00598         has_not_null |= entry->is_not_null;
00599         desc->attrs[attnum - 1]->attislocal = entry->is_local;
00600         desc->attrs[attnum - 1]->attinhcount = entry->inhcount;
00601     }
00602 
00603     if (has_not_null)
00604     {
00605         TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
00606 
00607         constr->has_not_null = true;
00608         constr->defval = NULL;
00609         constr->num_defval = 0;
00610         constr->check = NULL;
00611         constr->num_check = 0;
00612         desc->constr = constr;
00613     }
00614     else
00615     {
00616         desc->constr = NULL;
00617     }
00618 
00619     return desc;
00620 }
00621 
00622 /*
00623  * BuildDescFromLists
00624  *
00625  * Build a TupleDesc given lists of column names (as String nodes),
00626  * column type OIDs, typmods, and collation OIDs.
00627  *
00628  * No constraints are generated.
00629  *
00630  * This is essentially a cut-down version of BuildDescForRelation for use
00631  * with functions returning RECORD.
00632  */
00633 TupleDesc
00634 BuildDescFromLists(List *names, List *types, List *typmods, List *collations)
00635 {
00636     int         natts;
00637     AttrNumber  attnum;
00638     ListCell   *l1;
00639     ListCell   *l2;
00640     ListCell   *l3;
00641     ListCell   *l4;
00642     TupleDesc   desc;
00643 
00644     natts = list_length(names);
00645     Assert(natts == list_length(types));
00646     Assert(natts == list_length(typmods));
00647     Assert(natts == list_length(collations));
00648 
00649     /*
00650      * allocate a new tuple descriptor
00651      */
00652     desc = CreateTemplateTupleDesc(natts, false);
00653 
00654     attnum = 0;
00655 
00656     l2 = list_head(types);
00657     l3 = list_head(typmods);
00658     l4 = list_head(collations);
00659     foreach(l1, names)
00660     {
00661         char       *attname = strVal(lfirst(l1));
00662         Oid         atttypid;
00663         int32       atttypmod;
00664         Oid         attcollation;
00665 
00666         atttypid = lfirst_oid(l2);
00667         l2 = lnext(l2);
00668         atttypmod = lfirst_int(l3);
00669         l3 = lnext(l3);
00670         attcollation = lfirst_oid(l4);
00671         l4 = lnext(l4);
00672 
00673         attnum++;
00674 
00675         TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
00676         TupleDescInitEntryCollation(desc, attnum, attcollation);
00677     }
00678 
00679     return desc;
00680 }