PostgreSQL Source Code git master
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
tupdesc.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * tupdesc.c
4 * POSTGRES tuple descriptor support code
5 *
6 * Portions Copyright (c) 1996-2025, 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"
25#include "catalog/catalog.h"
27#include "catalog/pg_type.h"
28#include "common/hashfn.h"
29#include "utils/builtins.h"
30#include "utils/datum.h"
31#include "utils/resowner.h"
32#include "utils/syscache.h"
33
34/* ResourceOwner callbacks to hold tupledesc references */
35static void ResOwnerReleaseTupleDesc(Datum res);
36static char *ResOwnerPrintTupleDesc(Datum res);
37
39{
40 .name = "tupdesc reference",
41 .release_phase = RESOURCE_RELEASE_AFTER_LOCKS,
42 .release_priority = RELEASE_PRIO_TUPDESC_REFS,
43 .ReleaseResource = ResOwnerReleaseTupleDesc,
44 .DebugPrint = ResOwnerPrintTupleDesc
45};
46
47/* Convenience wrappers over ResourceOwnerRemember/Forget */
48static inline void
50{
52}
53
54static inline void
56{
58}
59
60/*
61 * populate_compact_attribute_internal
62 * Helper function for populate_compact_attribute()
63 */
64static inline void
67{
68 memset(dst, 0, sizeof(CompactAttribute));
69
70 dst->attcacheoff = -1;
71 dst->attlen = src->attlen;
72
73 dst->attbyval = src->attbyval;
74 dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
75 dst->atthasmissing = src->atthasmissing;
76 dst->attisdropped = src->attisdropped;
77 dst->attgenerated = (src->attgenerated != '\0');
78
79 /*
80 * Assign nullability status for this column. Assuming that a constraint
81 * exists, at this point we don't know if a not-null constraint is valid,
82 * so we assign UNKNOWN unless the table is a catalog, in which case we
83 * know it's valid.
84 */
85 dst->attnullability = !src->attnotnull ? ATTNULLABLE_UNRESTRICTED :
88
89 switch (src->attalign)
90 {
91 case TYPALIGN_INT:
92 dst->attalignby = ALIGNOF_INT;
93 break;
94 case TYPALIGN_CHAR:
95 dst->attalignby = sizeof(char);
96 break;
97 case TYPALIGN_DOUBLE:
98 dst->attalignby = ALIGNOF_DOUBLE;
99 break;
100 case TYPALIGN_SHORT:
101 dst->attalignby = ALIGNOF_SHORT;
102 break;
103 default:
104 dst->attalignby = 0;
105 elog(ERROR, "invalid attalign value: %c", src->attalign);
106 break;
107 }
108}
109
110/*
111 * populate_compact_attribute
112 * Fill in the corresponding CompactAttribute element from the
113 * Form_pg_attribute for the given attribute number. This must be called
114 * whenever a change is made to a Form_pg_attribute in the TupleDesc.
115 */
116void
118{
119 Form_pg_attribute src = TupleDescAttr(tupdesc, attnum);
120 CompactAttribute *dst;
121
122 /*
123 * Don't use TupleDescCompactAttr to prevent infinite recursion in assert
124 * builds.
125 */
126 dst = &tupdesc->compact_attrs[attnum];
127
129}
130
131/*
132 * verify_compact_attribute
133 * In Assert enabled builds, we verify that the CompactAttribute is
134 * populated correctly. This helps find bugs in places such as ALTER
135 * TABLE where code makes changes to the FormData_pg_attribute but
136 * forgets to call populate_compact_attribute().
137 *
138 * This is used in TupleDescCompactAttr(), but declared here to allow access
139 * to populate_compact_attribute_internal().
140 */
141void
143{
144#ifdef USE_ASSERT_CHECKING
145 CompactAttribute *cattr = &tupdesc->compact_attrs[attnum];
146 Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum);
148
149 /*
150 * Populate the temporary CompactAttribute from the corresponding
151 * Form_pg_attribute
152 */
154
155 /*
156 * Make the attcacheoff match since it's been reset to -1 by
157 * populate_compact_attribute_internal. Same with attnullability.
158 */
159 tmp.attcacheoff = cattr->attcacheoff;
160 tmp.attnullability = cattr->attnullability;
161
162 /* Check the freshly populated CompactAttribute matches the TupleDesc's */
163 Assert(memcmp(&tmp, cattr, sizeof(CompactAttribute)) == 0);
164#endif
165}
166
167/*
168 * CreateTemplateTupleDesc
169 * This function allocates an empty tuple descriptor structure.
170 *
171 * Tuple type ID information is initially set for an anonymous record type;
172 * caller can overwrite this if needed.
173 */
176{
177 TupleDesc desc;
178
179 /*
180 * sanity checks
181 */
182 Assert(natts >= 0);
183
184 /*
185 * Allocate enough memory for the tuple descriptor, the CompactAttribute
186 * array and also an array of FormData_pg_attribute.
187 *
188 * Note: the FormData_pg_attribute array stride is
189 * sizeof(FormData_pg_attribute), since we declare the array elements as
190 * FormData_pg_attribute for notational convenience. However, we only
191 * guarantee that the first ATTRIBUTE_FIXED_PART_SIZE bytes of each entry
192 * are valid; most code that copies tupdesc entries around copies just
193 * that much. In principle that could be less due to trailing padding,
194 * although with the current definition of pg_attribute there probably
195 * isn't any padding.
196 */
197 desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
198 natts * sizeof(CompactAttribute) +
199 natts * sizeof(FormData_pg_attribute));
200
201 /*
202 * Initialize other fields of the tupdesc.
203 */
204 desc->natts = natts;
205 desc->constr = NULL;
206 desc->tdtypeid = RECORDOID;
207 desc->tdtypmod = -1;
208 desc->tdrefcount = -1; /* assume not reference-counted */
209
210 return desc;
211}
212
213/*
214 * CreateTupleDesc
215 * This function allocates a new TupleDesc by copying a given
216 * Form_pg_attribute array.
217 *
218 * Tuple type ID information is initially set for an anonymous record type;
219 * caller can overwrite this if needed.
220 */
223{
224 TupleDesc desc;
225 int i;
226
227 desc = CreateTemplateTupleDesc(natts);
228
229 for (i = 0; i < natts; ++i)
230 {
231 memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
233 }
234 return desc;
235}
236
237/*
238 * CreateTupleDescCopy
239 * This function creates a new TupleDesc by copying from an existing
240 * TupleDesc.
241 *
242 * !!! Constraints and defaults are not copied !!!
243 */
246{
247 TupleDesc desc;
248 int i;
249
250 desc = CreateTemplateTupleDesc(tupdesc->natts);
251
252 /* Flat-copy the attribute array */
253 memcpy(TupleDescAttr(desc, 0),
254 TupleDescAttr(tupdesc, 0),
255 desc->natts * sizeof(FormData_pg_attribute));
256
257 /*
258 * Since we're not copying constraints and defaults, clear fields
259 * associated with them.
260 */
261 for (i = 0; i < desc->natts; i++)
262 {
263 Form_pg_attribute att = TupleDescAttr(desc, i);
264
265 att->attnotnull = false;
266 att->atthasdef = false;
267 att->atthasmissing = false;
268 att->attidentity = '\0';
269 att->attgenerated = '\0';
270
272 }
273
274 /* We can copy the tuple type identification, too */
275 desc->tdtypeid = tupdesc->tdtypeid;
276 desc->tdtypmod = tupdesc->tdtypmod;
277
278 return desc;
279}
280
281/*
282 * CreateTupleDescTruncatedCopy
283 * This function creates a new TupleDesc with only the first 'natts'
284 * attributes from an existing TupleDesc
285 *
286 * !!! Constraints and defaults are not copied !!!
287 */
290{
291 TupleDesc desc;
292 int i;
293
294 Assert(natts <= tupdesc->natts);
295
296 desc = CreateTemplateTupleDesc(natts);
297
298 /* Flat-copy the attribute array */
299 memcpy(TupleDescAttr(desc, 0),
300 TupleDescAttr(tupdesc, 0),
301 desc->natts * sizeof(FormData_pg_attribute));
302
303 /*
304 * Since we're not copying constraints and defaults, clear fields
305 * associated with them.
306 */
307 for (i = 0; i < desc->natts; i++)
308 {
309 Form_pg_attribute att = TupleDescAttr(desc, i);
310
311 att->attnotnull = false;
312 att->atthasdef = false;
313 att->atthasmissing = false;
314 att->attidentity = '\0';
315 att->attgenerated = '\0';
316
318 }
319
320 /* We can copy the tuple type identification, too */
321 desc->tdtypeid = tupdesc->tdtypeid;
322 desc->tdtypmod = tupdesc->tdtypmod;
323
324 return desc;
325}
326
327/*
328 * CreateTupleDescCopyConstr
329 * This function creates a new TupleDesc by copying from an existing
330 * TupleDesc (including its constraints and defaults).
331 */
334{
335 TupleDesc desc;
336 TupleConstr *constr = tupdesc->constr;
337 int i;
338
339 desc = CreateTemplateTupleDesc(tupdesc->natts);
340
341 /* Flat-copy the attribute array */
342 memcpy(TupleDescAttr(desc, 0),
343 TupleDescAttr(tupdesc, 0),
344 desc->natts * sizeof(FormData_pg_attribute));
345
346 for (i = 0; i < desc->natts; i++)
347 {
349
352 }
353
354 /* Copy the TupleConstr data structure, if any */
355 if (constr)
356 {
357 TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
358
359 cpy->has_not_null = constr->has_not_null;
362
363 if ((cpy->num_defval = constr->num_defval) > 0)
364 {
365 cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
366 memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
367 for (i = cpy->num_defval - 1; i >= 0; i--)
368 cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
369 }
370
371 if (constr->missing)
372 {
373 cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
374 memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
375 for (i = tupdesc->natts - 1; i >= 0; i--)
376 {
377 if (constr->missing[i].am_present)
378 {
379 CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
380
381 cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
382 attr->attbyval,
383 attr->attlen);
384 }
385 }
386 }
387
388 if ((cpy->num_check = constr->num_check) > 0)
389 {
390 cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
391 memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
392 for (i = cpy->num_check - 1; i >= 0; i--)
393 {
394 cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
395 cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
396 cpy->check[i].ccenforced = constr->check[i].ccenforced;
397 cpy->check[i].ccvalid = constr->check[i].ccvalid;
398 cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
399 }
400 }
401
402 desc->constr = cpy;
403 }
404
405 /* We can copy the tuple type identification, too */
406 desc->tdtypeid = tupdesc->tdtypeid;
407 desc->tdtypmod = tupdesc->tdtypmod;
408
409 return desc;
410}
411
412/*
413 * TupleDescCopy
414 * Copy a tuple descriptor into caller-supplied memory.
415 * The memory may be shared memory mapped at any address, and must
416 * be sufficient to hold TupleDescSize(src) bytes.
417 *
418 * !!! Constraints and defaults are not copied !!!
419 */
420void
422{
423 int i;
424
425 /* Flat-copy the header and attribute arrays */
426 memcpy(dst, src, TupleDescSize(src));
427
428 /*
429 * Since we're not copying constraints and defaults, clear fields
430 * associated with them.
431 */
432 for (i = 0; i < dst->natts; i++)
433 {
435
436 att->attnotnull = false;
437 att->atthasdef = false;
438 att->atthasmissing = false;
439 att->attidentity = '\0';
440 att->attgenerated = '\0';
441
443 }
444 dst->constr = NULL;
445
446 /*
447 * Also, assume the destination is not to be ref-counted. (Copying the
448 * source's refcount would be wrong in any case.)
449 */
450 dst->tdrefcount = -1;
451}
452
453/*
454 * TupleDescCopyEntry
455 * This function copies a single attribute structure from one tuple
456 * descriptor to another.
457 *
458 * !!! Constraints and defaults are not copied !!!
459 */
460void
462 TupleDesc src, AttrNumber srcAttno)
463{
464 Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
465 Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
466
467 /*
468 * sanity checks
469 */
472 Assert(srcAttno >= 1);
473 Assert(srcAttno <= src->natts);
474 Assert(dstAttno >= 1);
475 Assert(dstAttno <= dst->natts);
476
477 memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
478
479 dstAtt->attnum = dstAttno;
480
481 /* since we're not copying constraints or defaults, clear these */
482 dstAtt->attnotnull = false;
483 dstAtt->atthasdef = false;
484 dstAtt->atthasmissing = false;
485 dstAtt->attidentity = '\0';
486 dstAtt->attgenerated = '\0';
487
488 populate_compact_attribute(dst, dstAttno - 1);
489}
490
491/*
492 * Free a TupleDesc including all substructure
493 */
494void
496{
497 int i;
498
499 /*
500 * Possibly this should assert tdrefcount == 0, to disallow explicit
501 * freeing of un-refcounted tupdescs?
502 */
503 Assert(tupdesc->tdrefcount <= 0);
504
505 if (tupdesc->constr)
506 {
507 if (tupdesc->constr->num_defval > 0)
508 {
509 AttrDefault *attrdef = tupdesc->constr->defval;
510
511 for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
512 pfree(attrdef[i].adbin);
513 pfree(attrdef);
514 }
515 if (tupdesc->constr->missing)
516 {
517 AttrMissing *attrmiss = tupdesc->constr->missing;
518
519 for (i = tupdesc->natts - 1; i >= 0; i--)
520 {
521 if (attrmiss[i].am_present
522 && !TupleDescAttr(tupdesc, i)->attbyval)
523 pfree(DatumGetPointer(attrmiss[i].am_value));
524 }
525 pfree(attrmiss);
526 }
527 if (tupdesc->constr->num_check > 0)
528 {
529 ConstrCheck *check = tupdesc->constr->check;
530
531 for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
532 {
533 pfree(check[i].ccname);
534 pfree(check[i].ccbin);
535 }
536 pfree(check);
537 }
538 pfree(tupdesc->constr);
539 }
540
541 pfree(tupdesc);
542}
543
544/*
545 * Increment the reference count of a tupdesc, and log the reference in
546 * CurrentResourceOwner.
547 *
548 * Do not apply this to tupdescs that are not being refcounted. (Use the
549 * macro PinTupleDesc for tupdescs of uncertain status.)
550 */
551void
553{
554 Assert(tupdesc->tdrefcount >= 0);
555
557 tupdesc->tdrefcount++;
559}
560
561/*
562 * Decrement the reference count of a tupdesc, remove the corresponding
563 * reference from CurrentResourceOwner, and free the tupdesc if no more
564 * references remain.
565 *
566 * Do not apply this to tupdescs that are not being refcounted. (Use the
567 * macro ReleaseTupleDesc for tupdescs of uncertain status.)
568 */
569void
571{
572 Assert(tupdesc->tdrefcount > 0);
573
575 if (--tupdesc->tdrefcount == 0)
576 FreeTupleDesc(tupdesc);
577}
578
579/*
580 * Compare two TupleDesc structures for logical equality
581 */
582bool
584{
585 int i,
586 n;
587
588 if (tupdesc1->natts != tupdesc2->natts)
589 return false;
590 if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
591 return false;
592
593 /* tdtypmod and tdrefcount are not checked */
594
595 for (i = 0; i < tupdesc1->natts; i++)
596 {
597 Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
598 Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
599
600 /*
601 * We do not need to check every single field here: we can disregard
602 * attrelid and attnum (which were used to place the row in the attrs
603 * array in the first place). It might look like we could dispense
604 * with checking attlen/attbyval/attalign, since these are derived
605 * from atttypid; but in the case of dropped columns we must check
606 * them (since atttypid will be zero for all dropped columns) and in
607 * general it seems safer to check them always.
608 *
609 * We intentionally ignore atthasmissing, since that's not very
610 * relevant in tupdescs, which lack the attmissingval field.
611 */
612 if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
613 return false;
614 if (attr1->atttypid != attr2->atttypid)
615 return false;
616 if (attr1->attlen != attr2->attlen)
617 return false;
618 if (attr1->attndims != attr2->attndims)
619 return false;
620 if (attr1->atttypmod != attr2->atttypmod)
621 return false;
622 if (attr1->attbyval != attr2->attbyval)
623 return false;
624 if (attr1->attalign != attr2->attalign)
625 return false;
626 if (attr1->attstorage != attr2->attstorage)
627 return false;
628 if (attr1->attcompression != attr2->attcompression)
629 return false;
630 if (attr1->attnotnull != attr2->attnotnull)
631 return false;
632
633 /*
634 * When the column has a not-null constraint, we also need to consider
635 * its validity aspect, which only manifests in CompactAttribute->
636 * attnullability, so verify that.
637 */
638 if (attr1->attnotnull)
639 {
640 CompactAttribute *cattr1 = TupleDescCompactAttr(tupdesc1, i);
641 CompactAttribute *cattr2 = TupleDescCompactAttr(tupdesc2, i);
642
646
647 if (cattr1->attnullability != cattr2->attnullability)
648 return false;
649 }
650 if (attr1->atthasdef != attr2->atthasdef)
651 return false;
652 if (attr1->attidentity != attr2->attidentity)
653 return false;
654 if (attr1->attgenerated != attr2->attgenerated)
655 return false;
656 if (attr1->attisdropped != attr2->attisdropped)
657 return false;
658 if (attr1->attislocal != attr2->attislocal)
659 return false;
660 if (attr1->attinhcount != attr2->attinhcount)
661 return false;
662 if (attr1->attcollation != attr2->attcollation)
663 return false;
664 /* variable-length fields are not even present... */
665 }
666
667 if (tupdesc1->constr != NULL)
668 {
669 TupleConstr *constr1 = tupdesc1->constr;
670 TupleConstr *constr2 = tupdesc2->constr;
671
672 if (constr2 == NULL)
673 return false;
674 if (constr1->has_not_null != constr2->has_not_null)
675 return false;
676 if (constr1->has_generated_stored != constr2->has_generated_stored)
677 return false;
678 if (constr1->has_generated_virtual != constr2->has_generated_virtual)
679 return false;
680 n = constr1->num_defval;
681 if (n != (int) constr2->num_defval)
682 return false;
683 /* We assume here that both AttrDefault arrays are in adnum order */
684 for (i = 0; i < n; i++)
685 {
686 AttrDefault *defval1 = constr1->defval + i;
687 AttrDefault *defval2 = constr2->defval + i;
688
689 if (defval1->adnum != defval2->adnum)
690 return false;
691 if (strcmp(defval1->adbin, defval2->adbin) != 0)
692 return false;
693 }
694 if (constr1->missing)
695 {
696 if (!constr2->missing)
697 return false;
698 for (i = 0; i < tupdesc1->natts; i++)
699 {
700 AttrMissing *missval1 = constr1->missing + i;
701 AttrMissing *missval2 = constr2->missing + i;
702
703 if (missval1->am_present != missval2->am_present)
704 return false;
705 if (missval1->am_present)
706 {
707 CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
708
709 if (!datumIsEqual(missval1->am_value, missval2->am_value,
710 missatt1->attbyval, missatt1->attlen))
711 return false;
712 }
713 }
714 }
715 else if (constr2->missing)
716 return false;
717 n = constr1->num_check;
718 if (n != (int) constr2->num_check)
719 return false;
720
721 /*
722 * Similarly, we rely here on the ConstrCheck entries being sorted by
723 * name. If there are duplicate names, the outcome of the comparison
724 * is uncertain, but that should not happen.
725 */
726 for (i = 0; i < n; i++)
727 {
728 ConstrCheck *check1 = constr1->check + i;
729 ConstrCheck *check2 = constr2->check + i;
730
731 if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
732 strcmp(check1->ccbin, check2->ccbin) == 0 &&
733 check1->ccenforced == check2->ccenforced &&
734 check1->ccvalid == check2->ccvalid &&
735 check1->ccnoinherit == check2->ccnoinherit))
736 return false;
737 }
738 }
739 else if (tupdesc2->constr != NULL)
740 return false;
741 return true;
742}
743
744/*
745 * equalRowTypes
746 *
747 * This determines whether two tuple descriptors have equal row types. This
748 * only checks those fields in pg_attribute that are applicable for row types,
749 * while ignoring those fields that define the physical row storage or those
750 * that define table column metadata.
751 *
752 * Specifically, this checks:
753 *
754 * - same number of attributes
755 * - same composite type ID (but could both be zero)
756 * - corresponding attributes (in order) have same the name, type, typmod,
757 * collation
758 *
759 * This is used to check whether two record types are compatible, whether
760 * function return row types are the same, and other similar situations.
761 *
762 * (XXX There was some discussion whether attndims should be checked here, but
763 * for now it has been decided not to.)
764 *
765 * Note: We deliberately do not check the tdtypmod field. This allows
766 * typcache.c to use this routine to see if a cached record type matches a
767 * requested type.
768 */
769bool
771{
772 if (tupdesc1->natts != tupdesc2->natts)
773 return false;
774 if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
775 return false;
776
777 for (int i = 0; i < tupdesc1->natts; i++)
778 {
779 Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
780 Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
781
782 if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
783 return false;
784 if (attr1->atttypid != attr2->atttypid)
785 return false;
786 if (attr1->atttypmod != attr2->atttypmod)
787 return false;
788 if (attr1->attcollation != attr2->attcollation)
789 return false;
790
791 /* Record types derived from tables could have dropped fields. */
792 if (attr1->attisdropped != attr2->attisdropped)
793 return false;
794 }
795
796 return true;
797}
798
799/*
800 * hashRowType
801 *
802 * If two tuple descriptors would be considered equal by equalRowTypes()
803 * then their hash value will be equal according to this function.
804 */
805uint32
807{
808 uint32 s;
809 int i;
810
811 s = hash_combine(0, hash_uint32(desc->natts));
812 s = hash_combine(s, hash_uint32(desc->tdtypeid));
813 for (i = 0; i < desc->natts; ++i)
814 s = hash_combine(s, hash_uint32(TupleDescAttr(desc, i)->atttypid));
815
816 return s;
817}
818
819/*
820 * TupleDescInitEntry
821 * This function initializes a single attribute structure in
822 * a previously allocated tuple descriptor.
823 *
824 * If attributeName is NULL, the attname field is set to an empty string
825 * (this is for cases where we don't know or need a name for the field).
826 * Also, some callers use this function to change the datatype-related fields
827 * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
828 * to indicate that the attname field shouldn't be modified.
829 *
830 * Note that attcollation is set to the default for the specified datatype.
831 * If a nondefault collation is needed, insert it afterwards using
832 * TupleDescInitEntryCollation.
833 */
834void
836 AttrNumber attributeNumber,
837 const char *attributeName,
838 Oid oidtypeid,
839 int32 typmod,
840 int attdim)
841{
842 HeapTuple tuple;
843 Form_pg_type typeForm;
845
846 /*
847 * sanity checks
848 */
849 Assert(PointerIsValid(desc));
850 Assert(attributeNumber >= 1);
851 Assert(attributeNumber <= desc->natts);
852 Assert(attdim >= 0);
853 Assert(attdim <= PG_INT16_MAX);
854
855 /*
856 * initialize the attribute fields
857 */
858 att = TupleDescAttr(desc, attributeNumber - 1);
859
860 att->attrelid = 0; /* dummy value */
861
862 /*
863 * Note: attributeName can be NULL, because the planner doesn't always
864 * fill in valid resname values in targetlists, particularly for resjunk
865 * attributes. Also, do nothing if caller wants to re-use the old attname.
866 */
867 if (attributeName == NULL)
868 MemSet(NameStr(att->attname), 0, NAMEDATALEN);
869 else if (attributeName != NameStr(att->attname))
870 namestrcpy(&(att->attname), attributeName);
871
872 att->atttypmod = typmod;
873
874 att->attnum = attributeNumber;
875 att->attndims = attdim;
876
877 att->attnotnull = false;
878 att->atthasdef = false;
879 att->atthasmissing = false;
880 att->attidentity = '\0';
881 att->attgenerated = '\0';
882 att->attisdropped = false;
883 att->attislocal = true;
884 att->attinhcount = 0;
885 /* variable-length fields are not present in tupledescs */
886
887 tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
888 if (!HeapTupleIsValid(tuple))
889 elog(ERROR, "cache lookup failed for type %u", oidtypeid);
890 typeForm = (Form_pg_type) GETSTRUCT(tuple);
891
892 att->atttypid = oidtypeid;
893 att->attlen = typeForm->typlen;
894 att->attbyval = typeForm->typbyval;
895 att->attalign = typeForm->typalign;
896 att->attstorage = typeForm->typstorage;
897 att->attcompression = InvalidCompressionMethod;
898 att->attcollation = typeForm->typcollation;
899
900 populate_compact_attribute(desc, attributeNumber - 1);
901
902 ReleaseSysCache(tuple);
903}
904
905/*
906 * TupleDescInitBuiltinEntry
907 * Initialize a tuple descriptor without catalog access. Only
908 * a limited range of builtin types are supported.
909 */
910void
912 AttrNumber attributeNumber,
913 const char *attributeName,
914 Oid oidtypeid,
915 int32 typmod,
916 int attdim)
917{
919
920 /* sanity checks */
921 Assert(PointerIsValid(desc));
922 Assert(attributeNumber >= 1);
923 Assert(attributeNumber <= desc->natts);
924 Assert(attdim >= 0);
925 Assert(attdim <= PG_INT16_MAX);
926
927 /* initialize the attribute fields */
928 att = TupleDescAttr(desc, attributeNumber - 1);
929 att->attrelid = 0; /* dummy value */
930
931 /* unlike TupleDescInitEntry, we require an attribute name */
932 Assert(attributeName != NULL);
933 namestrcpy(&(att->attname), attributeName);
934
935 att->atttypmod = typmod;
936
937 att->attnum = attributeNumber;
938 att->attndims = attdim;
939
940 att->attnotnull = false;
941 att->atthasdef = false;
942 att->atthasmissing = false;
943 att->attidentity = '\0';
944 att->attgenerated = '\0';
945 att->attisdropped = false;
946 att->attislocal = true;
947 att->attinhcount = 0;
948 /* variable-length fields are not present in tupledescs */
949
950 att->atttypid = oidtypeid;
951
952 /*
953 * Our goal here is to support just enough types to let basic builtin
954 * commands work without catalog access - e.g. so that we can do certain
955 * things even in processes that are not connected to a database.
956 */
957 switch (oidtypeid)
958 {
959 case TEXTOID:
960 case TEXTARRAYOID:
961 att->attlen = -1;
962 att->attbyval = false;
963 att->attalign = TYPALIGN_INT;
964 att->attstorage = TYPSTORAGE_EXTENDED;
965 att->attcompression = InvalidCompressionMethod;
966 att->attcollation = DEFAULT_COLLATION_OID;
967 break;
968
969 case BOOLOID:
970 att->attlen = 1;
971 att->attbyval = true;
972 att->attalign = TYPALIGN_CHAR;
973 att->attstorage = TYPSTORAGE_PLAIN;
974 att->attcompression = InvalidCompressionMethod;
975 att->attcollation = InvalidOid;
976 break;
977
978 case INT4OID:
979 att->attlen = 4;
980 att->attbyval = true;
981 att->attalign = TYPALIGN_INT;
982 att->attstorage = TYPSTORAGE_PLAIN;
983 att->attcompression = InvalidCompressionMethod;
984 att->attcollation = InvalidOid;
985 break;
986
987 case INT8OID:
988 att->attlen = 8;
989 att->attbyval = FLOAT8PASSBYVAL;
990 att->attalign = TYPALIGN_DOUBLE;
991 att->attstorage = TYPSTORAGE_PLAIN;
992 att->attcompression = InvalidCompressionMethod;
993 att->attcollation = InvalidOid;
994 break;
995
996 case OIDOID:
997 att->attlen = 4;
998 att->attbyval = true;
999 att->attalign = TYPALIGN_INT;
1000 att->attstorage = TYPSTORAGE_PLAIN;
1001 att->attcompression = InvalidCompressionMethod;
1002 att->attcollation = InvalidOid;
1003 break;
1004
1005 default:
1006 elog(ERROR, "unsupported type %u", oidtypeid);
1007 }
1008
1009 populate_compact_attribute(desc, attributeNumber - 1);
1010}
1011
1012/*
1013 * TupleDescInitEntryCollation
1014 *
1015 * Assign a nondefault collation to a previously initialized tuple descriptor
1016 * entry.
1017 */
1018void
1020 AttrNumber attributeNumber,
1021 Oid collationid)
1022{
1023 /*
1024 * sanity checks
1025 */
1026 Assert(PointerIsValid(desc));
1027 Assert(attributeNumber >= 1);
1028 Assert(attributeNumber <= desc->natts);
1029
1030 TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
1031}
1032
1033/*
1034 * BuildDescFromLists
1035 *
1036 * Build a TupleDesc given lists of column names (as String nodes),
1037 * column type OIDs, typmods, and collation OIDs.
1038 *
1039 * No constraints are generated.
1040 *
1041 * This is for use with functions returning RECORD.
1042 */
1044BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
1045{
1046 int natts;
1048 ListCell *l1;
1049 ListCell *l2;
1050 ListCell *l3;
1051 ListCell *l4;
1052 TupleDesc desc;
1053
1054 natts = list_length(names);
1055 Assert(natts == list_length(types));
1056 Assert(natts == list_length(typmods));
1057 Assert(natts == list_length(collations));
1058
1059 /*
1060 * allocate a new tuple descriptor
1061 */
1062 desc = CreateTemplateTupleDesc(natts);
1063
1064 attnum = 0;
1065 forfour(l1, names, l2, types, l3, typmods, l4, collations)
1066 {
1067 char *attname = strVal(lfirst(l1));
1068 Oid atttypid = lfirst_oid(l2);
1069 int32 atttypmod = lfirst_int(l3);
1070 Oid attcollation = lfirst_oid(l4);
1071
1072 attnum++;
1073
1074 TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
1075 TupleDescInitEntryCollation(desc, attnum, attcollation);
1076 }
1077
1078 return desc;
1079}
1080
1081/*
1082 * Get default expression (or NULL if none) for the given attribute number.
1083 */
1084Node *
1086{
1087 Node *result = NULL;
1088
1089 if (tupdesc->constr)
1090 {
1091 AttrDefault *attrdef = tupdesc->constr->defval;
1092
1093 for (int i = 0; i < tupdesc->constr->num_defval; i++)
1094 {
1095 if (attrdef[i].adnum == attnum)
1096 {
1097 result = stringToNode(attrdef[i].adbin);
1098 break;
1099 }
1100 }
1101 }
1102
1103 return result;
1104}
1105
1106/* ResourceOwner callbacks */
1107
1108static void
1110{
1111 TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1112
1113 /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
1114 Assert(tupdesc->tdrefcount > 0);
1115 if (--tupdesc->tdrefcount == 0)
1116 FreeTupleDesc(tupdesc);
1117}
1118
1119static char *
1121{
1122 TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1123
1124 return psprintf("TupleDesc %p (%u,%d)",
1125 tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1126}
int16 AttrNumber
Definition: attnum.h:21
#define NameStr(name)
Definition: c.h:717
#define PointerIsValid(pointer)
Definition: c.h:734
#define FLOAT8PASSBYVAL
Definition: c.h:606
int32_t int32
Definition: c.h:498
uint32_t uint32
Definition: c.h:502
#define MemSet(start, val, len)
Definition: c.h:991
#define PG_INT16_MAX
Definition: c.h:557
bool IsCatalogRelationOid(Oid relid)
Definition: catalog.c:120
Datum datumCopy(Datum value, bool typByVal, int typLen)
Definition: datum.c:132
bool datumIsEqual(Datum value1, Datum value2, bool typByVal, int typLen)
Definition: datum.c:223
struct typedefs * types
Definition: ecpg.c:30
#define ERROR
Definition: elog.h:39
#define elog(elevel,...)
Definition: elog.h:226
static Datum hash_uint32(uint32 k)
Definition: hashfn.h:43
static uint32 hash_combine(uint32 a, uint32 b)
Definition: hashfn.h:68
Assert(PointerIsAligned(start, uint64))
#define HeapTupleIsValid(tuple)
Definition: htup.h:78
static void * GETSTRUCT(const HeapTupleData *tuple)
Definition: htup_details.h:728
int i
Definition: isn.c:77
char * pstrdup(const char *in)
Definition: mcxt.c:2322
void pfree(void *pointer)
Definition: mcxt.c:2147
void * palloc0(Size size)
Definition: mcxt.c:1970
void * palloc(Size size)
Definition: mcxt.c:1940
void namestrcpy(Name name, const char *str)
Definition: name.c:233
FormData_pg_attribute
Definition: pg_attribute.h:186
NameData attname
Definition: pg_attribute.h:41
bool attbyval
Definition: pg_attribute.h:94
#define ATTRIBUTE_FIXED_PART_SIZE
Definition: pg_attribute.h:194
int16 attnum
Definition: pg_attribute.h:74
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:202
#define NAMEDATALEN
#define lfirst(lc)
Definition: pg_list.h:172
static int list_length(const List *l)
Definition: pg_list.h:152
#define lfirst_int(lc)
Definition: pg_list.h:173
#define forfour(cell1, list1, cell2, list2, cell3, list3, cell4, list4)
Definition: pg_list.h:575
#define lfirst_oid(lc)
Definition: pg_list.h:174
FormData_pg_type * Form_pg_type
Definition: pg_type.h:261
static Datum PointerGetDatum(const void *X)
Definition: postgres.h:327
uintptr_t Datum
Definition: postgres.h:69
static Datum ObjectIdGetDatum(Oid X)
Definition: postgres.h:257
static Pointer DatumGetPointer(Datum X)
Definition: postgres.h:317
#define InvalidOid
Definition: postgres_ext.h:35
unsigned int Oid
Definition: postgres_ext.h:30
char * psprintf(const char *fmt,...)
Definition: psprintf.c:43
void * stringToNode(const char *str)
Definition: read.c:90
ResourceOwner CurrentResourceOwner
Definition: resowner.c:173
void ResourceOwnerForget(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:564
void ResourceOwnerRemember(ResourceOwner owner, Datum value, const ResourceOwnerDesc *kind)
Definition: resowner.c:524
void ResourceOwnerEnlarge(ResourceOwner owner)
Definition: resowner.c:452
@ RESOURCE_RELEASE_AFTER_LOCKS
Definition: resowner.h:56
#define RELEASE_PRIO_TUPDESC_REFS
Definition: resowner.h:74
AttrNumber adnum
Definition: tupdesc.h:24
char * adbin
Definition: tupdesc.h:25
bool attgenerated
Definition: tupdesc.h:78
uint8 attalignby
Definition: tupdesc.h:80
bool attisdropped
Definition: tupdesc.h:77
bool attispackable
Definition: tupdesc.h:74
int16 attlen
Definition: tupdesc.h:71
char attnullability
Definition: tupdesc.h:79
bool atthasmissing
Definition: tupdesc.h:76
int32 attcacheoff
Definition: tupdesc.h:70
char * ccname
Definition: tupdesc.h:30
bool ccenforced
Definition: tupdesc.h:32
bool ccnoinherit
Definition: tupdesc.h:34
bool ccvalid
Definition: tupdesc.h:33
char * ccbin
Definition: tupdesc.h:31
Definition: pg_list.h:54
Definition: nodes.h:135
const char * name
Definition: resowner.h:93
bool has_generated_virtual
Definition: tupdesc.h:47
bool has_not_null
Definition: tupdesc.h:45
AttrDefault * defval
Definition: tupdesc.h:40
bool has_generated_stored
Definition: tupdesc.h:46
struct AttrMissing * missing
Definition: tupdesc.h:42
ConstrCheck * check
Definition: tupdesc.h:41
uint16 num_defval
Definition: tupdesc.h:43
uint16 num_check
Definition: tupdesc.h:44
int tdrefcount
Definition: tupdesc.h:140
CompactAttribute compact_attrs[FLEXIBLE_ARRAY_MEMBER]
Definition: tupdesc.h:143
TupleConstr * constr
Definition: tupdesc.h:141
int32 tdtypmod
Definition: tupdesc.h:139
Oid tdtypeid
Definition: tupdesc.h:138
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:269
HeapTuple SearchSysCache1(int cacheId, Datum key1)
Definition: syscache.c:221
#define InvalidCompressionMethod
TupleDesc CreateTupleDescCopyConstr(TupleDesc tupdesc)
Definition: tupdesc.c:333
void TupleDescCopy(TupleDesc dst, TupleDesc src)
Definition: tupdesc.c:421
static void populate_compact_attribute_internal(Form_pg_attribute src, CompactAttribute *dst)
Definition: tupdesc.c:65
Node * TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
Definition: tupdesc.c:1085
void DecrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:570
void FreeTupleDesc(TupleDesc tupdesc)
Definition: tupdesc.c:495
void IncrTupleDescRefCount(TupleDesc tupdesc)
Definition: tupdesc.c:552
void verify_compact_attribute(TupleDesc tupdesc, int attnum)
Definition: tupdesc.c:142
TupleDesc CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:175
static void ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
Definition: tupdesc.c:49
static void ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
Definition: tupdesc.c:55
static void ResOwnerReleaseTupleDesc(Datum res)
Definition: tupdesc.c:1109
uint32 hashRowType(TupleDesc desc)
Definition: tupdesc.c:806
TupleDesc CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
Definition: tupdesc.c:289
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:245
void TupleDescInitBuiltinEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:911
static const ResourceOwnerDesc tupdesc_resowner_desc
Definition: tupdesc.c:38
TupleDesc BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
Definition: tupdesc.c:1044
void populate_compact_attribute(TupleDesc tupdesc, int attnum)
Definition: tupdesc.c:117
bool equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:770
void TupleDescInitEntryCollation(TupleDesc desc, AttrNumber attributeNumber, Oid collationid)
Definition: tupdesc.c:1019
TupleDesc CreateTupleDesc(int natts, Form_pg_attribute *attrs)
Definition: tupdesc.c:222
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:835
bool equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
Definition: tupdesc.c:583
void TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, TupleDesc src, AttrNumber srcAttno)
Definition: tupdesc.c:461
static char * ResOwnerPrintTupleDesc(Datum res)
Definition: tupdesc.c:1120
#define TupleDescSize(src)
Definition: tupdesc.h:198
#define ATTNULLABLE_UNKNOWN
Definition: tupdesc.h:85
#define ATTNULLABLE_VALID
Definition: tupdesc.h:86
static FormData_pg_attribute * TupleDescAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:160
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
Definition: tupdesc.h:175
struct CompactAttribute CompactAttribute
struct TupleDescData * TupleDesc
Definition: tupdesc.h:145
#define ATTNULLABLE_UNRESTRICTED
Definition: tupdesc.h:84
#define strVal(v)
Definition: value.h:82