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