Thanks to visit codestin.com
Credit goes to doxygen.postgresql.org

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