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 20999613 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
50 : {
51 20999613 : ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
52 20999613 : }
53 :
54 : static inline void
55 20987991 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
56 : {
57 20987991 : ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
58 20987991 : }
59 :
60 : /*
61 : * populate_compact_attribute_internal
62 : * Helper function for populate_compact_attribute()
63 : */
64 : static inline void
65 42916177 : populate_compact_attribute_internal(Form_pg_attribute src,
66 : CompactAttribute *dst)
67 : {
68 42916177 : memset(dst, 0, sizeof(CompactAttribute));
69 :
70 42916177 : dst->attcacheoff = -1;
71 42916177 : dst->attlen = src->attlen;
72 :
73 42916177 : dst->attbyval = src->attbyval;
74 42916177 : dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
75 42916177 : dst->atthasmissing = src->atthasmissing;
76 42916177 : dst->attisdropped = src->attisdropped;
77 42916177 : 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 66972705 : dst->attnullability = !src->attnotnull ? ATTNULLABLE_UNRESTRICTED :
86 24056528 : IsCatalogRelationOid(src->attrelid) ? ATTNULLABLE_VALID :
87 : ATTNULLABLE_UNKNOWN;
88 :
89 : /* Compute numeric alignment requirement, too */
90 42916177 : dst->attalignby = typalign_to_alignby(src->attalign);
91 42916177 : }
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 42916177 : populate_compact_attribute(TupleDesc tupdesc, int attnum)
101 : {
102 42916177 : 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 42916177 : dst = &tupdesc->compact_attrs[attnum];
110 :
111 42916177 : populate_compact_attribute_internal(src, dst);
112 42916177 : }
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 6494201 : 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 6494201 : desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
188 : natts * sizeof(CompactAttribute) +
189 6494201 : natts * sizeof(FormData_pg_attribute));
190 :
191 : /*
192 : * Initialize other fields of the tupdesc.
193 : */
194 6494201 : desc->natts = natts;
195 6494201 : desc->constr = NULL;
196 6494201 : desc->tdtypeid = RECORDOID;
197 6494201 : desc->tdtypmod = -1;
198 6494201 : desc->tdrefcount = -1; /* assume not reference-counted */
199 :
200 : /* This will be set to the correct value by TupleDescFinalize() */
201 6494201 : desc->firstNonCachedOffsetAttr = -1;
202 6494201 : desc->firstNonGuaranteedAttr = -1;
203 :
204 6494201 : 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 673003 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
217 : {
218 : TupleDesc desc;
219 : int i;
220 :
221 673003 : desc = CreateTemplateTupleDesc(natts);
222 :
223 10244011 : for (i = 0; i < natts; ++i)
224 : {
225 9571008 : memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
226 9571008 : populate_compact_attribute(desc, i);
227 : }
228 :
229 673003 : TupleDescFinalize(desc);
230 :
231 673003 : 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 262993 : CreateTupleDescCopy(TupleDesc tupdesc)
243 : {
244 : TupleDesc desc;
245 : int i;
246 :
247 262993 : desc = CreateTemplateTupleDesc(tupdesc->natts);
248 :
249 : /* Flat-copy the attribute array (unless there are no attributes) */
250 262993 : if (desc->natts > 0)
251 260612 : memcpy(TupleDescAttr(desc, 0),
252 260612 : TupleDescAttr(tupdesc, 0),
253 260612 : desc->natts * sizeof(FormData_pg_attribute));
254 :
255 : /*
256 : * Since we're not copying constraints and defaults, clear fields
257 : * associated with them.
258 : */
259 1308699 : for (i = 0; i < desc->natts; i++)
260 : {
261 1045706 : Form_pg_attribute att = TupleDescAttr(desc, i);
262 :
263 1045706 : att->attnotnull = false;
264 1045706 : att->atthasdef = false;
265 1045706 : att->atthasmissing = false;
266 1045706 : att->attidentity = '\0';
267 1045706 : att->attgenerated = '\0';
268 :
269 1045706 : populate_compact_attribute(desc, i);
270 : }
271 :
272 : /* We can copy the tuple type identification, too */
273 262993 : desc->tdtypeid = tupdesc->tdtypeid;
274 262993 : desc->tdtypmod = tupdesc->tdtypmod;
275 :
276 262993 : TupleDescFinalize(desc);
277 :
278 262993 : return desc;
279 : }
280 :
281 : /*
282 : * CreateTupleDescTruncatedCopy
283 : * This function creates a new TupleDesc with only the first 'natts'
284 : * attributes from an existing TupleDesc
285 : *
286 : * !!! Constraints and defaults are not copied !!!
287 : */
288 : TupleDesc
289 25496 : CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
290 : {
291 : TupleDesc desc;
292 : int i;
293 :
294 : Assert(natts <= tupdesc->natts);
295 :
296 25496 : desc = CreateTemplateTupleDesc(natts);
297 :
298 : /* Flat-copy the attribute array (unless there are no attributes) */
299 25496 : if (desc->natts > 0)
300 25496 : memcpy(TupleDescAttr(desc, 0),
301 25496 : TupleDescAttr(tupdesc, 0),
302 25496 : desc->natts * sizeof(FormData_pg_attribute));
303 :
304 : /*
305 : * Since we're not copying constraints and defaults, clear fields
306 : * associated with them.
307 : */
308 61934 : for (i = 0; i < desc->natts; i++)
309 : {
310 36438 : Form_pg_attribute att = TupleDescAttr(desc, i);
311 :
312 36438 : att->attnotnull = false;
313 36438 : att->atthasdef = false;
314 36438 : att->atthasmissing = false;
315 36438 : att->attidentity = '\0';
316 36438 : att->attgenerated = '\0';
317 :
318 36438 : populate_compact_attribute(desc, i);
319 : }
320 :
321 : /* We can copy the tuple type identification, too */
322 25496 : desc->tdtypeid = tupdesc->tdtypeid;
323 25496 : desc->tdtypmod = tupdesc->tdtypmod;
324 :
325 25496 : TupleDescFinalize(desc);
326 :
327 25496 : return desc;
328 : }
329 :
330 : /*
331 : * CreateTupleDescCopyConstr
332 : * This function creates a new TupleDesc by copying from an existing
333 : * TupleDesc (including its constraints and defaults).
334 : */
335 : TupleDesc
336 525404 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
337 : {
338 : TupleDesc desc;
339 525404 : TupleConstr *constr = tupdesc->constr;
340 : int i;
341 :
342 525404 : desc = CreateTemplateTupleDesc(tupdesc->natts);
343 :
344 : /* Flat-copy the attribute array (unless there are no attributes) */
345 525404 : if (desc->natts > 0)
346 525342 : memcpy(TupleDescAttr(desc, 0),
347 525342 : TupleDescAttr(tupdesc, 0),
348 525342 : desc->natts * sizeof(FormData_pg_attribute));
349 :
350 7551821 : for (i = 0; i < desc->natts; i++)
351 : {
352 7026417 : populate_compact_attribute(desc, i);
353 :
354 7026417 : TupleDescCompactAttr(desc, i)->attnullability =
355 14052834 : TupleDescCompactAttr(tupdesc, i)->attnullability;
356 : }
357 :
358 : /* Copy the TupleConstr data structure, if any */
359 525404 : if (constr)
360 : {
361 479351 : TupleConstr *cpy = palloc0_object(TupleConstr);
362 :
363 479351 : cpy->has_not_null = constr->has_not_null;
364 479351 : cpy->has_generated_stored = constr->has_generated_stored;
365 479351 : cpy->has_generated_virtual = constr->has_generated_virtual;
366 :
367 479351 : if ((cpy->num_defval = constr->num_defval) > 0)
368 : {
369 2933 : cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
370 2933 : memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
371 7177 : for (i = cpy->num_defval - 1; i >= 0; i--)
372 4244 : cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
373 : }
374 :
375 479351 : if (constr->missing)
376 : {
377 434 : cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
378 434 : memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
379 3326 : for (i = tupdesc->natts - 1; i >= 0; i--)
380 : {
381 2892 : if (constr->missing[i].am_present)
382 : {
383 782 : CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
384 :
385 782 : cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
386 782 : attr->attbyval,
387 782 : attr->attlen);
388 : }
389 : }
390 : }
391 :
392 479351 : if ((cpy->num_check = constr->num_check) > 0)
393 : {
394 1779 : cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
395 1779 : memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
396 5303 : for (i = cpy->num_check - 1; i >= 0; i--)
397 : {
398 3524 : cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
399 3524 : cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
400 3524 : cpy->check[i].ccenforced = constr->check[i].ccenforced;
401 3524 : cpy->check[i].ccvalid = constr->check[i].ccvalid;
402 3524 : cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
403 : }
404 : }
405 :
406 479351 : desc->constr = cpy;
407 : }
408 :
409 : /* We can copy the tuple type identification, too */
410 525404 : desc->tdtypeid = tupdesc->tdtypeid;
411 525404 : desc->tdtypmod = tupdesc->tdtypmod;
412 :
413 525404 : TupleDescFinalize(desc);
414 :
415 525404 : return desc;
416 : }
417 :
418 : /*
419 : * TupleDescCopy
420 : * Copy a tuple descriptor into caller-supplied memory.
421 : * The memory may be shared memory mapped at any address, and must
422 : * be sufficient to hold TupleDescSize(src) bytes.
423 : *
424 : * !!! Constraints and defaults are not copied !!!
425 : */
426 : void
427 236 : TupleDescCopy(TupleDesc dst, TupleDesc src)
428 : {
429 : int i;
430 :
431 : /* Flat-copy the header and attribute arrays */
432 236 : memcpy(dst, src, TupleDescSize(src));
433 :
434 : /*
435 : * Since we're not copying constraints and defaults, clear fields
436 : * associated with them.
437 : */
438 933 : for (i = 0; i < dst->natts; i++)
439 : {
440 697 : Form_pg_attribute att = TupleDescAttr(dst, i);
441 :
442 697 : att->attnotnull = false;
443 697 : att->atthasdef = false;
444 697 : att->atthasmissing = false;
445 697 : att->attidentity = '\0';
446 697 : att->attgenerated = '\0';
447 :
448 697 : populate_compact_attribute(dst, i);
449 : }
450 236 : dst->constr = NULL;
451 :
452 : /*
453 : * Also, assume the destination is not to be ref-counted. (Copying the
454 : * source's refcount would be wrong in any case.)
455 : */
456 236 : dst->tdrefcount = -1;
457 :
458 236 : TupleDescFinalize(dst);
459 236 : }
460 :
461 : /*
462 : * TupleDescCopyEntry
463 : * This function copies a single attribute structure from one tuple
464 : * descriptor to another.
465 : *
466 : * !!! Constraints and defaults are not copied !!!
467 : *
468 : * The caller must take care of calling TupleDescFinalize() on 'dst' once all
469 : * TupleDesc changes have been made.
470 : */
471 : void
472 2857 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
473 : TupleDesc src, AttrNumber srcAttno)
474 : {
475 2857 : Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
476 2857 : Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
477 :
478 : /*
479 : * sanity checks
480 : */
481 : Assert(src);
482 : Assert(dst);
483 : Assert(srcAttno >= 1);
484 : Assert(srcAttno <= src->natts);
485 : Assert(dstAttno >= 1);
486 : Assert(dstAttno <= dst->natts);
487 :
488 2857 : memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
489 :
490 2857 : dstAtt->attnum = dstAttno;
491 :
492 : /* since we're not copying constraints or defaults, clear these */
493 2857 : dstAtt->attnotnull = false;
494 2857 : dstAtt->atthasdef = false;
495 2857 : dstAtt->atthasmissing = false;
496 2857 : dstAtt->attidentity = '\0';
497 2857 : dstAtt->attgenerated = '\0';
498 :
499 2857 : populate_compact_attribute(dst, dstAttno - 1);
500 2857 : }
501 :
502 : /*
503 : * TupleDescFinalize
504 : * Finalize the given TupleDesc. This must be called after the
505 : * attributes arrays have been populated or adjusted by any code.
506 : *
507 : * Must be called after populate_compact_attribute() and before
508 : * BlessTupleDesc().
509 : */
510 : void
511 6627134 : TupleDescFinalize(TupleDesc tupdesc)
512 : {
513 6627134 : int firstNonCachedOffsetAttr = 0;
514 6627134 : int firstNonGuaranteedAttr = tupdesc->natts;
515 6627134 : int off = 0;
516 :
517 36907136 : for (int i = 0; i < tupdesc->natts; i++)
518 : {
519 33640410 : CompactAttribute *cattr = TupleDescCompactAttr(tupdesc, i);
520 :
521 : /*
522 : * Find the highest attnum which is guaranteed to exist in all tuples
523 : * in the table. We currently only pay attention to byval attributes
524 : * to allow additional optimizations during tuple deformation.
525 : */
526 33640410 : if (firstNonGuaranteedAttr == tupdesc->natts &&
527 14007144 : (cattr->attnullability != ATTNULLABLE_VALID || !cattr->attbyval ||
528 7914610 : cattr->atthasmissing || cattr->attisdropped || cattr->attlen <= 0))
529 6092534 : firstNonGuaranteedAttr = i;
530 :
531 33640410 : if (cattr->attlen <= 0)
532 3360408 : break;
533 :
534 30280002 : off = att_nominal_alignby(off, cattr->attalignby);
535 :
536 : /*
537 : * attcacheoff is an int16, so don't try to cache any offsets larger
538 : * than will fit in that type. Any attributes which are offset more
539 : * than 2^15 are likely due to variable-length attributes. Since we
540 : * don't cache offsets for or beyond variable-length attributes, using
541 : * an int16 rather than an int32 here is unlikely to cost us anything.
542 : */
543 30280002 : if (off > PG_INT16_MAX)
544 0 : break;
545 :
546 30280002 : cattr->attcacheoff = (int16) off;
547 :
548 30280002 : off += cattr->attlen;
549 30280002 : firstNonCachedOffsetAttr = i + 1;
550 : }
551 :
552 6627134 : tupdesc->firstNonCachedOffsetAttr = firstNonCachedOffsetAttr;
553 6627134 : tupdesc->firstNonGuaranteedAttr = firstNonGuaranteedAttr;
554 6627134 : }
555 :
556 : /*
557 : * Free a TupleDesc including all substructure
558 : */
559 : void
560 983691 : FreeTupleDesc(TupleDesc tupdesc)
561 : {
562 : int i;
563 :
564 : /*
565 : * Possibly this should assert tdrefcount == 0, to disallow explicit
566 : * freeing of un-refcounted tupdescs?
567 : */
568 : Assert(tupdesc->tdrefcount <= 0);
569 :
570 983691 : if (tupdesc->constr)
571 : {
572 304549 : if (tupdesc->constr->num_defval > 0)
573 : {
574 22950 : AttrDefault *attrdef = tupdesc->constr->defval;
575 :
576 56245 : for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
577 33295 : pfree(attrdef[i].adbin);
578 22950 : pfree(attrdef);
579 : }
580 304549 : if (tupdesc->constr->missing)
581 : {
582 2503 : AttrMissing *attrmiss = tupdesc->constr->missing;
583 :
584 17853 : for (i = tupdesc->natts - 1; i >= 0; i--)
585 : {
586 15350 : if (attrmiss[i].am_present
587 5308 : && !TupleDescAttr(tupdesc, i)->attbyval)
588 2001 : pfree(DatumGetPointer(attrmiss[i].am_value));
589 : }
590 2503 : pfree(attrmiss);
591 : }
592 304549 : if (tupdesc->constr->num_check > 0)
593 : {
594 8345 : ConstrCheck *check = tupdesc->constr->check;
595 :
596 23310 : for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
597 : {
598 14965 : pfree(check[i].ccname);
599 14965 : pfree(check[i].ccbin);
600 : }
601 8345 : pfree(check);
602 : }
603 304549 : pfree(tupdesc->constr);
604 : }
605 :
606 983691 : pfree(tupdesc);
607 983691 : }
608 :
609 : /*
610 : * Increment the reference count of a tupdesc, and log the reference in
611 : * CurrentResourceOwner.
612 : *
613 : * Do not apply this to tupdescs that are not being refcounted. (Use the
614 : * macro PinTupleDesc for tupdescs of uncertain status.)
615 : */
616 : void
617 20999613 : IncrTupleDescRefCount(TupleDesc tupdesc)
618 : {
619 : Assert(tupdesc->tdrefcount >= 0);
620 :
621 20999613 : ResourceOwnerEnlarge(CurrentResourceOwner);
622 20999613 : tupdesc->tdrefcount++;
623 20999613 : ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
624 20999613 : }
625 :
626 : /*
627 : * Decrement the reference count of a tupdesc, remove the corresponding
628 : * reference from CurrentResourceOwner, and free the tupdesc if no more
629 : * references remain.
630 : *
631 : * Do not apply this to tupdescs that are not being refcounted. (Use the
632 : * macro ReleaseTupleDesc for tupdescs of uncertain status.)
633 : */
634 : void
635 20987991 : DecrTupleDescRefCount(TupleDesc tupdesc)
636 : {
637 : Assert(tupdesc->tdrefcount > 0);
638 :
639 20987991 : ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
640 20987991 : if (--tupdesc->tdrefcount == 0)
641 0 : FreeTupleDesc(tupdesc);
642 20987991 : }
643 :
644 : /*
645 : * Compare two TupleDesc structures for logical equality
646 : */
647 : bool
648 280593 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
649 : {
650 : int i,
651 : n;
652 :
653 280593 : if (tupdesc1->natts != tupdesc2->natts)
654 1965 : return false;
655 278628 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
656 0 : return false;
657 :
658 : /* tdtypmod and tdrefcount are not checked */
659 :
660 1314321 : for (i = 0; i < tupdesc1->natts; i++)
661 : {
662 1045733 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
663 1045733 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
664 :
665 : /*
666 : * We do not need to check every single field here: we can disregard
667 : * attrelid and attnum (which were used to place the row in the attrs
668 : * array in the first place). It might look like we could dispense
669 : * with checking attlen/attbyval/attalign, since these are derived
670 : * from atttypid; but in the case of dropped columns we must check
671 : * them (since atttypid will be zero for all dropped columns) and in
672 : * general it seems safer to check them always.
673 : *
674 : * We intentionally ignore atthasmissing, since that's not very
675 : * relevant in tupdescs, which lack the attmissingval field.
676 : */
677 1045733 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
678 907 : return false;
679 1044826 : if (attr1->atttypid != attr2->atttypid)
680 758 : return false;
681 1044068 : if (attr1->attlen != attr2->attlen)
682 6 : return false;
683 1044062 : if (attr1->attndims != attr2->attndims)
684 0 : return false;
685 1044062 : if (attr1->atttypmod != attr2->atttypmod)
686 28 : return false;
687 1044034 : if (attr1->attbyval != attr2->attbyval)
688 34 : return false;
689 1044000 : if (attr1->attalign != attr2->attalign)
690 0 : return false;
691 1044000 : if (attr1->attstorage != attr2->attstorage)
692 157 : return false;
693 1043843 : if (attr1->attcompression != attr2->attcompression)
694 43 : return false;
695 1043800 : if (attr1->attnotnull != attr2->attnotnull)
696 1162 : return false;
697 :
698 : /*
699 : * When the column has a not-null constraint, we also need to consider
700 : * its validity aspect, which only manifests in CompactAttribute->
701 : * attnullability, so verify that.
702 : */
703 1042638 : if (attr1->attnotnull)
704 : {
705 345315 : CompactAttribute *cattr1 = TupleDescCompactAttr(tupdesc1, i);
706 345315 : CompactAttribute *cattr2 = TupleDescCompactAttr(tupdesc2, i);
707 :
708 : Assert(cattr1->attnullability != ATTNULLABLE_UNKNOWN);
709 : Assert((cattr1->attnullability == ATTNULLABLE_UNKNOWN) ==
710 : (cattr2->attnullability == ATTNULLABLE_UNKNOWN));
711 :
712 345315 : if (cattr1->attnullability != cattr2->attnullability)
713 70 : return false;
714 : }
715 1042568 : if (attr1->atthasdef != attr2->atthasdef)
716 3624 : return false;
717 1038944 : if (attr1->attidentity != attr2->attidentity)
718 118 : return false;
719 1038826 : if (attr1->attgenerated != attr2->attgenerated)
720 13 : return false;
721 1038813 : if (attr1->attisdropped != attr2->attisdropped)
722 0 : return false;
723 1038813 : if (attr1->attislocal != attr2->attislocal)
724 2615 : return false;
725 1036198 : if (attr1->attinhcount != attr2->attinhcount)
726 505 : return false;
727 1035693 : if (attr1->attcollation != attr2->attcollation)
728 0 : return false;
729 : /* variable-length fields are not even present... */
730 : }
731 :
732 268588 : if (tupdesc1->constr != NULL)
733 : {
734 99268 : TupleConstr *constr1 = tupdesc1->constr;
735 99268 : TupleConstr *constr2 = tupdesc2->constr;
736 :
737 99268 : if (constr2 == NULL)
738 175 : return false;
739 99093 : if (constr1->has_not_null != constr2->has_not_null)
740 0 : return false;
741 99093 : if (constr1->has_generated_stored != constr2->has_generated_stored)
742 460 : return false;
743 98633 : if (constr1->has_generated_virtual != constr2->has_generated_virtual)
744 274 : return false;
745 98359 : n = constr1->num_defval;
746 98359 : if (n != (int) constr2->num_defval)
747 0 : return false;
748 : /* We assume here that both AttrDefault arrays are in adnum order */
749 111474 : for (i = 0; i < n; i++)
750 : {
751 13115 : AttrDefault *defval1 = constr1->defval + i;
752 13115 : AttrDefault *defval2 = constr2->defval + i;
753 :
754 13115 : if (defval1->adnum != defval2->adnum)
755 0 : return false;
756 13115 : if (strcmp(defval1->adbin, defval2->adbin) != 0)
757 0 : return false;
758 : }
759 98359 : if (constr1->missing)
760 : {
761 486 : if (!constr2->missing)
762 60 : return false;
763 2547 : for (i = 0; i < tupdesc1->natts; i++)
764 : {
765 2226 : AttrMissing *missval1 = constr1->missing + i;
766 2226 : AttrMissing *missval2 = constr2->missing + i;
767 :
768 2226 : if (missval1->am_present != missval2->am_present)
769 105 : return false;
770 2121 : if (missval1->am_present)
771 : {
772 724 : CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
773 :
774 724 : if (!datumIsEqual(missval1->am_value, missval2->am_value,
775 724 : missatt1->attbyval, missatt1->attlen))
776 0 : return false;
777 : }
778 : }
779 : }
780 97873 : else if (constr2->missing)
781 242 : return false;
782 97952 : n = constr1->num_check;
783 97952 : if (n != (int) constr2->num_check)
784 1175 : return false;
785 :
786 : /*
787 : * Similarly, we rely here on the ConstrCheck entries being sorted by
788 : * name. If there are duplicate names, the outcome of the comparison
789 : * is uncertain, but that should not happen.
790 : */
791 99583 : for (i = 0; i < n; i++)
792 : {
793 2950 : ConstrCheck *check1 = constr1->check + i;
794 2950 : ConstrCheck *check2 = constr2->check + i;
795 :
796 2950 : if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
797 2950 : strcmp(check1->ccbin, check2->ccbin) == 0 &&
798 2950 : check1->ccenforced == check2->ccenforced &&
799 2862 : check1->ccvalid == check2->ccvalid &&
800 2806 : check1->ccnoinherit == check2->ccnoinherit))
801 144 : return false;
802 : }
803 : }
804 169320 : else if (tupdesc2->constr != NULL)
805 1289 : return false;
806 264664 : return true;
807 : }
808 :
809 : /*
810 : * equalRowTypes
811 : *
812 : * This determines whether two tuple descriptors have equal row types. This
813 : * only checks those fields in pg_attribute that are applicable for row types,
814 : * while ignoring those fields that define the physical row storage or those
815 : * that define table column metadata.
816 : *
817 : * Specifically, this checks:
818 : *
819 : * - same number of attributes
820 : * - same composite type ID (but could both be zero)
821 : * - corresponding attributes (in order) have same the name, type, typmod,
822 : * collation
823 : *
824 : * This is used to check whether two record types are compatible, whether
825 : * function return row types are the same, and other similar situations.
826 : *
827 : * (XXX There was some discussion whether attndims should be checked here, but
828 : * for now it has been decided not to.)
829 : *
830 : * Note: We deliberately do not check the tdtypmod field. This allows
831 : * typcache.c to use this routine to see if a cached record type matches a
832 : * requested type.
833 : */
834 : bool
835 273585 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
836 : {
837 273585 : if (tupdesc1->natts != tupdesc2->natts)
838 110 : return false;
839 273475 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
840 1274 : return false;
841 :
842 3639697 : for (int i = 0; i < tupdesc1->natts; i++)
843 : {
844 3373261 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
845 3373261 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
846 :
847 3373261 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
848 5749 : return false;
849 3367512 : if (attr1->atttypid != attr2->atttypid)
850 14 : return false;
851 3367498 : if (attr1->atttypmod != attr2->atttypmod)
852 2 : return false;
853 3367496 : if (attr1->attcollation != attr2->attcollation)
854 0 : return false;
855 :
856 : /* Record types derived from tables could have dropped fields. */
857 3367496 : if (attr1->attisdropped != attr2->attisdropped)
858 0 : return false;
859 : }
860 :
861 266436 : return true;
862 : }
863 :
864 : /*
865 : * hashRowType
866 : *
867 : * If two tuple descriptors would be considered equal by equalRowTypes()
868 : * then their hash value will be equal according to this function.
869 : */
870 : uint32
871 282224 : hashRowType(TupleDesc desc)
872 : {
873 : uint32 s;
874 : int i;
875 :
876 282224 : s = hash_combine(0, hash_bytes_uint32(desc->natts));
877 282224 : s = hash_combine(s, hash_bytes_uint32(desc->tdtypeid));
878 3816814 : for (i = 0; i < desc->natts; ++i)
879 3534590 : s = hash_combine(s, hash_bytes_uint32(TupleDescAttr(desc, i)->atttypid));
880 :
881 282224 : return s;
882 : }
883 :
884 : /*
885 : * TupleDescInitEntry
886 : * This function initializes a single attribute structure in
887 : * a previously allocated tuple descriptor.
888 : *
889 : * If attributeName is NULL, the attname field is set to an empty string
890 : * (this is for cases where we don't know or need a name for the field).
891 : * Also, some callers use this function to change the datatype-related fields
892 : * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
893 : * to indicate that the attname field shouldn't be modified.
894 : *
895 : * Note that attcollation is set to the default for the specified datatype.
896 : * If a nondefault collation is needed, insert it afterwards using
897 : * TupleDescInitEntryCollation.
898 : */
899 : void
900 7870781 : TupleDescInitEntry(TupleDesc desc,
901 : AttrNumber attributeNumber,
902 : const char *attributeName,
903 : Oid oidtypeid,
904 : int32 typmod,
905 : int attdim)
906 : {
907 : HeapTuple tuple;
908 : Form_pg_type typeForm;
909 : Form_pg_attribute att;
910 :
911 : /*
912 : * sanity checks
913 : */
914 : Assert(desc);
915 : Assert(attributeNumber >= 1);
916 : Assert(attributeNumber <= desc->natts);
917 : Assert(attdim >= 0);
918 : Assert(attdim <= PG_INT16_MAX);
919 :
920 : /*
921 : * initialize the attribute fields
922 : */
923 7870781 : att = TupleDescAttr(desc, attributeNumber - 1);
924 :
925 7870781 : att->attrelid = 0; /* dummy value */
926 :
927 : /*
928 : * Note: attributeName can be NULL, because the planner doesn't always
929 : * fill in valid resname values in targetlists, particularly for resjunk
930 : * attributes. Also, do nothing if caller wants to re-use the old attname.
931 : */
932 7870781 : if (attributeName == NULL)
933 12815906 : MemSet(NameStr(att->attname), 0, NAMEDATALEN);
934 5134507 : else if (attributeName != NameStr(att->attname))
935 5132085 : namestrcpy(&(att->attname), attributeName);
936 :
937 7870781 : att->atttypmod = typmod;
938 :
939 7870781 : att->attnum = attributeNumber;
940 7870781 : att->attndims = attdim;
941 :
942 7870781 : att->attnotnull = false;
943 7870781 : att->atthasdef = false;
944 7870781 : att->atthasmissing = false;
945 7870781 : att->attidentity = '\0';
946 7870781 : att->attgenerated = '\0';
947 7870781 : att->attisdropped = false;
948 7870781 : att->attislocal = true;
949 7870781 : att->attinhcount = 0;
950 : /* variable-length fields are not present in tupledescs */
951 :
952 7870781 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
953 7870781 : if (!HeapTupleIsValid(tuple))
954 0 : elog(ERROR, "cache lookup failed for type %u", oidtypeid);
955 7870781 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
956 :
957 7870781 : att->atttypid = oidtypeid;
958 7870781 : att->attlen = typeForm->typlen;
959 7870781 : att->attbyval = typeForm->typbyval;
960 7870781 : att->attalign = typeForm->typalign;
961 7870781 : att->attstorage = typeForm->typstorage;
962 7870781 : att->attcompression = InvalidCompressionMethod;
963 7870781 : att->attcollation = typeForm->typcollation;
964 :
965 7870781 : populate_compact_attribute(desc, attributeNumber - 1);
966 :
967 7870781 : ReleaseSysCache(tuple);
968 7870781 : }
969 :
970 : /*
971 : * TupleDescInitBuiltinEntry
972 : * Initialize a tuple descriptor without catalog access. Only
973 : * a limited range of builtin types are supported.
974 : */
975 : void
976 8082 : TupleDescInitBuiltinEntry(TupleDesc desc,
977 : AttrNumber attributeNumber,
978 : const char *attributeName,
979 : Oid oidtypeid,
980 : int32 typmod,
981 : int attdim)
982 : {
983 : Form_pg_attribute att;
984 :
985 : /* sanity checks */
986 : Assert(desc);
987 : Assert(attributeNumber >= 1);
988 : Assert(attributeNumber <= desc->natts);
989 : Assert(attdim >= 0);
990 : Assert(attdim <= PG_INT16_MAX);
991 :
992 : /* initialize the attribute fields */
993 8082 : att = TupleDescAttr(desc, attributeNumber - 1);
994 8082 : att->attrelid = 0; /* dummy value */
995 :
996 : /* unlike TupleDescInitEntry, we require an attribute name */
997 : Assert(attributeName != NULL);
998 8082 : namestrcpy(&(att->attname), attributeName);
999 :
1000 8082 : att->atttypmod = typmod;
1001 :
1002 8082 : att->attnum = attributeNumber;
1003 8082 : att->attndims = attdim;
1004 :
1005 8082 : att->attnotnull = false;
1006 8082 : att->atthasdef = false;
1007 8082 : att->atthasmissing = false;
1008 8082 : att->attidentity = '\0';
1009 8082 : att->attgenerated = '\0';
1010 8082 : att->attisdropped = false;
1011 8082 : att->attislocal = true;
1012 8082 : att->attinhcount = 0;
1013 : /* variable-length fields are not present in tupledescs */
1014 :
1015 8082 : att->atttypid = oidtypeid;
1016 :
1017 : /*
1018 : * Our goal here is to support just enough types to let basic builtin
1019 : * commands work without catalog access - e.g. so that we can do certain
1020 : * things even in processes that are not connected to a database.
1021 : */
1022 8082 : switch (oidtypeid)
1023 : {
1024 6588 : case TEXTOID:
1025 : case TEXTARRAYOID:
1026 6588 : att->attlen = -1;
1027 6588 : att->attbyval = false;
1028 6588 : att->attalign = TYPALIGN_INT;
1029 6588 : att->attstorage = TYPSTORAGE_EXTENDED;
1030 6588 : att->attcompression = InvalidCompressionMethod;
1031 6588 : att->attcollation = DEFAULT_COLLATION_OID;
1032 6588 : break;
1033 :
1034 0 : case BOOLOID:
1035 0 : att->attlen = 1;
1036 0 : att->attbyval = true;
1037 0 : att->attalign = TYPALIGN_CHAR;
1038 0 : att->attstorage = TYPSTORAGE_PLAIN;
1039 0 : att->attcompression = InvalidCompressionMethod;
1040 0 : att->attcollation = InvalidOid;
1041 0 : break;
1042 :
1043 0 : case INT4OID:
1044 0 : att->attlen = 4;
1045 0 : att->attbyval = true;
1046 0 : att->attalign = TYPALIGN_INT;
1047 0 : att->attstorage = TYPSTORAGE_PLAIN;
1048 0 : att->attcompression = InvalidCompressionMethod;
1049 0 : att->attcollation = InvalidOid;
1050 0 : break;
1051 :
1052 1322 : case INT8OID:
1053 1322 : att->attlen = 8;
1054 1322 : att->attbyval = true;
1055 1322 : att->attalign = TYPALIGN_DOUBLE;
1056 1322 : att->attstorage = TYPSTORAGE_PLAIN;
1057 1322 : att->attcompression = InvalidCompressionMethod;
1058 1322 : att->attcollation = InvalidOid;
1059 1322 : break;
1060 :
1061 172 : case OIDOID:
1062 172 : att->attlen = 4;
1063 172 : att->attbyval = true;
1064 172 : att->attalign = TYPALIGN_INT;
1065 172 : att->attstorage = TYPSTORAGE_PLAIN;
1066 172 : att->attcompression = InvalidCompressionMethod;
1067 172 : att->attcollation = InvalidOid;
1068 172 : break;
1069 :
1070 0 : default:
1071 0 : elog(ERROR, "unsupported type %u", oidtypeid);
1072 : }
1073 :
1074 8082 : populate_compact_attribute(desc, attributeNumber - 1);
1075 8082 : }
1076 :
1077 : /*
1078 : * TupleDescInitEntryCollation
1079 : *
1080 : * Assign a nondefault collation to a previously initialized tuple descriptor
1081 : * entry.
1082 : */
1083 : void
1084 4239021 : TupleDescInitEntryCollation(TupleDesc desc,
1085 : AttrNumber attributeNumber,
1086 : Oid collationid)
1087 : {
1088 : /*
1089 : * sanity checks
1090 : */
1091 : Assert(desc);
1092 : Assert(attributeNumber >= 1);
1093 : Assert(attributeNumber <= desc->natts);
1094 :
1095 4239021 : TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
1096 4239021 : }
1097 :
1098 : /*
1099 : * BuildDescFromLists
1100 : *
1101 : * Build a TupleDesc given lists of column names (as String nodes),
1102 : * column type OIDs, typmods, and collation OIDs.
1103 : *
1104 : * No constraints are generated.
1105 : *
1106 : * This is for use with functions returning RECORD.
1107 : */
1108 : TupleDesc
1109 903 : BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
1110 : {
1111 : int natts;
1112 : AttrNumber attnum;
1113 : ListCell *l1;
1114 : ListCell *l2;
1115 : ListCell *l3;
1116 : ListCell *l4;
1117 : TupleDesc desc;
1118 :
1119 903 : natts = list_length(names);
1120 : Assert(natts == list_length(types));
1121 : Assert(natts == list_length(typmods));
1122 : Assert(natts == list_length(collations));
1123 :
1124 : /*
1125 : * allocate a new tuple descriptor
1126 : */
1127 903 : desc = CreateTemplateTupleDesc(natts);
1128 :
1129 903 : attnum = 0;
1130 3160 : forfour(l1, names, l2, types, l3, typmods, l4, collations)
1131 : {
1132 2257 : char *attname = strVal(lfirst(l1));
1133 2257 : Oid atttypid = lfirst_oid(l2);
1134 2257 : int32 atttypmod = lfirst_int(l3);
1135 2257 : Oid attcollation = lfirst_oid(l4);
1136 :
1137 2257 : attnum++;
1138 :
1139 2257 : TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
1140 2257 : TupleDescInitEntryCollation(desc, attnum, attcollation);
1141 : }
1142 :
1143 903 : TupleDescFinalize(desc);
1144 :
1145 903 : return desc;
1146 : }
1147 :
1148 : /*
1149 : * Get default expression (or NULL if none) for the given attribute number.
1150 : */
1151 : Node *
1152 78316 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
1153 : {
1154 78316 : Node *result = NULL;
1155 :
1156 78316 : if (tupdesc->constr)
1157 : {
1158 78316 : AttrDefault *attrdef = tupdesc->constr->defval;
1159 :
1160 118604 : for (int i = 0; i < tupdesc->constr->num_defval; i++)
1161 : {
1162 118604 : if (attrdef[i].adnum == attnum)
1163 : {
1164 78316 : result = stringToNode(attrdef[i].adbin);
1165 78316 : break;
1166 : }
1167 : }
1168 : }
1169 :
1170 78316 : return result;
1171 : }
1172 :
1173 : /* ResourceOwner callbacks */
1174 :
1175 : static void
1176 11622 : ResOwnerReleaseTupleDesc(Datum res)
1177 : {
1178 11622 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1179 :
1180 : /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
1181 : Assert(tupdesc->tdrefcount > 0);
1182 11622 : if (--tupdesc->tdrefcount == 0)
1183 407 : FreeTupleDesc(tupdesc);
1184 11622 : }
1185 :
1186 : static char *
1187 0 : ResOwnerPrintTupleDesc(Datum res)
1188 : {
1189 0 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1190 :
1191 0 : return psprintf("TupleDesc %p (%u,%d)",
1192 : tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1193 : }
|