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
].ccvalid
= constr
->check
[i
].ccvalid
;
380 cpy
->check
[i
].ccnoinherit
= constr
->check
[i
].ccnoinherit
;
387 /* We can copy the tuple type identification, too */
388 desc
->tdtypeid
= tupdesc
->tdtypeid
;
389 desc
->tdtypmod
= tupdesc
->tdtypmod
;
396 * Copy a tuple descriptor into caller-supplied memory.
397 * The memory may be shared memory mapped at any address, and must
398 * be sufficient to hold TupleDescSize(src) bytes.
400 * !!! Constraints and defaults are not copied !!!
403 TupleDescCopy(TupleDesc dst
, TupleDesc src
)
407 /* Flat-copy the header and attribute arrays */
408 memcpy(dst
, src
, TupleDescSize(src
));
411 * Since we're not copying constraints and defaults, clear fields
412 * associated with them.
414 for (i
= 0; i
< dst
->natts
; i
++)
416 Form_pg_attribute att
= TupleDescAttr(dst
, i
);
418 att
->attnotnull
= false;
419 att
->atthasdef
= false;
420 att
->atthasmissing
= false;
421 att
->attidentity
= '\0';
422 att
->attgenerated
= '\0';
424 populate_compact_attribute(dst
, i
);
429 * Also, assume the destination is not to be ref-counted. (Copying the
430 * source's refcount would be wrong in any case.)
432 dst
->tdrefcount
= -1;
437 * This function copies a single attribute structure from one tuple
438 * descriptor to another.
440 * !!! Constraints and defaults are not copied !!!
443 TupleDescCopyEntry(TupleDesc dst
, AttrNumber dstAttno
,
444 TupleDesc src
, AttrNumber srcAttno
)
446 Form_pg_attribute dstAtt
= TupleDescAttr(dst
, dstAttno
- 1);
447 Form_pg_attribute srcAtt
= TupleDescAttr(src
, srcAttno
- 1);
452 Assert(PointerIsValid(src
));
453 Assert(PointerIsValid(dst
));
454 Assert(srcAttno
>= 1);
455 Assert(srcAttno
<= src
->natts
);
456 Assert(dstAttno
>= 1);
457 Assert(dstAttno
<= dst
->natts
);
459 memcpy(dstAtt
, srcAtt
, ATTRIBUTE_FIXED_PART_SIZE
);
461 dstAtt
->attnum
= dstAttno
;
463 /* since we're not copying constraints or defaults, clear these */
464 dstAtt
->attnotnull
= false;
465 dstAtt
->atthasdef
= false;
466 dstAtt
->atthasmissing
= false;
467 dstAtt
->attidentity
= '\0';
468 dstAtt
->attgenerated
= '\0';
470 populate_compact_attribute(dst
, dstAttno
- 1);
474 * Free a TupleDesc including all substructure
477 FreeTupleDesc(TupleDesc tupdesc
)
482 * Possibly this should assert tdrefcount == 0, to disallow explicit
483 * freeing of un-refcounted tupdescs?
485 Assert(tupdesc
->tdrefcount
<= 0);
489 if (tupdesc
->constr
->num_defval
> 0)
491 AttrDefault
*attrdef
= tupdesc
->constr
->defval
;
493 for (i
= tupdesc
->constr
->num_defval
- 1; i
>= 0; i
--)
494 pfree(attrdef
[i
].adbin
);
497 if (tupdesc
->constr
->missing
)
499 AttrMissing
*attrmiss
= tupdesc
->constr
->missing
;
501 for (i
= tupdesc
->natts
- 1; i
>= 0; i
--)
503 if (attrmiss
[i
].am_present
504 && !TupleDescAttr(tupdesc
, i
)->attbyval
)
505 pfree(DatumGetPointer(attrmiss
[i
].am_value
));
509 if (tupdesc
->constr
->num_check
> 0)
511 ConstrCheck
*check
= tupdesc
->constr
->check
;
513 for (i
= tupdesc
->constr
->num_check
- 1; i
>= 0; i
--)
515 pfree(check
[i
].ccname
);
516 pfree(check
[i
].ccbin
);
520 pfree(tupdesc
->constr
);
527 * Increment the reference count of a tupdesc, and log the reference in
528 * CurrentResourceOwner.
530 * Do not apply this to tupdescs that are not being refcounted. (Use the
531 * macro PinTupleDesc for tupdescs of uncertain status.)
534 IncrTupleDescRefCount(TupleDesc tupdesc
)
536 Assert(tupdesc
->tdrefcount
>= 0);
538 ResourceOwnerEnlarge(CurrentResourceOwner
);
539 tupdesc
->tdrefcount
++;
540 ResourceOwnerRememberTupleDesc(CurrentResourceOwner
, tupdesc
);
544 * Decrement the reference count of a tupdesc, remove the corresponding
545 * reference from CurrentResourceOwner, and free the tupdesc if no more
548 * Do not apply this to tupdescs that are not being refcounted. (Use the
549 * macro ReleaseTupleDesc for tupdescs of uncertain status.)
552 DecrTupleDescRefCount(TupleDesc tupdesc
)
554 Assert(tupdesc
->tdrefcount
> 0);
556 ResourceOwnerForgetTupleDesc(CurrentResourceOwner
, tupdesc
);
557 if (--tupdesc
->tdrefcount
== 0)
558 FreeTupleDesc(tupdesc
);
562 * Compare two TupleDesc structures for logical equality
565 equalTupleDescs(TupleDesc tupdesc1
, TupleDesc tupdesc2
)
570 if (tupdesc1
->natts
!= tupdesc2
->natts
)
572 if (tupdesc1
->tdtypeid
!= tupdesc2
->tdtypeid
)
575 /* tdtypmod and tdrefcount are not checked */
577 for (i
= 0; i
< tupdesc1
->natts
; i
++)
579 Form_pg_attribute attr1
= TupleDescAttr(tupdesc1
, i
);
580 Form_pg_attribute attr2
= TupleDescAttr(tupdesc2
, i
);
583 * We do not need to check every single field here: we can disregard
584 * attrelid and attnum (which were used to place the row in the attrs
585 * array in the first place). It might look like we could dispense
586 * with checking attlen/attbyval/attalign, since these are derived
587 * from atttypid; but in the case of dropped columns we must check
588 * them (since atttypid will be zero for all dropped columns) and in
589 * general it seems safer to check them always.
591 * We intentionally ignore atthasmissing, since that's not very
592 * relevant in tupdescs, which lack the attmissingval field.
594 if (strcmp(NameStr(attr1
->attname
), NameStr(attr2
->attname
)) != 0)
596 if (attr1
->atttypid
!= attr2
->atttypid
)
598 if (attr1
->attlen
!= attr2
->attlen
)
600 if (attr1
->attndims
!= attr2
->attndims
)
602 if (attr1
->atttypmod
!= attr2
->atttypmod
)
604 if (attr1
->attbyval
!= attr2
->attbyval
)
606 if (attr1
->attalign
!= attr2
->attalign
)
608 if (attr1
->attstorage
!= attr2
->attstorage
)
610 if (attr1
->attcompression
!= attr2
->attcompression
)
612 if (attr1
->attnotnull
!= attr2
->attnotnull
)
614 if (attr1
->atthasdef
!= attr2
->atthasdef
)
616 if (attr1
->attidentity
!= attr2
->attidentity
)
618 if (attr1
->attgenerated
!= attr2
->attgenerated
)
620 if (attr1
->attisdropped
!= attr2
->attisdropped
)
622 if (attr1
->attislocal
!= attr2
->attislocal
)
624 if (attr1
->attinhcount
!= attr2
->attinhcount
)
626 if (attr1
->attcollation
!= attr2
->attcollation
)
628 /* variable-length fields are not even present... */
631 if (tupdesc1
->constr
!= NULL
)
633 TupleConstr
*constr1
= tupdesc1
->constr
;
634 TupleConstr
*constr2
= tupdesc2
->constr
;
638 if (constr1
->has_not_null
!= constr2
->has_not_null
)
640 if (constr1
->has_generated_stored
!= constr2
->has_generated_stored
)
642 n
= constr1
->num_defval
;
643 if (n
!= (int) constr2
->num_defval
)
645 /* We assume here that both AttrDefault arrays are in adnum order */
646 for (i
= 0; i
< n
; i
++)
648 AttrDefault
*defval1
= constr1
->defval
+ i
;
649 AttrDefault
*defval2
= constr2
->defval
+ i
;
651 if (defval1
->adnum
!= defval2
->adnum
)
653 if (strcmp(defval1
->adbin
, defval2
->adbin
) != 0)
656 if (constr1
->missing
)
658 if (!constr2
->missing
)
660 for (i
= 0; i
< tupdesc1
->natts
; i
++)
662 AttrMissing
*missval1
= constr1
->missing
+ i
;
663 AttrMissing
*missval2
= constr2
->missing
+ i
;
665 if (missval1
->am_present
!= missval2
->am_present
)
667 if (missval1
->am_present
)
669 CompactAttribute
*missatt1
= TupleDescCompactAttr(tupdesc1
, i
);
671 if (!datumIsEqual(missval1
->am_value
, missval2
->am_value
,
672 missatt1
->attbyval
, missatt1
->attlen
))
677 else if (constr2
->missing
)
679 n
= constr1
->num_check
;
680 if (n
!= (int) constr2
->num_check
)
684 * Similarly, we rely here on the ConstrCheck entries being sorted by
685 * name. If there are duplicate names, the outcome of the comparison
686 * is uncertain, but that should not happen.
688 for (i
= 0; i
< n
; i
++)
690 ConstrCheck
*check1
= constr1
->check
+ i
;
691 ConstrCheck
*check2
= constr2
->check
+ i
;
693 if (!(strcmp(check1
->ccname
, check2
->ccname
) == 0 &&
694 strcmp(check1
->ccbin
, check2
->ccbin
) == 0 &&
695 check1
->ccvalid
== check2
->ccvalid
&&
696 check1
->ccnoinherit
== check2
->ccnoinherit
))
700 else if (tupdesc2
->constr
!= NULL
)
708 * This determines whether two tuple descriptors have equal row types. This
709 * only checks those fields in pg_attribute that are applicable for row types,
710 * while ignoring those fields that define the physical row storage or those
711 * that define table column metadata.
713 * Specifically, this checks:
715 * - same number of attributes
716 * - same composite type ID (but could both be zero)
717 * - corresponding attributes (in order) have same the name, type, typmod,
720 * This is used to check whether two record types are compatible, whether
721 * function return row types are the same, and other similar situations.
723 * (XXX There was some discussion whether attndims should be checked here, but
724 * for now it has been decided not to.)
726 * Note: We deliberately do not check the tdtypmod field. This allows
727 * typcache.c to use this routine to see if a cached record type matches a
731 equalRowTypes(TupleDesc tupdesc1
, TupleDesc tupdesc2
)
733 if (tupdesc1
->natts
!= tupdesc2
->natts
)
735 if (tupdesc1
->tdtypeid
!= tupdesc2
->tdtypeid
)
738 for (int i
= 0; i
< tupdesc1
->natts
; i
++)
740 Form_pg_attribute attr1
= TupleDescAttr(tupdesc1
, i
);
741 Form_pg_attribute attr2
= TupleDescAttr(tupdesc2
, i
);
743 if (strcmp(NameStr(attr1
->attname
), NameStr(attr2
->attname
)) != 0)
745 if (attr1
->atttypid
!= attr2
->atttypid
)
747 if (attr1
->atttypmod
!= attr2
->atttypmod
)
749 if (attr1
->attcollation
!= attr2
->attcollation
)
752 /* Record types derived from tables could have dropped fields. */
753 if (attr1
->attisdropped
!= attr2
->attisdropped
)
763 * If two tuple descriptors would be considered equal by equalRowTypes()
764 * then their hash value will be equal according to this function.
767 hashRowType(TupleDesc desc
)
772 s
= hash_combine(0, hash_uint32(desc
->natts
));
773 s
= hash_combine(s
, hash_uint32(desc
->tdtypeid
));
774 for (i
= 0; i
< desc
->natts
; ++i
)
775 s
= hash_combine(s
, hash_uint32(TupleDescAttr(desc
, i
)->atttypid
));
782 * This function initializes a single attribute structure in
783 * a previously allocated tuple descriptor.
785 * If attributeName is NULL, the attname field is set to an empty string
786 * (this is for cases where we don't know or need a name for the field).
787 * Also, some callers use this function to change the datatype-related fields
788 * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
789 * to indicate that the attname field shouldn't be modified.
791 * Note that attcollation is set to the default for the specified datatype.
792 * If a nondefault collation is needed, insert it afterwards using
793 * TupleDescInitEntryCollation.
796 TupleDescInitEntry(TupleDesc desc
,
797 AttrNumber attributeNumber
,
798 const char *attributeName
,
804 Form_pg_type typeForm
;
805 Form_pg_attribute att
;
810 Assert(PointerIsValid(desc
));
811 Assert(attributeNumber
>= 1);
812 Assert(attributeNumber
<= desc
->natts
);
814 Assert(attdim
<= PG_INT16_MAX
);
817 * initialize the attribute fields
819 att
= TupleDescAttr(desc
, attributeNumber
- 1);
821 att
->attrelid
= 0; /* dummy value */
824 * Note: attributeName can be NULL, because the planner doesn't always
825 * fill in valid resname values in targetlists, particularly for resjunk
826 * attributes. Also, do nothing if caller wants to re-use the old attname.
828 if (attributeName
== NULL
)
829 MemSet(NameStr(att
->attname
), 0, NAMEDATALEN
);
830 else if (attributeName
!= NameStr(att
->attname
))
831 namestrcpy(&(att
->attname
), attributeName
);
833 att
->atttypmod
= typmod
;
835 att
->attnum
= attributeNumber
;
836 att
->attndims
= attdim
;
838 att
->attnotnull
= false;
839 att
->atthasdef
= false;
840 att
->atthasmissing
= false;
841 att
->attidentity
= '\0';
842 att
->attgenerated
= '\0';
843 att
->attisdropped
= false;
844 att
->attislocal
= true;
845 att
->attinhcount
= 0;
846 /* variable-length fields are not present in tupledescs */
848 tuple
= SearchSysCache1(TYPEOID
, ObjectIdGetDatum(oidtypeid
));
849 if (!HeapTupleIsValid(tuple
))
850 elog(ERROR
, "cache lookup failed for type %u", oidtypeid
);
851 typeForm
= (Form_pg_type
) GETSTRUCT(tuple
);
853 att
->atttypid
= oidtypeid
;
854 att
->attlen
= typeForm
->typlen
;
855 att
->attbyval
= typeForm
->typbyval
;
856 att
->attalign
= typeForm
->typalign
;
857 att
->attstorage
= typeForm
->typstorage
;
858 att
->attcompression
= InvalidCompressionMethod
;
859 att
->attcollation
= typeForm
->typcollation
;
861 populate_compact_attribute(desc
, attributeNumber
- 1);
863 ReleaseSysCache(tuple
);
867 * TupleDescInitBuiltinEntry
868 * Initialize a tuple descriptor without catalog access. Only
869 * a limited range of builtin types are supported.
872 TupleDescInitBuiltinEntry(TupleDesc desc
,
873 AttrNumber attributeNumber
,
874 const char *attributeName
,
879 Form_pg_attribute att
;
882 Assert(PointerIsValid(desc
));
883 Assert(attributeNumber
>= 1);
884 Assert(attributeNumber
<= desc
->natts
);
886 Assert(attdim
<= PG_INT16_MAX
);
888 /* initialize the attribute fields */
889 att
= TupleDescAttr(desc
, attributeNumber
- 1);
890 att
->attrelid
= 0; /* dummy value */
892 /* unlike TupleDescInitEntry, we require an attribute name */
893 Assert(attributeName
!= NULL
);
894 namestrcpy(&(att
->attname
), attributeName
);
896 att
->atttypmod
= typmod
;
898 att
->attnum
= attributeNumber
;
899 att
->attndims
= attdim
;
901 att
->attnotnull
= false;
902 att
->atthasdef
= false;
903 att
->atthasmissing
= false;
904 att
->attidentity
= '\0';
905 att
->attgenerated
= '\0';
906 att
->attisdropped
= false;
907 att
->attislocal
= true;
908 att
->attinhcount
= 0;
909 /* variable-length fields are not present in tupledescs */
911 att
->atttypid
= oidtypeid
;
914 * Our goal here is to support just enough types to let basic builtin
915 * commands work without catalog access - e.g. so that we can do certain
916 * things even in processes that are not connected to a database.
923 att
->attbyval
= false;
924 att
->attalign
= TYPALIGN_INT
;
925 att
->attstorage
= TYPSTORAGE_EXTENDED
;
926 att
->attcompression
= InvalidCompressionMethod
;
927 att
->attcollation
= DEFAULT_COLLATION_OID
;
932 att
->attbyval
= true;
933 att
->attalign
= TYPALIGN_CHAR
;
934 att
->attstorage
= TYPSTORAGE_PLAIN
;
935 att
->attcompression
= InvalidCompressionMethod
;
936 att
->attcollation
= InvalidOid
;
941 att
->attbyval
= true;
942 att
->attalign
= TYPALIGN_INT
;
943 att
->attstorage
= TYPSTORAGE_PLAIN
;
944 att
->attcompression
= InvalidCompressionMethod
;
945 att
->attcollation
= InvalidOid
;
950 att
->attbyval
= FLOAT8PASSBYVAL
;
951 att
->attalign
= TYPALIGN_DOUBLE
;
952 att
->attstorage
= TYPSTORAGE_PLAIN
;
953 att
->attcompression
= InvalidCompressionMethod
;
954 att
->attcollation
= InvalidOid
;
959 att
->attbyval
= true;
960 att
->attalign
= TYPALIGN_INT
;
961 att
->attstorage
= TYPSTORAGE_PLAIN
;
962 att
->attcompression
= InvalidCompressionMethod
;
963 att
->attcollation
= InvalidOid
;
967 elog(ERROR
, "unsupported type %u", oidtypeid
);
970 populate_compact_attribute(desc
, attributeNumber
- 1);
974 * TupleDescInitEntryCollation
976 * Assign a nondefault collation to a previously initialized tuple descriptor
980 TupleDescInitEntryCollation(TupleDesc desc
,
981 AttrNumber attributeNumber
,
987 Assert(PointerIsValid(desc
));
988 Assert(attributeNumber
>= 1);
989 Assert(attributeNumber
<= desc
->natts
);
991 TupleDescAttr(desc
, attributeNumber
- 1)->attcollation
= collationid
;
997 * Build a TupleDesc given lists of column names (as String nodes),
998 * column type OIDs, typmods, and collation OIDs.
1000 * No constraints are generated.
1002 * This is for use with functions returning RECORD.
1005 BuildDescFromLists(const List
*names
, const List
*types
, const List
*typmods
, const List
*collations
)
1015 natts
= list_length(names
);
1016 Assert(natts
== list_length(types
));
1017 Assert(natts
== list_length(typmods
));
1018 Assert(natts
== list_length(collations
));
1021 * allocate a new tuple descriptor
1023 desc
= CreateTemplateTupleDesc(natts
);
1026 forfour(l1
, names
, l2
, types
, l3
, typmods
, l4
, collations
)
1028 char *attname
= strVal(lfirst(l1
));
1029 Oid atttypid
= lfirst_oid(l2
);
1030 int32 atttypmod
= lfirst_int(l3
);
1031 Oid attcollation
= lfirst_oid(l4
);
1035 TupleDescInitEntry(desc
, attnum
, attname
, atttypid
, atttypmod
, 0);
1036 TupleDescInitEntryCollation(desc
, attnum
, attcollation
);
1043 * Get default expression (or NULL if none) for the given attribute number.
1046 TupleDescGetDefault(TupleDesc tupdesc
, AttrNumber attnum
)
1048 Node
*result
= NULL
;
1050 if (tupdesc
->constr
)
1052 AttrDefault
*attrdef
= tupdesc
->constr
->defval
;
1054 for (int i
= 0; i
< tupdesc
->constr
->num_defval
; i
++)
1056 if (attrdef
[i
].adnum
== attnum
)
1058 result
= stringToNode(attrdef
[i
].adbin
);
1067 /* ResourceOwner callbacks */
1070 ResOwnerReleaseTupleDesc(Datum res
)
1072 TupleDesc tupdesc
= (TupleDesc
) DatumGetPointer(res
);
1074 /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
1075 Assert(tupdesc
->tdrefcount
> 0);
1076 if (--tupdesc
->tdrefcount
== 0)
1077 FreeTupleDesc(tupdesc
);
1081 ResOwnerPrintTupleDesc(Datum res
)
1083 TupleDesc tupdesc
= (TupleDesc
) DatumGetPointer(res
);
1085 return psprintf("TupleDesc %p (%u,%d)",
1086 tupdesc
, tupdesc
->tdtypeid
, tupdesc
->tdtypmod
);