Line data Source code
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"
23 : #include "access/toast_compression.h"
24 : #include "access/tupdesc_details.h"
25 : #include "catalog/catalog.h"
26 : #include "catalog/pg_collation.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 */
35 : static void ResOwnerReleaseTupleDesc(Datum res);
36 : static char *ResOwnerPrintTupleDesc(Datum res);
37 :
38 : static const ResourceOwnerDesc tupdesc_resowner_desc =
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 */
48 : static inline void
49 33211748 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
50 : {
51 33211748 : ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
52 33211748 : }
53 :
54 : static inline void
55 33195764 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
56 : {
57 33195764 : ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
58 33195764 : }
59 :
60 : /*
61 : * populate_compact_attribute_internal
62 : * Helper function for populate_compact_attribute()
63 : */
64 : static inline void
65 75500074 : populate_compact_attribute_internal(Form_pg_attribute src,
66 : CompactAttribute *dst)
67 : {
68 75500074 : memset(dst, 0, sizeof(CompactAttribute));
69 :
70 75500074 : dst->attcacheoff = -1;
71 75500074 : dst->attlen = src->attlen;
72 :
73 75500074 : dst->attbyval = src->attbyval;
74 75500074 : dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
75 75500074 : dst->atthasmissing = src->atthasmissing;
76 75500074 : dst->attisdropped = src->attisdropped;
77 75500074 : 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 117913002 : dst->attnullability = !src->attnotnull ? ATTNULLABLE_UNRESTRICTED :
86 42412928 : IsCatalogRelationOid(src->attrelid) ? ATTNULLABLE_VALID :
87 : ATTNULLABLE_UNKNOWN;
88 :
89 : /* Compute numeric alignment requirement, too */
90 75500074 : dst->attalignby = typalign_to_alignby(src->attalign);
91 75500074 : }
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 : */
99 : void
100 75500074 : populate_compact_attribute(TupleDesc tupdesc, int attnum)
101 : {
102 75500074 : Form_pg_attribute src = TupleDescAttr(tupdesc, attnum);
103 : CompactAttribute *dst;
104 :
105 : /*
106 : * Don't use TupleDescCompactAttr to prevent infinite recursion in assert
107 : * builds.
108 : */
109 75500074 : dst = &tupdesc->compact_attrs[attnum];
110 :
111 75500074 : populate_compact_attribute_internal(src, dst);
112 75500074 : }
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 : */
124 : void
125 0 : verify_compact_attribute(TupleDesc tupdesc, int attnum)
126 : {
127 : #ifdef USE_ASSERT_CHECKING
128 : CompactAttribute cattr;
129 : Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum);
130 : CompactAttribute tmp;
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 : */
143 : populate_compact_attribute_internal(attr, &tmp);
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 0 : }
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 : */
164 : TupleDesc
165 10850818 : CreateTemplateTupleDesc(int natts)
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 10850818 : desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
188 10850818 : natts * sizeof(CompactAttribute) +
189 : natts * sizeof(FormData_pg_attribute));
190 :
191 : /*
192 : * Initialize other fields of the tupdesc.
193 : */
194 10850818 : desc->natts = natts;
195 10850818 : desc->constr = NULL;
196 10850818 : desc->tdtypeid = RECORDOID;
197 10850818 : desc->tdtypmod = -1;
198 10850818 : desc->tdrefcount = -1; /* assume not reference-counted */
199 :
200 10850818 : 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 : */
211 : TupleDesc
212 1189986 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
213 : {
214 : TupleDesc desc;
215 : int i;
216 :
217 1189986 : desc = CreateTemplateTupleDesc(natts);
218 :
219 18196668 : for (i = 0; i < natts; ++i)
220 : {
221 17006682 : memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
222 17006682 : populate_compact_attribute(desc, i);
223 : }
224 1189986 : 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 : */
234 : TupleDesc
235 431028 : CreateTupleDescCopy(TupleDesc tupdesc)
236 : {
237 : TupleDesc desc;
238 : int i;
239 :
240 431028 : desc = CreateTemplateTupleDesc(tupdesc->natts);
241 :
242 : /* Flat-copy the attribute array */
243 431028 : memcpy(TupleDescAttr(desc, 0),
244 431028 : TupleDescAttr(tupdesc, 0),
245 431028 : 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 2276894 : for (i = 0; i < desc->natts; i++)
252 : {
253 1845866 : Form_pg_attribute att = TupleDescAttr(desc, i);
254 :
255 1845866 : att->attnotnull = false;
256 1845866 : att->atthasdef = false;
257 1845866 : att->atthasmissing = false;
258 1845866 : att->attidentity = '\0';
259 1845866 : att->attgenerated = '\0';
260 :
261 1845866 : populate_compact_attribute(desc, i);
262 : }
263 :
264 : /* We can copy the tuple type identification, too */
265 431028 : desc->tdtypeid = tupdesc->tdtypeid;
266 431028 : desc->tdtypmod = tupdesc->tdtypmod;
267 :
268 431028 : 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 : */
278 : TupleDesc
279 36468 : CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
280 : {
281 : TupleDesc desc;
282 : int i;
283 :
284 : Assert(natts <= tupdesc->natts);
285 :
286 36468 : desc = CreateTemplateTupleDesc(natts);
287 :
288 : /* Flat-copy the attribute array */
289 36468 : memcpy(TupleDescAttr(desc, 0),
290 36468 : TupleDescAttr(tupdesc, 0),
291 36468 : 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 84954 : for (i = 0; i < desc->natts; i++)
298 : {
299 48486 : Form_pg_attribute att = TupleDescAttr(desc, i);
300 :
301 48486 : att->attnotnull = false;
302 48486 : att->atthasdef = false;
303 48486 : att->atthasmissing = false;
304 48486 : att->attidentity = '\0';
305 48486 : att->attgenerated = '\0';
306 :
307 48486 : populate_compact_attribute(desc, i);
308 : }
309 :
310 : /* We can copy the tuple type identification, too */
311 36468 : desc->tdtypeid = tupdesc->tdtypeid;
312 36468 : desc->tdtypmod = tupdesc->tdtypmod;
313 :
314 36468 : 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 : */
322 : TupleDesc
323 923960 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
324 : {
325 : TupleDesc desc;
326 923960 : TupleConstr *constr = tupdesc->constr;
327 : int i;
328 :
329 923960 : desc = CreateTemplateTupleDesc(tupdesc->natts);
330 :
331 : /* Flat-copy the attribute array */
332 923960 : memcpy(TupleDescAttr(desc, 0),
333 923960 : TupleDescAttr(tupdesc, 0),
334 923960 : desc->natts * sizeof(FormData_pg_attribute));
335 :
336 13473018 : for (i = 0; i < desc->natts; i++)
337 : {
338 12549058 : populate_compact_attribute(desc, i);
339 :
340 12549058 : TupleDescCompactAttr(desc, i)->attnullability =
341 25098116 : TupleDescCompactAttr(tupdesc, i)->attnullability;
342 : }
343 :
344 : /* Copy the TupleConstr data structure, if any */
345 923960 : if (constr)
346 : {
347 845620 : TupleConstr *cpy = palloc0_object(TupleConstr);
348 :
349 845620 : cpy->has_not_null = constr->has_not_null;
350 845620 : cpy->has_generated_stored = constr->has_generated_stored;
351 845620 : cpy->has_generated_virtual = constr->has_generated_virtual;
352 :
353 845620 : if ((cpy->num_defval = constr->num_defval) > 0)
354 : {
355 4096 : cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
356 4096 : memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
357 10040 : for (i = cpy->num_defval - 1; i >= 0; i--)
358 5944 : cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
359 : }
360 :
361 845620 : if (constr->missing)
362 : {
363 640 : cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
364 640 : memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
365 4932 : for (i = tupdesc->natts - 1; i >= 0; i--)
366 : {
367 4292 : if (constr->missing[i].am_present)
368 : {
369 1144 : CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
370 :
371 1144 : cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
372 1144 : attr->attbyval,
373 1144 : attr->attlen);
374 : }
375 : }
376 : }
377 :
378 845620 : if ((cpy->num_check = constr->num_check) > 0)
379 : {
380 2350 : cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
381 2350 : memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
382 6414 : for (i = cpy->num_check - 1; i >= 0; i--)
383 : {
384 4064 : cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
385 4064 : cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
386 4064 : cpy->check[i].ccenforced = constr->check[i].ccenforced;
387 4064 : cpy->check[i].ccvalid = constr->check[i].ccvalid;
388 4064 : cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
389 : }
390 : }
391 :
392 845620 : desc->constr = cpy;
393 : }
394 :
395 : /* We can copy the tuple type identification, too */
396 923960 : desc->tdtypeid = tupdesc->tdtypeid;
397 923960 : desc->tdtypmod = tupdesc->tdtypmod;
398 :
399 923960 : 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 : */
410 : void
411 332 : TupleDescCopy(TupleDesc dst, TupleDesc src)
412 : {
413 : int i;
414 :
415 : /* Flat-copy the header and attribute arrays */
416 332 : memcpy(dst, src, TupleDescSize(src));
417 :
418 : /*
419 : * Since we're not copying constraints and defaults, clear fields
420 : * associated with them.
421 : */
422 1256 : for (i = 0; i < dst->natts; i++)
423 : {
424 924 : Form_pg_attribute att = TupleDescAttr(dst, i);
425 :
426 924 : att->attnotnull = false;
427 924 : att->atthasdef = false;
428 924 : att->atthasmissing = false;
429 924 : att->attidentity = '\0';
430 924 : att->attgenerated = '\0';
431 :
432 924 : populate_compact_attribute(dst, i);
433 : }
434 332 : 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 332 : dst->tdrefcount = -1;
441 332 : }
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 : */
450 : void
451 4366 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
452 : TupleDesc src, AttrNumber srcAttno)
453 : {
454 4366 : Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
455 4366 : Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
456 :
457 : /*
458 : * sanity checks
459 : */
460 : Assert(src);
461 : Assert(dst);
462 : Assert(srcAttno >= 1);
463 : Assert(srcAttno <= src->natts);
464 : Assert(dstAttno >= 1);
465 : Assert(dstAttno <= dst->natts);
466 :
467 4366 : memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
468 :
469 4366 : dstAtt->attnum = dstAttno;
470 :
471 : /* since we're not copying constraints or defaults, clear these */
472 4366 : dstAtt->attnotnull = false;
473 4366 : dstAtt->atthasdef = false;
474 4366 : dstAtt->atthasmissing = false;
475 4366 : dstAtt->attidentity = '\0';
476 4366 : dstAtt->attgenerated = '\0';
477 :
478 4366 : populate_compact_attribute(dst, dstAttno - 1);
479 4366 : }
480 :
481 : /*
482 : * Free a TupleDesc including all substructure
483 : */
484 : void
485 1506956 : FreeTupleDesc(TupleDesc tupdesc)
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 1506956 : if (tupdesc->constr)
496 : {
497 459190 : if (tupdesc->constr->num_defval > 0)
498 : {
499 34484 : AttrDefault *attrdef = tupdesc->constr->defval;
500 :
501 83908 : for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
502 49424 : pfree(attrdef[i].adbin);
503 34484 : pfree(attrdef);
504 : }
505 459190 : if (tupdesc->constr->missing)
506 : {
507 3750 : AttrMissing *attrmiss = tupdesc->constr->missing;
508 :
509 26906 : for (i = tupdesc->natts - 1; i >= 0; i--)
510 : {
511 23156 : if (attrmiss[i].am_present
512 7890 : && !TupleDescAttr(tupdesc, i)->attbyval)
513 2926 : pfree(DatumGetPointer(attrmiss[i].am_value));
514 : }
515 3750 : pfree(attrmiss);
516 : }
517 459190 : if (tupdesc->constr->num_check > 0)
518 : {
519 11630 : ConstrCheck *check = tupdesc->constr->check;
520 :
521 31302 : for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
522 : {
523 19672 : pfree(check[i].ccname);
524 19672 : pfree(check[i].ccbin);
525 : }
526 11630 : pfree(check);
527 : }
528 459190 : pfree(tupdesc->constr);
529 : }
530 :
531 1506956 : pfree(tupdesc);
532 1506956 : }
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 : */
541 : void
542 33211748 : IncrTupleDescRefCount(TupleDesc tupdesc)
543 : {
544 : Assert(tupdesc->tdrefcount >= 0);
545 :
546 33211748 : ResourceOwnerEnlarge(CurrentResourceOwner);
547 33211748 : tupdesc->tdrefcount++;
548 33211748 : ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
549 33211748 : }
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 : */
559 : void
560 33195764 : DecrTupleDescRefCount(TupleDesc tupdesc)
561 : {
562 : Assert(tupdesc->tdrefcount > 0);
563 :
564 33195764 : ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
565 33195764 : if (--tupdesc->tdrefcount == 0)
566 0 : FreeTupleDesc(tupdesc);
567 33195764 : }
568 :
569 : /*
570 : * Compare two TupleDesc structures for logical equality
571 : */
572 : bool
573 448424 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
574 : {
575 : int i,
576 : n;
577 :
578 448424 : if (tupdesc1->natts != tupdesc2->natts)
579 2726 : return false;
580 445698 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
581 0 : return false;
582 :
583 : /* tdtypmod and tdrefcount are not checked */
584 :
585 2132778 : for (i = 0; i < tupdesc1->natts; i++)
586 : {
587 1702548 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
588 1702548 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
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 1702548 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
603 1334 : return false;
604 1701214 : if (attr1->atttypid != attr2->atttypid)
605 1182 : return false;
606 1700032 : if (attr1->attlen != attr2->attlen)
607 10 : return false;
608 1700022 : if (attr1->attndims != attr2->attndims)
609 0 : return false;
610 1700022 : if (attr1->atttypmod != attr2->atttypmod)
611 42 : return false;
612 1699980 : if (attr1->attbyval != attr2->attbyval)
613 68 : return false;
614 1699912 : if (attr1->attalign != attr2->attalign)
615 0 : return false;
616 1699912 : if (attr1->attstorage != attr2->attstorage)
617 258 : return false;
618 1699654 : if (attr1->attcompression != attr2->attcompression)
619 72 : return false;
620 1699582 : if (attr1->attnotnull != attr2->attnotnull)
621 1772 : 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 1697810 : if (attr1->attnotnull)
629 : {
630 581140 : CompactAttribute *cattr1 = TupleDescCompactAttr(tupdesc1, i);
631 581140 : CompactAttribute *cattr2 = TupleDescCompactAttr(tupdesc2, i);
632 :
633 : Assert(cattr1->attnullability != ATTNULLABLE_UNKNOWN);
634 : Assert((cattr1->attnullability == ATTNULLABLE_UNKNOWN) ==
635 : (cattr2->attnullability == ATTNULLABLE_UNKNOWN));
636 :
637 581140 : if (cattr1->attnullability != cattr2->attnullability)
638 106 : return false;
639 : }
640 1697704 : if (attr1->atthasdef != attr2->atthasdef)
641 5448 : return false;
642 1692256 : if (attr1->attidentity != attr2->attidentity)
643 190 : return false;
644 1692066 : if (attr1->attgenerated != attr2->attgenerated)
645 20 : return false;
646 1692046 : if (attr1->attisdropped != attr2->attisdropped)
647 0 : return false;
648 1692046 : if (attr1->attislocal != attr2->attislocal)
649 4116 : return false;
650 1687930 : if (attr1->attinhcount != attr2->attinhcount)
651 850 : return false;
652 1687080 : if (attr1->attcollation != attr2->attcollation)
653 0 : return false;
654 : /* variable-length fields are not even present... */
655 : }
656 :
657 430230 : if (tupdesc1->constr != NULL)
658 : {
659 159096 : TupleConstr *constr1 = tupdesc1->constr;
660 159096 : TupleConstr *constr2 = tupdesc2->constr;
661 :
662 159096 : if (constr2 == NULL)
663 230 : return false;
664 158866 : if (constr1->has_not_null != constr2->has_not_null)
665 0 : return false;
666 158866 : if (constr1->has_generated_stored != constr2->has_generated_stored)
667 632 : return false;
668 158234 : if (constr1->has_generated_virtual != constr2->has_generated_virtual)
669 424 : return false;
670 157810 : n = constr1->num_defval;
671 157810 : if (n != (int) constr2->num_defval)
672 0 : return false;
673 : /* We assume here that both AttrDefault arrays are in adnum order */
674 177736 : for (i = 0; i < n; i++)
675 : {
676 19926 : AttrDefault *defval1 = constr1->defval + i;
677 19926 : AttrDefault *defval2 = constr2->defval + i;
678 :
679 19926 : if (defval1->adnum != defval2->adnum)
680 0 : return false;
681 19926 : if (strcmp(defval1->adbin, defval2->adbin) != 0)
682 0 : return false;
683 : }
684 157810 : if (constr1->missing)
685 : {
686 716 : if (!constr2->missing)
687 84 : return false;
688 3824 : for (i = 0; i < tupdesc1->natts; i++)
689 : {
690 3338 : AttrMissing *missval1 = constr1->missing + i;
691 3338 : AttrMissing *missval2 = constr2->missing + i;
692 :
693 3338 : if (missval1->am_present != missval2->am_present)
694 146 : return false;
695 3192 : if (missval1->am_present)
696 : {
697 1062 : CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
698 :
699 1062 : if (!datumIsEqual(missval1->am_value, missval2->am_value,
700 1062 : missatt1->attbyval, missatt1->attlen))
701 0 : return false;
702 : }
703 : }
704 : }
705 157094 : else if (constr2->missing)
706 374 : return false;
707 157206 : n = constr1->num_check;
708 157206 : if (n != (int) constr2->num_check)
709 1600 : 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 159744 : for (i = 0; i < n; i++)
717 : {
718 4240 : ConstrCheck *check1 = constr1->check + i;
719 4240 : ConstrCheck *check2 = constr2->check + i;
720 :
721 4240 : if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
722 4240 : strcmp(check1->ccbin, check2->ccbin) == 0 &&
723 4240 : check1->ccenforced == check2->ccenforced &&
724 4222 : check1->ccvalid == check2->ccvalid &&
725 4138 : check1->ccnoinherit == check2->ccnoinherit))
726 102 : return false;
727 : }
728 : }
729 271134 : else if (tupdesc2->constr != NULL)
730 1976 : return false;
731 424662 : 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 : */
759 : bool
760 472184 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
761 : {
762 472184 : if (tupdesc1->natts != tupdesc2->natts)
763 168 : return false;
764 472016 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
765 1898 : return false;
766 :
767 7800166 : for (int i = 0; i < tupdesc1->natts; i++)
768 : {
769 7338858 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
770 7338858 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
771 :
772 7338858 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
773 8784 : return false;
774 7330074 : if (attr1->atttypid != attr2->atttypid)
775 22 : return false;
776 7330052 : if (attr1->atttypmod != attr2->atttypmod)
777 4 : return false;
778 7330048 : if (attr1->attcollation != attr2->attcollation)
779 0 : return false;
780 :
781 : /* Record types derived from tables could have dropped fields. */
782 7330048 : if (attr1->attisdropped != attr2->attisdropped)
783 0 : return false;
784 : }
785 :
786 461308 : 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 : */
795 : uint32
796 491774 : hashRowType(TupleDesc desc)
797 : {
798 : uint32 s;
799 : int i;
800 :
801 491774 : s = hash_combine(0, hash_bytes_uint32(desc->natts));
802 491774 : s = hash_combine(s, hash_bytes_uint32(desc->tdtypeid));
803 8173394 : for (i = 0; i < desc->natts; ++i)
804 7681620 : s = hash_combine(s, hash_bytes_uint32(TupleDescAttr(desc, i)->atttypid));
805 :
806 491774 : 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 : */
824 : void
825 14423366 : TupleDescInitEntry(TupleDesc desc,
826 : AttrNumber attributeNumber,
827 : const char *attributeName,
828 : Oid oidtypeid,
829 : int32 typmod,
830 : int attdim)
831 : {
832 : HeapTuple tuple;
833 : Form_pg_type typeForm;
834 : Form_pg_attribute att;
835 :
836 : /*
837 : * sanity checks
838 : */
839 : Assert(desc);
840 : Assert(attributeNumber >= 1);
841 : Assert(attributeNumber <= desc->natts);
842 : Assert(attdim >= 0);
843 : Assert(attdim <= PG_INT16_MAX);
844 :
845 : /*
846 : * initialize the attribute fields
847 : */
848 14423366 : att = TupleDescAttr(desc, attributeNumber - 1);
849 :
850 14423366 : 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 14423366 : if (attributeName == NULL)
858 19924212 : MemSet(NameStr(att->attname), 0, NAMEDATALEN);
859 10183378 : else if (attributeName != NameStr(att->attname))
860 10179886 : namestrcpy(&(att->attname), attributeName);
861 :
862 14423366 : att->atttypmod = typmod;
863 :
864 14423366 : att->attnum = attributeNumber;
865 14423366 : att->attndims = attdim;
866 :
867 14423366 : att->attnotnull = false;
868 14423366 : att->atthasdef = false;
869 14423366 : att->atthasmissing = false;
870 14423366 : att->attidentity = '\0';
871 14423366 : att->attgenerated = '\0';
872 14423366 : att->attisdropped = false;
873 14423366 : att->attislocal = true;
874 14423366 : att->attinhcount = 0;
875 : /* variable-length fields are not present in tupledescs */
876 :
877 14423366 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
878 14423366 : if (!HeapTupleIsValid(tuple))
879 0 : elog(ERROR, "cache lookup failed for type %u", oidtypeid);
880 14423366 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
881 :
882 14423366 : att->atttypid = oidtypeid;
883 14423366 : att->attlen = typeForm->typlen;
884 14423366 : att->attbyval = typeForm->typbyval;
885 14423366 : att->attalign = typeForm->typalign;
886 14423366 : att->attstorage = typeForm->typstorage;
887 14423366 : att->attcompression = InvalidCompressionMethod;
888 14423366 : att->attcollation = typeForm->typcollation;
889 :
890 14423366 : populate_compact_attribute(desc, attributeNumber - 1);
891 :
892 14423366 : ReleaseSysCache(tuple);
893 14423366 : }
894 :
895 : /*
896 : * TupleDescInitBuiltinEntry
897 : * Initialize a tuple descriptor without catalog access. Only
898 : * a limited range of builtin types are supported.
899 : */
900 : void
901 14292 : TupleDescInitBuiltinEntry(TupleDesc desc,
902 : AttrNumber attributeNumber,
903 : const char *attributeName,
904 : Oid oidtypeid,
905 : int32 typmod,
906 : int attdim)
907 : {
908 : Form_pg_attribute att;
909 :
910 : /* sanity checks */
911 : Assert(desc);
912 : Assert(attributeNumber >= 1);
913 : Assert(attributeNumber <= desc->natts);
914 : Assert(attdim >= 0);
915 : Assert(attdim <= PG_INT16_MAX);
916 :
917 : /* initialize the attribute fields */
918 14292 : att = TupleDescAttr(desc, attributeNumber - 1);
919 14292 : att->attrelid = 0; /* dummy value */
920 :
921 : /* unlike TupleDescInitEntry, we require an attribute name */
922 : Assert(attributeName != NULL);
923 14292 : namestrcpy(&(att->attname), attributeName);
924 :
925 14292 : att->atttypmod = typmod;
926 :
927 14292 : att->attnum = attributeNumber;
928 14292 : att->attndims = attdim;
929 :
930 14292 : att->attnotnull = false;
931 14292 : att->atthasdef = false;
932 14292 : att->atthasmissing = false;
933 14292 : att->attidentity = '\0';
934 14292 : att->attgenerated = '\0';
935 14292 : att->attisdropped = false;
936 14292 : att->attislocal = true;
937 14292 : att->attinhcount = 0;
938 : /* variable-length fields are not present in tupledescs */
939 :
940 14292 : 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 14292 : switch (oidtypeid)
948 : {
949 11450 : case TEXTOID:
950 : case TEXTARRAYOID:
951 11450 : att->attlen = -1;
952 11450 : att->attbyval = false;
953 11450 : att->attalign = TYPALIGN_INT;
954 11450 : att->attstorage = TYPSTORAGE_EXTENDED;
955 11450 : att->attcompression = InvalidCompressionMethod;
956 11450 : att->attcollation = DEFAULT_COLLATION_OID;
957 11450 : break;
958 :
959 0 : case BOOLOID:
960 0 : att->attlen = 1;
961 0 : att->attbyval = true;
962 0 : att->attalign = TYPALIGN_CHAR;
963 0 : att->attstorage = TYPSTORAGE_PLAIN;
964 0 : att->attcompression = InvalidCompressionMethod;
965 0 : att->attcollation = InvalidOid;
966 0 : break;
967 :
968 0 : case INT4OID:
969 0 : att->attlen = 4;
970 0 : att->attbyval = true;
971 0 : att->attalign = TYPALIGN_INT;
972 0 : att->attstorage = TYPSTORAGE_PLAIN;
973 0 : att->attcompression = InvalidCompressionMethod;
974 0 : att->attcollation = InvalidOid;
975 0 : break;
976 :
977 2510 : case INT8OID:
978 2510 : att->attlen = 8;
979 2510 : att->attbyval = true;
980 2510 : att->attalign = TYPALIGN_DOUBLE;
981 2510 : att->attstorage = TYPSTORAGE_PLAIN;
982 2510 : att->attcompression = InvalidCompressionMethod;
983 2510 : att->attcollation = InvalidOid;
984 2510 : break;
985 :
986 332 : case OIDOID:
987 332 : att->attlen = 4;
988 332 : att->attbyval = true;
989 332 : att->attalign = TYPALIGN_INT;
990 332 : att->attstorage = TYPSTORAGE_PLAIN;
991 332 : att->attcompression = InvalidCompressionMethod;
992 332 : att->attcollation = InvalidOid;
993 332 : break;
994 :
995 0 : default:
996 0 : elog(ERROR, "unsupported type %u", oidtypeid);
997 : }
998 :
999 14292 : populate_compact_attribute(desc, attributeNumber - 1);
1000 14292 : }
1001 :
1002 : /*
1003 : * TupleDescInitEntryCollation
1004 : *
1005 : * Assign a nondefault collation to a previously initialized tuple descriptor
1006 : * entry.
1007 : */
1008 : void
1009 6630316 : TupleDescInitEntryCollation(TupleDesc desc,
1010 : AttrNumber attributeNumber,
1011 : Oid collationid)
1012 : {
1013 : /*
1014 : * sanity checks
1015 : */
1016 : Assert(desc);
1017 : Assert(attributeNumber >= 1);
1018 : Assert(attributeNumber <= desc->natts);
1019 :
1020 6630316 : TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
1021 6630316 : }
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 : */
1033 : TupleDesc
1034 1416 : BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
1035 : {
1036 : int natts;
1037 : AttrNumber attnum;
1038 : ListCell *l1;
1039 : ListCell *l2;
1040 : ListCell *l3;
1041 : ListCell *l4;
1042 : TupleDesc desc;
1043 :
1044 1416 : 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 1416 : desc = CreateTemplateTupleDesc(natts);
1053 :
1054 1416 : attnum = 0;
1055 4992 : forfour(l1, names, l2, types, l3, typmods, l4, collations)
1056 : {
1057 3576 : char *attname = strVal(lfirst(l1));
1058 3576 : Oid atttypid = lfirst_oid(l2);
1059 3576 : int32 atttypmod = lfirst_int(l3);
1060 3576 : Oid attcollation = lfirst_oid(l4);
1061 :
1062 3576 : attnum++;
1063 :
1064 3576 : TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
1065 3576 : TupleDescInitEntryCollation(desc, attnum, attcollation);
1066 : }
1067 :
1068 1416 : return desc;
1069 : }
1070 :
1071 : /*
1072 : * Get default expression (or NULL if none) for the given attribute number.
1073 : */
1074 : Node *
1075 152272 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
1076 : {
1077 152272 : Node *result = NULL;
1078 :
1079 152272 : if (tupdesc->constr)
1080 : {
1081 152272 : AttrDefault *attrdef = tupdesc->constr->defval;
1082 :
1083 229584 : for (int i = 0; i < tupdesc->constr->num_defval; i++)
1084 : {
1085 229584 : if (attrdef[i].adnum == attnum)
1086 : {
1087 152272 : result = stringToNode(attrdef[i].adbin);
1088 152272 : break;
1089 : }
1090 : }
1091 : }
1092 :
1093 152272 : return result;
1094 : }
1095 :
1096 : /* ResourceOwner callbacks */
1097 :
1098 : static void
1099 15984 : ResOwnerReleaseTupleDesc(Datum res)
1100 : {
1101 15984 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1102 :
1103 : /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
1104 : Assert(tupdesc->tdrefcount > 0);
1105 15984 : if (--tupdesc->tdrefcount == 0)
1106 492 : FreeTupleDesc(tupdesc);
1107 15984 : }
1108 :
1109 : static char *
1110 0 : ResOwnerPrintTupleDesc(Datum res)
1111 : {
1112 0 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1113 :
1114 0 : return psprintf("TupleDesc %p (%u,%d)",
1115 : tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1116 : }
|