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