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 29568470 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
49 : {
50 29568470 : ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
51 29568470 : }
52 :
53 : static inline void
54 29555288 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
55 : {
56 29555288 : ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
57 29555288 : }
58 :
59 : /*
60 : * populate_compact_attribute_internal
61 : * Helper function for populate_compact_attribute()
62 : */
63 : static inline void
64 65138482 : populate_compact_attribute_internal(Form_pg_attribute src,
65 : CompactAttribute *dst)
66 : {
67 65138482 : memset(dst, 0, sizeof(CompactAttribute));
68 :
69 65138482 : dst->attcacheoff = -1;
70 65138482 : dst->attlen = src->attlen;
71 :
72 65138482 : dst->attbyval = src->attbyval;
73 65138482 : dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
74 65138482 : dst->atthasmissing = src->atthasmissing;
75 65138482 : dst->attisdropped = src->attisdropped;
76 65138482 : dst->attgenerated = (src->attgenerated != '\0');
77 65138482 : dst->attnotnull = src->attnotnull;
78 :
79 65138482 : switch (src->attalign)
80 : {
81 41618190 : case TYPALIGN_INT:
82 41618190 : dst->attalignby = ALIGNOF_INT;
83 41618190 : break;
84 16679250 : case TYPALIGN_CHAR:
85 16679250 : dst->attalignby = sizeof(char);
86 16679250 : break;
87 3794458 : case TYPALIGN_DOUBLE:
88 3794458 : dst->attalignby = ALIGNOF_DOUBLE;
89 3794458 : break;
90 3046584 : case TYPALIGN_SHORT:
91 3046584 : dst->attalignby = ALIGNOF_SHORT;
92 3046584 : break;
93 0 : default:
94 0 : dst->attalignby = 0;
95 0 : elog(ERROR, "invalid attalign value: %c", src->attalign);
96 : break;
97 : }
98 65138482 : }
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 65138482 : populate_compact_attribute(TupleDesc tupdesc, int attnum)
108 : {
109 65138482 : 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 65138482 : dst = &tupdesc->compact_attrs[attnum];
117 :
118 65138482 : populate_compact_attribute_internal(src, dst);
119 65138482 : }
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 9584058 : 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 9584058 : desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
187 9584058 : natts * sizeof(CompactAttribute) +
188 : natts * sizeof(FormData_pg_attribute));
189 :
190 : /*
191 : * Initialize other fields of the tupdesc.
192 : */
193 9584058 : desc->natts = natts;
194 9584058 : desc->constr = NULL;
195 9584058 : desc->tdtypeid = RECORDOID;
196 9584058 : desc->tdtypmod = -1;
197 9584058 : desc->tdrefcount = -1; /* assume not reference-counted */
198 :
199 9584058 : 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 1032070 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
212 : {
213 : TupleDesc desc;
214 : int i;
215 :
216 1032070 : desc = CreateTemplateTupleDesc(natts);
217 :
218 15763510 : for (i = 0; i < natts; ++i)
219 : {
220 14731440 : memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
221 14731440 : populate_compact_attribute(desc, i);
222 : }
223 1032070 : 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 387178 : CreateTupleDescCopy(TupleDesc tupdesc)
235 : {
236 : TupleDesc desc;
237 : int i;
238 :
239 387178 : desc = CreateTemplateTupleDesc(tupdesc->natts);
240 :
241 : /* Flat-copy the attribute array */
242 387178 : memcpy(TupleDescAttr(desc, 0),
243 387178 : TupleDescAttr(tupdesc, 0),
244 387178 : 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 1994652 : for (i = 0; i < desc->natts; i++)
251 : {
252 1607474 : Form_pg_attribute att = TupleDescAttr(desc, i);
253 :
254 1607474 : att->attnotnull = false;
255 1607474 : att->atthasdef = false;
256 1607474 : att->atthasmissing = false;
257 1607474 : att->attidentity = '\0';
258 1607474 : att->attgenerated = '\0';
259 :
260 1607474 : populate_compact_attribute(desc, i);
261 : }
262 :
263 : /* We can copy the tuple type identification, too */
264 387178 : desc->tdtypeid = tupdesc->tdtypeid;
265 387178 : desc->tdtypmod = tupdesc->tdtypmod;
266 :
267 387178 : 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 35046 : CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
279 : {
280 : TupleDesc desc;
281 : int i;
282 :
283 : Assert(natts <= tupdesc->natts);
284 :
285 35046 : desc = CreateTemplateTupleDesc(natts);
286 :
287 : /* Flat-copy the attribute array */
288 35046 : memcpy(TupleDescAttr(desc, 0),
289 35046 : TupleDescAttr(tupdesc, 0),
290 35046 : 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 81752 : for (i = 0; i < desc->natts; i++)
297 : {
298 46706 : Form_pg_attribute att = TupleDescAttr(desc, i);
299 :
300 46706 : att->attnotnull = false;
301 46706 : att->atthasdef = false;
302 46706 : att->atthasmissing = false;
303 46706 : att->attidentity = '\0';
304 46706 : att->attgenerated = '\0';
305 :
306 46706 : populate_compact_attribute(desc, i);
307 : }
308 :
309 : /* We can copy the tuple type identification, too */
310 35046 : desc->tdtypeid = tupdesc->tdtypeid;
311 35046 : desc->tdtypmod = tupdesc->tdtypmod;
312 :
313 35046 : 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 806132 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
323 : {
324 : TupleDesc desc;
325 806132 : TupleConstr *constr = tupdesc->constr;
326 : int i;
327 :
328 806132 : desc = CreateTemplateTupleDesc(tupdesc->natts);
329 :
330 : /* Flat-copy the attribute array */
331 806132 : memcpy(TupleDescAttr(desc, 0),
332 806132 : TupleDescAttr(tupdesc, 0),
333 806132 : desc->natts * sizeof(FormData_pg_attribute));
334 :
335 12179188 : for (i = 0; i < desc->natts; i++)
336 11373056 : populate_compact_attribute(desc, i);
337 :
338 : /* Copy the TupleConstr data structure, if any */
339 806132 : if (constr)
340 : {
341 751038 : TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
342 :
343 751038 : cpy->has_not_null = constr->has_not_null;
344 751038 : cpy->has_generated_stored = constr->has_generated_stored;
345 :
346 751038 : if ((cpy->num_defval = constr->num_defval) > 0)
347 : {
348 2844 : cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
349 2844 : memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
350 7012 : for (i = cpy->num_defval - 1; i >= 0; i--)
351 4168 : cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
352 : }
353 :
354 751038 : if (constr->missing)
355 : {
356 584 : cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
357 584 : memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
358 4658 : for (i = tupdesc->natts - 1; i >= 0; i--)
359 : {
360 4074 : if (constr->missing[i].am_present)
361 : {
362 1082 : CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
363 :
364 1082 : cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
365 1082 : attr->attbyval,
366 1082 : attr->attlen);
367 : }
368 : }
369 : }
370 :
371 751038 : if ((cpy->num_check = constr->num_check) > 0)
372 : {
373 2050 : cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
374 2050 : memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
375 5376 : for (i = cpy->num_check - 1; i >= 0; i--)
376 : {
377 3326 : cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
378 3326 : cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
379 3326 : cpy->check[i].ccenforced = constr->check[i].ccenforced;
380 3326 : cpy->check[i].ccvalid = constr->check[i].ccvalid;
381 3326 : cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
382 : }
383 : }
384 :
385 751038 : desc->constr = cpy;
386 : }
387 :
388 : /* We can copy the tuple type identification, too */
389 806132 : desc->tdtypeid = tupdesc->tdtypeid;
390 806132 : desc->tdtypmod = tupdesc->tdtypmod;
391 :
392 806132 : return desc;
393 : }
394 :
395 : /*
396 : * TupleDescCopy
397 : * Copy a tuple descriptor into caller-supplied memory.
398 : * The memory may be shared memory mapped at any address, and must
399 : * be sufficient to hold TupleDescSize(src) bytes.
400 : *
401 : * !!! Constraints and defaults are not copied !!!
402 : */
403 : void
404 168 : TupleDescCopy(TupleDesc dst, TupleDesc src)
405 : {
406 : int i;
407 :
408 : /* Flat-copy the header and attribute arrays */
409 168 : memcpy(dst, src, TupleDescSize(src));
410 :
411 : /*
412 : * Since we're not copying constraints and defaults, clear fields
413 : * associated with them.
414 : */
415 684 : for (i = 0; i < dst->natts; i++)
416 : {
417 516 : Form_pg_attribute att = TupleDescAttr(dst, i);
418 :
419 516 : att->attnotnull = false;
420 516 : att->atthasdef = false;
421 516 : att->atthasmissing = false;
422 516 : att->attidentity = '\0';
423 516 : att->attgenerated = '\0';
424 :
425 516 : populate_compact_attribute(dst, i);
426 : }
427 168 : dst->constr = NULL;
428 :
429 : /*
430 : * Also, assume the destination is not to be ref-counted. (Copying the
431 : * source's refcount would be wrong in any case.)
432 : */
433 168 : dst->tdrefcount = -1;
434 168 : }
435 :
436 : /*
437 : * TupleDescCopyEntry
438 : * This function copies a single attribute structure from one tuple
439 : * descriptor to another.
440 : *
441 : * !!! Constraints and defaults are not copied !!!
442 : */
443 : void
444 3618 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
445 : TupleDesc src, AttrNumber srcAttno)
446 : {
447 3618 : Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
448 3618 : Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
449 :
450 : /*
451 : * sanity checks
452 : */
453 : Assert(PointerIsValid(src));
454 : Assert(PointerIsValid(dst));
455 : Assert(srcAttno >= 1);
456 : Assert(srcAttno <= src->natts);
457 : Assert(dstAttno >= 1);
458 : Assert(dstAttno <= dst->natts);
459 :
460 3618 : memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
461 :
462 3618 : dstAtt->attnum = dstAttno;
463 :
464 : /* since we're not copying constraints or defaults, clear these */
465 3618 : dstAtt->attnotnull = false;
466 3618 : dstAtt->atthasdef = false;
467 3618 : dstAtt->atthasmissing = false;
468 3618 : dstAtt->attidentity = '\0';
469 3618 : dstAtt->attgenerated = '\0';
470 :
471 3618 : populate_compact_attribute(dst, dstAttno - 1);
472 3618 : }
473 :
474 : /*
475 : * Free a TupleDesc including all substructure
476 : */
477 : void
478 1326416 : FreeTupleDesc(TupleDesc tupdesc)
479 : {
480 : int i;
481 :
482 : /*
483 : * Possibly this should assert tdrefcount == 0, to disallow explicit
484 : * freeing of un-refcounted tupdescs?
485 : */
486 : Assert(tupdesc->tdrefcount <= 0);
487 :
488 1326416 : if (tupdesc->constr)
489 : {
490 395304 : if (tupdesc->constr->num_defval > 0)
491 : {
492 24248 : AttrDefault *attrdef = tupdesc->constr->defval;
493 :
494 58624 : for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
495 34376 : pfree(attrdef[i].adbin);
496 24248 : pfree(attrdef);
497 : }
498 395304 : if (tupdesc->constr->missing)
499 : {
500 3334 : AttrMissing *attrmiss = tupdesc->constr->missing;
501 :
502 24476 : for (i = tupdesc->natts - 1; i >= 0; i--)
503 : {
504 21142 : if (attrmiss[i].am_present
505 7150 : && !TupleDescAttr(tupdesc, i)->attbyval)
506 2684 : pfree(DatumGetPointer(attrmiss[i].am_value));
507 : }
508 3334 : pfree(attrmiss);
509 : }
510 395304 : if (tupdesc->constr->num_check > 0)
511 : {
512 10016 : ConstrCheck *check = tupdesc->constr->check;
513 :
514 25224 : for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
515 : {
516 15208 : pfree(check[i].ccname);
517 15208 : pfree(check[i].ccbin);
518 : }
519 10016 : pfree(check);
520 : }
521 395304 : pfree(tupdesc->constr);
522 : }
523 :
524 1326416 : pfree(tupdesc);
525 1326416 : }
526 :
527 : /*
528 : * Increment the reference count of a tupdesc, and log the reference in
529 : * CurrentResourceOwner.
530 : *
531 : * Do not apply this to tupdescs that are not being refcounted. (Use the
532 : * macro PinTupleDesc for tupdescs of uncertain status.)
533 : */
534 : void
535 29568470 : IncrTupleDescRefCount(TupleDesc tupdesc)
536 : {
537 : Assert(tupdesc->tdrefcount >= 0);
538 :
539 29568470 : ResourceOwnerEnlarge(CurrentResourceOwner);
540 29568470 : tupdesc->tdrefcount++;
541 29568470 : ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
542 29568470 : }
543 :
544 : /*
545 : * Decrement the reference count of a tupdesc, remove the corresponding
546 : * reference from CurrentResourceOwner, and free the tupdesc if no more
547 : * references remain.
548 : *
549 : * Do not apply this to tupdescs that are not being refcounted. (Use the
550 : * macro ReleaseTupleDesc for tupdescs of uncertain status.)
551 : */
552 : void
553 29555288 : DecrTupleDescRefCount(TupleDesc tupdesc)
554 : {
555 : Assert(tupdesc->tdrefcount > 0);
556 :
557 29555288 : ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
558 29555288 : if (--tupdesc->tdrefcount == 0)
559 4 : FreeTupleDesc(tupdesc);
560 29555288 : }
561 :
562 : /*
563 : * Compare two TupleDesc structures for logical equality
564 : */
565 : bool
566 387484 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
567 : {
568 : int i,
569 : n;
570 :
571 387484 : if (tupdesc1->natts != tupdesc2->natts)
572 2450 : return false;
573 385034 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
574 0 : return false;
575 :
576 : /* tdtypmod and tdrefcount are not checked */
577 :
578 1850876 : for (i = 0; i < tupdesc1->natts; i++)
579 : {
580 1477258 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
581 1477258 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
582 :
583 : /*
584 : * We do not need to check every single field here: we can disregard
585 : * attrelid and attnum (which were used to place the row in the attrs
586 : * array in the first place). It might look like we could dispense
587 : * with checking attlen/attbyval/attalign, since these are derived
588 : * from atttypid; but in the case of dropped columns we must check
589 : * them (since atttypid will be zero for all dropped columns) and in
590 : * general it seems safer to check them always.
591 : *
592 : * We intentionally ignore atthasmissing, since that's not very
593 : * relevant in tupdescs, which lack the attmissingval field.
594 : */
595 1477258 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
596 1254 : return false;
597 1476004 : if (attr1->atttypid != attr2->atttypid)
598 974 : return false;
599 1475030 : if (attr1->attlen != attr2->attlen)
600 8 : return false;
601 1475022 : if (attr1->attndims != attr2->attndims)
602 0 : return false;
603 1475022 : if (attr1->atttypmod != attr2->atttypmod)
604 42 : return false;
605 1474980 : if (attr1->attbyval != attr2->attbyval)
606 62 : return false;
607 1474918 : if (attr1->attalign != attr2->attalign)
608 0 : return false;
609 1474918 : if (attr1->attstorage != attr2->attstorage)
610 208 : return false;
611 1474710 : if (attr1->attcompression != attr2->attcompression)
612 62 : return false;
613 1474648 : if (attr1->attnotnull != attr2->attnotnull)
614 1438 : return false;
615 1473210 : if (attr1->atthasdef != attr2->atthasdef)
616 3898 : return false;
617 1469312 : if (attr1->attidentity != attr2->attidentity)
618 178 : return false;
619 1469134 : if (attr1->attgenerated != attr2->attgenerated)
620 20 : return false;
621 1469114 : if (attr1->attisdropped != attr2->attisdropped)
622 0 : return false;
623 1469114 : if (attr1->attislocal != attr2->attislocal)
624 2552 : return false;
625 1466562 : if (attr1->attinhcount != attr2->attinhcount)
626 720 : return false;
627 1465842 : if (attr1->attcollation != attr2->attcollation)
628 0 : return false;
629 : /* variable-length fields are not even present... */
630 : }
631 :
632 373618 : if (tupdesc1->constr != NULL)
633 : {
634 129806 : TupleConstr *constr1 = tupdesc1->constr;
635 129806 : TupleConstr *constr2 = tupdesc2->constr;
636 :
637 129806 : if (constr2 == NULL)
638 212 : return false;
639 129594 : if (constr1->has_not_null != constr2->has_not_null)
640 0 : return false;
641 129594 : if (constr1->has_generated_stored != constr2->has_generated_stored)
642 506 : return false;
643 129088 : n = constr1->num_defval;
644 129088 : if (n != (int) constr2->num_defval)
645 0 : return false;
646 : /* We assume here that both AttrDefault arrays are in adnum order */
647 141496 : for (i = 0; i < n; i++)
648 : {
649 12408 : AttrDefault *defval1 = constr1->defval + i;
650 12408 : AttrDefault *defval2 = constr2->defval + i;
651 :
652 12408 : if (defval1->adnum != defval2->adnum)
653 0 : return false;
654 12408 : if (strcmp(defval1->adbin, defval2->adbin) != 0)
655 0 : return false;
656 : }
657 129088 : if (constr1->missing)
658 : {
659 520 : if (!constr2->missing)
660 66 : return false;
661 2600 : for (i = 0; i < tupdesc1->natts; i++)
662 : {
663 2146 : AttrMissing *missval1 = constr1->missing + i;
664 2146 : AttrMissing *missval2 = constr2->missing + i;
665 :
666 2146 : if (missval1->am_present != missval2->am_present)
667 0 : return false;
668 2146 : if (missval1->am_present)
669 : {
670 572 : CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
671 :
672 572 : if (!datumIsEqual(missval1->am_value, missval2->am_value,
673 572 : missatt1->attbyval, missatt1->attlen))
674 0 : return false;
675 : }
676 : }
677 : }
678 128568 : else if (constr2->missing)
679 4 : return false;
680 129018 : n = constr1->num_check;
681 129018 : if (n != (int) constr2->num_check)
682 1342 : return false;
683 :
684 : /*
685 : * Similarly, we rely here on the ConstrCheck entries being sorted by
686 : * name. If there are duplicate names, the outcome of the comparison
687 : * is uncertain, but that should not happen.
688 : */
689 130610 : for (i = 0; i < n; i++)
690 : {
691 3024 : ConstrCheck *check1 = constr1->check + i;
692 3024 : ConstrCheck *check2 = constr2->check + i;
693 :
694 3024 : if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
695 3024 : strcmp(check1->ccbin, check2->ccbin) == 0 &&
696 3024 : check1->ccenforced == check2->ccenforced &&
697 3012 : check1->ccvalid == check2->ccvalid &&
698 2934 : check1->ccnoinherit == check2->ccnoinherit))
699 90 : return false;
700 : }
701 : }
702 243812 : else if (tupdesc2->constr != NULL)
703 1536 : return false;
704 369862 : return true;
705 : }
706 :
707 : /*
708 : * equalRowTypes
709 : *
710 : * This determines whether two tuple descriptors have equal row types. This
711 : * only checks those fields in pg_attribute that are applicable for row types,
712 : * while ignoring those fields that define the physical row storage or those
713 : * that define table column metadata.
714 : *
715 : * Specifically, this checks:
716 : *
717 : * - same number of attributes
718 : * - same composite type ID (but could both be zero)
719 : * - corresponding attributes (in order) have same the name, type, typmod,
720 : * collation
721 : *
722 : * This is used to check whether two record types are compatible, whether
723 : * function return row types are the same, and other similar situations.
724 : *
725 : * (XXX There was some discussion whether attndims should be checked here, but
726 : * for now it has been decided not to.)
727 : *
728 : * Note: We deliberately do not check the tdtypmod field. This allows
729 : * typcache.c to use this routine to see if a cached record type matches a
730 : * requested type.
731 : */
732 : bool
733 322448 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
734 : {
735 322448 : if (tupdesc1->natts != tupdesc2->natts)
736 168 : return false;
737 322280 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
738 1732 : return false;
739 :
740 5114728 : for (int i = 0; i < tupdesc1->natts; i++)
741 : {
742 4797850 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
743 4797850 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
744 :
745 4797850 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
746 3644 : return false;
747 4794206 : if (attr1->atttypid != attr2->atttypid)
748 22 : return false;
749 4794184 : if (attr1->atttypmod != attr2->atttypmod)
750 4 : return false;
751 4794180 : if (attr1->attcollation != attr2->attcollation)
752 0 : return false;
753 :
754 : /* Record types derived from tables could have dropped fields. */
755 4794180 : if (attr1->attisdropped != attr2->attisdropped)
756 0 : return false;
757 : }
758 :
759 316878 : return true;
760 : }
761 :
762 : /*
763 : * hashRowType
764 : *
765 : * If two tuple descriptors would be considered equal by equalRowTypes()
766 : * then their hash value will be equal according to this function.
767 : */
768 : uint32
769 341056 : hashRowType(TupleDesc desc)
770 : {
771 : uint32 s;
772 : int i;
773 :
774 341056 : s = hash_combine(0, hash_uint32(desc->natts));
775 341056 : s = hash_combine(s, hash_uint32(desc->tdtypeid));
776 5402110 : for (i = 0; i < desc->natts; ++i)
777 5061054 : s = hash_combine(s, hash_uint32(TupleDescAttr(desc, i)->atttypid));
778 :
779 341056 : return s;
780 : }
781 :
782 : /*
783 : * TupleDescInitEntry
784 : * This function initializes a single attribute structure in
785 : * a previously allocated tuple descriptor.
786 : *
787 : * If attributeName is NULL, the attname field is set to an empty string
788 : * (this is for cases where we don't know or need a name for the field).
789 : * Also, some callers use this function to change the datatype-related fields
790 : * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
791 : * to indicate that the attname field shouldn't be modified.
792 : *
793 : * Note that attcollation is set to the default for the specified datatype.
794 : * If a nondefault collation is needed, insert it afterwards using
795 : * TupleDescInitEntryCollation.
796 : */
797 : void
798 10934036 : TupleDescInitEntry(TupleDesc desc,
799 : AttrNumber attributeNumber,
800 : const char *attributeName,
801 : Oid oidtypeid,
802 : int32 typmod,
803 : int attdim)
804 : {
805 : HeapTuple tuple;
806 : Form_pg_type typeForm;
807 : Form_pg_attribute att;
808 :
809 : /*
810 : * sanity checks
811 : */
812 : Assert(PointerIsValid(desc));
813 : Assert(attributeNumber >= 1);
814 : Assert(attributeNumber <= desc->natts);
815 : Assert(attdim >= 0);
816 : Assert(attdim <= PG_INT16_MAX);
817 :
818 : /*
819 : * initialize the attribute fields
820 : */
821 10934036 : att = TupleDescAttr(desc, attributeNumber - 1);
822 :
823 10934036 : att->attrelid = 0; /* dummy value */
824 :
825 : /*
826 : * Note: attributeName can be NULL, because the planner doesn't always
827 : * fill in valid resname values in targetlists, particularly for resjunk
828 : * attributes. Also, do nothing if caller wants to re-use the old attname.
829 : */
830 10934036 : if (attributeName == NULL)
831 16887828 : MemSet(NameStr(att->attname), 0, NAMEDATALEN);
832 7331984 : else if (attributeName != NameStr(att->attname))
833 7329044 : namestrcpy(&(att->attname), attributeName);
834 :
835 10934036 : att->atttypmod = typmod;
836 :
837 10934036 : att->attnum = attributeNumber;
838 10934036 : att->attndims = attdim;
839 :
840 10934036 : att->attnotnull = false;
841 10934036 : att->atthasdef = false;
842 10934036 : att->atthasmissing = false;
843 10934036 : att->attidentity = '\0';
844 10934036 : att->attgenerated = '\0';
845 10934036 : att->attisdropped = false;
846 10934036 : att->attislocal = true;
847 10934036 : att->attinhcount = 0;
848 : /* variable-length fields are not present in tupledescs */
849 :
850 10934036 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
851 10934036 : if (!HeapTupleIsValid(tuple))
852 0 : elog(ERROR, "cache lookup failed for type %u", oidtypeid);
853 10934036 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
854 :
855 10934036 : att->atttypid = oidtypeid;
856 10934036 : att->attlen = typeForm->typlen;
857 10934036 : att->attbyval = typeForm->typbyval;
858 10934036 : att->attalign = typeForm->typalign;
859 10934036 : att->attstorage = typeForm->typstorage;
860 10934036 : att->attcompression = InvalidCompressionMethod;
861 10934036 : att->attcollation = typeForm->typcollation;
862 :
863 10934036 : populate_compact_attribute(desc, attributeNumber - 1);
864 :
865 10934036 : ReleaseSysCache(tuple);
866 10934036 : }
867 :
868 : /*
869 : * TupleDescInitBuiltinEntry
870 : * Initialize a tuple descriptor without catalog access. Only
871 : * a limited range of builtin types are supported.
872 : */
873 : void
874 12918 : TupleDescInitBuiltinEntry(TupleDesc desc,
875 : AttrNumber attributeNumber,
876 : const char *attributeName,
877 : Oid oidtypeid,
878 : int32 typmod,
879 : int attdim)
880 : {
881 : Form_pg_attribute att;
882 :
883 : /* sanity checks */
884 : Assert(PointerIsValid(desc));
885 : Assert(attributeNumber >= 1);
886 : Assert(attributeNumber <= desc->natts);
887 : Assert(attdim >= 0);
888 : Assert(attdim <= PG_INT16_MAX);
889 :
890 : /* initialize the attribute fields */
891 12918 : att = TupleDescAttr(desc, attributeNumber - 1);
892 12918 : att->attrelid = 0; /* dummy value */
893 :
894 : /* unlike TupleDescInitEntry, we require an attribute name */
895 : Assert(attributeName != NULL);
896 12918 : namestrcpy(&(att->attname), attributeName);
897 :
898 12918 : att->atttypmod = typmod;
899 :
900 12918 : att->attnum = attributeNumber;
901 12918 : att->attndims = attdim;
902 :
903 12918 : att->attnotnull = false;
904 12918 : att->atthasdef = false;
905 12918 : att->atthasmissing = false;
906 12918 : att->attidentity = '\0';
907 12918 : att->attgenerated = '\0';
908 12918 : att->attisdropped = false;
909 12918 : att->attislocal = true;
910 12918 : att->attinhcount = 0;
911 : /* variable-length fields are not present in tupledescs */
912 :
913 12918 : att->atttypid = oidtypeid;
914 :
915 : /*
916 : * Our goal here is to support just enough types to let basic builtin
917 : * commands work without catalog access - e.g. so that we can do certain
918 : * things even in processes that are not connected to a database.
919 : */
920 12918 : switch (oidtypeid)
921 : {
922 10362 : case TEXTOID:
923 : case TEXTARRAYOID:
924 10362 : att->attlen = -1;
925 10362 : att->attbyval = false;
926 10362 : att->attalign = TYPALIGN_INT;
927 10362 : att->attstorage = TYPSTORAGE_EXTENDED;
928 10362 : att->attcompression = InvalidCompressionMethod;
929 10362 : att->attcollation = DEFAULT_COLLATION_OID;
930 10362 : break;
931 :
932 0 : case BOOLOID:
933 0 : att->attlen = 1;
934 0 : att->attbyval = true;
935 0 : att->attalign = TYPALIGN_CHAR;
936 0 : att->attstorage = TYPSTORAGE_PLAIN;
937 0 : att->attcompression = InvalidCompressionMethod;
938 0 : att->attcollation = InvalidOid;
939 0 : break;
940 :
941 0 : case INT4OID:
942 0 : att->attlen = 4;
943 0 : att->attbyval = true;
944 0 : att->attalign = TYPALIGN_INT;
945 0 : att->attstorage = TYPSTORAGE_PLAIN;
946 0 : att->attcompression = InvalidCompressionMethod;
947 0 : att->attcollation = InvalidOid;
948 0 : break;
949 :
950 2248 : case INT8OID:
951 2248 : att->attlen = 8;
952 2248 : att->attbyval = FLOAT8PASSBYVAL;
953 2248 : att->attalign = TYPALIGN_DOUBLE;
954 2248 : att->attstorage = TYPSTORAGE_PLAIN;
955 2248 : att->attcompression = InvalidCompressionMethod;
956 2248 : att->attcollation = InvalidOid;
957 2248 : break;
958 :
959 308 : case OIDOID:
960 308 : att->attlen = 4;
961 308 : att->attbyval = true;
962 308 : att->attalign = TYPALIGN_INT;
963 308 : att->attstorage = TYPSTORAGE_PLAIN;
964 308 : att->attcompression = InvalidCompressionMethod;
965 308 : att->attcollation = InvalidOid;
966 308 : break;
967 :
968 0 : default:
969 0 : elog(ERROR, "unsupported type %u", oidtypeid);
970 : }
971 :
972 12918 : populate_compact_attribute(desc, attributeNumber - 1);
973 12918 : }
974 :
975 : /*
976 : * TupleDescInitEntryCollation
977 : *
978 : * Assign a nondefault collation to a previously initialized tuple descriptor
979 : * entry.
980 : */
981 : void
982 5734796 : TupleDescInitEntryCollation(TupleDesc desc,
983 : AttrNumber attributeNumber,
984 : Oid collationid)
985 : {
986 : /*
987 : * sanity checks
988 : */
989 : Assert(PointerIsValid(desc));
990 : Assert(attributeNumber >= 1);
991 : Assert(attributeNumber <= desc->natts);
992 :
993 5734796 : TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
994 5734796 : }
995 :
996 : /*
997 : * BuildDescFromLists
998 : *
999 : * Build a TupleDesc given lists of column names (as String nodes),
1000 : * column type OIDs, typmods, and collation OIDs.
1001 : *
1002 : * No constraints are generated.
1003 : *
1004 : * This is for use with functions returning RECORD.
1005 : */
1006 : TupleDesc
1007 1410 : BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
1008 : {
1009 : int natts;
1010 : AttrNumber attnum;
1011 : ListCell *l1;
1012 : ListCell *l2;
1013 : ListCell *l3;
1014 : ListCell *l4;
1015 : TupleDesc desc;
1016 :
1017 1410 : natts = list_length(names);
1018 : Assert(natts == list_length(types));
1019 : Assert(natts == list_length(typmods));
1020 : Assert(natts == list_length(collations));
1021 :
1022 : /*
1023 : * allocate a new tuple descriptor
1024 : */
1025 1410 : desc = CreateTemplateTupleDesc(natts);
1026 :
1027 1410 : attnum = 0;
1028 4974 : forfour(l1, names, l2, types, l3, typmods, l4, collations)
1029 : {
1030 3564 : char *attname = strVal(lfirst(l1));
1031 3564 : Oid atttypid = lfirst_oid(l2);
1032 3564 : int32 atttypmod = lfirst_int(l3);
1033 3564 : Oid attcollation = lfirst_oid(l4);
1034 :
1035 3564 : attnum++;
1036 :
1037 3564 : TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
1038 3564 : TupleDescInitEntryCollation(desc, attnum, attcollation);
1039 : }
1040 :
1041 1410 : return desc;
1042 : }
1043 :
1044 : /*
1045 : * Get default expression (or NULL if none) for the given attribute number.
1046 : */
1047 : Node *
1048 149184 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
1049 : {
1050 149184 : Node *result = NULL;
1051 :
1052 149184 : if (tupdesc->constr)
1053 : {
1054 149184 : AttrDefault *attrdef = tupdesc->constr->defval;
1055 :
1056 225246 : for (int i = 0; i < tupdesc->constr->num_defval; i++)
1057 : {
1058 225246 : if (attrdef[i].adnum == attnum)
1059 : {
1060 149184 : result = stringToNode(attrdef[i].adbin);
1061 149184 : break;
1062 : }
1063 : }
1064 : }
1065 :
1066 149184 : return result;
1067 : }
1068 :
1069 : /* ResourceOwner callbacks */
1070 :
1071 : static void
1072 13182 : ResOwnerReleaseTupleDesc(Datum res)
1073 : {
1074 13182 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1075 :
1076 : /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
1077 : Assert(tupdesc->tdrefcount > 0);
1078 13182 : if (--tupdesc->tdrefcount == 0)
1079 424 : FreeTupleDesc(tupdesc);
1080 13182 : }
1081 :
1082 : static char *
1083 0 : ResOwnerPrintTupleDesc(Datum res)
1084 : {
1085 0 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1086 :
1087 0 : return psprintf("TupleDesc %p (%u,%d)",
1088 : tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1089 : }
|