1 /*-------------------------------------------------------------------------
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
11 * src/backend/access/common/tupdesc.c
14 * some of the executor utility code such as "ExecTypeFromTL" should be
17 *-------------------------------------------------------------------------
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 */
48 ResourceOwnerRememberTupleDesc(ResourceOwner owner
, TupleDesc tupdesc
)
50 ResourceOwnerRemember(owner
, PointerGetDatum(tupdesc
), &tupdesc_resowner_desc
);
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()
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
)
82 dst
->attalignby
= ALIGNOF_INT
;
85 dst
->attalignby
= sizeof(char);
88 dst
->attalignby
= ALIGNOF_DOUBLE
;
91 dst
->attalignby
= ALIGNOF_SHORT
;
95 elog(ERROR
, "invalid attalign value: %c", src
->attalign
);
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.
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
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().
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
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);
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.
164 CreateTemplateTupleDesc(int natts
)
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
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.
195 desc
->tdtypeid
= RECORDOID
;
197 desc
->tdrefcount
= -1; /* assume not reference-counted */
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.
211 CreateTupleDesc(int natts
, Form_pg_attribute
*attrs
)
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
);
227 * CreateTupleDescCopy
228 * This function creates a new TupleDesc by copying from an existing
231 * !!! Constraints and defaults are not copied !!!
234 CreateTupleDescCopy(TupleDesc tupdesc
)
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
;
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 !!!
278 CreateTupleDescTruncatedCopy(TupleDesc tupdesc
, int natts
)
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
;
317 * CreateTupleDescCopyConstr
318 * This function creates a new TupleDesc by copying from an existing
319 * TupleDesc (including its constraints and defaults).
322 CreateTupleDescCopyConstr(TupleDesc tupdesc
)
325 TupleConstr
*constr
= tupdesc
->constr
;
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 */
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
);
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
,
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
;
388 /* We can copy the tuple type identification, too */
389 desc
->tdtypeid
= tupdesc
->tdtypeid
;
390 desc
->tdtypmod
= tupdesc
->tdtypmod
;
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 !!!
404 TupleDescCopy(TupleDesc dst
, TupleDesc src
)
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
);
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;
438 * This function copies a single attribute structure from one tuple
439 * descriptor to another.
441 * !!! Constraints and defaults are not copied !!!
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);
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
478 FreeTupleDesc(TupleDesc tupdesc
)
483 * Possibly this should assert tdrefcount == 0, to disallow explicit
484 * freeing of un-refcounted tupdescs?
486 Assert(tupdesc
->tdrefcount
<= 0);
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
);
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
));
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
);
521 pfree(tupdesc
->constr
);
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.)
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
549 * Do not apply this to tupdescs that are not being refcounted. (Use the
550 * macro ReleaseTupleDesc for tupdescs of uncertain status.)
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
566 equalTupleDescs(TupleDesc tupdesc1
, TupleDesc tupdesc2
)
571 if (tupdesc1
->natts
!= tupdesc2
->natts
)
573 if (tupdesc1
->tdtypeid
!= tupdesc2
->tdtypeid
)
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)
597 if (attr1
->atttypid
!= attr2
->atttypid
)
599 if (attr1
->attlen
!= attr2
->attlen
)
601 if (attr1
->attndims
!= attr2
->attndims
)
603 if (attr1
->atttypmod
!= attr2
->atttypmod
)
605 if (attr1
->attbyval
!= attr2
->attbyval
)
607 if (attr1
->attalign
!= attr2
->attalign
)
609 if (attr1
->attstorage
!= attr2
->attstorage
)
611 if (attr1
->attcompression
!= attr2
->attcompression
)
613 if (attr1
->attnotnull
!= attr2
->attnotnull
)
615 if (attr1
->atthasdef
!= attr2
->atthasdef
)
617 if (attr1
->attidentity
!= attr2
->attidentity
)
619 if (attr1
->attgenerated
!= attr2
->attgenerated
)
621 if (attr1
->attisdropped
!= attr2
->attisdropped
)
623 if (attr1
->attislocal
!= attr2
->attislocal
)
625 if (attr1
->attinhcount
!= attr2
->attinhcount
)
627 if (attr1
->attcollation
!= attr2
->attcollation
)
629 /* variable-length fields are not even present... */
632 if (tupdesc1
->constr
!= NULL
)
634 TupleConstr
*constr1
= tupdesc1
->constr
;
635 TupleConstr
*constr2
= tupdesc2
->constr
;
639 if (constr1
->has_not_null
!= constr2
->has_not_null
)
641 if (constr1
->has_generated_stored
!= constr2
->has_generated_stored
)
643 n
= constr1
->num_defval
;
644 if (n
!= (int) constr2
->num_defval
)
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
)
654 if (strcmp(defval1
->adbin
, defval2
->adbin
) != 0)
657 if (constr1
->missing
)
659 if (!constr2
->missing
)
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
)
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
))
678 else if (constr2
->missing
)
680 n
= constr1
->num_check
;
681 if (n
!= (int) constr2
->num_check
)
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
))
702 else if (tupdesc2
->constr
!= NULL
)
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,
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
733 equalRowTypes(TupleDesc tupdesc1
, TupleDesc tupdesc2
)
735 if (tupdesc1
->natts
!= tupdesc2
->natts
)
737 if (tupdesc1
->tdtypeid
!= tupdesc2
->tdtypeid
)
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)
747 if (attr1
->atttypid
!= attr2
->atttypid
)
749 if (attr1
->atttypmod
!= attr2
->atttypmod
)
751 if (attr1
->attcollation
!= attr2
->attcollation
)
754 /* Record types derived from tables could have dropped fields. */
755 if (attr1
->attisdropped
!= attr2
->attisdropped
)
765 * If two tuple descriptors would be considered equal by equalRowTypes()
766 * then their hash value will be equal according to this function.
769 hashRowType(TupleDesc desc
)
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
));
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.
798 TupleDescInitEntry(TupleDesc desc
,
799 AttrNumber attributeNumber
,
800 const char *attributeName
,
806 Form_pg_type typeForm
;
807 Form_pg_attribute att
;
812 Assert(PointerIsValid(desc
));
813 Assert(attributeNumber
>= 1);
814 Assert(attributeNumber
<= desc
->natts
);
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.
874 TupleDescInitBuiltinEntry(TupleDesc desc
,
875 AttrNumber attributeNumber
,
876 const char *attributeName
,
881 Form_pg_attribute att
;
884 Assert(PointerIsValid(desc
));
885 Assert(attributeNumber
>= 1);
886 Assert(attributeNumber
<= desc
->natts
);
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.
925 att
->attbyval
= false;
926 att
->attalign
= TYPALIGN_INT
;
927 att
->attstorage
= TYPSTORAGE_EXTENDED
;
928 att
->attcompression
= InvalidCompressionMethod
;
929 att
->attcollation
= DEFAULT_COLLATION_OID
;
934 att
->attbyval
= true;
935 att
->attalign
= TYPALIGN_CHAR
;
936 att
->attstorage
= TYPSTORAGE_PLAIN
;
937 att
->attcompression
= InvalidCompressionMethod
;
938 att
->attcollation
= InvalidOid
;
943 att
->attbyval
= true;
944 att
->attalign
= TYPALIGN_INT
;
945 att
->attstorage
= TYPSTORAGE_PLAIN
;
946 att
->attcompression
= InvalidCompressionMethod
;
947 att
->attcollation
= InvalidOid
;
952 att
->attbyval
= FLOAT8PASSBYVAL
;
953 att
->attalign
= TYPALIGN_DOUBLE
;
954 att
->attstorage
= TYPSTORAGE_PLAIN
;
955 att
->attcompression
= InvalidCompressionMethod
;
956 att
->attcollation
= InvalidOid
;
961 att
->attbyval
= true;
962 att
->attalign
= TYPALIGN_INT
;
963 att
->attstorage
= TYPSTORAGE_PLAIN
;
964 att
->attcompression
= InvalidCompressionMethod
;
965 att
->attcollation
= InvalidOid
;
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
982 TupleDescInitEntryCollation(TupleDesc desc
,
983 AttrNumber attributeNumber
,
989 Assert(PointerIsValid(desc
));
990 Assert(attributeNumber
>= 1);
991 Assert(attributeNumber
<= desc
->natts
);
993 TupleDescAttr(desc
, attributeNumber
- 1)->attcollation
= collationid
;
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.
1007 BuildDescFromLists(const List
*names
, const List
*types
, const List
*typmods
, const List
*collations
)
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
);
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
);
1037 TupleDescInitEntry(desc
, attnum
, attname
, atttypid
, atttypmod
, 0);
1038 TupleDescInitEntryCollation(desc
, attnum
, attcollation
);
1045 * Get default expression (or NULL if none) for the given attribute number.
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
);
1069 /* ResourceOwner callbacks */
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
);
1083 ResOwnerPrintTupleDesc(Datum res
)
1085 TupleDesc tupdesc
= (TupleDesc
) DatumGetPointer(res
);
1087 return psprintf("TupleDesc %p (%u,%d)",
1088 tupdesc
, tupdesc
->tdtypeid
, tupdesc
->tdtypmod
);