1 /*-------------------------------------------------------------------------
4 * POSTGRES tuple descriptor support code
6 * Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/access/common/tupdesc.c,v 1.105 2004/08/29 04:12:17 momjian Exp $
14 * some of the executor utility code such as "ExecTypeFromTL" should be
17 *-------------------------------------------------------------------------
23 #include "access/heapam.h"
24 #include "catalog/namespace.h"
25 #include "catalog/pg_type.h"
26 #include "nodes/parsenodes.h"
27 #include "parser/parse_type.h"
28 #include "utils/builtins.h"
29 #include "utils/lsyscache.h"
30 #include "utils/syscache.h"
31 #include "utils/typcache.h"
34 /* ----------------------------------------------------------------
35 * CreateTemplateTupleDesc
37 * This function allocates and zeros a tuple descriptor structure.
39 * Tuple type ID information is initially set for an anonymous record type;
40 * caller can overwrite this if needed.
41 * ----------------------------------------------------------------
44 CreateTemplateTupleDesc(int natts, bool hasoid)
51 AssertArg(natts >= 0);
54 * Allocate enough memory for the tuple descriptor, and zero the
55 * attrs[] array since TupleDescInitEntry assumes that the array
56 * is filled with NULL pointers.
58 desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
61 desc->attrs = (Form_pg_attribute *)
62 palloc0(natts * sizeof(Form_pg_attribute));
67 * Initialize other fields of the tupdesc.
71 desc->tdtypeid = RECORDOID;
73 desc->tdhasoid = hasoid;
78 /* ----------------------------------------------------------------
81 * This function allocates a new TupleDesc pointing to a given
82 * Form_pg_attribute array
84 * Tuple type ID information is initially set for an anonymous record type;
85 * caller can overwrite this if needed.
86 * ----------------------------------------------------------------
89 CreateTupleDesc(int natts, bool hasoid, Form_pg_attribute *attrs)
96 AssertArg(natts >= 0);
98 desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
102 desc->tdtypeid = RECORDOID;
104 desc->tdhasoid = hasoid;
109 /* ----------------------------------------------------------------
110 * CreateTupleDescCopy
112 * This function creates a new TupleDesc by copying from an existing
115 * !!! Constraints and defaults are not copied !!!
116 * ----------------------------------------------------------------
119 CreateTupleDescCopy(TupleDesc tupdesc)
124 desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
125 desc->natts = tupdesc->natts;
128 desc->attrs = (Form_pg_attribute *)
129 palloc(desc->natts * sizeof(Form_pg_attribute));
130 for (i = 0; i < desc->natts; i++)
132 desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
133 memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
134 desc->attrs[i]->attnotnull = false;
135 desc->attrs[i]->atthasdef = false;
143 desc->tdtypeid = tupdesc->tdtypeid;
144 desc->tdtypmod = tupdesc->tdtypmod;
145 desc->tdhasoid = tupdesc->tdhasoid;
150 /* ----------------------------------------------------------------
151 * CreateTupleDescCopyConstr
153 * This function creates a new TupleDesc by copying from an existing
154 * TupleDesc (including its constraints and defaults)
155 * ----------------------------------------------------------------
158 CreateTupleDescCopyConstr(TupleDesc tupdesc)
161 TupleConstr *constr = tupdesc->constr;
164 desc = (TupleDesc) palloc(sizeof(struct tupleDesc));
165 desc->natts = tupdesc->natts;
168 desc->attrs = (Form_pg_attribute *)
169 palloc(desc->natts * sizeof(Form_pg_attribute));
170 for (i = 0; i < desc->natts; i++)
172 desc->attrs[i] = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
173 memcpy(desc->attrs[i], tupdesc->attrs[i], ATTRIBUTE_TUPLE_SIZE);
181 TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
183 cpy->has_not_null = constr->has_not_null;
185 if ((cpy->num_defval = constr->num_defval) > 0)
187 cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
188 memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
189 for (i = cpy->num_defval - 1; i >= 0; i--)
191 if (constr->defval[i].adbin)
192 cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
196 if ((cpy->num_check = constr->num_check) > 0)
198 cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
199 memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
200 for (i = cpy->num_check - 1; i >= 0; i--)
202 if (constr->check[i].ccname)
203 cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
204 if (constr->check[i].ccbin)
205 cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
214 desc->tdtypeid = tupdesc->tdtypeid;
215 desc->tdtypmod = tupdesc->tdtypmod;
216 desc->tdhasoid = tupdesc->tdhasoid;
222 * Free a TupleDesc including all substructure
225 FreeTupleDesc(TupleDesc tupdesc)
229 for (i = 0; i < tupdesc->natts; i++)
230 pfree(tupdesc->attrs[i]);
232 pfree(tupdesc->attrs);
235 if (tupdesc->constr->num_defval > 0)
237 AttrDefault *attrdef = tupdesc->constr->defval;
239 for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
241 if (attrdef[i].adbin)
242 pfree(attrdef[i].adbin);
246 if (tupdesc->constr->num_check > 0)
248 ConstrCheck *check = tupdesc->constr->check;
250 for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
253 pfree(check[i].ccname);
255 pfree(check[i].ccbin);
259 pfree(tupdesc->constr);
266 * Compare two TupleDesc structures for logical equality
268 * Note: we deliberately do not check the attrelid and tdtypmod fields.
269 * This allows typcache.c to use this routine to see if a cached record type
270 * matches a requested type, and is harmless for relcache.c's uses.
273 equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
279 if (tupdesc1->natts != tupdesc2->natts)
281 if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
283 if (tupdesc1->tdhasoid != tupdesc2->tdhasoid)
286 for (i = 0; i < tupdesc1->natts; i++)
288 Form_pg_attribute attr1 = tupdesc1->attrs[i];
289 Form_pg_attribute attr2 = tupdesc2->attrs[i];
292 * We do not need to check every single field here: we can
293 * disregard attrelid, attnum (it was used to place the row in the
294 * attrs array) and everything derived from the column datatype.
295 * Also, attcacheoff must NOT be checked since it's possibly not
296 * set in both copies.
298 if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
300 if (attr1->atttypid != attr2->atttypid)
302 if (attr1->attstattarget != attr2->attstattarget)
304 if (attr1->attndims != attr2->attndims)
306 if (attr1->atttypmod != attr2->atttypmod)
308 if (attr1->attstorage != attr2->attstorage)
310 if (attr1->attnotnull != attr2->attnotnull)
312 if (attr1->atthasdef != attr2->atthasdef)
314 if (attr1->attisdropped != attr2->attisdropped)
316 if (attr1->attislocal != attr2->attislocal)
318 if (attr1->attinhcount != attr2->attinhcount)
322 if (tupdesc1->constr != NULL)
324 TupleConstr *constr1 = tupdesc1->constr;
325 TupleConstr *constr2 = tupdesc2->constr;
329 if (constr1->has_not_null != constr2->has_not_null)
331 n = constr1->num_defval;
332 if (n != (int) constr2->num_defval)
334 for (i = 0; i < n; i++)
336 AttrDefault *defval1 = constr1->defval + i;
337 AttrDefault *defval2 = constr2->defval;
340 * We can't assume that the items are always read from the
341 * system catalogs in the same order; so use the adnum field
342 * to identify the matching item to compare.
344 for (j = 0; j < n; defval2++, j++)
346 if (defval1->adnum == defval2->adnum)
351 if (strcmp(defval1->adbin, defval2->adbin) != 0)
354 n = constr1->num_check;
355 if (n != (int) constr2->num_check)
357 for (i = 0; i < n; i++)
359 ConstrCheck *check1 = constr1->check + i;
360 ConstrCheck *check2 = constr2->check;
363 * Similarly, don't assume that the checks are always read in
364 * the same order; match them up by name and contents. (The
365 * name *should* be unique, but...)
367 for (j = 0; j < n; check2++, j++)
369 if (strcmp(check1->ccname, check2->ccname) == 0 &&
370 strcmp(check1->ccbin, check2->ccbin) == 0)
377 else if (tupdesc2->constr != NULL)
382 /* ----------------------------------------------------------------
385 * This function initializes a single attribute structure in
386 * a preallocated tuple descriptor.
387 * ----------------------------------------------------------------
390 TupleDescInitEntry(TupleDesc desc,
391 AttrNumber attributeNumber,
392 const char *attributeName,
398 Form_pg_type typeForm;
399 Form_pg_attribute att;
404 AssertArg(PointerIsValid(desc));
405 AssertArg(attributeNumber >= 1);
406 AssertArg(attributeNumber <= desc->natts);
407 AssertArg(!PointerIsValid(desc->attrs[attributeNumber - 1]));
410 * allocate storage for this attribute
413 att = (Form_pg_attribute) palloc(ATTRIBUTE_TUPLE_SIZE);
414 desc->attrs[attributeNumber - 1] = att;
417 * initialize the attribute fields
419 att->attrelid = 0; /* dummy value */
422 * Note: attributeName can be NULL, because the planner doesn't always
423 * fill in valid resname values in targetlists, particularly for resjunk
426 if (attributeName != NULL)
427 namestrcpy(&(att->attname), attributeName);
429 MemSet(NameStr(att->attname), 0, NAMEDATALEN);
431 att->attstattarget = -1;
432 att->attcacheoff = -1;
433 att->atttypmod = typmod;
435 att->attnum = attributeNumber;
436 att->attndims = attdim;
438 att->attnotnull = false;
439 att->atthasdef = false;
440 att->attisdropped = false;
441 att->attislocal = true;
442 att->attinhcount = 0;
444 tuple = SearchSysCache(TYPEOID,
445 ObjectIdGetDatum(oidtypeid),
447 if (!HeapTupleIsValid(tuple))
448 elog(ERROR, "cache lookup failed for type %u", oidtypeid);
449 typeForm = (Form_pg_type) GETSTRUCT(tuple);
451 att->atttypid = oidtypeid;
452 att->attlen = typeForm->typlen;
453 att->attbyval = typeForm->typbyval;
454 att->attalign = typeForm->typalign;
455 att->attstorage = typeForm->typstorage;
457 ReleaseSysCache(tuple);
462 * BuildDescForRelation
464 * Given a relation schema (list of ColumnDef nodes), build a TupleDesc.
466 * Note: the default assumption is no OIDs; caller may modify the returned
467 * TupleDesc if it wants OIDs. Also, tdtypeid will need to be filled in
471 BuildDescForRelation(List *schema)
477 AttrDefault *attrdef = NULL;
478 TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));
485 * allocate a new tuple descriptor
487 natts = list_length(schema);
488 desc = CreateTemplateTupleDesc(natts, false);
489 constr->has_not_null = false;
495 ColumnDef *entry = lfirst(l);
498 * for each entry in the list, get the name and type information
499 * from the list and have TupleDescInitEntry fill in the attribute
500 * information we need.
504 attname = entry->colname;
505 atttypmod = entry->typename->typmod;
506 attdim = list_length(entry->typename->arrayBounds);
508 if (entry->typename->setof)
510 (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
511 errmsg("column \"%s\" cannot be declared SETOF",
514 TupleDescInitEntry(desc, attnum, attname,
515 typenameTypeId(entry->typename),
518 /* Fill in additional stuff not handled by TupleDescInitEntry */
519 if (entry->is_not_null)
520 constr->has_not_null = true;
521 desc->attrs[attnum - 1]->attnotnull = entry->is_not_null;
524 * Note we copy only pre-cooked default expressions. Digestion of
525 * raw ones is someone else's problem.
527 if (entry->cooked_default != NULL)
530 attrdef = (AttrDefault *) palloc(natts * sizeof(AttrDefault));
531 attrdef[ndef].adnum = attnum;
532 attrdef[ndef].adbin = pstrdup(entry->cooked_default);
534 desc->attrs[attnum - 1]->atthasdef = true;
537 desc->attrs[attnum - 1]->attislocal = entry->is_local;
538 desc->attrs[attnum - 1]->attinhcount = entry->inhcount;
541 if (constr->has_not_null || ndef > 0)
543 desc->constr = constr;
545 if (ndef > 0) /* DEFAULTs */
548 constr->defval = (AttrDefault *)
549 repalloc(attrdef, ndef * sizeof(AttrDefault));
551 constr->defval = attrdef;
552 constr->num_defval = ndef;
556 constr->defval = NULL;
557 constr->num_defval = 0;
559 constr->check = NULL;
560 constr->num_check = 0;
573 * RelationNameGetTupleDesc
575 * Given a (possibly qualified) relation name, build a TupleDesc.
578 RelationNameGetTupleDesc(const char *relname)
585 /* Open relation and copy the tuple description */
586 relname_list = stringToQualifiedNameList(relname, "RelationNameGetTupleDesc");
587 relvar = makeRangeVarFromNameList(relname_list);
588 rel = relation_openrv(relvar, AccessShareLock);
589 tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));
590 relation_close(rel, AccessShareLock);
598 * Given a type Oid, build a TupleDesc.
600 * If the type is composite, *and* a colaliases List is provided, *and*
601 * the List is of natts length, use the aliases instead of the relation
602 * attnames. (NB: this usage is deprecated since it may result in
603 * creation of unnecessary transient record types.)
605 * If the type is a base type, a single item alias List is required.
608 TypeGetTupleDesc(Oid typeoid, List *colaliases)
610 char functyptype = get_typtype(typeoid);
611 TupleDesc tupdesc = NULL;
614 * Build a suitable tupledesc representing the output rows
616 if (functyptype == 'c')
618 /* Composite data type, e.g. a table's row type */
619 tupdesc = CreateTupleDescCopy(lookup_rowtype_tupdesc(typeoid, -1));
621 if (colaliases != NIL)
623 int natts = tupdesc->natts;
626 /* does the list length match the number of attributes? */
627 if (list_length(colaliases) != natts)
629 (errcode(ERRCODE_DATATYPE_MISMATCH),
630 errmsg("number of aliases does not match number of columns")));
632 /* OK, use the aliases instead */
633 for (varattno = 0; varattno < natts; varattno++)
635 char *label = strVal(list_nth(colaliases, varattno));
638 namestrcpy(&(tupdesc->attrs[varattno]->attname), label);
641 /* The tuple type is now an anonymous record type */
642 tupdesc->tdtypeid = RECORDOID;
643 tupdesc->tdtypmod = -1;
646 else if (functyptype == 'b' || functyptype == 'd')
648 /* Must be a base data type, i.e. scalar */
651 /* the alias list is required for base types */
652 if (colaliases == NIL)
654 (errcode(ERRCODE_DATATYPE_MISMATCH),
655 errmsg("no column alias was provided")));
657 /* the alias list length must be 1 */
658 if (list_length(colaliases) != 1)
660 (errcode(ERRCODE_DATATYPE_MISMATCH),
661 errmsg("number of aliases does not match number of columns")));
663 /* OK, get the column alias */
664 attname = strVal(linitial(colaliases));
666 tupdesc = CreateTemplateTupleDesc(1, false);
667 TupleDescInitEntry(tupdesc,
674 else if (typeoid == RECORDOID)
676 /* XXX can't support this because typmod wasn't passed in ... */
678 (errcode(ERRCODE_DATATYPE_MISMATCH),
679 errmsg("could not determine row description for function returning record")));
683 /* crummy error message, but parser should have caught this */
684 elog(ERROR, "function in FROM has unsupported return type");