At update of non-LP_NORMAL TID, fail instead of corrupting page header.
[pgsql.git] / src / backend / access / common / tupdesc.c
blobfe197447912c4485adb2739dd8dce0142f0534cf
1 /*-------------------------------------------------------------------------
3 * tupdesc.c
4 * POSTGRES tuple descriptor support code
6 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
10 * IDENTIFICATION
11 * src/backend/access/common/tupdesc.c
13 * NOTES
14 * some of the executor utility code such as "ExecTypeFromTL" should be
15 * moved here.
17 *-------------------------------------------------------------------------
20 #include "postgres.h"
22 #include "access/htup_details.h"
23 #include "access/toast_compression.h"
24 #include "access/tupdesc_details.h"
25 #include "catalog/pg_collation.h"
26 #include "catalog/pg_type.h"
27 #include "common/hashfn.h"
28 #include "utils/builtins.h"
29 #include "utils/datum.h"
30 #include "utils/resowner.h"
31 #include "utils/syscache.h"
33 /* ResourceOwner callbacks to hold tupledesc references */
34 static void ResOwnerReleaseTupleDesc(Datum res);
35 static char *ResOwnerPrintTupleDesc(Datum res);
37 static const ResourceOwnerDesc tupdesc_resowner_desc =
39 .name = "tupdesc reference",
40 .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
41 .release_priority = RELEASE_PRIO_TUPDESC_REFS,
42 .ReleaseResource = ResOwnerReleaseTupleDesc,
43 .DebugPrint = ResOwnerPrintTupleDesc
46 /* Convenience wrappers over ResourceOwnerRemember/Forget */
47 static inline void
48 ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
50 ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
53 static inline void
54 ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
56 ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
60 * populate_compact_attribute_internal
61 * Helper function for populate_compact_attribute()
63 static inline void
64 populate_compact_attribute_internal(Form_pg_attribute src,
65 CompactAttribute *dst)
67 memset(dst, 0, sizeof(CompactAttribute));
69 dst->attcacheoff = -1;
70 dst->attlen = src->attlen;
72 dst->attbyval = src->attbyval;
73 dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
74 dst->atthasmissing = src->atthasmissing;
75 dst->attisdropped = src->attisdropped;
76 dst->attgenerated = (src->attgenerated != '\0');
77 dst->attnotnull = src->attnotnull;
79 switch (src->attalign)
81 case TYPALIGN_INT:
82 dst->attalignby = ALIGNOF_INT;
83 break;
84 case TYPALIGN_CHAR:
85 dst->attalignby = sizeof(char);
86 break;
87 case TYPALIGN_DOUBLE:
88 dst->attalignby = ALIGNOF_DOUBLE;
89 break;
90 case TYPALIGN_SHORT:
91 dst->attalignby = ALIGNOF_SHORT;
92 break;
93 default:
94 dst->attalignby = 0;
95 elog(ERROR, "invalid attalign value: %c", src->attalign);
96 break;
101 * populate_compact_attribute
102 * Fill in the corresponding CompactAttribute element from the
103 * Form_pg_attribute for the given attribute number. This must be called
104 * whenever a change is made to a Form_pg_attribute in the TupleDesc.
106 void
107 populate_compact_attribute(TupleDesc tupdesc, int attnum)
109 Form_pg_attribute src = TupleDescAttr(tupdesc, attnum);
110 CompactAttribute *dst;
113 * Don't use TupleDescCompactAttr to prevent infinite recursion in assert
114 * builds.
116 dst = &tupdesc->compact_attrs[attnum];
118 populate_compact_attribute_internal(src, dst);
122 * verify_compact_attribute
123 * In Assert enabled builds, we verify that the CompactAttribute is
124 * populated correctly. This helps find bugs in places such as ALTER
125 * TABLE where code makes changes to the FormData_pg_attribute but
126 * forgets to call populate_compact_attribute().
128 * This is used in TupleDescCompactAttr(), but declared here to allow access
129 * to populate_compact_attribute_internal().
131 void
132 verify_compact_attribute(TupleDesc tupdesc, int attnum)
134 #ifdef USE_ASSERT_CHECKING
135 CompactAttribute *cattr = &tupdesc->compact_attrs[attnum];
136 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum);
137 CompactAttribute tmp;
140 * Populate the temporary CompactAttribute from the corresponding
141 * Form_pg_attribute
143 populate_compact_attribute_internal(attr, &tmp);
146 * Make the attcacheoff match since it's been reset to -1 by
147 * populate_compact_attribute_internal.
149 tmp.attcacheoff = cattr->attcacheoff;
151 /* Check the freshly populated CompactAttribute matches the TupleDesc's */
152 Assert(memcmp(&tmp, cattr, sizeof(CompactAttribute)) == 0);
153 #endif
157 * CreateTemplateTupleDesc
158 * This function allocates an empty tuple descriptor structure.
160 * Tuple type ID information is initially set for an anonymous record type;
161 * caller can overwrite this if needed.
163 TupleDesc
164 CreateTemplateTupleDesc(int natts)
166 TupleDesc desc;
169 * sanity checks
171 Assert(natts >= 0);
174 * Allocate enough memory for the tuple descriptor, the CompactAttribute
175 * array and also an array of FormData_pg_attribute.
177 * Note: the FormData_pg_attribute array stride is
178 * sizeof(FormData_pg_attribute), since we declare the array elements as
179 * FormData_pg_attribute for notational convenience. However, we only
180 * guarantee that the first ATTRIBUTE_FIXED_PART_SIZE bytes of each entry
181 * are valid; most code that copies tupdesc entries around copies just
182 * that much. In principle that could be less due to trailing padding,
183 * although with the current definition of pg_attribute there probably
184 * isn't any padding.
186 desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
187 natts * sizeof(CompactAttribute) +
188 natts * sizeof(FormData_pg_attribute));
191 * Initialize other fields of the tupdesc.
193 desc->natts = natts;
194 desc->constr = NULL;
195 desc->tdtypeid = RECORDOID;
196 desc->tdtypmod = -1;
197 desc->tdrefcount = -1; /* assume not reference-counted */
199 return desc;
203 * CreateTupleDesc
204 * This function allocates a new TupleDesc by copying a given
205 * Form_pg_attribute array.
207 * Tuple type ID information is initially set for an anonymous record type;
208 * caller can overwrite this if needed.
210 TupleDesc
211 CreateTupleDesc(int natts, Form_pg_attribute *attrs)
213 TupleDesc desc;
214 int i;
216 desc = CreateTemplateTupleDesc(natts);
218 for (i = 0; i < natts; ++i)
220 memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
221 populate_compact_attribute(desc, i);
223 return desc;
227 * CreateTupleDescCopy
228 * This function creates a new TupleDesc by copying from an existing
229 * TupleDesc.
231 * !!! Constraints and defaults are not copied !!!
233 TupleDesc
234 CreateTupleDescCopy(TupleDesc tupdesc)
236 TupleDesc desc;
237 int i;
239 desc = CreateTemplateTupleDesc(tupdesc->natts);
241 /* Flat-copy the attribute array */
242 memcpy(TupleDescAttr(desc, 0),
243 TupleDescAttr(tupdesc, 0),
244 desc->natts * sizeof(FormData_pg_attribute));
247 * Since we're not copying constraints and defaults, clear fields
248 * associated with them.
250 for (i = 0; i < desc->natts; i++)
252 Form_pg_attribute att = TupleDescAttr(desc, i);
254 att->attnotnull = false;
255 att->atthasdef = false;
256 att->atthasmissing = false;
257 att->attidentity = '\0';
258 att->attgenerated = '\0';
260 populate_compact_attribute(desc, i);
263 /* We can copy the tuple type identification, too */
264 desc->tdtypeid = tupdesc->tdtypeid;
265 desc->tdtypmod = tupdesc->tdtypmod;
267 return desc;
271 * CreateTupleDescTruncatedCopy
272 * This function creates a new TupleDesc with only the first 'natts'
273 * attributes from an existing TupleDesc
275 * !!! Constraints and defaults are not copied !!!
277 TupleDesc
278 CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
280 TupleDesc desc;
281 int i;
283 Assert(natts <= tupdesc->natts);
285 desc = CreateTemplateTupleDesc(natts);
287 /* Flat-copy the attribute array */
288 memcpy(TupleDescAttr(desc, 0),
289 TupleDescAttr(tupdesc, 0),
290 desc->natts * sizeof(FormData_pg_attribute));
293 * Since we're not copying constraints and defaults, clear fields
294 * associated with them.
296 for (i = 0; i < desc->natts; i++)
298 Form_pg_attribute att = TupleDescAttr(desc, i);
300 att->attnotnull = false;
301 att->atthasdef = false;
302 att->atthasmissing = false;
303 att->attidentity = '\0';
304 att->attgenerated = '\0';
306 populate_compact_attribute(desc, i);
309 /* We can copy the tuple type identification, too */
310 desc->tdtypeid = tupdesc->tdtypeid;
311 desc->tdtypmod = tupdesc->tdtypmod;
313 return desc;
317 * CreateTupleDescCopyConstr
318 * This function creates a new TupleDesc by copying from an existing
319 * TupleDesc (including its constraints and defaults).
321 TupleDesc
322 CreateTupleDescCopyConstr(TupleDesc tupdesc)
324 TupleDesc desc;
325 TupleConstr *constr = tupdesc->constr;
326 int i;
328 desc = CreateTemplateTupleDesc(tupdesc->natts);
330 /* Flat-copy the attribute array */
331 memcpy(TupleDescAttr(desc, 0),
332 TupleDescAttr(tupdesc, 0),
333 desc->natts * sizeof(FormData_pg_attribute));
335 for (i = 0; i < desc->natts; i++)
336 populate_compact_attribute(desc, i);
338 /* Copy the TupleConstr data structure, if any */
339 if (constr)
341 TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
343 cpy->has_not_null = constr->has_not_null;
344 cpy->has_generated_stored = constr->has_generated_stored;
346 if ((cpy->num_defval = constr->num_defval) > 0)
348 cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
349 memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
350 for (i = cpy->num_defval - 1; i >= 0; i--)
351 cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
354 if (constr->missing)
356 cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
357 memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
358 for (i = tupdesc->natts - 1; i >= 0; i--)
360 if (constr->missing[i].am_present)
362 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
364 cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
365 attr->attbyval,
366 attr->attlen);
371 if ((cpy->num_check = constr->num_check) > 0)
373 cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
374 memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
375 for (i = cpy->num_check - 1; i >= 0; i--)
377 cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
378 cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
379 cpy->check[i].ccenforced = constr->check[i].ccenforced;
380 cpy->check[i].ccvalid = constr->check[i].ccvalid;
381 cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
385 desc->constr = cpy;
388 /* We can copy the tuple type identification, too */
389 desc->tdtypeid = tupdesc->tdtypeid;
390 desc->tdtypmod = tupdesc->tdtypmod;
392 return desc;
396 * TupleDescCopy
397 * Copy a tuple descriptor into caller-supplied memory.
398 * The memory may be shared memory mapped at any address, and must
399 * be sufficient to hold TupleDescSize(src) bytes.
401 * !!! Constraints and defaults are not copied !!!
403 void
404 TupleDescCopy(TupleDesc dst, TupleDesc src)
406 int i;
408 /* Flat-copy the header and attribute arrays */
409 memcpy(dst, src, TupleDescSize(src));
412 * Since we're not copying constraints and defaults, clear fields
413 * associated with them.
415 for (i = 0; i < dst->natts; i++)
417 Form_pg_attribute att = TupleDescAttr(dst, i);
419 att->attnotnull = false;
420 att->atthasdef = false;
421 att->atthasmissing = false;
422 att->attidentity = '\0';
423 att->attgenerated = '\0';
425 populate_compact_attribute(dst, i);
427 dst->constr = NULL;
430 * Also, assume the destination is not to be ref-counted. (Copying the
431 * source's refcount would be wrong in any case.)
433 dst->tdrefcount = -1;
437 * TupleDescCopyEntry
438 * This function copies a single attribute structure from one tuple
439 * descriptor to another.
441 * !!! Constraints and defaults are not copied !!!
443 void
444 TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
445 TupleDesc src, AttrNumber srcAttno)
447 Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
448 Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
451 * sanity checks
453 Assert(PointerIsValid(src));
454 Assert(PointerIsValid(dst));
455 Assert(srcAttno >= 1);
456 Assert(srcAttno <= src->natts);
457 Assert(dstAttno >= 1);
458 Assert(dstAttno <= dst->natts);
460 memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
462 dstAtt->attnum = dstAttno;
464 /* since we're not copying constraints or defaults, clear these */
465 dstAtt->attnotnull = false;
466 dstAtt->atthasdef = false;
467 dstAtt->atthasmissing = false;
468 dstAtt->attidentity = '\0';
469 dstAtt->attgenerated = '\0';
471 populate_compact_attribute(dst, dstAttno - 1);
475 * Free a TupleDesc including all substructure
477 void
478 FreeTupleDesc(TupleDesc tupdesc)
480 int i;
483 * Possibly this should assert tdrefcount == 0, to disallow explicit
484 * freeing of un-refcounted tupdescs?
486 Assert(tupdesc->tdrefcount <= 0);
488 if (tupdesc->constr)
490 if (tupdesc->constr->num_defval > 0)
492 AttrDefault *attrdef = tupdesc->constr->defval;
494 for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
495 pfree(attrdef[i].adbin);
496 pfree(attrdef);
498 if (tupdesc->constr->missing)
500 AttrMissing *attrmiss = tupdesc->constr->missing;
502 for (i = tupdesc->natts - 1; i >= 0; i--)
504 if (attrmiss[i].am_present
505 && !TupleDescAttr(tupdesc, i)->attbyval)
506 pfree(DatumGetPointer(attrmiss[i].am_value));
508 pfree(attrmiss);
510 if (tupdesc->constr->num_check > 0)
512 ConstrCheck *check = tupdesc->constr->check;
514 for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
516 pfree(check[i].ccname);
517 pfree(check[i].ccbin);
519 pfree(check);
521 pfree(tupdesc->constr);
524 pfree(tupdesc);
528 * Increment the reference count of a tupdesc, and log the reference in
529 * CurrentResourceOwner.
531 * Do not apply this to tupdescs that are not being refcounted. (Use the
532 * macro PinTupleDesc for tupdescs of uncertain status.)
534 void
535 IncrTupleDescRefCount(TupleDesc tupdesc)
537 Assert(tupdesc->tdrefcount >= 0);
539 ResourceOwnerEnlarge(CurrentResourceOwner);
540 tupdesc->tdrefcount++;
541 ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
545 * Decrement the reference count of a tupdesc, remove the corresponding
546 * reference from CurrentResourceOwner, and free the tupdesc if no more
547 * references remain.
549 * Do not apply this to tupdescs that are not being refcounted. (Use the
550 * macro ReleaseTupleDesc for tupdescs of uncertain status.)
552 void
553 DecrTupleDescRefCount(TupleDesc tupdesc)
555 Assert(tupdesc->tdrefcount > 0);
557 ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
558 if (--tupdesc->tdrefcount == 0)
559 FreeTupleDesc(tupdesc);
563 * Compare two TupleDesc structures for logical equality
565 bool
566 equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
568 int i,
571 if (tupdesc1->natts != tupdesc2->natts)
572 return false;
573 if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
574 return false;
576 /* tdtypmod and tdrefcount are not checked */
578 for (i = 0; i < tupdesc1->natts; i++)
580 Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
581 Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
584 * We do not need to check every single field here: we can disregard
585 * attrelid and attnum (which were used to place the row in the attrs
586 * array in the first place). It might look like we could dispense
587 * with checking attlen/attbyval/attalign, since these are derived
588 * from atttypid; but in the case of dropped columns we must check
589 * them (since atttypid will be zero for all dropped columns) and in
590 * general it seems safer to check them always.
592 * We intentionally ignore atthasmissing, since that's not very
593 * relevant in tupdescs, which lack the attmissingval field.
595 if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
596 return false;
597 if (attr1->atttypid != attr2->atttypid)
598 return false;
599 if (attr1->attlen != attr2->attlen)
600 return false;
601 if (attr1->attndims != attr2->attndims)
602 return false;
603 if (attr1->atttypmod != attr2->atttypmod)
604 return false;
605 if (attr1->attbyval != attr2->attbyval)
606 return false;
607 if (attr1->attalign != attr2->attalign)
608 return false;
609 if (attr1->attstorage != attr2->attstorage)
610 return false;
611 if (attr1->attcompression != attr2->attcompression)
612 return false;
613 if (attr1->attnotnull != attr2->attnotnull)
614 return false;
615 if (attr1->atthasdef != attr2->atthasdef)
616 return false;
617 if (attr1->attidentity != attr2->attidentity)
618 return false;
619 if (attr1->attgenerated != attr2->attgenerated)
620 return false;
621 if (attr1->attisdropped != attr2->attisdropped)
622 return false;
623 if (attr1->attislocal != attr2->attislocal)
624 return false;
625 if (attr1->attinhcount != attr2->attinhcount)
626 return false;
627 if (attr1->attcollation != attr2->attcollation)
628 return false;
629 /* variable-length fields are not even present... */
632 if (tupdesc1->constr != NULL)
634 TupleConstr *constr1 = tupdesc1->constr;
635 TupleConstr *constr2 = tupdesc2->constr;
637 if (constr2 == NULL)
638 return false;
639 if (constr1->has_not_null != constr2->has_not_null)
640 return false;
641 if (constr1->has_generated_stored != constr2->has_generated_stored)
642 return false;
643 n = constr1->num_defval;
644 if (n != (int) constr2->num_defval)
645 return false;
646 /* We assume here that both AttrDefault arrays are in adnum order */
647 for (i = 0; i < n; i++)
649 AttrDefault *defval1 = constr1->defval + i;
650 AttrDefault *defval2 = constr2->defval + i;
652 if (defval1->adnum != defval2->adnum)
653 return false;
654 if (strcmp(defval1->adbin, defval2->adbin) != 0)
655 return false;
657 if (constr1->missing)
659 if (!constr2->missing)
660 return false;
661 for (i = 0; i < tupdesc1->natts; i++)
663 AttrMissing *missval1 = constr1->missing + i;
664 AttrMissing *missval2 = constr2->missing + i;
666 if (missval1->am_present != missval2->am_present)
667 return false;
668 if (missval1->am_present)
670 CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
672 if (!datumIsEqual(missval1->am_value, missval2->am_value,
673 missatt1->attbyval, missatt1->attlen))
674 return false;
678 else if (constr2->missing)
679 return false;
680 n = constr1->num_check;
681 if (n != (int) constr2->num_check)
682 return false;
685 * Similarly, we rely here on the ConstrCheck entries being sorted by
686 * name. If there are duplicate names, the outcome of the comparison
687 * is uncertain, but that should not happen.
689 for (i = 0; i < n; i++)
691 ConstrCheck *check1 = constr1->check + i;
692 ConstrCheck *check2 = constr2->check + i;
694 if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
695 strcmp(check1->ccbin, check2->ccbin) == 0 &&
696 check1->ccenforced == check2->ccenforced &&
697 check1->ccvalid == check2->ccvalid &&
698 check1->ccnoinherit == check2->ccnoinherit))
699 return false;
702 else if (tupdesc2->constr != NULL)
703 return false;
704 return true;
708 * equalRowTypes
710 * This determines whether two tuple descriptors have equal row types. This
711 * only checks those fields in pg_attribute that are applicable for row types,
712 * while ignoring those fields that define the physical row storage or those
713 * that define table column metadata.
715 * Specifically, this checks:
717 * - same number of attributes
718 * - same composite type ID (but could both be zero)
719 * - corresponding attributes (in order) have same the name, type, typmod,
720 * collation
722 * This is used to check whether two record types are compatible, whether
723 * function return row types are the same, and other similar situations.
725 * (XXX There was some discussion whether attndims should be checked here, but
726 * for now it has been decided not to.)
728 * Note: We deliberately do not check the tdtypmod field. This allows
729 * typcache.c to use this routine to see if a cached record type matches a
730 * requested type.
732 bool
733 equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
735 if (tupdesc1->natts != tupdesc2->natts)
736 return false;
737 if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
738 return false;
740 for (int i = 0; i < tupdesc1->natts; i++)
742 Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
743 Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
745 if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
746 return false;
747 if (attr1->atttypid != attr2->atttypid)
748 return false;
749 if (attr1->atttypmod != attr2->atttypmod)
750 return false;
751 if (attr1->attcollation != attr2->attcollation)
752 return false;
754 /* Record types derived from tables could have dropped fields. */
755 if (attr1->attisdropped != attr2->attisdropped)
756 return false;
759 return true;
763 * hashRowType
765 * If two tuple descriptors would be considered equal by equalRowTypes()
766 * then their hash value will be equal according to this function.
768 uint32
769 hashRowType(TupleDesc desc)
771 uint32 s;
772 int i;
774 s = hash_combine(0, hash_uint32(desc->natts));
775 s = hash_combine(s, hash_uint32(desc->tdtypeid));
776 for (i = 0; i < desc->natts; ++i)
777 s = hash_combine(s, hash_uint32(TupleDescAttr(desc, i)->atttypid));
779 return s;
783 * TupleDescInitEntry
784 * This function initializes a single attribute structure in
785 * a previously allocated tuple descriptor.
787 * If attributeName is NULL, the attname field is set to an empty string
788 * (this is for cases where we don't know or need a name for the field).
789 * Also, some callers use this function to change the datatype-related fields
790 * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
791 * to indicate that the attname field shouldn't be modified.
793 * Note that attcollation is set to the default for the specified datatype.
794 * If a nondefault collation is needed, insert it afterwards using
795 * TupleDescInitEntryCollation.
797 void
798 TupleDescInitEntry(TupleDesc desc,
799 AttrNumber attributeNumber,
800 const char *attributeName,
801 Oid oidtypeid,
802 int32 typmod,
803 int attdim)
805 HeapTuple tuple;
806 Form_pg_type typeForm;
807 Form_pg_attribute att;
810 * sanity checks
812 Assert(PointerIsValid(desc));
813 Assert(attributeNumber >= 1);
814 Assert(attributeNumber <= desc->natts);
815 Assert(attdim >= 0);
816 Assert(attdim <= PG_INT16_MAX);
819 * initialize the attribute fields
821 att = TupleDescAttr(desc, attributeNumber - 1);
823 att->attrelid = 0; /* dummy value */
826 * Note: attributeName can be NULL, because the planner doesn't always
827 * fill in valid resname values in targetlists, particularly for resjunk
828 * attributes. Also, do nothing if caller wants to re-use the old attname.
830 if (attributeName == NULL)
831 MemSet(NameStr(att->attname), 0, NAMEDATALEN);
832 else if (attributeName != NameStr(att->attname))
833 namestrcpy(&(att->attname), attributeName);
835 att->atttypmod = typmod;
837 att->attnum = attributeNumber;
838 att->attndims = attdim;
840 att->attnotnull = false;
841 att->atthasdef = false;
842 att->atthasmissing = false;
843 att->attidentity = '\0';
844 att->attgenerated = '\0';
845 att->attisdropped = false;
846 att->attislocal = true;
847 att->attinhcount = 0;
848 /* variable-length fields are not present in tupledescs */
850 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
851 if (!HeapTupleIsValid(tuple))
852 elog(ERROR, "cache lookup failed for type %u", oidtypeid);
853 typeForm = (Form_pg_type) GETSTRUCT(tuple);
855 att->atttypid = oidtypeid;
856 att->attlen = typeForm->typlen;
857 att->attbyval = typeForm->typbyval;
858 att->attalign = typeForm->typalign;
859 att->attstorage = typeForm->typstorage;
860 att->attcompression = InvalidCompressionMethod;
861 att->attcollation = typeForm->typcollation;
863 populate_compact_attribute(desc, attributeNumber - 1);
865 ReleaseSysCache(tuple);
869 * TupleDescInitBuiltinEntry
870 * Initialize a tuple descriptor without catalog access. Only
871 * a limited range of builtin types are supported.
873 void
874 TupleDescInitBuiltinEntry(TupleDesc desc,
875 AttrNumber attributeNumber,
876 const char *attributeName,
877 Oid oidtypeid,
878 int32 typmod,
879 int attdim)
881 Form_pg_attribute att;
883 /* sanity checks */
884 Assert(PointerIsValid(desc));
885 Assert(attributeNumber >= 1);
886 Assert(attributeNumber <= desc->natts);
887 Assert(attdim >= 0);
888 Assert(attdim <= PG_INT16_MAX);
890 /* initialize the attribute fields */
891 att = TupleDescAttr(desc, attributeNumber - 1);
892 att->attrelid = 0; /* dummy value */
894 /* unlike TupleDescInitEntry, we require an attribute name */
895 Assert(attributeName != NULL);
896 namestrcpy(&(att->attname), attributeName);
898 att->atttypmod = typmod;
900 att->attnum = attributeNumber;
901 att->attndims = attdim;
903 att->attnotnull = false;
904 att->atthasdef = false;
905 att->atthasmissing = false;
906 att->attidentity = '\0';
907 att->attgenerated = '\0';
908 att->attisdropped = false;
909 att->attislocal = true;
910 att->attinhcount = 0;
911 /* variable-length fields are not present in tupledescs */
913 att->atttypid = oidtypeid;
916 * Our goal here is to support just enough types to let basic builtin
917 * commands work without catalog access - e.g. so that we can do certain
918 * things even in processes that are not connected to a database.
920 switch (oidtypeid)
922 case TEXTOID:
923 case TEXTARRAYOID:
924 att->attlen = -1;
925 att->attbyval = false;
926 att->attalign = TYPALIGN_INT;
927 att->attstorage = TYPSTORAGE_EXTENDED;
928 att->attcompression = InvalidCompressionMethod;
929 att->attcollation = DEFAULT_COLLATION_OID;
930 break;
932 case BOOLOID:
933 att->attlen = 1;
934 att->attbyval = true;
935 att->attalign = TYPALIGN_CHAR;
936 att->attstorage = TYPSTORAGE_PLAIN;
937 att->attcompression = InvalidCompressionMethod;
938 att->attcollation = InvalidOid;
939 break;
941 case INT4OID:
942 att->attlen = 4;
943 att->attbyval = true;
944 att->attalign = TYPALIGN_INT;
945 att->attstorage = TYPSTORAGE_PLAIN;
946 att->attcompression = InvalidCompressionMethod;
947 att->attcollation = InvalidOid;
948 break;
950 case INT8OID:
951 att->attlen = 8;
952 att->attbyval = FLOAT8PASSBYVAL;
953 att->attalign = TYPALIGN_DOUBLE;
954 att->attstorage = TYPSTORAGE_PLAIN;
955 att->attcompression = InvalidCompressionMethod;
956 att->attcollation = InvalidOid;
957 break;
959 case OIDOID:
960 att->attlen = 4;
961 att->attbyval = true;
962 att->attalign = TYPALIGN_INT;
963 att->attstorage = TYPSTORAGE_PLAIN;
964 att->attcompression = InvalidCompressionMethod;
965 att->attcollation = InvalidOid;
966 break;
968 default:
969 elog(ERROR, "unsupported type %u", oidtypeid);
972 populate_compact_attribute(desc, attributeNumber - 1);
976 * TupleDescInitEntryCollation
978 * Assign a nondefault collation to a previously initialized tuple descriptor
979 * entry.
981 void
982 TupleDescInitEntryCollation(TupleDesc desc,
983 AttrNumber attributeNumber,
984 Oid collationid)
987 * sanity checks
989 Assert(PointerIsValid(desc));
990 Assert(attributeNumber >= 1);
991 Assert(attributeNumber <= desc->natts);
993 TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
997 * BuildDescFromLists
999 * Build a TupleDesc given lists of column names (as String nodes),
1000 * column type OIDs, typmods, and collation OIDs.
1002 * No constraints are generated.
1004 * This is for use with functions returning RECORD.
1006 TupleDesc
1007 BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
1009 int natts;
1010 AttrNumber attnum;
1011 ListCell *l1;
1012 ListCell *l2;
1013 ListCell *l3;
1014 ListCell *l4;
1015 TupleDesc desc;
1017 natts = list_length(names);
1018 Assert(natts == list_length(types));
1019 Assert(natts == list_length(typmods));
1020 Assert(natts == list_length(collations));
1023 * allocate a new tuple descriptor
1025 desc = CreateTemplateTupleDesc(natts);
1027 attnum = 0;
1028 forfour(l1, names, l2, types, l3, typmods, l4, collations)
1030 char *attname = strVal(lfirst(l1));
1031 Oid atttypid = lfirst_oid(l2);
1032 int32 atttypmod = lfirst_int(l3);
1033 Oid attcollation = lfirst_oid(l4);
1035 attnum++;
1037 TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
1038 TupleDescInitEntryCollation(desc, attnum, attcollation);
1041 return desc;
1045 * Get default expression (or NULL if none) for the given attribute number.
1047 Node *
1048 TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
1050 Node *result = NULL;
1052 if (tupdesc->constr)
1054 AttrDefault *attrdef = tupdesc->constr->defval;
1056 for (int i = 0; i < tupdesc->constr->num_defval; i++)
1058 if (attrdef[i].adnum == attnum)
1060 result = stringToNode(attrdef[i].adbin);
1061 break;
1066 return result;
1069 /* ResourceOwner callbacks */
1071 static void
1072 ResOwnerReleaseTupleDesc(Datum res)
1074 TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1076 /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
1077 Assert(tupdesc->tdrefcount > 0);
1078 if (--tupdesc->tdrefcount == 0)
1079 FreeTupleDesc(tupdesc);
1082 static char *
1083 ResOwnerPrintTupleDesc(Datum res)
1085 TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1087 return psprintf("TupleDesc %p (%u,%d)",
1088 tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);