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