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