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
965 heikki.linnakangas@i 49 :CBC 20483228 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
50 : : {
51 : 20483228 : ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
52 : 20483228 : }
53 : :
54 : : static inline void
55 : 20471471 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
56 : : {
57 : 20471471 : ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
58 : 20471471 : }
59 : :
60 : : /*
61 : : * populate_compact_attribute_internal
62 : : * Helper function for populate_compact_attribute()
63 : : */
64 : : static inline void
553 drowley@postgresql.o 65 : 1331046119 : populate_compact_attribute_internal(Form_pg_attribute src,
66 : : CompactAttribute *dst)
67 : : {
557 68 : 1331046119 : memset(dst, 0, sizeof(CompactAttribute));
69 : :
70 : 1331046119 : dst->attcacheoff = -1;
71 : 1331046119 : dst->attlen = src->attlen;
72 : :
73 : 1331046119 : dst->attbyval = src->attbyval;
74 : 1331046119 : dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
75 : 1331046119 : dst->atthasmissing = src->atthasmissing;
76 : 1331046119 : dst->attisdropped = src->attisdropped;
77 : 1331046119 : 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 : : */
449 alvherre@alvh.no-ip. 85 [ + + + + ]: 1695604427 : dst->attnullability = !src->attnotnull ? ATTNULLABLE_UNRESTRICTED :
86 : 364558308 : IsCatalogRelationOid(src->attrelid) ? ATTNULLABLE_VALID :
87 : : ATTNULLABLE_UNKNOWN;
88 : :
89 : : /* Compute numeric alignment requirement, too */
148 tgl@sss.pgh.pa.us 90 :GNC 1331046119 : dst->attalignby = typalign_to_alignby(src->attalign);
557 drowley@postgresql.o 91 :CBC 1331046119 : }
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
553 100 : 40891528 : populate_compact_attribute(TupleDesc tupdesc, int attnum)
101 : : {
102 : 40891528 : 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 : 40891528 : dst = &tupdesc->compact_attrs[attnum];
110 : :
111 : 40891528 : populate_compact_attribute_internal(src, dst);
112 : 40891528 : }
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 : 1290154591 : verify_compact_attribute(TupleDesc tupdesc, int attnum)
126 : : {
127 : : #ifdef USE_ASSERT_CHECKING
128 : : CompactAttribute cattr;
129 : 1290154591 : 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 : : */
378 137 : 1290154591 : memcpy(&cattr, &tupdesc->compact_attrs[attnum], sizeof(CompactAttribute));
138 : :
139 : : /*
140 : : * Populate the temporary CompactAttribute from the corresponding
141 : : * Form_pg_attribute
142 : : */
553 143 : 1290154591 : 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 : : */
378 149 : 1290154591 : tmp.attcacheoff = cattr.attcacheoff;
150 : 1290154591 : tmp.attnullability = cattr.attnullability;
151 : :
152 : : /* Check the freshly populated CompactAttribute matches the TupleDesc's */
153 [ - + ]: 1290154591 : Assert(memcmp(&tmp, &cattr, sizeof(CompactAttribute)) == 0);
154 : : #endif
535 155 : 1290154591 : }
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
2779 andres@anarazel.de 165 : 6095671 : CreateTemplateTupleDesc(int natts)
166 : : {
167 : : TupleDesc desc;
168 : :
169 : : /*
170 : : * sanity checks
171 : : */
1341 peter@eisentraut.org 172 [ - + ]: 6095671 : 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 : : */
557 drowley@postgresql.o 187 : 6095671 : desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
557 drowley@postgresql.o 188 :ECB (4666180) : natts * sizeof(CompactAttribute) +
3236 andres@anarazel.de 189 :GIC 6095671 : natts * sizeof(FormData_pg_attribute));
190 : :
191 : : /*
192 : : * Initialize other fields of the tupdesc.
193 : : */
8125 tgl@sss.pgh.pa.us 194 :CBC 6095671 : desc->natts = natts;
8676 195 : 6095671 : desc->constr = NULL;
8125 196 : 6095671 : desc->tdtypeid = RECORDOID;
197 : 6095671 : desc->tdtypmod = -1;
7319 198 : 6095671 : desc->tdrefcount = -1; /* assume not reference-counted */
199 : :
200 : : /* This will be set to the correct value by TupleDescFinalize() */
106 drowley@postgresql.o 201 :GNC 6095671 : desc->firstNonCachedOffsetAttr = -1;
202 : 6095671 : desc->firstNonGuaranteedAttr = -1;
203 : :
10164 bruce@momjian.us 204 :CBC 6095671 : 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
2779 andres@anarazel.de 216 : 655828 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
217 : : {
218 : : TupleDesc desc;
219 : : int i;
220 : :
221 : 655828 : desc = CreateTemplateTupleDesc(natts);
222 : :
3236 223 [ + + ]: 9989756 : for (i = 0; i < natts; ++i)
224 : : {
225 : 9333928 : memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
557 drowley@postgresql.o 226 : 9333928 : populate_compact_attribute(desc, i);
227 : : }
228 : :
106 drowley@postgresql.o 229 :GNC 655828 : TupleDescFinalize(desc);
230 : :
10164 bruce@momjian.us 231 :CBC 655828 : 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
10948 scrappy@hub.org 242 : 258760 : CreateTupleDescCopy(TupleDesc tupdesc)
243 : : {
244 : : TupleDesc desc;
245 : : int i;
246 : :
2779 andres@anarazel.de 247 : 258760 : desc = CreateTemplateTupleDesc(tupdesc->natts);
248 : :
249 : : /* Flat-copy the attribute array (unless there are no attributes) */
98 rhaas@postgresql.org 250 [ + + ]:GNC 258760 : if (desc->natts > 0)
251 : 256377 : memcpy(TupleDescAttr(desc, 0),
252 : 256377 : TupleDescAttr(tupdesc, 0),
253 : 256377 : desc->natts * sizeof(FormData_pg_attribute));
254 : :
255 : : /*
256 : : * Since we're not copying constraints and defaults, clear fields
257 : : * associated with them.
258 : : */
7785 tgl@sss.pgh.pa.us 259 [ + + ]:CBC 1259803 : for (i = 0; i < desc->natts; i++)
260 : : {
3236 andres@anarazel.de 261 : 1001043 : Form_pg_attribute att = TupleDescAttr(desc, i);
262 : :
263 : 1001043 : att->attnotnull = false;
264 : 1001043 : att->atthasdef = false;
3016 andrew@dunslane.net 265 : 1001043 : att->atthasmissing = false;
3236 andres@anarazel.de 266 : 1001043 : att->attidentity = '\0';
2649 peter@eisentraut.org 267 : 1001043 : att->attgenerated = '\0';
268 : :
557 drowley@postgresql.o 269 : 1001043 : populate_compact_attribute(desc, i);
270 : : }
271 : :
272 : : /* We can copy the tuple type identification, too */
273 : 258760 : desc->tdtypeid = tupdesc->tdtypeid;
274 : 258760 : desc->tdtypmod = tupdesc->tdtypmod;
275 : :
106 drowley@postgresql.o 276 :GNC 258760 : TupleDescFinalize(desc);
277 : :
557 drowley@postgresql.o 278 :CBC 258760 : 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 : 25315 : CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
290 : : {
291 : : TupleDesc desc;
292 : : int i;
293 : :
294 [ - + ]: 25315 : Assert(natts <= tupdesc->natts);
295 : :
296 : 25315 : desc = CreateTemplateTupleDesc(natts);
297 : :
298 : : /* Flat-copy the attribute array (unless there are no attributes) */
98 rhaas@postgresql.org 299 [ + - ]:GNC 25315 : if (desc->natts > 0)
300 : 25315 : memcpy(TupleDescAttr(desc, 0),
301 : 25315 : TupleDescAttr(tupdesc, 0),
302 : 25315 : desc->natts * sizeof(FormData_pg_attribute));
303 : :
304 : : /*
305 : : * Since we're not copying constraints and defaults, clear fields
306 : : * associated with them.
307 : : */
557 drowley@postgresql.o 308 [ + + ]:CBC 61673 : for (i = 0; i < desc->natts; i++)
309 : : {
310 : 36358 : Form_pg_attribute att = TupleDescAttr(desc, i);
311 : :
312 : 36358 : att->attnotnull = false;
313 : 36358 : att->atthasdef = false;
314 : 36358 : att->atthasmissing = false;
315 : 36358 : att->attidentity = '\0';
316 : 36358 : att->attgenerated = '\0';
317 : :
318 : 36358 : populate_compact_attribute(desc, i);
319 : : }
320 : :
321 : : /* We can copy the tuple type identification, too */
8125 tgl@sss.pgh.pa.us 322 : 25315 : desc->tdtypeid = tupdesc->tdtypeid;
323 : 25315 : desc->tdtypmod = tupdesc->tdtypmod;
324 : :
106 drowley@postgresql.o 325 :GNC 25315 : TupleDescFinalize(desc);
326 : :
10523 bruce@momjian.us 327 :CBC 25315 : 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
10539 vadim4o@yahoo.com 336 : 503924 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
337 : : {
338 : : TupleDesc desc;
10522 bruce@momjian.us 339 : 503924 : TupleConstr *constr = tupdesc->constr;
340 : : int i;
341 : :
2779 andres@anarazel.de 342 : 503924 : desc = CreateTemplateTupleDesc(tupdesc->natts);
343 : :
344 : : /* Flat-copy the attribute array (unless there are no attributes) */
98 rhaas@postgresql.org 345 [ + + ]:GNC 503924 : if (desc->natts > 0)
346 : 503862 : memcpy(TupleDescAttr(desc, 0),
347 : 503862 : TupleDescAttr(tupdesc, 0),
348 : 503862 : desc->natts * sizeof(FormData_pg_attribute));
349 : :
557 drowley@postgresql.o 350 [ + + ]:CBC 7191982 : for (i = 0; i < desc->natts; i++)
351 : : {
352 : 6688058 : populate_compact_attribute(desc, i);
353 : :
449 alvherre@alvh.no-ip. 354 : 6688058 : TupleDescCompactAttr(desc, i)->attnullability =
355 : 13376116 : TupleDescCompactAttr(tupdesc, i)->attnullability;
356 : : }
357 : :
358 : : /* Copy the TupleConstr data structure, if any */
10523 bruce@momjian.us 359 [ + + ]: 503924 : if (constr)
360 : : {
202 michael@paquier.xyz 361 :GNC 458628 : TupleConstr *cpy = palloc0_object(TupleConstr);
362 : :
10523 bruce@momjian.us 363 :CBC 458628 : cpy->has_not_null = constr->has_not_null;
2649 peter@eisentraut.org 364 : 458628 : cpy->has_generated_stored = constr->has_generated_stored;
508 365 : 458628 : cpy->has_generated_virtual = constr->has_generated_virtual;
366 : :
10523 bruce@momjian.us 367 [ + + ]: 458628 : if ((cpy->num_defval = constr->num_defval) > 0)
368 : : {
369 : 2962 : cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
370 : 2962 : memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
371 [ + + ]: 7193 : for (i = cpy->num_defval - 1; i >= 0; i--)
1911 tgl@sss.pgh.pa.us 372 : 4231 : cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
373 : : }
374 : :
3016 andrew@dunslane.net 375 [ + + ]: 458628 : if (constr->missing)
376 : : {
377 : 430 : cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
378 : 430 : memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
379 [ + + ]: 3294 : for (i = tupdesc->natts - 1; i >= 0; i--)
380 : : {
2925 akapila@postgresql.o 381 [ + + ]: 2864 : if (constr->missing[i].am_present)
382 : : {
557 drowley@postgresql.o 383 : 766 : CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
384 : :
2925 akapila@postgresql.o 385 : 766 : cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
386 : 766 : attr->attbyval,
387 : 766 : attr->attlen);
388 : : }
389 : : }
390 : : }
391 : :
10523 bruce@momjian.us 392 [ + + ]: 458628 : if ((cpy->num_check = constr->num_check) > 0)
393 : : {
394 : 1835 : cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
395 : 1835 : memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
396 [ + + ]: 5423 : for (i = cpy->num_check - 1; i >= 0; i--)
397 : : {
1911 tgl@sss.pgh.pa.us 398 : 3588 : cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
399 : 3588 : cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
535 peter@eisentraut.org 400 : 3588 : cpy->check[i].ccenforced = constr->check[i].ccenforced;
5508 alvherre@alvh.no-ip. 401 : 3588 : cpy->check[i].ccvalid = constr->check[i].ccvalid;
4482 noah@leadboat.com 402 : 3588 : cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
403 : : }
404 : : }
405 : :
10523 bruce@momjian.us 406 : 458628 : desc->constr = cpy;
407 : : }
408 : :
409 : : /* We can copy the tuple type identification, too */
8125 tgl@sss.pgh.pa.us 410 : 503924 : desc->tdtypeid = tupdesc->tdtypeid;
411 : 503924 : desc->tdtypmod = tupdesc->tdtypmod;
412 : :
106 drowley@postgresql.o 413 :GNC 503924 : TupleDescFinalize(desc);
414 : :
10523 bruce@momjian.us 415 :CBC 503924 : 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
3211 andres@anarazel.de 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 : : */
3100 tgl@sss.pgh.pa.us 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;
3016 andrew@dunslane.net 444 : 697 : att->atthasmissing = false;
3100 tgl@sss.pgh.pa.us 445 : 697 : att->attidentity = '\0';
2649 peter@eisentraut.org 446 : 697 : att->attgenerated = '\0';
447 : :
557 drowley@postgresql.o 448 : 697 : populate_compact_attribute(dst, i);
449 : : }
3211 andres@anarazel.de 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 : :
106 drowley@postgresql.o 458 :GNC 236 : TupleDescFinalize(dst);
3211 andres@anarazel.de 459 :CBC 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
4604 tgl@sss.pgh.pa.us 472 : 2872 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
473 : : TupleDesc src, AttrNumber srcAttno)
474 : : {
3236 andres@anarazel.de 475 : 2872 : Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
476 : 2872 : Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
477 : :
478 : : /*
479 : : * sanity checks
480 : : */
279 peter@eisentraut.org 481 [ - + ]:GNC 2872 : Assert(src);
482 [ - + ]: 2872 : Assert(dst);
1341 peter@eisentraut.org 483 [ - + ]:CBC 2872 : Assert(srcAttno >= 1);
484 [ - + ]: 2872 : Assert(srcAttno <= src->natts);
485 [ - + ]: 2872 : Assert(dstAttno >= 1);
486 [ - + ]: 2872 : Assert(dstAttno <= dst->natts);
487 : :
3236 andres@anarazel.de 488 : 2872 : memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
489 : :
490 : 2872 : dstAtt->attnum = dstAttno;
491 : :
492 : : /* since we're not copying constraints or defaults, clear these */
493 : 2872 : dstAtt->attnotnull = false;
494 : 2872 : dstAtt->atthasdef = false;
3016 andrew@dunslane.net 495 : 2872 : dstAtt->atthasmissing = false;
3236 andres@anarazel.de 496 : 2872 : dstAtt->attidentity = '\0';
2649 peter@eisentraut.org 497 : 2872 : dstAtt->attgenerated = '\0';
498 : :
557 drowley@postgresql.o 499 : 2872 : populate_compact_attribute(dst, dstAttno - 1);
4604 tgl@sss.pgh.pa.us 500 : 2872 : }
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
106 drowley@postgresql.o 511 :GNC 6229464 : TupleDescFinalize(TupleDesc tupdesc)
512 : : {
513 : 6229464 : int firstNonCachedOffsetAttr = 0;
514 : 6229464 : int firstNonGuaranteedAttr = tupdesc->natts;
515 : 6229464 : int off = 0;
516 : :
517 [ + + ]: 34786248 : for (int i = 0; i < tupdesc->natts; i++)
518 : : {
519 : 31719956 : CompactAttribute *cattr = TupleDescCompactAttr(tupdesc, i);
24 520 : 31719956 : Form_pg_attribute attr = TupleDescAttr(tupdesc, i);
521 : :
522 : : /*
523 : : * Find the highest attnum which is guaranteed to exist in all tuples
524 : : * in the table. We currently only pay attention to byval attributes
525 : : * to allow additional optimizations during tuple deformation.
526 : : */
106 527 [ + + ]: 31719956 : if (firstNonGuaranteedAttr == tupdesc->natts &&
528 [ + + + + : 13148767 : (cattr->attnullability != ATTNULLABLE_VALID || !cattr->attbyval ||
+ + ]
24 529 [ + - ]: 7434122 : cattr->atthasmissing || cattr->attisdropped ||
530 [ + - ]: 7434122 : cattr->attlen <= 0 ||
531 [ + + ]: 7434122 : attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL))
106 532 : 5714948 : firstNonGuaranteedAttr = i;
533 : :
534 : : /*
535 : : * Don't cache offsets beyond fixed-width attributes. Virtual
536 : : * generated attributes are stored as NULLs in the tuple, so we don't
537 : : * cache offsets beyond these.
538 : : */
24 539 [ + + ]: 31719956 : if (cattr->attlen <= 0 ||
540 [ + + ]: 28562347 : attr->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
541 : : break;
542 : :
106 543 : 28556784 : off = att_nominal_alignby(off, cattr->attalignby);
544 : :
545 : : /*
546 : : * attcacheoff is an int16, so don't try to cache any offsets larger
547 : : * than will fit in that type. Any attributes which are offset more
548 : : * than 2^15 are likely due to variable-length attributes. Since we
549 : : * don't cache offsets for or beyond variable-length attributes, using
550 : : * an int16 rather than an int32 here is unlikely to cost us anything.
551 : : */
105 552 [ - + ]: 28556784 : if (off > PG_INT16_MAX)
105 drowley@postgresql.o 553 :UNC 0 : break;
554 : :
105 drowley@postgresql.o 555 :GNC 28556784 : cattr->attcacheoff = (int16) off;
556 : :
106 557 : 28556784 : off += cattr->attlen;
558 : 28556784 : firstNonCachedOffsetAttr = i + 1;
559 : : }
560 : :
561 : 6229464 : tupdesc->firstNonCachedOffsetAttr = firstNonCachedOffsetAttr;
562 : 6229464 : tupdesc->firstNonGuaranteedAttr = firstNonGuaranteedAttr;
563 : 6229464 : }
564 : :
565 : : /*
566 : : * Free a TupleDesc including all substructure
567 : : */
568 : : void
10523 bruce@momjian.us 569 :CBC 952966 : FreeTupleDesc(TupleDesc tupdesc)
570 : : {
571 : : int i;
572 : :
573 : : /*
574 : : * Possibly this should assert tdrefcount == 0, to disallow explicit
575 : : * freeing of un-refcounted tupdescs?
576 : : */
7319 tgl@sss.pgh.pa.us 577 [ - + ]: 952966 : Assert(tupdesc->tdrefcount <= 0);
578 : :
10523 bruce@momjian.us 579 [ + + ]: 952966 : if (tupdesc->constr)
580 : : {
581 [ + + ]: 283804 : if (tupdesc->constr->num_defval > 0)
582 : : {
10522 583 : 23465 : AttrDefault *attrdef = tupdesc->constr->defval;
584 : :
10523 585 [ + + ]: 57256 : for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
1911 tgl@sss.pgh.pa.us 586 : 33791 : pfree(attrdef[i].adbin);
10523 bruce@momjian.us 587 : 23465 : pfree(attrdef);
588 : : }
3016 andrew@dunslane.net 589 [ + + ]: 283804 : if (tupdesc->constr->missing)
590 : : {
591 : 2565 : AttrMissing *attrmiss = tupdesc->constr->missing;
592 : :
593 [ + + ]: 18086 : for (i = tupdesc->natts - 1; i >= 0; i--)
594 : : {
2925 akapila@postgresql.o 595 [ + + ]: 15521 : if (attrmiss[i].am_present
3016 andrew@dunslane.net 596 [ + + ]: 5346 : && !TupleDescAttr(tupdesc, i)->attbyval)
2925 akapila@postgresql.o 597 : 2022 : pfree(DatumGetPointer(attrmiss[i].am_value));
598 : : }
3016 andrew@dunslane.net 599 : 2565 : pfree(attrmiss);
600 : : }
10523 bruce@momjian.us 601 [ + + ]: 283804 : if (tupdesc->constr->num_check > 0)
602 : : {
10522 603 : 8709 : ConstrCheck *check = tupdesc->constr->check;
604 : :
10523 605 [ + + ]: 24006 : for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
606 : : {
1911 tgl@sss.pgh.pa.us 607 : 15297 : pfree(check[i].ccname);
608 : 15297 : pfree(check[i].ccbin);
609 : : }
10523 bruce@momjian.us 610 : 8709 : pfree(check);
611 : : }
612 : 283804 : pfree(tupdesc->constr);
613 : : }
614 : :
615 : 952966 : pfree(tupdesc);
10539 vadim4o@yahoo.com 616 : 952966 : }
617 : :
618 : : /*
619 : : * Increment the reference count of a tupdesc, and log the reference in
620 : : * CurrentResourceOwner.
621 : : *
622 : : * Do not apply this to tupdescs that are not being refcounted. (Use the
623 : : * macro PinTupleDesc for tupdescs of uncertain status.)
624 : : */
625 : : void
7319 tgl@sss.pgh.pa.us 626 : 20483228 : IncrTupleDescRefCount(TupleDesc tupdesc)
627 : : {
628 [ - + ]: 20483228 : Assert(tupdesc->tdrefcount >= 0);
629 : :
965 heikki.linnakangas@i 630 : 20483228 : ResourceOwnerEnlarge(CurrentResourceOwner);
7319 tgl@sss.pgh.pa.us 631 : 20483228 : tupdesc->tdrefcount++;
632 : 20483228 : ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
633 : 20483228 : }
634 : :
635 : : /*
636 : : * Decrement the reference count of a tupdesc, remove the corresponding
637 : : * reference from CurrentResourceOwner, and free the tupdesc if no more
638 : : * references remain.
639 : : *
640 : : * Do not apply this to tupdescs that are not being refcounted. (Use the
641 : : * macro ReleaseTupleDesc for tupdescs of uncertain status.)
642 : : */
643 : : void
644 : 20471471 : DecrTupleDescRefCount(TupleDesc tupdesc)
645 : : {
646 [ - + ]: 20471471 : Assert(tupdesc->tdrefcount > 0);
647 : :
648 : 20471471 : ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
649 [ - + ]: 20471471 : if (--tupdesc->tdrefcount == 0)
7319 tgl@sss.pgh.pa.us 650 :LBC (2) : FreeTupleDesc(tupdesc);
7319 tgl@sss.pgh.pa.us 651 :CBC 20471471 : }
652 : :
653 : : /*
654 : : * Compare two TupleDesc structures for logical equality
655 : : */
656 : : bool
9647 657 : 266242 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
658 : : {
659 : : int i,
660 : : n;
661 : :
662 [ + + ]: 266242 : if (tupdesc1->natts != tupdesc2->natts)
663 : 1959 : return false;
8125 664 [ - + ]: 264283 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
8125 tgl@sss.pgh.pa.us 665 :UBC 0 : return false;
666 : :
667 : : /* tdtypmod and tdrefcount are not checked */
668 : :
9647 tgl@sss.pgh.pa.us 669 [ + + ]:CBC 1198855 : for (i = 0; i < tupdesc1->natts; i++)
670 : : {
3236 andres@anarazel.de 671 : 944840 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
672 : 944840 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
673 : :
674 : : /*
675 : : * We do not need to check every single field here: we can disregard
676 : : * attrelid and attnum (which were used to place the row in the attrs
677 : : * array in the first place). It might look like we could dispense
678 : : * with checking attlen/attbyval/attalign, since these are derived
679 : : * from atttypid; but in the case of dropped columns we must check
680 : : * them (since atttypid will be zero for all dropped columns) and in
681 : : * general it seems safer to check them always.
682 : : *
683 : : * We intentionally ignore atthasmissing, since that's not very
684 : : * relevant in tupdescs, which lack the attmissingval field.
685 : : */
9647 tgl@sss.pgh.pa.us 686 [ + + ]: 944840 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
687 : 926 : return false;
688 [ + + ]: 943914 : if (attr1->atttypid != attr2->atttypid)
689 : 756 : return false;
7747 690 [ + + ]: 943158 : if (attr1->attlen != attr2->attlen)
691 : 6 : return false;
8125 692 [ - + ]: 943152 : if (attr1->attndims != attr2->attndims)
8125 tgl@sss.pgh.pa.us 693 :UBC 0 : return false;
9647 tgl@sss.pgh.pa.us 694 [ + + ]:CBC 943152 : if (attr1->atttypmod != attr2->atttypmod)
695 : 28 : return false;
7747 696 [ + + ]: 943124 : if (attr1->attbyval != attr2->attbyval)
697 : 34 : return false;
1864 698 [ - + ]: 943090 : if (attr1->attalign != attr2->attalign)
1864 tgl@sss.pgh.pa.us 699 :UBC 0 : return false;
9647 tgl@sss.pgh.pa.us 700 [ + + ]:CBC 943090 : if (attr1->attstorage != attr2->attstorage)
701 : 165 : return false;
1864 702 [ + + ]: 942925 : if (attr1->attcompression != attr2->attcompression)
7747 703 : 44 : return false;
9647 704 [ + + ]: 942881 : if (attr1->attnotnull != attr2->attnotnull)
705 : 1166 : return false;
706 : :
707 : : /*
708 : : * When the column has a not-null constraint, we also need to consider
709 : : * its validity aspect, which only manifests in CompactAttribute->
710 : : * attnullability, so verify that.
711 : : */
449 alvherre@alvh.no-ip. 712 [ + + ]: 941715 : if (attr1->attnotnull)
713 : : {
714 : 278954 : CompactAttribute *cattr1 = TupleDescCompactAttr(tupdesc1, i);
715 : 278954 : CompactAttribute *cattr2 = TupleDescCompactAttr(tupdesc2, i);
716 : :
717 [ - + ]: 278954 : Assert(cattr1->attnullability != ATTNULLABLE_UNKNOWN);
718 [ - + ]: 278954 : Assert((cattr1->attnullability == ATTNULLABLE_UNKNOWN) ==
719 : : (cattr2->attnullability == ATTNULLABLE_UNKNOWN));
720 : :
721 [ + + ]: 278954 : if (cattr1->attnullability != cattr2->attnullability)
722 : 70 : return false;
723 : : }
8705 tgl@sss.pgh.pa.us 724 [ + + ]: 941645 : if (attr1->atthasdef != attr2->atthasdef)
725 : 3681 : return false;
3372 peter_e@gmx.net 726 [ + + ]: 937964 : if (attr1->attidentity != attr2->attidentity)
727 : 118 : return false;
2649 peter@eisentraut.org 728 [ + + ]: 937846 : if (attr1->attgenerated != attr2->attgenerated)
729 : 13 : return false;
8733 tgl@sss.pgh.pa.us 730 [ - + ]: 937833 : if (attr1->attisdropped != attr2->attisdropped)
8733 tgl@sss.pgh.pa.us 731 :UBC 0 : return false;
8682 tgl@sss.pgh.pa.us 732 [ + + ]:CBC 937833 : if (attr1->attislocal != attr2->attislocal)
733 : 2748 : return false;
734 [ + + ]: 935085 : if (attr1->attinhcount != attr2->attinhcount)
8705 735 : 513 : return false;
5548 736 [ - + ]: 934572 : if (attr1->attcollation != attr2->attcollation)
5548 tgl@sss.pgh.pa.us 737 :UBC 0 : return false;
738 : : /* variable-length fields are not even present... */
739 : : }
740 : :
9647 tgl@sss.pgh.pa.us 741 [ + + ]:CBC 254015 : if (tupdesc1->constr != NULL)
742 : : {
9575 bruce@momjian.us 743 : 89509 : TupleConstr *constr1 = tupdesc1->constr;
744 : 89509 : TupleConstr *constr2 = tupdesc2->constr;
745 : :
9647 tgl@sss.pgh.pa.us 746 [ + + ]: 89509 : if (constr2 == NULL)
747 : 175 : return false;
9365 748 [ - + ]: 89334 : if (constr1->has_not_null != constr2->has_not_null)
9365 tgl@sss.pgh.pa.us 749 :UBC 0 : return false;
2649 peter@eisentraut.org 750 [ + + ]:CBC 89334 : if (constr1->has_generated_stored != constr2->has_generated_stored)
751 : 468 : return false;
508 752 [ + + ]: 88866 : if (constr1->has_generated_virtual != constr2->has_generated_virtual)
753 : 294 : return false;
9365 tgl@sss.pgh.pa.us 754 : 88572 : n = constr1->num_defval;
755 [ - + ]: 88572 : if (n != (int) constr2->num_defval)
9647 tgl@sss.pgh.pa.us 756 :UBC 0 : return false;
757 : : /* We assume here that both AttrDefault arrays are in adnum order */
9365 tgl@sss.pgh.pa.us 758 [ + + ]:CBC 101923 : for (i = 0; i < n; i++)
759 : : {
9575 bruce@momjian.us 760 : 13351 : AttrDefault *defval1 = constr1->defval + i;
1911 tgl@sss.pgh.pa.us 761 : 13351 : AttrDefault *defval2 = constr2->defval + i;
762 : :
763 [ - + ]: 13351 : if (defval1->adnum != defval2->adnum)
9647 tgl@sss.pgh.pa.us 764 :UBC 0 : return false;
9647 tgl@sss.pgh.pa.us 765 [ - + ]:CBC 13351 : if (strcmp(defval1->adbin, defval2->adbin) != 0)
9647 tgl@sss.pgh.pa.us 766 :UBC 0 : return false;
767 : : }
3016 andrew@dunslane.net 768 [ + + ]:CBC 88572 : if (constr1->missing)
769 : : {
770 [ + + ]: 524 : if (!constr2->missing)
771 : 65 : return false;
772 [ + + ]: 2686 : for (i = 0; i < tupdesc1->natts; i++)
773 : : {
774 : 2328 : AttrMissing *missval1 = constr1->missing + i;
775 : 2328 : AttrMissing *missval2 = constr2->missing + i;
776 : :
2925 akapila@postgresql.o 777 [ + + ]: 2328 : if (missval1->am_present != missval2->am_present)
3016 andrew@dunslane.net 778 : 101 : return false;
2925 akapila@postgresql.o 779 [ + + ]: 2227 : if (missval1->am_present)
780 : : {
557 drowley@postgresql.o 781 : 761 : CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
782 : :
2925 akapila@postgresql.o 783 [ - + ]: 761 : if (!datumIsEqual(missval1->am_value, missval2->am_value,
3016 andrew@dunslane.net 784 : 761 : missatt1->attbyval, missatt1->attlen))
3016 andrew@dunslane.net 785 :UBC 0 : return false;
786 : : }
787 : : }
788 : : }
3016 andrew@dunslane.net 789 [ + + ]:CBC 88048 : else if (constr2->missing)
790 : 255 : return false;
9365 tgl@sss.pgh.pa.us 791 : 88151 : n = constr1->num_check;
792 [ + + ]: 88151 : if (n != (int) constr2->num_check)
9647 793 : 1179 : return false;
794 : :
795 : : /*
796 : : * Similarly, we rely here on the ConstrCheck entries being sorted by
797 : : * name. If there are duplicate names, the outcome of the comparison
798 : : * is uncertain, but that should not happen.
799 : : */
9365 800 [ + + ]: 89804 : for (i = 0; i < n; i++)
801 : : {
9575 bruce@momjian.us 802 : 2988 : ConstrCheck *check1 = constr1->check + i;
1911 tgl@sss.pgh.pa.us 803 : 2988 : ConstrCheck *check2 = constr2->check + i;
804 : :
805 [ + - ]: 2988 : if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
806 [ + - ]: 2988 : strcmp(check1->ccbin, check2->ccbin) == 0 &&
535 peter@eisentraut.org 807 [ + + ]: 2988 : check1->ccenforced == check2->ccenforced &&
1911 tgl@sss.pgh.pa.us 808 [ + + ]: 2888 : check1->ccvalid == check2->ccvalid &&
809 [ - + ]: 2832 : check1->ccnoinherit == check2->ccnoinherit))
9647 810 : 156 : return false;
811 : : }
812 : : }
813 [ + + ]: 164506 : else if (tupdesc2->constr != NULL)
814 : 1381 : return false;
815 : 249941 : return true;
816 : : }
817 : :
818 : : /*
819 : : * equalRowTypes
820 : : *
821 : : * This determines whether two tuple descriptors have equal row types. This
822 : : * only checks those fields in pg_attribute that are applicable for row types,
823 : : * while ignoring those fields that define the physical row storage or those
824 : : * that define table column metadata.
825 : : *
826 : : * Specifically, this checks:
827 : : *
828 : : * - same number of attributes
829 : : * - same composite type ID (but could both be zero)
830 : : * - corresponding attributes (in order) have same the name, type, typmod,
831 : : * collation
832 : : *
833 : : * This is used to check whether two record types are compatible, whether
834 : : * function return row types are the same, and other similar situations.
835 : : *
836 : : * (XXX There was some discussion whether attndims should be checked here, but
837 : : * for now it has been decided not to.)
838 : : *
839 : : * Note: We deliberately do not check the tdtypmod field. This allows
840 : : * typcache.c to use this routine to see if a cached record type matches a
841 : : * requested type.
842 : : */
843 : : bool
835 peter@eisentraut.org 844 : 279403 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
845 : : {
846 [ + + ]: 279403 : if (tupdesc1->natts != tupdesc2->natts)
847 : 113 : return false;
848 [ + + ]: 279290 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
849 : 1286 : return false;
850 : :
851 [ + + ]: 3877488 : for (int i = 0; i < tupdesc1->natts; i++)
852 : : {
853 : 3605288 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
854 : 3605288 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
855 : :
856 [ + + ]: 3605288 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
857 : 5786 : return false;
858 [ + + ]: 3599502 : if (attr1->atttypid != attr2->atttypid)
859 : 14 : return false;
860 [ + + ]: 3599488 : if (attr1->atttypmod != attr2->atttypmod)
861 : 4 : return false;
862 [ - + ]: 3599484 : if (attr1->attcollation != attr2->attcollation)
835 peter@eisentraut.org 863 :UBC 0 : return false;
864 : :
865 : : /* Record types derived from tables could have dropped fields. */
835 peter@eisentraut.org 866 [ - + ]:CBC 3599484 : if (attr1->attisdropped != attr2->attisdropped)
835 peter@eisentraut.org 867 :UBC 0 : return false;
868 : : }
869 : :
835 peter@eisentraut.org 870 :CBC 272200 : return true;
871 : : }
872 : :
873 : : /*
874 : : * hashRowType
875 : : *
876 : : * If two tuple descriptors would be considered equal by equalRowTypes()
877 : : * then their hash value will be equal according to this function.
878 : : */
879 : : uint32
880 : 287792 : hashRowType(TupleDesc desc)
881 : : {
882 : : uint32 s;
883 : : int i;
884 : :
329 peter@eisentraut.org 885 :GNC 287792 : s = hash_combine(0, hash_bytes_uint32(desc->natts));
886 : 287792 : s = hash_combine(s, hash_bytes_uint32(desc->tdtypeid));
3234 andres@anarazel.de 887 [ + + ]:CBC 4061040 : for (i = 0; i < desc->natts; ++i)
329 peter@eisentraut.org 888 :GNC 3773248 : s = hash_combine(s, hash_bytes_uint32(TupleDescAttr(desc, i)->atttypid));
889 : :
3234 andres@anarazel.de 890 :CBC 287792 : return s;
891 : : }
892 : :
893 : : /*
894 : : * TupleDescInitEntry
895 : : * This function initializes a single attribute structure in
896 : : * a previously allocated tuple descriptor.
897 : : *
898 : : * If attributeName is NULL, the attname field is set to an empty string
899 : : * (this is for cases where we don't know or need a name for the field).
900 : : * Also, some callers use this function to change the datatype-related fields
901 : : * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
902 : : * to indicate that the attname field shouldn't be modified.
903 : : *
904 : : * Note that attcollation is set to the default for the specified datatype.
905 : : * If a nondefault collation is needed, insert it afterwards using
906 : : * TupleDescInitEntryCollation.
907 : : */
908 : : void
10948 scrappy@hub.org 909 : 7984348 : TupleDescInitEntry(TupleDesc desc,
910 : : AttrNumber attributeNumber,
911 : : const char *attributeName,
912 : : Oid oidtypeid,
913 : : int32 typmod,
914 : : int attdim)
915 : : {
916 : : HeapTuple tuple;
917 : : Form_pg_type typeForm;
918 : : Form_pg_attribute att;
919 : :
920 : : /*
921 : : * sanity checks
922 : : */
279 peter@eisentraut.org 923 [ - + ]:GNC 7984348 : Assert(desc);
1341 peter@eisentraut.org 924 [ - + ]:CBC 7984348 : Assert(attributeNumber >= 1);
925 [ - + ]: 7984348 : Assert(attributeNumber <= desc->natts);
1190 926 [ - + ]: 7984348 : Assert(attdim >= 0);
927 [ - + ]: 7984348 : Assert(attdim <= PG_INT16_MAX);
928 : :
929 : : /*
930 : : * initialize the attribute fields
931 : : */
3236 andres@anarazel.de 932 : 7984348 : att = TupleDescAttr(desc, attributeNumber - 1);
933 : :
10523 bruce@momjian.us 934 : 7984348 : att->attrelid = 0; /* dummy value */
935 : :
936 : : /*
937 : : * Note: attributeName can be NULL, because the planner doesn't always
938 : : * fill in valid resname values in targetlists, particularly for resjunk
939 : : * attributes. Also, do nothing if caller wants to re-use the old attname.
940 : : */
4628 tgl@sss.pgh.pa.us 941 [ + + ]: 7984348 : if (attributeName == NULL)
9732 bruce@momjian.us 942 [ + + + - : 12470972 : MemSet(NameStr(att->attname), 0, NAMEDATALEN);
+ - + - +
+ ]
4628 tgl@sss.pgh.pa.us 943 [ + + ]: 5319264 : else if (attributeName != NameStr(att->attname))
944 : 5316863 : namestrcpy(&(att->attname), attributeName);
945 : :
10367 bruce@momjian.us 946 : 7984348 : att->atttypmod = typmod;
947 : :
10523 948 : 7984348 : att->attnum = attributeNumber;
9185 tgl@sss.pgh.pa.us 949 : 7984348 : att->attndims = attdim;
950 : :
10523 bruce@momjian.us 951 : 7984348 : att->attnotnull = false;
952 : 7984348 : att->atthasdef = false;
3016 andrew@dunslane.net 953 : 7984348 : att->atthasmissing = false;
3372 peter_e@gmx.net 954 : 7984348 : att->attidentity = '\0';
2649 peter@eisentraut.org 955 : 7984348 : att->attgenerated = '\0';
8733 tgl@sss.pgh.pa.us 956 : 7984348 : att->attisdropped = false;
8682 957 : 7984348 : att->attislocal = true;
958 : 7984348 : att->attinhcount = 0;
959 : : /* variable-length fields are not present in tupledescs */
960 : :
5980 rhaas@postgresql.org 961 : 7984348 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
10523 bruce@momjian.us 962 [ - + ]: 7984348 : if (!HeapTupleIsValid(tuple))
8380 tgl@sss.pgh.pa.us 963 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", oidtypeid);
10164 bruce@momjian.us 964 :CBC 7984348 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
965 : :
8125 tgl@sss.pgh.pa.us 966 : 7984348 : att->atttypid = oidtypeid;
967 : 7984348 : att->attlen = typeForm->typlen;
968 : 7984348 : att->attbyval = typeForm->typbyval;
969 : 7984348 : att->attalign = typeForm->typalign;
970 : 7984348 : att->attstorage = typeForm->typstorage;
1860 971 : 7984348 : att->attcompression = InvalidCompressionMethod;
1864 972 : 7984348 : att->attcollation = typeForm->typcollation;
973 : :
557 drowley@postgresql.o 974 : 7984348 : populate_compact_attribute(desc, attributeNumber - 1);
975 : :
9357 tgl@sss.pgh.pa.us 976 : 7984348 : ReleaseSysCache(tuple);
10948 scrappy@hub.org 977 : 7984348 : }
978 : :
979 : : /*
980 : : * TupleDescInitBuiltinEntry
981 : : * Initialize a tuple descriptor without catalog access. Only
982 : : * a limited range of builtin types are supported.
983 : : */
984 : : void
3444 rhaas@postgresql.org 985 : 8156 : TupleDescInitBuiltinEntry(TupleDesc desc,
986 : : AttrNumber attributeNumber,
987 : : const char *attributeName,
988 : : Oid oidtypeid,
989 : : int32 typmod,
990 : : int attdim)
991 : : {
992 : : Form_pg_attribute att;
993 : :
994 : : /* sanity checks */
279 peter@eisentraut.org 995 [ - + ]:GNC 8156 : Assert(desc);
1341 peter@eisentraut.org 996 [ - + ]:CBC 8156 : Assert(attributeNumber >= 1);
997 [ - + ]: 8156 : Assert(attributeNumber <= desc->natts);
1190 998 [ - + ]: 8156 : Assert(attdim >= 0);
999 [ - + ]: 8156 : Assert(attdim <= PG_INT16_MAX);
1000 : :
1001 : : /* initialize the attribute fields */
3236 andres@anarazel.de 1002 : 8156 : att = TupleDescAttr(desc, attributeNumber - 1);
3444 rhaas@postgresql.org 1003 : 8156 : att->attrelid = 0; /* dummy value */
1004 : :
1005 : : /* unlike TupleDescInitEntry, we require an attribute name */
1006 [ - + ]: 8156 : Assert(attributeName != NULL);
1007 : 8156 : namestrcpy(&(att->attname), attributeName);
1008 : :
1009 : 8156 : att->atttypmod = typmod;
1010 : :
1011 : 8156 : att->attnum = attributeNumber;
1012 : 8156 : att->attndims = attdim;
1013 : :
1014 : 8156 : att->attnotnull = false;
1015 : 8156 : att->atthasdef = false;
3016 andrew@dunslane.net 1016 : 8156 : att->atthasmissing = false;
3372 peter_e@gmx.net 1017 : 8156 : att->attidentity = '\0';
2649 peter@eisentraut.org 1018 : 8156 : att->attgenerated = '\0';
3444 rhaas@postgresql.org 1019 : 8156 : att->attisdropped = false;
1020 : 8156 : att->attislocal = true;
1021 : 8156 : att->attinhcount = 0;
1022 : : /* variable-length fields are not present in tupledescs */
1023 : :
1024 : 8156 : att->atttypid = oidtypeid;
1025 : :
1026 : : /*
1027 : : * Our goal here is to support just enough types to let basic builtin
1028 : : * commands work without catalog access - e.g. so that we can do certain
1029 : : * things even in processes that are not connected to a database.
1030 : : */
1031 [ + - - + : 8156 : switch (oidtypeid)
+ - ]
1032 : : {
1033 : 6652 : case TEXTOID:
1034 : : case TEXTARRAYOID:
1035 : 6652 : att->attlen = -1;
1036 : 6652 : att->attbyval = false;
2309 tgl@sss.pgh.pa.us 1037 : 6652 : att->attalign = TYPALIGN_INT;
1038 : 6652 : att->attstorage = TYPSTORAGE_EXTENDED;
1860 1039 : 6652 : att->attcompression = InvalidCompressionMethod;
3444 rhaas@postgresql.org 1040 : 6652 : att->attcollation = DEFAULT_COLLATION_OID;
1041 : 6652 : break;
1042 : :
3444 rhaas@postgresql.org 1043 :UBC 0 : case BOOLOID:
1044 : 0 : att->attlen = 1;
1045 : 0 : att->attbyval = true;
2309 tgl@sss.pgh.pa.us 1046 : 0 : att->attalign = TYPALIGN_CHAR;
1047 : 0 : att->attstorage = TYPSTORAGE_PLAIN;
1864 1048 : 0 : att->attcompression = InvalidCompressionMethod;
3444 rhaas@postgresql.org 1049 : 0 : att->attcollation = InvalidOid;
1050 : 0 : break;
1051 : :
1052 : 0 : case INT4OID:
1053 : 0 : att->attlen = 4;
1054 : 0 : att->attbyval = true;
2309 tgl@sss.pgh.pa.us 1055 : 0 : att->attalign = TYPALIGN_INT;
1056 : 0 : att->attstorage = TYPSTORAGE_PLAIN;
1864 1057 : 0 : att->attcompression = InvalidCompressionMethod;
3444 rhaas@postgresql.org 1058 : 0 : att->attcollation = InvalidOid;
3436 1059 : 0 : break;
1060 : :
3436 rhaas@postgresql.org 1061 :CBC 1329 : case INT8OID:
1062 : 1329 : att->attlen = 8;
321 tgl@sss.pgh.pa.us 1063 :GNC 1329 : att->attbyval = true;
2309 tgl@sss.pgh.pa.us 1064 :CBC 1329 : att->attalign = TYPALIGN_DOUBLE;
1065 : 1329 : att->attstorage = TYPSTORAGE_PLAIN;
1864 1066 : 1329 : att->attcompression = InvalidCompressionMethod;
3436 rhaas@postgresql.org 1067 : 1329 : att->attcollation = InvalidOid;
3444 1068 : 1329 : break;
1069 : :
1457 peter@eisentraut.org 1070 : 175 : case OIDOID:
1071 : 175 : att->attlen = 4;
1072 : 175 : att->attbyval = true;
1073 : 175 : att->attalign = TYPALIGN_INT;
1074 : 175 : att->attstorage = TYPSTORAGE_PLAIN;
1075 : 175 : att->attcompression = InvalidCompressionMethod;
1076 : 175 : att->attcollation = InvalidOid;
1077 : 175 : break;
1078 : :
2759 tgl@sss.pgh.pa.us 1079 :UBC 0 : default:
1080 [ # # ]: 0 : elog(ERROR, "unsupported type %u", oidtypeid);
1081 : : }
1082 : :
557 drowley@postgresql.o 1083 :CBC 8156 : populate_compact_attribute(desc, attributeNumber - 1);
3444 rhaas@postgresql.org 1084 : 8156 : }
1085 : :
1086 : : /*
1087 : : * TupleDescInitEntryCollation
1088 : : *
1089 : : * Assign a nondefault collation to a previously initialized tuple descriptor
1090 : : * entry.
1091 : : */
1092 : : void
5621 peter_e@gmx.net 1093 : 4115471 : TupleDescInitEntryCollation(TupleDesc desc,
1094 : : AttrNumber attributeNumber,
1095 : : Oid collationid)
1096 : : {
1097 : : /*
1098 : : * sanity checks
1099 : : */
279 peter@eisentraut.org 1100 [ - + ]:GNC 4115471 : Assert(desc);
1341 peter@eisentraut.org 1101 [ - + ]:CBC 4115471 : Assert(attributeNumber >= 1);
1102 [ - + ]: 4115471 : Assert(attributeNumber <= desc->natts);
1103 : :
3236 andres@anarazel.de 1104 : 4115471 : TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
5621 peter_e@gmx.net 1105 : 4115471 : }
1106 : :
1107 : : /*
1108 : : * BuildDescFromLists
1109 : : *
1110 : : * Build a TupleDesc given lists of column names (as String nodes),
1111 : : * column type OIDs, typmods, and collation OIDs.
1112 : : *
1113 : : * No constraints are generated.
1114 : : *
1115 : : * This is for use with functions returning RECORD.
1116 : : */
1117 : : TupleDesc
1008 peter@eisentraut.org 1118 : 901 : BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
1119 : : {
1120 : : int natts;
1121 : : AttrNumber attnum;
1122 : : ListCell *l1;
1123 : : ListCell *l2;
1124 : : ListCell *l3;
1125 : : ListCell *l4;
1126 : : TupleDesc desc;
1127 : :
7411 tgl@sss.pgh.pa.us 1128 : 901 : natts = list_length(names);
1129 [ - + ]: 901 : Assert(natts == list_length(types));
1130 [ - + ]: 901 : Assert(natts == list_length(typmods));
5621 peter_e@gmx.net 1131 [ - + ]: 901 : Assert(natts == list_length(collations));
1132 : :
1133 : : /*
1134 : : * allocate a new tuple descriptor
1135 : : */
2779 andres@anarazel.de 1136 : 901 : desc = CreateTemplateTupleDesc(natts);
1137 : :
7411 tgl@sss.pgh.pa.us 1138 : 901 : attnum = 0;
2679 1139 [ + - + + : 3162 : forfour(l1, names, l2, types, l3, typmods, l4, collations)
+ - + + +
- + + + -
+ + + + +
- + - + -
+ + ]
1140 : : {
7411 1141 : 2261 : char *attname = strVal(lfirst(l1));
2679 1142 : 2261 : Oid atttypid = lfirst_oid(l2);
1143 : 2261 : int32 atttypmod = lfirst_int(l3);
1144 : 2261 : Oid attcollation = lfirst_oid(l4);
1145 : :
7411 1146 : 2261 : attnum++;
1147 : :
1148 : 2261 : TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
5621 peter_e@gmx.net 1149 : 2261 : TupleDescInitEntryCollation(desc, attnum, attcollation);
1150 : : }
1151 : :
106 drowley@postgresql.o 1152 :GNC 901 : TupleDescFinalize(desc);
1153 : :
7411 tgl@sss.pgh.pa.us 1154 :CBC 901 : return desc;
1155 : : }
1156 : :
1157 : : /*
1158 : : * Get default expression (or NULL if none) for the given attribute number.
1159 : : */
1160 : : Node *
1007 peter@eisentraut.org 1161 : 78343 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
1162 : : {
1163 : 78343 : Node *result = NULL;
1164 : :
1165 [ + - ]: 78343 : if (tupdesc->constr)
1166 : : {
1167 : 78343 : AttrDefault *attrdef = tupdesc->constr->defval;
1168 : :
1169 [ + - ]: 118675 : for (int i = 0; i < tupdesc->constr->num_defval; i++)
1170 : : {
1171 [ + + ]: 118675 : if (attrdef[i].adnum == attnum)
1172 : : {
1173 : 78343 : result = stringToNode(attrdef[i].adbin);
1174 : 78343 : break;
1175 : : }
1176 : : }
1177 : : }
1178 : :
1179 : 78343 : return result;
1180 : : }
1181 : :
1182 : : /* ResourceOwner callbacks */
1183 : :
1184 : : static void
965 heikki.linnakangas@i 1185 : 11757 : ResOwnerReleaseTupleDesc(Datum res)
1186 : : {
1187 : 11757 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1188 : :
1189 : : /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
1190 [ - + ]: 11757 : Assert(tupdesc->tdrefcount > 0);
1191 [ + + ]: 11757 : if (--tupdesc->tdrefcount == 0)
1192 : 394 : FreeTupleDesc(tupdesc);
1193 : 11757 : }
1194 : :
1195 : : static char *
965 heikki.linnakangas@i 1196 :UBC 0 : ResOwnerPrintTupleDesc(Datum res)
1197 : : {
1198 : 0 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1199 : :
1200 : 0 : return psprintf("TupleDesc %p (%u,%d)",
1201 : : tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1202 : : }
|