Age Owner Branch data TLA 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
858 heikki.linnakangas@i 49 :CBC 17014856 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
50 : : {
51 : 17014856 : ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
52 : 17014856 : }
53 : :
54 : : static inline void
55 : 17006724 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
56 : : {
57 : 17006724 : ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
58 : 17006724 : }
59 : :
60 : : /*
61 : : * populate_compact_attribute_internal
62 : : * Helper function for populate_compact_attribute()
63 : : */
64 : : static inline void
446 drowley@postgresql.o 65 : 1686953596 : populate_compact_attribute_internal(Form_pg_attribute src,
66 : : CompactAttribute *dst)
67 : : {
450 68 : 1686953596 : memset(dst, 0, sizeof(CompactAttribute));
69 : :
70 : 1686953596 : dst->attcacheoff = -1;
71 : 1686953596 : dst->attlen = src->attlen;
72 : :
73 : 1686953596 : dst->attbyval = src->attbyval;
74 : 1686953596 : dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
75 : 1686953596 : dst->atthasmissing = src->atthasmissing;
76 : 1686953596 : dst->attisdropped = src->attisdropped;
77 : 1686953596 : 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 : : */
342 alvherre@alvh.no-ip. 85 [ + + + + ]: 2221539889 : dst->attnullability = !src->attnotnull ? ATTNULLABLE_UNRESTRICTED :
86 : 534586293 : IsCatalogRelationOid(src->attrelid) ? ATTNULLABLE_VALID :
87 : : ATTNULLABLE_UNKNOWN;
88 : :
89 : : /* Compute numeric alignment requirement, too */
41 tgl@sss.pgh.pa.us 90 :GNC 1686953596 : dst->attalignby = typalign_to_alignby(src->attalign);
450 drowley@postgresql.o 91 :CBC 1686953596 : }
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
446 100 : 38634157 : populate_compact_attribute(TupleDesc tupdesc, int attnum)
101 : : {
102 : 38634157 : 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 : 38634157 : dst = &tupdesc->compact_attrs[attnum];
110 : :
111 : 38634157 : populate_compact_attribute_internal(src, dst);
112 : 38634157 : }
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 : 1648319439 : verify_compact_attribute(TupleDesc tupdesc, int attnum)
126 : : {
127 : : #ifdef USE_ASSERT_CHECKING
128 : : CompactAttribute cattr;
129 : 1648319439 : 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 : : */
271 137 : 1648319439 : memcpy(&cattr, &tupdesc->compact_attrs[attnum], sizeof(CompactAttribute));
138 : :
139 : : /*
140 : : * Populate the temporary CompactAttribute from the corresponding
141 : : * Form_pg_attribute
142 : : */
446 143 : 1648319439 : 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 : : */
271 149 : 1648319439 : tmp.attcacheoff = cattr.attcacheoff;
150 : 1648319439 : tmp.attnullability = cattr.attnullability;
151 : :
152 : : /* Check the freshly populated CompactAttribute matches the TupleDesc's */
153 [ - + ]: 1648319439 : Assert(memcmp(&tmp, &cattr, sizeof(CompactAttribute)) == 0);
154 : : #endif
428 155 : 1648319439 : }
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
2672 andres@anarazel.de 165 : 6744607 : CreateTemplateTupleDesc(int natts)
166 : : {
167 : : TupleDesc desc;
168 : :
169 : : /*
170 : : * sanity checks
171 : : */
1234 peter@eisentraut.org 172 [ - + ]: 6744607 : 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 : : */
450 drowley@postgresql.o 187 : 6744607 : desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
188 : 6744607 : natts * sizeof(CompactAttribute) +
189 : : natts * sizeof(FormData_pg_attribute));
190 : :
191 : : /*
192 : : * Initialize other fields of the tupdesc.
193 : : */
8018 tgl@sss.pgh.pa.us 194 : 6744607 : desc->natts = natts;
8569 195 : 6744607 : desc->constr = NULL;
8018 196 : 6744607 : desc->tdtypeid = RECORDOID;
197 : 6744607 : desc->tdtypmod = -1;
7212 198 : 6744607 : desc->tdrefcount = -1; /* assume not reference-counted */
199 : :
10057 bruce@momjian.us 200 : 6744607 : return desc;
201 : : }
202 : :
203 : : /*
204 : : * CreateTupleDesc
205 : : * This function allocates a new TupleDesc by copying a given
206 : : * Form_pg_attribute array.
207 : : *
208 : : * Tuple type ID information is initially set for an anonymous record type;
209 : : * caller can overwrite this if needed.
210 : : */
211 : : TupleDesc
2672 andres@anarazel.de 212 : 595481 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
213 : : {
214 : : TupleDesc desc;
215 : : int i;
216 : :
217 : 595481 : desc = CreateTemplateTupleDesc(natts);
218 : :
3129 219 [ + + ]: 9103229 : for (i = 0; i < natts; ++i)
220 : : {
221 : 8507748 : memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
450 drowley@postgresql.o 222 : 8507748 : populate_compact_attribute(desc, i);
223 : : }
10057 bruce@momjian.us 224 : 595481 : return desc;
225 : : }
226 : :
227 : : /*
228 : : * CreateTupleDescCopy
229 : : * This function creates a new TupleDesc by copying from an existing
230 : : * TupleDesc.
231 : : *
232 : : * !!! Constraints and defaults are not copied !!!
233 : : */
234 : : TupleDesc
10841 scrappy@hub.org 235 : 620586 : CreateTupleDescCopy(TupleDesc tupdesc)
236 : : {
237 : : TupleDesc desc;
238 : : int i;
239 : :
2672 andres@anarazel.de 240 : 620586 : desc = CreateTemplateTupleDesc(tupdesc->natts);
241 : :
242 : : /* Flat-copy the attribute array */
2993 tgl@sss.pgh.pa.us 243 : 620586 : memcpy(TupleDescAttr(desc, 0),
244 : 620586 : TupleDescAttr(tupdesc, 0),
245 : 620586 : desc->natts * sizeof(FormData_pg_attribute));
246 : :
247 : : /*
248 : : * Since we're not copying constraints and defaults, clear fields
249 : : * associated with them.
250 : : */
7678 251 [ + + ]: 1924306 : for (i = 0; i < desc->natts; i++)
252 : : {
3129 andres@anarazel.de 253 : 1303720 : Form_pg_attribute att = TupleDescAttr(desc, i);
254 : :
255 : 1303720 : att->attnotnull = false;
256 : 1303720 : att->atthasdef = false;
2909 andrew@dunslane.net 257 : 1303720 : att->atthasmissing = false;
3129 andres@anarazel.de 258 : 1303720 : att->attidentity = '\0';
2542 peter@eisentraut.org 259 : 1303720 : att->attgenerated = '\0';
260 : :
450 drowley@postgresql.o 261 : 1303720 : populate_compact_attribute(desc, i);
262 : : }
263 : :
264 : : /* We can copy the tuple type identification, too */
265 : 620586 : desc->tdtypeid = tupdesc->tdtypeid;
266 : 620586 : desc->tdtypmod = tupdesc->tdtypmod;
267 : :
268 : 620586 : return desc;
269 : : }
270 : :
271 : : /*
272 : : * CreateTupleDescTruncatedCopy
273 : : * This function creates a new TupleDesc with only the first 'natts'
274 : : * attributes from an existing TupleDesc
275 : : *
276 : : * !!! Constraints and defaults are not copied !!!
277 : : */
278 : : TupleDesc
279 : 18511 : CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
280 : : {
281 : : TupleDesc desc;
282 : : int i;
283 : :
284 [ - + ]: 18511 : Assert(natts <= tupdesc->natts);
285 : :
286 : 18511 : desc = CreateTemplateTupleDesc(natts);
287 : :
288 : : /* Flat-copy the attribute array */
289 : 18511 : memcpy(TupleDescAttr(desc, 0),
290 : 18511 : TupleDescAttr(tupdesc, 0),
291 : 18511 : desc->natts * sizeof(FormData_pg_attribute));
292 : :
293 : : /*
294 : : * Since we're not copying constraints and defaults, clear fields
295 : : * associated with them.
296 : : */
297 [ + + ]: 43045 : for (i = 0; i < desc->natts; i++)
298 : : {
299 : 24534 : Form_pg_attribute att = TupleDescAttr(desc, i);
300 : :
301 : 24534 : att->attnotnull = false;
302 : 24534 : att->atthasdef = false;
303 : 24534 : att->atthasmissing = false;
304 : 24534 : att->attidentity = '\0';
305 : 24534 : att->attgenerated = '\0';
306 : :
307 : 24534 : populate_compact_attribute(desc, i);
308 : : }
309 : :
310 : : /* We can copy the tuple type identification, too */
8018 tgl@sss.pgh.pa.us 311 : 18511 : desc->tdtypeid = tupdesc->tdtypeid;
312 : 18511 : desc->tdtypmod = tupdesc->tdtypmod;
313 : :
10416 bruce@momjian.us 314 : 18511 : return desc;
315 : : }
316 : :
317 : : /*
318 : : * CreateTupleDescCopyConstr
319 : : * This function creates a new TupleDesc by copying from an existing
320 : : * TupleDesc (including its constraints and defaults).
321 : : */
322 : : TupleDesc
10432 vadim4o@yahoo.com 323 : 433012 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
324 : : {
325 : : TupleDesc desc;
10415 bruce@momjian.us 326 : 433012 : TupleConstr *constr = tupdesc->constr;
327 : : int i;
328 : :
2672 andres@anarazel.de 329 : 433012 : desc = CreateTemplateTupleDesc(tupdesc->natts);
330 : :
331 : : /* Flat-copy the attribute array */
2993 tgl@sss.pgh.pa.us 332 : 433012 : memcpy(TupleDescAttr(desc, 0),
333 : 433012 : TupleDescAttr(tupdesc, 0),
334 : 433012 : desc->natts * sizeof(FormData_pg_attribute));
335 : :
450 drowley@postgresql.o 336 [ + + ]: 6387761 : for (i = 0; i < desc->natts; i++)
337 : : {
338 : 5954749 : populate_compact_attribute(desc, i);
339 : :
342 alvherre@alvh.no-ip. 340 : 5954749 : TupleDescCompactAttr(desc, i)->attnullability =
341 : 11909498 : TupleDescCompactAttr(tupdesc, i)->attnullability;
342 : : }
343 : :
344 : : /* Copy the TupleConstr data structure, if any */
10416 bruce@momjian.us 345 [ + + ]: 433012 : if (constr)
346 : : {
95 michael@paquier.xyz 347 :GNC 393215 : TupleConstr *cpy = palloc0_object(TupleConstr);
348 : :
10416 bruce@momjian.us 349 :CBC 393215 : cpy->has_not_null = constr->has_not_null;
2542 peter@eisentraut.org 350 : 393215 : cpy->has_generated_stored = constr->has_generated_stored;
401 351 : 393215 : cpy->has_generated_virtual = constr->has_generated_virtual;
352 : :
10416 bruce@momjian.us 353 [ + + ]: 393215 : if ((cpy->num_defval = constr->num_defval) > 0)
354 : : {
355 : 2161 : cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
356 : 2161 : memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
357 [ + + ]: 5291 : for (i = cpy->num_defval - 1; i >= 0; i--)
1804 tgl@sss.pgh.pa.us 358 : 3130 : cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
359 : : }
360 : :
2909 andrew@dunslane.net 361 [ + + ]: 393215 : if (constr->missing)
362 : : {
363 : 331 : cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
364 : 331 : memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
365 [ + + ]: 2519 : for (i = tupdesc->natts - 1; i >= 0; i--)
366 : : {
2818 akapila@postgresql.o 367 [ + + ]: 2188 : if (constr->missing[i].am_present)
368 : : {
450 drowley@postgresql.o 369 : 592 : CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
370 : :
2818 akapila@postgresql.o 371 : 592 : cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
372 : 592 : attr->attbyval,
373 : 592 : attr->attlen);
374 : : }
375 : : }
376 : : }
377 : :
10416 bruce@momjian.us 378 [ + + ]: 393215 : if ((cpy->num_check = constr->num_check) > 0)
379 : : {
380 : 1346 : cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
381 : 1346 : memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
382 [ + + ]: 4005 : for (i = cpy->num_check - 1; i >= 0; i--)
383 : : {
1804 tgl@sss.pgh.pa.us 384 : 2659 : cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
385 : 2659 : cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
428 peter@eisentraut.org 386 : 2659 : cpy->check[i].ccenforced = constr->check[i].ccenforced;
5401 alvherre@alvh.no-ip. 387 : 2659 : cpy->check[i].ccvalid = constr->check[i].ccvalid;
4375 noah@leadboat.com 388 : 2659 : cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
389 : : }
390 : : }
391 : :
10416 bruce@momjian.us 392 : 393215 : desc->constr = cpy;
393 : : }
394 : :
395 : : /* We can copy the tuple type identification, too */
8018 tgl@sss.pgh.pa.us 396 : 433012 : desc->tdtypeid = tupdesc->tdtypeid;
397 : 433012 : desc->tdtypmod = tupdesc->tdtypmod;
398 : :
10416 bruce@momjian.us 399 : 433012 : return desc;
400 : : }
401 : :
402 : : /*
403 : : * TupleDescCopy
404 : : * Copy a tuple descriptor into caller-supplied memory.
405 : : * The memory may be shared memory mapped at any address, and must
406 : : * be sufficient to hold TupleDescSize(src) bytes.
407 : : *
408 : : * !!! Constraints and defaults are not copied !!!
409 : : */
410 : : void
3104 andres@anarazel.de 411 : 166 : TupleDescCopy(TupleDesc dst, TupleDesc src)
412 : : {
413 : : int i;
414 : :
415 : : /* Flat-copy the header and attribute arrays */
416 : 166 : memcpy(dst, src, TupleDescSize(src));
417 : :
418 : : /*
419 : : * Since we're not copying constraints and defaults, clear fields
420 : : * associated with them.
421 : : */
2993 tgl@sss.pgh.pa.us 422 [ + + ]: 628 : for (i = 0; i < dst->natts; i++)
423 : : {
424 : 462 : Form_pg_attribute att = TupleDescAttr(dst, i);
425 : :
426 : 462 : att->attnotnull = false;
427 : 462 : att->atthasdef = false;
2909 andrew@dunslane.net 428 : 462 : att->atthasmissing = false;
2993 tgl@sss.pgh.pa.us 429 : 462 : att->attidentity = '\0';
2542 peter@eisentraut.org 430 : 462 : att->attgenerated = '\0';
431 : :
450 drowley@postgresql.o 432 : 462 : populate_compact_attribute(dst, i);
433 : : }
3104 andres@anarazel.de 434 : 166 : dst->constr = NULL;
435 : :
436 : : /*
437 : : * Also, assume the destination is not to be ref-counted. (Copying the
438 : : * source's refcount would be wrong in any case.)
439 : : */
440 : 166 : dst->tdrefcount = -1;
441 : 166 : }
442 : :
443 : : /*
444 : : * TupleDescCopyEntry
445 : : * This function copies a single attribute structure from one tuple
446 : : * descriptor to another.
447 : : *
448 : : * !!! Constraints and defaults are not copied !!!
449 : : */
450 : : void
4497 tgl@sss.pgh.pa.us 451 : 2193 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
452 : : TupleDesc src, AttrNumber srcAttno)
453 : : {
3129 andres@anarazel.de 454 : 2193 : Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
455 : 2193 : Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
456 : :
457 : : /*
458 : : * sanity checks
459 : : */
172 peter@eisentraut.org 460 [ - + ]:GNC 2193 : Assert(src);
461 [ - + ]: 2193 : Assert(dst);
1234 peter@eisentraut.org 462 [ - + ]:CBC 2193 : Assert(srcAttno >= 1);
463 [ - + ]: 2193 : Assert(srcAttno <= src->natts);
464 [ - + ]: 2193 : Assert(dstAttno >= 1);
465 [ - + ]: 2193 : Assert(dstAttno <= dst->natts);
466 : :
3129 andres@anarazel.de 467 : 2193 : memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
468 : :
469 : 2193 : dstAtt->attnum = dstAttno;
470 : :
471 : : /* since we're not copying constraints or defaults, clear these */
472 : 2193 : dstAtt->attnotnull = false;
473 : 2193 : dstAtt->atthasdef = false;
2909 andrew@dunslane.net 474 : 2193 : dstAtt->atthasmissing = false;
3129 andres@anarazel.de 475 : 2193 : dstAtt->attidentity = '\0';
2542 peter@eisentraut.org 476 : 2193 : dstAtt->attgenerated = '\0';
477 : :
450 drowley@postgresql.o 478 : 2193 : populate_compact_attribute(dst, dstAttno - 1);
4497 tgl@sss.pgh.pa.us 479 : 2193 : }
480 : :
481 : : /*
482 : : * Free a TupleDesc including all substructure
483 : : */
484 : : void
10416 bruce@momjian.us 485 : 728770 : FreeTupleDesc(TupleDesc tupdesc)
486 : : {
487 : : int i;
488 : :
489 : : /*
490 : : * Possibly this should assert tdrefcount == 0, to disallow explicit
491 : : * freeing of un-refcounted tupdescs?
492 : : */
7212 tgl@sss.pgh.pa.us 493 [ - + ]: 728770 : Assert(tupdesc->tdrefcount <= 0);
494 : :
10416 bruce@momjian.us 495 [ + + ]: 728770 : if (tupdesc->constr)
496 : : {
497 [ + + ]: 213170 : if (tupdesc->constr->num_defval > 0)
498 : : {
10415 499 : 17605 : AttrDefault *attrdef = tupdesc->constr->defval;
500 : :
10416 501 [ + + ]: 42849 : for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
1804 tgl@sss.pgh.pa.us 502 : 25244 : pfree(attrdef[i].adbin);
10416 bruce@momjian.us 503 : 17605 : pfree(attrdef);
504 : : }
2909 andrew@dunslane.net 505 [ + + ]: 213170 : if (tupdesc->constr->missing)
506 : : {
507 : 1935 : AttrMissing *attrmiss = tupdesc->constr->missing;
508 : :
509 [ + + ]: 13745 : for (i = tupdesc->natts - 1; i >= 0; i--)
510 : : {
2818 akapila@postgresql.o 511 [ + + ]: 11810 : if (attrmiss[i].am_present
2909 andrew@dunslane.net 512 [ + + ]: 4041 : && !TupleDescAttr(tupdesc, i)->attbyval)
2818 akapila@postgresql.o 513 : 1463 : pfree(DatumGetPointer(attrmiss[i].am_value));
514 : : }
2909 andrew@dunslane.net 515 : 1935 : pfree(attrmiss);
516 : : }
10416 bruce@momjian.us 517 [ + + ]: 213170 : if (tupdesc->constr->num_check > 0)
518 : : {
10415 519 : 6379 : ConstrCheck *check = tupdesc->constr->check;
520 : :
10416 521 [ + + ]: 17739 : for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
522 : : {
1804 tgl@sss.pgh.pa.us 523 : 11360 : pfree(check[i].ccname);
524 : 11360 : pfree(check[i].ccbin);
525 : : }
10416 bruce@momjian.us 526 : 6379 : pfree(check);
527 : : }
528 : 213170 : pfree(tupdesc->constr);
529 : : }
530 : :
531 : 728770 : pfree(tupdesc);
10432 vadim4o@yahoo.com 532 : 728770 : }
533 : :
534 : : /*
535 : : * Increment the reference count of a tupdesc, and log the reference in
536 : : * CurrentResourceOwner.
537 : : *
538 : : * Do not apply this to tupdescs that are not being refcounted. (Use the
539 : : * macro PinTupleDesc for tupdescs of uncertain status.)
540 : : */
541 : : void
7212 tgl@sss.pgh.pa.us 542 : 17014856 : IncrTupleDescRefCount(TupleDesc tupdesc)
543 : : {
544 [ - + ]: 17014856 : Assert(tupdesc->tdrefcount >= 0);
545 : :
858 heikki.linnakangas@i 546 : 17014856 : ResourceOwnerEnlarge(CurrentResourceOwner);
7212 tgl@sss.pgh.pa.us 547 : 17014856 : tupdesc->tdrefcount++;
548 : 17014856 : ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
549 : 17014856 : }
550 : :
551 : : /*
552 : : * Decrement the reference count of a tupdesc, remove the corresponding
553 : : * reference from CurrentResourceOwner, and free the tupdesc if no more
554 : : * references remain.
555 : : *
556 : : * Do not apply this to tupdescs that are not being refcounted. (Use the
557 : : * macro ReleaseTupleDesc for tupdescs of uncertain status.)
558 : : */
559 : : void
560 : 17006724 : DecrTupleDescRefCount(TupleDesc tupdesc)
561 : : {
562 [ - + ]: 17006724 : Assert(tupdesc->tdrefcount > 0);
563 : :
564 : 17006724 : ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
565 [ - + ]: 17006724 : if (--tupdesc->tdrefcount == 0)
7212 tgl@sss.pgh.pa.us 566 :LBC (2) : FreeTupleDesc(tupdesc);
7212 tgl@sss.pgh.pa.us 567 :CBC 17006724 : }
568 : :
569 : : /*
570 : : * Compare two TupleDesc structures for logical equality
571 : : */
572 : : bool
9540 573 : 209008 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
574 : : {
575 : : int i,
576 : : n;
577 : :
578 [ + + ]: 209008 : if (tupdesc1->natts != tupdesc2->natts)
579 : 1409 : return false;
8018 580 [ - + ]: 207599 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
8018 tgl@sss.pgh.pa.us 581 :UBC 0 : return false;
582 : :
583 : : /* tdtypmod and tdrefcount are not checked */
584 : :
9540 tgl@sss.pgh.pa.us 585 [ + + ]:CBC 962325 : for (i = 0; i < tupdesc1->natts; i++)
586 : : {
3129 andres@anarazel.de 587 : 762506 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
588 : 762506 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
589 : :
590 : : /*
591 : : * We do not need to check every single field here: we can disregard
592 : : * attrelid and attnum (which were used to place the row in the attrs
593 : : * array in the first place). It might look like we could dispense
594 : : * with checking attlen/attbyval/attalign, since these are derived
595 : : * from atttypid; but in the case of dropped columns we must check
596 : : * them (since atttypid will be zero for all dropped columns) and in
597 : : * general it seems safer to check them always.
598 : : *
599 : : * We intentionally ignore atthasmissing, since that's not very
600 : : * relevant in tupdescs, which lack the attmissingval field.
601 : : */
9540 tgl@sss.pgh.pa.us 602 [ + + ]: 762506 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
603 : 676 : return false;
604 [ + + ]: 761830 : if (attr1->atttypid != attr2->atttypid)
605 : 589 : return false;
7640 606 [ + + ]: 761241 : if (attr1->attlen != attr2->attlen)
607 : 5 : return false;
8018 608 [ - + ]: 761236 : if (attr1->attndims != attr2->attndims)
8018 tgl@sss.pgh.pa.us 609 :UBC 0 : return false;
9540 tgl@sss.pgh.pa.us 610 [ + + ]:CBC 761236 : if (attr1->atttypmod != attr2->atttypmod)
611 : 21 : return false;
7640 612 [ + + ]: 761215 : if (attr1->attbyval != attr2->attbyval)
613 : 34 : return false;
1757 614 [ - + ]: 761181 : if (attr1->attalign != attr2->attalign)
1757 tgl@sss.pgh.pa.us 615 :UBC 0 : return false;
9540 tgl@sss.pgh.pa.us 616 [ + + ]:CBC 761181 : if (attr1->attstorage != attr2->attstorage)
617 : 129 : return false;
1757 618 [ + + ]: 761052 : if (attr1->attcompression != attr2->attcompression)
7640 619 : 36 : return false;
9540 620 [ + + ]: 761016 : if (attr1->attnotnull != attr2->attnotnull)
621 : 887 : return false;
622 : :
623 : : /*
624 : : * When the column has a not-null constraint, we also need to consider
625 : : * its validity aspect, which only manifests in CompactAttribute->
626 : : * attnullability, so verify that.
627 : : */
342 alvherre@alvh.no-ip. 628 [ + + ]: 760129 : if (attr1->attnotnull)
629 : : {
630 : 229680 : CompactAttribute *cattr1 = TupleDescCompactAttr(tupdesc1, i);
631 : 229680 : CompactAttribute *cattr2 = TupleDescCompactAttr(tupdesc2, i);
632 : :
633 [ - + ]: 229680 : Assert(cattr1->attnullability != ATTNULLABLE_UNKNOWN);
634 [ - + ]: 229680 : Assert((cattr1->attnullability == ATTNULLABLE_UNKNOWN) ==
635 : : (cattr2->attnullability == ATTNULLABLE_UNKNOWN));
636 : :
637 [ + + ]: 229680 : if (cattr1->attnullability != cattr2->attnullability)
638 : 53 : return false;
639 : : }
8598 tgl@sss.pgh.pa.us 640 [ + + ]: 760076 : if (attr1->atthasdef != attr2->atthasdef)
641 : 2753 : return false;
3265 peter_e@gmx.net 642 [ + + ]: 757323 : if (attr1->attidentity != attr2->attidentity)
643 : 95 : return false;
2542 peter@eisentraut.org 644 [ + + ]: 757228 : if (attr1->attgenerated != attr2->attgenerated)
645 : 10 : return false;
8626 tgl@sss.pgh.pa.us 646 [ - + ]: 757218 : if (attr1->attisdropped != attr2->attisdropped)
8626 tgl@sss.pgh.pa.us 647 :UBC 0 : return false;
8575 tgl@sss.pgh.pa.us 648 [ + + ]:CBC 757218 : if (attr1->attislocal != attr2->attislocal)
649 : 2064 : return false;
650 [ + + ]: 755154 : if (attr1->attinhcount != attr2->attinhcount)
8598 651 : 428 : return false;
5441 652 [ - + ]: 754726 : if (attr1->attcollation != attr2->attcollation)
5441 tgl@sss.pgh.pa.us 653 :UBC 0 : return false;
654 : : /* variable-length fields are not even present... */
655 : : }
656 : :
9540 tgl@sss.pgh.pa.us 657 [ + + ]:CBC 199819 : if (tupdesc1->constr != NULL)
658 : : {
9468 bruce@momjian.us 659 : 70780 : TupleConstr *constr1 = tupdesc1->constr;
660 : 70780 : TupleConstr *constr2 = tupdesc2->constr;
661 : :
9540 tgl@sss.pgh.pa.us 662 [ + + ]: 70780 : if (constr2 == NULL)
663 : 115 : return false;
9258 664 [ - + ]: 70665 : if (constr1->has_not_null != constr2->has_not_null)
9258 tgl@sss.pgh.pa.us 665 :UBC 0 : return false;
2542 peter@eisentraut.org 666 [ + + ]:CBC 70665 : if (constr1->has_generated_stored != constr2->has_generated_stored)
667 : 316 : return false;
401 668 [ + + ]: 70349 : if (constr1->has_generated_virtual != constr2->has_generated_virtual)
669 : 212 : return false;
9258 tgl@sss.pgh.pa.us 670 : 70137 : n = constr1->num_defval;
671 [ - + ]: 70137 : if (n != (int) constr2->num_defval)
9540 tgl@sss.pgh.pa.us 672 :UBC 0 : return false;
673 : : /* We assume here that both AttrDefault arrays are in adnum order */
9258 tgl@sss.pgh.pa.us 674 [ + + ]:CBC 80245 : for (i = 0; i < n; i++)
675 : : {
9468 bruce@momjian.us 676 : 10108 : AttrDefault *defval1 = constr1->defval + i;
1804 tgl@sss.pgh.pa.us 677 : 10108 : AttrDefault *defval2 = constr2->defval + i;
678 : :
679 [ - + ]: 10108 : if (defval1->adnum != defval2->adnum)
9540 tgl@sss.pgh.pa.us 680 :UBC 0 : return false;
9540 tgl@sss.pgh.pa.us 681 [ - + ]:CBC 10108 : if (strcmp(defval1->adbin, defval2->adbin) != 0)
9540 tgl@sss.pgh.pa.us 682 :UBC 0 : return false;
683 : : }
2909 andrew@dunslane.net 684 [ + + ]:CBC 70137 : if (constr1->missing)
685 : : {
686 [ + + ]: 380 : if (!constr2->missing)
687 : 45 : return false;
688 [ + + ]: 2000 : for (i = 0; i < tupdesc1->natts; i++)
689 : : {
690 : 1744 : AttrMissing *missval1 = constr1->missing + i;
691 : 1744 : AttrMissing *missval2 = constr2->missing + i;
692 : :
2818 akapila@postgresql.o 693 [ + + ]: 1744 : if (missval1->am_present != missval2->am_present)
2909 andrew@dunslane.net 694 : 79 : return false;
2818 akapila@postgresql.o 695 [ + + ]: 1665 : if (missval1->am_present)
696 : : {
450 drowley@postgresql.o 697 : 559 : CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
698 : :
2818 akapila@postgresql.o 699 [ - + ]: 559 : if (!datumIsEqual(missval1->am_value, missval2->am_value,
2909 andrew@dunslane.net 700 : 559 : missatt1->attbyval, missatt1->attlen))
2909 andrew@dunslane.net 701 :UBC 0 : return false;
702 : : }
703 : : }
704 : : }
2909 andrew@dunslane.net 705 [ + + ]:CBC 69757 : else if (constr2->missing)
706 : 194 : return false;
9258 tgl@sss.pgh.pa.us 707 : 69819 : n = constr1->num_check;
708 [ + + ]: 69819 : if (n != (int) constr2->num_check)
9540 709 : 893 : return false;
710 : :
711 : : /*
712 : : * Similarly, we rely here on the ConstrCheck entries being sorted by
713 : : * name. If there are duplicate names, the outcome of the comparison
714 : : * is uncertain, but that should not happen.
715 : : */
9258 716 [ + + ]: 71092 : for (i = 0; i < n; i++)
717 : : {
9468 bruce@momjian.us 718 : 2274 : ConstrCheck *check1 = constr1->check + i;
1804 tgl@sss.pgh.pa.us 719 : 2274 : ConstrCheck *check2 = constr2->check + i;
720 : :
721 [ + - ]: 2274 : if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
722 [ + - ]: 2274 : strcmp(check1->ccbin, check2->ccbin) == 0 &&
428 peter@eisentraut.org 723 [ + + ]: 2274 : check1->ccenforced == check2->ccenforced &&
1804 tgl@sss.pgh.pa.us 724 [ + + ]: 2208 : check1->ccvalid == check2->ccvalid &&
725 [ - + ]: 2166 : check1->ccnoinherit == check2->ccnoinherit))
9540 726 : 108 : return false;
727 : : }
728 : : }
729 [ + + ]: 129039 : else if (tupdesc2->constr != NULL)
730 : 1013 : return false;
731 : 196844 : return true;
732 : : }
733 : :
734 : : /*
735 : : * equalRowTypes
736 : : *
737 : : * This determines whether two tuple descriptors have equal row types. This
738 : : * only checks those fields in pg_attribute that are applicable for row types,
739 : : * while ignoring those fields that define the physical row storage or those
740 : : * that define table column metadata.
741 : : *
742 : : * Specifically, this checks:
743 : : *
744 : : * - same number of attributes
745 : : * - same composite type ID (but could both be zero)
746 : : * - corresponding attributes (in order) have same the name, type, typmod,
747 : : * collation
748 : : *
749 : : * This is used to check whether two record types are compatible, whether
750 : : * function return row types are the same, and other similar situations.
751 : : *
752 : : * (XXX There was some discussion whether attndims should be checked here, but
753 : : * for now it has been decided not to.)
754 : : *
755 : : * Note: We deliberately do not check the tdtypmod field. This allows
756 : : * typcache.c to use this routine to see if a cached record type matches a
757 : : * requested type.
758 : : */
759 : : bool
728 peter@eisentraut.org 760 : 231478 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
761 : : {
762 [ + + ]: 231478 : if (tupdesc1->natts != tupdesc2->natts)
763 : 84 : return false;
764 [ + + ]: 231394 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
765 : 966 : return false;
766 : :
767 [ + + ]: 3740947 : for (int i = 0; i < tupdesc1->natts; i++)
768 : : {
769 : 3514924 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
770 : 3514924 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
771 : :
772 [ + + ]: 3514924 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
773 : 4392 : return false;
774 [ + + ]: 3510532 : if (attr1->atttypid != attr2->atttypid)
775 : 11 : return false;
776 [ + + ]: 3510521 : if (attr1->atttypmod != attr2->atttypmod)
777 : 2 : return false;
778 [ - + ]: 3510519 : if (attr1->attcollation != attr2->attcollation)
728 peter@eisentraut.org 779 :UBC 0 : return false;
780 : :
781 : : /* Record types derived from tables could have dropped fields. */
728 peter@eisentraut.org 782 [ - + ]:CBC 3510519 : if (attr1->attisdropped != attr2->attisdropped)
728 peter@eisentraut.org 783 :UBC 0 : return false;
784 : : }
785 : :
728 peter@eisentraut.org 786 :CBC 226023 : return true;
787 : : }
788 : :
789 : : /*
790 : : * hashRowType
791 : : *
792 : : * If two tuple descriptors would be considered equal by equalRowTypes()
793 : : * then their hash value will be equal according to this function.
794 : : */
795 : : uint32
796 : 241781 : hashRowType(TupleDesc desc)
797 : : {
798 : : uint32 s;
799 : : int i;
800 : :
222 peter@eisentraut.org 801 :GNC 241781 : s = hash_combine(0, hash_bytes_uint32(desc->natts));
802 : 241781 : s = hash_combine(s, hash_bytes_uint32(desc->tdtypeid));
3127 andres@anarazel.de 803 [ + + ]:CBC 3933292 : for (i = 0; i < desc->natts; ++i)
222 peter@eisentraut.org 804 :GNC 3691511 : s = hash_combine(s, hash_bytes_uint32(TupleDescAttr(desc, i)->atttypid));
805 : :
3127 andres@anarazel.de 806 :CBC 241781 : return s;
807 : : }
808 : :
809 : : /*
810 : : * TupleDescInitEntry
811 : : * This function initializes a single attribute structure in
812 : : * a previously allocated tuple descriptor.
813 : : *
814 : : * If attributeName is NULL, the attname field is set to an empty string
815 : : * (this is for cases where we don't know or need a name for the field).
816 : : * Also, some callers use this function to change the datatype-related fields
817 : : * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
818 : : * to indicate that the attname field shouldn't be modified.
819 : : *
820 : : * Note that attcollation is set to the default for the specified datatype.
821 : : * If a nondefault collation is needed, insert it afterwards using
822 : : * TupleDescInitEntryCollation.
823 : : */
824 : : void
10841 scrappy@hub.org 825 : 9300894 : TupleDescInitEntry(TupleDesc desc,
826 : : AttrNumber attributeNumber,
827 : : const char *attributeName,
828 : : Oid oidtypeid,
829 : : int32 typmod,
830 : : int attdim)
831 : : {
832 : : HeapTuple tuple;
833 : : Form_pg_type typeForm;
834 : : Form_pg_attribute att;
835 : :
836 : : /*
837 : : * sanity checks
838 : : */
172 peter@eisentraut.org 839 [ - + ]:GNC 9300894 : Assert(desc);
1234 peter@eisentraut.org 840 [ - + ]:CBC 9300894 : Assert(attributeNumber >= 1);
841 [ - + ]: 9300894 : Assert(attributeNumber <= desc->natts);
1083 842 [ - + ]: 9300894 : Assert(attdim >= 0);
843 [ - + ]: 9300894 : Assert(attdim <= PG_INT16_MAX);
844 : :
845 : : /*
846 : : * initialize the attribute fields
847 : : */
3129 andres@anarazel.de 848 : 9300894 : att = TupleDescAttr(desc, attributeNumber - 1);
849 : :
10416 bruce@momjian.us 850 : 9300894 : att->attrelid = 0; /* dummy value */
851 : :
852 : : /*
853 : : * Note: attributeName can be NULL, because the planner doesn't always
854 : : * fill in valid resname values in targetlists, particularly for resjunk
855 : : * attributes. Also, do nothing if caller wants to re-use the old attname.
856 : : */
4521 tgl@sss.pgh.pa.us 857 [ + + ]: 9300894 : if (attributeName == NULL)
9625 bruce@momjian.us 858 [ + + + - : 10657239 : MemSet(NameStr(att->attname), 0, NAMEDATALEN);
+ - + - +
+ ]
4521 tgl@sss.pgh.pa.us 859 [ + + ]: 7029759 : else if (attributeName != NameStr(att->attname))
860 : 7028013 : namestrcpy(&(att->attname), attributeName);
861 : :
10260 bruce@momjian.us 862 : 9300894 : att->atttypmod = typmod;
863 : :
10416 864 : 9300894 : att->attnum = attributeNumber;
9078 tgl@sss.pgh.pa.us 865 : 9300894 : att->attndims = attdim;
866 : :
10416 bruce@momjian.us 867 : 9300894 : att->attnotnull = false;
868 : 9300894 : att->atthasdef = false;
2909 andrew@dunslane.net 869 : 9300894 : att->atthasmissing = false;
3265 peter_e@gmx.net 870 : 9300894 : att->attidentity = '\0';
2542 peter@eisentraut.org 871 : 9300894 : att->attgenerated = '\0';
8626 tgl@sss.pgh.pa.us 872 : 9300894 : att->attisdropped = false;
8575 873 : 9300894 : att->attislocal = true;
874 : 9300894 : att->attinhcount = 0;
875 : : /* variable-length fields are not present in tupledescs */
876 : :
5873 rhaas@postgresql.org 877 : 9300894 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
10416 bruce@momjian.us 878 [ - + ]: 9300894 : if (!HeapTupleIsValid(tuple))
8273 tgl@sss.pgh.pa.us 879 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", oidtypeid);
10057 bruce@momjian.us 880 :CBC 9300894 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
881 : :
8018 tgl@sss.pgh.pa.us 882 : 9300894 : att->atttypid = oidtypeid;
883 : 9300894 : att->attlen = typeForm->typlen;
884 : 9300894 : att->attbyval = typeForm->typbyval;
885 : 9300894 : att->attalign = typeForm->typalign;
886 : 9300894 : att->attstorage = typeForm->typstorage;
1753 887 : 9300894 : att->attcompression = InvalidCompressionMethod;
1757 888 : 9300894 : att->attcollation = typeForm->typcollation;
889 : :
450 drowley@postgresql.o 890 : 9300894 : populate_compact_attribute(desc, attributeNumber - 1);
891 : :
9250 tgl@sss.pgh.pa.us 892 : 9300894 : ReleaseSysCache(tuple);
10841 scrappy@hub.org 893 : 9300894 : }
894 : :
895 : : /*
896 : : * TupleDescInitBuiltinEntry
897 : : * Initialize a tuple descriptor without catalog access. Only
898 : : * a limited range of builtin types are supported.
899 : : */
900 : : void
3337 rhaas@postgresql.org 901 : 7335 : TupleDescInitBuiltinEntry(TupleDesc desc,
902 : : AttrNumber attributeNumber,
903 : : const char *attributeName,
904 : : Oid oidtypeid,
905 : : int32 typmod,
906 : : int attdim)
907 : : {
908 : : Form_pg_attribute att;
909 : :
910 : : /* sanity checks */
172 peter@eisentraut.org 911 [ - + ]:GNC 7335 : Assert(desc);
1234 peter@eisentraut.org 912 [ - + ]:CBC 7335 : Assert(attributeNumber >= 1);
913 [ - + ]: 7335 : Assert(attributeNumber <= desc->natts);
1083 914 [ - + ]: 7335 : Assert(attdim >= 0);
915 [ - + ]: 7335 : Assert(attdim <= PG_INT16_MAX);
916 : :
917 : : /* initialize the attribute fields */
3129 andres@anarazel.de 918 : 7335 : att = TupleDescAttr(desc, attributeNumber - 1);
3337 rhaas@postgresql.org 919 : 7335 : att->attrelid = 0; /* dummy value */
920 : :
921 : : /* unlike TupleDescInitEntry, we require an attribute name */
922 [ - + ]: 7335 : Assert(attributeName != NULL);
923 : 7335 : namestrcpy(&(att->attname), attributeName);
924 : :
925 : 7335 : att->atttypmod = typmod;
926 : :
927 : 7335 : att->attnum = attributeNumber;
928 : 7335 : att->attndims = attdim;
929 : :
930 : 7335 : att->attnotnull = false;
931 : 7335 : att->atthasdef = false;
2909 andrew@dunslane.net 932 : 7335 : att->atthasmissing = false;
3265 peter_e@gmx.net 933 : 7335 : att->attidentity = '\0';
2542 peter@eisentraut.org 934 : 7335 : att->attgenerated = '\0';
3337 rhaas@postgresql.org 935 : 7335 : att->attisdropped = false;
936 : 7335 : att->attislocal = true;
937 : 7335 : att->attinhcount = 0;
938 : : /* variable-length fields are not present in tupledescs */
939 : :
940 : 7335 : att->atttypid = oidtypeid;
941 : :
942 : : /*
943 : : * Our goal here is to support just enough types to let basic builtin
944 : : * commands work without catalog access - e.g. so that we can do certain
945 : : * things even in processes that are not connected to a database.
946 : : */
947 [ + - - + : 7335 : switch (oidtypeid)
+ - ]
948 : : {
949 : 5869 : case TEXTOID:
950 : : case TEXTARRAYOID:
951 : 5869 : att->attlen = -1;
952 : 5869 : att->attbyval = false;
2202 tgl@sss.pgh.pa.us 953 : 5869 : att->attalign = TYPALIGN_INT;
954 : 5869 : att->attstorage = TYPSTORAGE_EXTENDED;
1753 955 : 5869 : att->attcompression = InvalidCompressionMethod;
3337 rhaas@postgresql.org 956 : 5869 : att->attcollation = DEFAULT_COLLATION_OID;
957 : 5869 : break;
958 : :
3337 rhaas@postgresql.org 959 :UBC 0 : case BOOLOID:
960 : 0 : att->attlen = 1;
961 : 0 : att->attbyval = true;
2202 tgl@sss.pgh.pa.us 962 : 0 : att->attalign = TYPALIGN_CHAR;
963 : 0 : att->attstorage = TYPSTORAGE_PLAIN;
1757 964 : 0 : att->attcompression = InvalidCompressionMethod;
3337 rhaas@postgresql.org 965 : 0 : att->attcollation = InvalidOid;
966 : 0 : break;
967 : :
968 : 0 : case INT4OID:
969 : 0 : att->attlen = 4;
970 : 0 : att->attbyval = true;
2202 tgl@sss.pgh.pa.us 971 : 0 : att->attalign = TYPALIGN_INT;
972 : 0 : att->attstorage = TYPSTORAGE_PLAIN;
1757 973 : 0 : att->attcompression = InvalidCompressionMethod;
3337 rhaas@postgresql.org 974 : 0 : att->attcollation = InvalidOid;
3329 975 : 0 : break;
976 : :
3329 rhaas@postgresql.org 977 :CBC 1293 : case INT8OID:
978 : 1293 : att->attlen = 8;
214 tgl@sss.pgh.pa.us 979 :GNC 1293 : att->attbyval = true;
2202 tgl@sss.pgh.pa.us 980 :CBC 1293 : att->attalign = TYPALIGN_DOUBLE;
981 : 1293 : att->attstorage = TYPSTORAGE_PLAIN;
1757 982 : 1293 : att->attcompression = InvalidCompressionMethod;
3329 rhaas@postgresql.org 983 : 1293 : att->attcollation = InvalidOid;
3337 984 : 1293 : break;
985 : :
1350 peter@eisentraut.org 986 : 173 : case OIDOID:
987 : 173 : att->attlen = 4;
988 : 173 : att->attbyval = true;
989 : 173 : att->attalign = TYPALIGN_INT;
990 : 173 : att->attstorage = TYPSTORAGE_PLAIN;
991 : 173 : att->attcompression = InvalidCompressionMethod;
992 : 173 : att->attcollation = InvalidOid;
993 : 173 : break;
994 : :
2652 tgl@sss.pgh.pa.us 995 :UBC 0 : default:
996 [ # # ]: 0 : elog(ERROR, "unsupported type %u", oidtypeid);
997 : : }
998 : :
450 drowley@postgresql.o 999 :CBC 7335 : populate_compact_attribute(desc, attributeNumber - 1);
3337 rhaas@postgresql.org 1000 : 7335 : }
1001 : :
1002 : : /*
1003 : : * TupleDescInitEntryCollation
1004 : : *
1005 : : * Assign a nondefault collation to a previously initialized tuple descriptor
1006 : : * entry.
1007 : : */
1008 : : void
5514 peter_e@gmx.net 1009 : 5555537 : TupleDescInitEntryCollation(TupleDesc desc,
1010 : : AttrNumber attributeNumber,
1011 : : Oid collationid)
1012 : : {
1013 : : /*
1014 : : * sanity checks
1015 : : */
172 peter@eisentraut.org 1016 [ - + ]:GNC 5555537 : Assert(desc);
1234 peter@eisentraut.org 1017 [ - + ]:CBC 5555537 : Assert(attributeNumber >= 1);
1018 [ - + ]: 5555537 : Assert(attributeNumber <= desc->natts);
1019 : :
3129 andres@anarazel.de 1020 : 5555537 : TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
5514 peter_e@gmx.net 1021 : 5555537 : }
1022 : :
1023 : : /*
1024 : : * BuildDescFromLists
1025 : : *
1026 : : * Build a TupleDesc given lists of column names (as String nodes),
1027 : : * column type OIDs, typmods, and collation OIDs.
1028 : : *
1029 : : * No constraints are generated.
1030 : : *
1031 : : * This is for use with functions returning RECORD.
1032 : : */
1033 : : TupleDesc
901 peter@eisentraut.org 1034 : 711 : BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
1035 : : {
1036 : : int natts;
1037 : : AttrNumber attnum;
1038 : : ListCell *l1;
1039 : : ListCell *l2;
1040 : : ListCell *l3;
1041 : : ListCell *l4;
1042 : : TupleDesc desc;
1043 : :
7304 tgl@sss.pgh.pa.us 1044 : 711 : natts = list_length(names);
1045 [ - + ]: 711 : Assert(natts == list_length(types));
1046 [ - + ]: 711 : Assert(natts == list_length(typmods));
5514 peter_e@gmx.net 1047 [ - + ]: 711 : Assert(natts == list_length(collations));
1048 : :
1049 : : /*
1050 : : * allocate a new tuple descriptor
1051 : : */
2672 andres@anarazel.de 1052 : 711 : desc = CreateTemplateTupleDesc(natts);
1053 : :
7304 tgl@sss.pgh.pa.us 1054 : 711 : attnum = 0;
2572 1055 [ + - + + : 2502 : forfour(l1, names, l2, types, l3, typmods, l4, collations)
+ - + + +
- + + + -
+ + + + +
- + - + -
+ + ]
1056 : : {
7304 1057 : 1791 : char *attname = strVal(lfirst(l1));
2572 1058 : 1791 : Oid atttypid = lfirst_oid(l2);
1059 : 1791 : int32 atttypmod = lfirst_int(l3);
1060 : 1791 : Oid attcollation = lfirst_oid(l4);
1061 : :
7304 1062 : 1791 : attnum++;
1063 : :
1064 : 1791 : TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
5514 peter_e@gmx.net 1065 : 1791 : TupleDescInitEntryCollation(desc, attnum, attcollation);
1066 : : }
1067 : :
7304 tgl@sss.pgh.pa.us 1068 : 711 : return desc;
1069 : : }
1070 : :
1071 : : /*
1072 : : * Get default expression (or NULL if none) for the given attribute number.
1073 : : */
1074 : : Node *
900 peter@eisentraut.org 1075 : 75786 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
1076 : : {
1077 : 75786 : Node *result = NULL;
1078 : :
1079 [ + - ]: 75786 : if (tupdesc->constr)
1080 : : {
1081 : 75786 : AttrDefault *attrdef = tupdesc->constr->defval;
1082 : :
1083 [ + - ]: 114467 : for (int i = 0; i < tupdesc->constr->num_defval; i++)
1084 : : {
1085 [ + + ]: 114467 : if (attrdef[i].adnum == attnum)
1086 : : {
1087 : 75786 : result = stringToNode(attrdef[i].adbin);
1088 : 75786 : break;
1089 : : }
1090 : : }
1091 : : }
1092 : :
1093 : 75786 : return result;
1094 : : }
1095 : :
1096 : : /* ResourceOwner callbacks */
1097 : :
1098 : : static void
858 heikki.linnakangas@i 1099 : 8132 : ResOwnerReleaseTupleDesc(Datum res)
1100 : : {
1101 : 8132 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1102 : :
1103 : : /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
1104 [ - + ]: 8132 : Assert(tupdesc->tdrefcount > 0);
1105 [ + + ]: 8132 : if (--tupdesc->tdrefcount == 0)
1106 : 290 : FreeTupleDesc(tupdesc);
1107 : 8132 : }
1108 : :
1109 : : static char *
858 heikki.linnakangas@i 1110 :UBC 0 : ResOwnerPrintTupleDesc(Datum res)
1111 : : {
1112 : 0 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1113 : :
1114 : 0 : return psprintf("TupleDesc %p (%u,%d)",
1115 : : tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1116 : : }
|