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