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