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 : }
|