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