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