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-2025, PostgreSQL Global Development Group
7 : : * Portions Copyright (c) 1994, Regents of the University of California
8 : : *
9 : : *
10 : : * IDENTIFICATION
11 : : * src/backend/access/common/tupdesc.c
12 : : *
13 : : * NOTES
14 : : * some of the executor utility code such as "ExecTypeFromTL" should be
15 : : * moved here.
16 : : *
17 : : *-------------------------------------------------------------------------
18 : : */
19 : :
20 : : #include "postgres.h"
21 : :
22 : : #include "access/htup_details.h"
23 : : #include "access/toast_compression.h"
24 : : #include "access/tupdesc_details.h"
25 : : #include "catalog/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
668 heikki.linnakangas@i 49 :CBC 15257028 : ResourceOwnerRememberTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
50 : : {
51 : 15257028 : ResourceOwnerRemember(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
52 : 15257028 : }
53 : :
54 : : static inline void
55 : 15249314 : ResourceOwnerForgetTupleDesc(ResourceOwner owner, TupleDesc tupdesc)
56 : : {
57 : 15249314 : ResourceOwnerForget(owner, PointerGetDatum(tupdesc), &tupdesc_resowner_desc);
58 : 15249314 : }
59 : :
60 : : /*
61 : : * populate_compact_attribute_internal
62 : : * Helper function for populate_compact_attribute()
63 : : */
64 : : static inline void
256 drowley@postgresql.o 65 : 1446378357 : populate_compact_attribute_internal(Form_pg_attribute src,
66 : : CompactAttribute *dst)
67 : : {
260 68 : 1446378357 : memset(dst, 0, sizeof(CompactAttribute));
69 : :
70 : 1446378357 : dst->attcacheoff = -1;
71 : 1446378357 : dst->attlen = src->attlen;
72 : :
73 : 1446378357 : dst->attbyval = src->attbyval;
74 : 1446378357 : dst->attispackable = (src->attstorage != TYPSTORAGE_PLAIN);
75 : 1446378357 : dst->atthasmissing = src->atthasmissing;
76 : 1446378357 : dst->attisdropped = src->attisdropped;
77 : 1446378357 : 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 : : */
152 alvherre@alvh.no-ip. 85 [ + + + + ]: 1914577927 : dst->attnullability = !src->attnotnull ? ATTNULLABLE_UNRESTRICTED :
86 : 468199570 : IsCatalogRelationOid(src->attrelid) ? ATTNULLABLE_VALID :
87 : : ATTNULLABLE_UNKNOWN;
88 : :
259 drowley@postgresql.o 89 [ + + + + : 1446378357 : switch (src->attalign)
- ]
90 : : {
91 : 1043755579 : case TYPALIGN_INT:
92 : 1043755579 : dst->attalignby = ALIGNOF_INT;
93 : 1043755579 : break;
94 : 241938387 : case TYPALIGN_CHAR:
95 : 241938387 : dst->attalignby = sizeof(char);
96 : 241938387 : break;
97 : 96895612 : case TYPALIGN_DOUBLE:
98 : 96895612 : dst->attalignby = ALIGNOF_DOUBLE;
99 : 96895612 : break;
100 : 63788779 : case TYPALIGN_SHORT:
101 : 63788779 : dst->attalignby = ALIGNOF_SHORT;
102 : 63788779 : break;
259 drowley@postgresql.o 103 :UBC 0 : default:
104 : 0 : dst->attalignby = 0;
105 [ # # ]: 0 : elog(ERROR, "invalid attalign value: %c", src->attalign);
106 : : break;
107 : : }
260 drowley@postgresql.o 108 :CBC 1446378357 : }
109 : :
110 : : /*
111 : : * populate_compact_attribute
112 : : * Fill in the corresponding CompactAttribute element from the
113 : : * Form_pg_attribute for the given attribute number. This must be called
114 : : * whenever a change is made to a Form_pg_attribute in the TupleDesc.
115 : : */
116 : : void
256 117 : 32085490 : populate_compact_attribute(TupleDesc tupdesc, int attnum)
118 : : {
119 : 32085490 : Form_pg_attribute src = TupleDescAttr(tupdesc, attnum);
120 : : CompactAttribute *dst;
121 : :
122 : : /*
123 : : * Don't use TupleDescCompactAttr to prevent infinite recursion in assert
124 : : * builds.
125 : : */
126 : 32085490 : dst = &tupdesc->compact_attrs[attnum];
127 : :
128 : 32085490 : populate_compact_attribute_internal(src, dst);
129 : 32085490 : }
130 : :
131 : : /*
132 : : * verify_compact_attribute
133 : : * In Assert enabled builds, we verify that the CompactAttribute is
134 : : * populated correctly. This helps find bugs in places such as ALTER
135 : : * TABLE where code makes changes to the FormData_pg_attribute but
136 : : * forgets to call populate_compact_attribute().
137 : : *
138 : : * This is used in TupleDescCompactAttr(), but declared here to allow access
139 : : * to populate_compact_attribute_internal().
140 : : */
141 : : void
142 : 1414292867 : verify_compact_attribute(TupleDesc tupdesc, int attnum)
143 : : {
144 : : #ifdef USE_ASSERT_CHECKING
145 : : CompactAttribute cattr;
146 : 1414292867 : Form_pg_attribute attr = TupleDescAttr(tupdesc, attnum);
147 : : CompactAttribute tmp;
148 : :
149 : : /*
150 : : * Make a temp copy of the TupleDesc's CompactAttribute. This may be a
151 : : * shared TupleDesc and the attcacheoff might get changed by another
152 : : * backend.
153 : : */
81 154 : 1414292867 : memcpy(&cattr, &tupdesc->compact_attrs[attnum], sizeof(CompactAttribute));
155 : :
156 : : /*
157 : : * Populate the temporary CompactAttribute from the corresponding
158 : : * Form_pg_attribute
159 : : */
256 160 : 1414292867 : populate_compact_attribute_internal(attr, &tmp);
161 : :
162 : : /*
163 : : * Make the attcacheoff match since it's been reset to -1 by
164 : : * populate_compact_attribute_internal. Same with attnullability.
165 : : */
81 166 : 1414292867 : tmp.attcacheoff = cattr.attcacheoff;
167 : 1414292867 : tmp.attnullability = cattr.attnullability;
168 : :
169 : : /* Check the freshly populated CompactAttribute matches the TupleDesc's */
170 [ - + ]: 1414292867 : Assert(memcmp(&tmp, &cattr, sizeof(CompactAttribute)) == 0);
171 : : #endif
238 172 : 1414292867 : }
173 : :
174 : : /*
175 : : * CreateTemplateTupleDesc
176 : : * This function allocates an empty tuple descriptor structure.
177 : : *
178 : : * Tuple type ID information is initially set for an anonymous record type;
179 : : * caller can overwrite this if needed.
180 : : */
181 : : TupleDesc
2482 andres@anarazel.de 182 : 4567157 : CreateTemplateTupleDesc(int natts)
183 : : {
184 : : TupleDesc desc;
185 : :
186 : : /*
187 : : * sanity checks
188 : : */
1044 peter@eisentraut.org 189 [ - + ]: 4567157 : Assert(natts >= 0);
190 : :
191 : : /*
192 : : * Allocate enough memory for the tuple descriptor, the CompactAttribute
193 : : * array and also an array of FormData_pg_attribute.
194 : : *
195 : : * Note: the FormData_pg_attribute array stride is
196 : : * sizeof(FormData_pg_attribute), since we declare the array elements as
197 : : * FormData_pg_attribute for notational convenience. However, we only
198 : : * guarantee that the first ATTRIBUTE_FIXED_PART_SIZE bytes of each entry
199 : : * are valid; most code that copies tupdesc entries around copies just
200 : : * that much. In principle that could be less due to trailing padding,
201 : : * although with the current definition of pg_attribute there probably
202 : : * isn't any padding.
203 : : */
260 drowley@postgresql.o 204 : 4567157 : desc = (TupleDesc) palloc(offsetof(struct TupleDescData, compact_attrs) +
205 : 4567157 : natts * sizeof(CompactAttribute) +
206 : : natts * sizeof(FormData_pg_attribute));
207 : :
208 : : /*
209 : : * Initialize other fields of the tupdesc.
210 : : */
7828 tgl@sss.pgh.pa.us 211 : 4567157 : desc->natts = natts;
8379 212 : 4567157 : desc->constr = NULL;
7828 213 : 4567157 : desc->tdtypeid = RECORDOID;
214 : 4567157 : desc->tdtypmod = -1;
7022 215 : 4567157 : desc->tdrefcount = -1; /* assume not reference-counted */
216 : :
9867 bruce@momjian.us 217 : 4567157 : return desc;
218 : : }
219 : :
220 : : /*
221 : : * CreateTupleDesc
222 : : * This function allocates a new TupleDesc by copying a given
223 : : * Form_pg_attribute array.
224 : : *
225 : : * Tuple type ID information is initially set for an anonymous record type;
226 : : * caller can overwrite this if needed.
227 : : */
228 : : TupleDesc
2482 andres@anarazel.de 229 : 577102 : CreateTupleDesc(int natts, Form_pg_attribute *attrs)
230 : : {
231 : : TupleDesc desc;
232 : : int i;
233 : :
234 : 577102 : desc = CreateTemplateTupleDesc(natts);
235 : :
2939 236 [ + + ]: 8831464 : for (i = 0; i < natts; ++i)
237 : : {
238 : 8254362 : memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
260 drowley@postgresql.o 239 : 8254362 : populate_compact_attribute(desc, i);
240 : : }
9867 bruce@momjian.us 241 : 577102 : return desc;
242 : : }
243 : :
244 : : /*
245 : : * CreateTupleDescCopy
246 : : * This function creates a new TupleDesc by copying from an existing
247 : : * TupleDesc.
248 : : *
249 : : * !!! Constraints and defaults are not copied !!!
250 : : */
251 : : TupleDesc
10651 scrappy@hub.org 252 : 200543 : CreateTupleDescCopy(TupleDesc tupdesc)
253 : : {
254 : : TupleDesc desc;
255 : : int i;
256 : :
2482 andres@anarazel.de 257 : 200543 : desc = CreateTemplateTupleDesc(tupdesc->natts);
258 : :
259 : : /* Flat-copy the attribute array */
2803 tgl@sss.pgh.pa.us 260 : 200543 : memcpy(TupleDescAttr(desc, 0),
261 : 200543 : TupleDescAttr(tupdesc, 0),
262 : 200543 : desc->natts * sizeof(FormData_pg_attribute));
263 : :
264 : : /*
265 : : * Since we're not copying constraints and defaults, clear fields
266 : : * associated with them.
267 : : */
7488 268 [ + + ]: 1023725 : for (i = 0; i < desc->natts; i++)
269 : : {
2939 andres@anarazel.de 270 : 823182 : Form_pg_attribute att = TupleDescAttr(desc, i);
271 : :
272 : 823182 : att->attnotnull = false;
273 : 823182 : att->atthasdef = false;
2719 andrew@dunslane.net 274 : 823182 : att->atthasmissing = false;
2939 andres@anarazel.de 275 : 823182 : att->attidentity = '\0';
2352 peter@eisentraut.org 276 : 823182 : att->attgenerated = '\0';
277 : :
260 drowley@postgresql.o 278 : 823182 : populate_compact_attribute(desc, i);
279 : : }
280 : :
281 : : /* We can copy the tuple type identification, too */
282 : 200543 : desc->tdtypeid = tupdesc->tdtypeid;
283 : 200543 : desc->tdtypmod = tupdesc->tdtypmod;
284 : :
285 : 200543 : return desc;
286 : : }
287 : :
288 : : /*
289 : : * CreateTupleDescTruncatedCopy
290 : : * This function creates a new TupleDesc with only the first 'natts'
291 : : * attributes from an existing TupleDesc
292 : : *
293 : : * !!! Constraints and defaults are not copied !!!
294 : : */
295 : : TupleDesc
296 : 17929 : CreateTupleDescTruncatedCopy(TupleDesc tupdesc, int natts)
297 : : {
298 : : TupleDesc desc;
299 : : int i;
300 : :
301 [ - + ]: 17929 : Assert(natts <= tupdesc->natts);
302 : :
303 : 17929 : desc = CreateTemplateTupleDesc(natts);
304 : :
305 : : /* Flat-copy the attribute array */
306 : 17929 : memcpy(TupleDescAttr(desc, 0),
307 : 17929 : TupleDescAttr(tupdesc, 0),
308 : 17929 : desc->natts * sizeof(FormData_pg_attribute));
309 : :
310 : : /*
311 : : * Since we're not copying constraints and defaults, clear fields
312 : : * associated with them.
313 : : */
314 [ + + ]: 41242 : for (i = 0; i < desc->natts; i++)
315 : : {
316 : 23313 : Form_pg_attribute att = TupleDescAttr(desc, i);
317 : :
318 : 23313 : att->attnotnull = false;
319 : 23313 : att->atthasdef = false;
320 : 23313 : att->atthasmissing = false;
321 : 23313 : att->attidentity = '\0';
322 : 23313 : att->attgenerated = '\0';
323 : :
324 : 23313 : populate_compact_attribute(desc, i);
325 : : }
326 : :
327 : : /* We can copy the tuple type identification, too */
7828 tgl@sss.pgh.pa.us 328 : 17929 : desc->tdtypeid = tupdesc->tdtypeid;
329 : 17929 : desc->tdtypmod = tupdesc->tdtypmod;
330 : :
10226 bruce@momjian.us 331 : 17929 : return desc;
332 : : }
333 : :
334 : : /*
335 : : * CreateTupleDescCopyConstr
336 : : * This function creates a new TupleDesc by copying from an existing
337 : : * TupleDesc (including its constraints and defaults).
338 : : */
339 : : TupleDesc
10242 vadim4o@yahoo.com 340 : 377930 : CreateTupleDescCopyConstr(TupleDesc tupdesc)
341 : : {
342 : : TupleDesc desc;
10225 bruce@momjian.us 343 : 377930 : TupleConstr *constr = tupdesc->constr;
344 : : int i;
345 : :
2482 andres@anarazel.de 346 : 377930 : desc = CreateTemplateTupleDesc(tupdesc->natts);
347 : :
348 : : /* Flat-copy the attribute array */
2803 tgl@sss.pgh.pa.us 349 : 377930 : memcpy(TupleDescAttr(desc, 0),
350 : 377930 : TupleDescAttr(tupdesc, 0),
351 : 377930 : desc->natts * sizeof(FormData_pg_attribute));
352 : :
260 drowley@postgresql.o 353 [ + + ]: 5562561 : for (i = 0; i < desc->natts; i++)
354 : : {
355 : 5184631 : populate_compact_attribute(desc, i);
356 : :
152 alvherre@alvh.no-ip. 357 : 5184631 : TupleDescCompactAttr(desc, i)->attnullability =
358 : 10369262 : TupleDescCompactAttr(tupdesc, i)->attnullability;
359 : : }
360 : :
361 : : /* Copy the TupleConstr data structure, if any */
10226 bruce@momjian.us 362 [ + + ]: 377930 : if (constr)
363 : : {
7828 tgl@sss.pgh.pa.us 364 : 349846 : TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr));
365 : :
10226 bruce@momjian.us 366 : 349846 : cpy->has_not_null = constr->has_not_null;
2352 peter@eisentraut.org 367 : 349846 : cpy->has_generated_stored = constr->has_generated_stored;
211 368 : 349846 : cpy->has_generated_virtual = constr->has_generated_virtual;
369 : :
10226 bruce@momjian.us 370 [ + + ]: 349846 : if ((cpy->num_defval = constr->num_defval) > 0)
371 : : {
372 : 1871 : cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault));
373 : 1871 : memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault));
374 [ + + ]: 4566 : for (i = cpy->num_defval - 1; i >= 0; i--)
1614 tgl@sss.pgh.pa.us 375 : 2695 : cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin);
376 : : }
377 : :
2719 andrew@dunslane.net 378 [ + + ]: 349846 : if (constr->missing)
379 : : {
380 : 313 : cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing));
381 : 313 : memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing));
382 [ + + ]: 2431 : for (i = tupdesc->natts - 1; i >= 0; i--)
383 : : {
2628 akapila@postgresql.o 384 [ + + ]: 2118 : if (constr->missing[i].am_present)
385 : : {
260 drowley@postgresql.o 386 : 565 : CompactAttribute *attr = TupleDescCompactAttr(tupdesc, i);
387 : :
2628 akapila@postgresql.o 388 : 565 : cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value,
389 : 565 : attr->attbyval,
390 : 565 : attr->attlen);
391 : : }
392 : : }
393 : : }
394 : :
10226 bruce@momjian.us 395 [ + + ]: 349846 : if ((cpy->num_check = constr->num_check) > 0)
396 : : {
397 : 1100 : cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck));
398 : 1100 : memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck));
399 [ + + ]: 2985 : for (i = cpy->num_check - 1; i >= 0; i--)
400 : : {
1614 tgl@sss.pgh.pa.us 401 : 1885 : cpy->check[i].ccname = pstrdup(constr->check[i].ccname);
402 : 1885 : cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin);
238 peter@eisentraut.org 403 : 1885 : cpy->check[i].ccenforced = constr->check[i].ccenforced;
5211 alvherre@alvh.no-ip. 404 : 1885 : cpy->check[i].ccvalid = constr->check[i].ccvalid;
4185 noah@leadboat.com 405 : 1885 : cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit;
406 : : }
407 : : }
408 : :
10226 bruce@momjian.us 409 : 349846 : desc->constr = cpy;
410 : : }
411 : :
412 : : /* We can copy the tuple type identification, too */
7828 tgl@sss.pgh.pa.us 413 : 377930 : desc->tdtypeid = tupdesc->tdtypeid;
414 : 377930 : desc->tdtypmod = tupdesc->tdtypmod;
415 : :
10226 bruce@momjian.us 416 : 377930 : return desc;
417 : : }
418 : :
419 : : /*
420 : : * TupleDescCopy
421 : : * Copy a tuple descriptor into caller-supplied memory.
422 : : * The memory may be shared memory mapped at any address, and must
423 : : * be sufficient to hold TupleDescSize(src) bytes.
424 : : *
425 : : * !!! Constraints and defaults are not copied !!!
426 : : */
427 : : void
2914 andres@anarazel.de 428 : 87 : TupleDescCopy(TupleDesc dst, TupleDesc src)
429 : : {
430 : : int i;
431 : :
432 : : /* Flat-copy the header and attribute arrays */
433 : 87 : memcpy(dst, src, TupleDescSize(src));
434 : :
435 : : /*
436 : : * Since we're not copying constraints and defaults, clear fields
437 : : * associated with them.
438 : : */
2803 tgl@sss.pgh.pa.us 439 [ + + ]: 354 : for (i = 0; i < dst->natts; i++)
440 : : {
441 : 267 : Form_pg_attribute att = TupleDescAttr(dst, i);
442 : :
443 : 267 : att->attnotnull = false;
444 : 267 : att->atthasdef = false;
2719 andrew@dunslane.net 445 : 267 : att->atthasmissing = false;
2803 tgl@sss.pgh.pa.us 446 : 267 : att->attidentity = '\0';
2352 peter@eisentraut.org 447 : 267 : att->attgenerated = '\0';
448 : :
260 drowley@postgresql.o 449 : 267 : populate_compact_attribute(dst, i);
450 : : }
2914 andres@anarazel.de 451 : 87 : dst->constr = NULL;
452 : :
453 : : /*
454 : : * Also, assume the destination is not to be ref-counted. (Copying the
455 : : * source's refcount would be wrong in any case.)
456 : : */
457 : 87 : dst->tdrefcount = -1;
458 : 87 : }
459 : :
460 : : /*
461 : : * TupleDescCopyEntry
462 : : * This function copies a single attribute structure from one tuple
463 : : * descriptor to another.
464 : : *
465 : : * !!! Constraints and defaults are not copied !!!
466 : : */
467 : : void
4307 tgl@sss.pgh.pa.us 468 : 2151 : TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno,
469 : : TupleDesc src, AttrNumber srcAttno)
470 : : {
2939 andres@anarazel.de 471 : 2151 : Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1);
472 : 2151 : Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1);
473 : :
474 : : /*
475 : : * sanity checks
476 : : */
1044 peter@eisentraut.org 477 [ - + ]: 2151 : Assert(PointerIsValid(src));
478 [ - + ]: 2151 : Assert(PointerIsValid(dst));
479 [ - + ]: 2151 : Assert(srcAttno >= 1);
480 [ - + ]: 2151 : Assert(srcAttno <= src->natts);
481 [ - + ]: 2151 : Assert(dstAttno >= 1);
482 [ - + ]: 2151 : Assert(dstAttno <= dst->natts);
483 : :
2939 andres@anarazel.de 484 : 2151 : memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE);
485 : :
486 : 2151 : dstAtt->attnum = dstAttno;
487 : :
488 : : /* since we're not copying constraints or defaults, clear these */
489 : 2151 : dstAtt->attnotnull = false;
490 : 2151 : dstAtt->atthasdef = false;
2719 andrew@dunslane.net 491 : 2151 : dstAtt->atthasmissing = false;
2939 andres@anarazel.de 492 : 2151 : dstAtt->attidentity = '\0';
2352 peter@eisentraut.org 493 : 2151 : dstAtt->attgenerated = '\0';
494 : :
260 drowley@postgresql.o 495 : 2151 : populate_compact_attribute(dst, dstAttno - 1);
4307 tgl@sss.pgh.pa.us 496 : 2151 : }
497 : :
498 : : /*
499 : : * Free a TupleDesc including all substructure
500 : : */
501 : : void
10226 bruce@momjian.us 502 : 662562 : FreeTupleDesc(TupleDesc tupdesc)
503 : : {
504 : : int i;
505 : :
506 : : /*
507 : : * Possibly this should assert tdrefcount == 0, to disallow explicit
508 : : * freeing of un-refcounted tupdescs?
509 : : */
7022 tgl@sss.pgh.pa.us 510 [ - + ]: 662562 : Assert(tupdesc->tdrefcount <= 0);
511 : :
10226 bruce@momjian.us 512 [ + + ]: 662562 : if (tupdesc->constr)
513 : : {
514 [ + + ]: 196143 : if (tupdesc->constr->num_defval > 0)
515 : : {
10225 516 : 15247 : AttrDefault *attrdef = tupdesc->constr->defval;
517 : :
10226 518 [ + + ]: 37117 : for (i = tupdesc->constr->num_defval - 1; i >= 0; i--)
1614 tgl@sss.pgh.pa.us 519 : 21870 : pfree(attrdef[i].adbin);
10226 bruce@momjian.us 520 : 15247 : pfree(attrdef);
521 : : }
2719 andrew@dunslane.net 522 [ + + ]: 196143 : if (tupdesc->constr->missing)
523 : : {
524 : 1835 : AttrMissing *attrmiss = tupdesc->constr->missing;
525 : :
526 [ + + ]: 13214 : for (i = tupdesc->natts - 1; i >= 0; i--)
527 : : {
2628 akapila@postgresql.o 528 [ + + ]: 11379 : if (attrmiss[i].am_present
2719 andrew@dunslane.net 529 [ + + ]: 3905 : && !TupleDescAttr(tupdesc, i)->attbyval)
2628 akapila@postgresql.o 530 : 1463 : pfree(DatumGetPointer(attrmiss[i].am_value));
531 : : }
2719 andrew@dunslane.net 532 : 1835 : pfree(attrmiss);
533 : : }
10226 bruce@momjian.us 534 [ + + ]: 196143 : if (tupdesc->constr->num_check > 0)
535 : : {
10225 536 : 5408 : ConstrCheck *check = tupdesc->constr->check;
537 : :
10226 538 [ + + ]: 13991 : for (i = tupdesc->constr->num_check - 1; i >= 0; i--)
539 : : {
1614 tgl@sss.pgh.pa.us 540 : 8583 : pfree(check[i].ccname);
541 : 8583 : pfree(check[i].ccbin);
542 : : }
10226 bruce@momjian.us 543 : 5408 : pfree(check);
544 : : }
545 : 196143 : pfree(tupdesc->constr);
546 : : }
547 : :
548 : 662562 : pfree(tupdesc);
10242 vadim4o@yahoo.com 549 : 662562 : }
550 : :
551 : : /*
552 : : * Increment the reference count of a tupdesc, and log the reference in
553 : : * CurrentResourceOwner.
554 : : *
555 : : * Do not apply this to tupdescs that are not being refcounted. (Use the
556 : : * macro PinTupleDesc for tupdescs of uncertain status.)
557 : : */
558 : : void
7022 tgl@sss.pgh.pa.us 559 : 15257028 : IncrTupleDescRefCount(TupleDesc tupdesc)
560 : : {
561 [ - + ]: 15257028 : Assert(tupdesc->tdrefcount >= 0);
562 : :
668 heikki.linnakangas@i 563 : 15257028 : ResourceOwnerEnlarge(CurrentResourceOwner);
7022 tgl@sss.pgh.pa.us 564 : 15257028 : tupdesc->tdrefcount++;
565 : 15257028 : ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc);
566 : 15257028 : }
567 : :
568 : : /*
569 : : * Decrement the reference count of a tupdesc, remove the corresponding
570 : : * reference from CurrentResourceOwner, and free the tupdesc if no more
571 : : * references remain.
572 : : *
573 : : * Do not apply this to tupdescs that are not being refcounted. (Use the
574 : : * macro ReleaseTupleDesc for tupdescs of uncertain status.)
575 : : */
576 : : void
577 : 15249314 : DecrTupleDescRefCount(TupleDesc tupdesc)
578 : : {
579 [ - + ]: 15249314 : Assert(tupdesc->tdrefcount > 0);
580 : :
581 : 15249314 : ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc);
582 [ + + ]: 15249314 : if (--tupdesc->tdrefcount == 0)
583 : 2 : FreeTupleDesc(tupdesc);
584 : 15249314 : }
585 : :
586 : : /*
587 : : * Compare two TupleDesc structures for logical equality
588 : : */
589 : : bool
9350 590 : 193387 : equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2)
591 : : {
592 : : int i,
593 : : n;
594 : :
595 [ + + ]: 193387 : if (tupdesc1->natts != tupdesc2->natts)
596 : 1348 : return false;
7828 597 [ - + ]: 192039 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
7828 tgl@sss.pgh.pa.us 598 :UBC 0 : return false;
599 : :
600 : : /* tdtypmod and tdrefcount are not checked */
601 : :
9350 tgl@sss.pgh.pa.us 602 [ + + ]:CBC 901797 : for (i = 0; i < tupdesc1->natts; i++)
603 : : {
2939 andres@anarazel.de 604 : 716458 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
605 : 716458 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
606 : :
607 : : /*
608 : : * We do not need to check every single field here: we can disregard
609 : : * attrelid and attnum (which were used to place the row in the attrs
610 : : * array in the first place). It might look like we could dispense
611 : : * with checking attlen/attbyval/attalign, since these are derived
612 : : * from atttypid; but in the case of dropped columns we must check
613 : : * them (since atttypid will be zero for all dropped columns) and in
614 : : * general it seems safer to check them always.
615 : : *
616 : : * We intentionally ignore atthasmissing, since that's not very
617 : : * relevant in tupdescs, which lack the attmissingval field.
618 : : */
9350 tgl@sss.pgh.pa.us 619 [ + + ]: 716458 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
620 : 646 : return false;
621 [ + + ]: 715812 : if (attr1->atttypid != attr2->atttypid)
622 : 535 : return false;
7450 623 [ + + ]: 715277 : if (attr1->attlen != attr2->attlen)
624 : 5 : return false;
7828 625 [ - + ]: 715272 : if (attr1->attndims != attr2->attndims)
7828 tgl@sss.pgh.pa.us 626 :UBC 0 : return false;
9350 tgl@sss.pgh.pa.us 627 [ + + ]:CBC 715272 : if (attr1->atttypmod != attr2->atttypmod)
628 : 21 : return false;
7450 629 [ + + ]: 715251 : if (attr1->attbyval != attr2->attbyval)
630 : 34 : return false;
1567 631 [ - + ]: 715217 : if (attr1->attalign != attr2->attalign)
1567 tgl@sss.pgh.pa.us 632 :UBC 0 : return false;
9350 tgl@sss.pgh.pa.us 633 [ + + ]:CBC 715217 : if (attr1->attstorage != attr2->attstorage)
634 : 117 : return false;
1567 635 [ + + ]: 715100 : if (attr1->attcompression != attr2->attcompression)
7450 636 : 36 : return false;
9350 637 [ + + ]: 715064 : if (attr1->attnotnull != attr2->attnotnull)
638 : 867 : return false;
639 : :
640 : : /*
641 : : * When the column has a not-null constraint, we also need to consider
642 : : * its validity aspect, which only manifests in CompactAttribute->
643 : : * attnullability, so verify that.
644 : : */
152 alvherre@alvh.no-ip. 645 [ + + ]: 714197 : if (attr1->attnotnull)
646 : : {
647 : 216112 : CompactAttribute *cattr1 = TupleDescCompactAttr(tupdesc1, i);
648 : 216112 : CompactAttribute *cattr2 = TupleDescCompactAttr(tupdesc2, i);
649 : :
650 [ - + ]: 216112 : Assert(cattr1->attnullability != ATTNULLABLE_UNKNOWN);
651 [ - + ]: 216112 : Assert((cattr1->attnullability == ATTNULLABLE_UNKNOWN) ==
652 : : (cattr2->attnullability == ATTNULLABLE_UNKNOWN));
653 : :
654 [ + + ]: 216112 : if (cattr1->attnullability != cattr2->attnullability)
655 : 44 : return false;
656 : : }
8408 tgl@sss.pgh.pa.us 657 [ + + ]: 714153 : if (attr1->atthasdef != attr2->atthasdef)
658 : 2498 : return false;
3075 peter_e@gmx.net 659 [ + + ]: 711655 : if (attr1->attidentity != attr2->attidentity)
660 : 89 : return false;
2352 peter@eisentraut.org 661 [ + + ]: 711566 : if (attr1->attgenerated != attr2->attgenerated)
662 : 10 : return false;
8436 tgl@sss.pgh.pa.us 663 [ - + ]: 711556 : if (attr1->attisdropped != attr2->attisdropped)
8436 tgl@sss.pgh.pa.us 664 :UBC 0 : return false;
8385 tgl@sss.pgh.pa.us 665 [ + + ]:CBC 711556 : if (attr1->attislocal != attr2->attislocal)
666 : 1377 : return false;
667 [ + + ]: 710179 : if (attr1->attinhcount != attr2->attinhcount)
8408 668 : 421 : return false;
5251 669 [ - + ]: 709758 : if (attr1->attcollation != attr2->attcollation)
5251 tgl@sss.pgh.pa.us 670 :UBC 0 : return false;
671 : : /* variable-length fields are not even present... */
672 : : }
673 : :
9350 tgl@sss.pgh.pa.us 674 [ + + ]:CBC 185339 : if (tupdesc1->constr != NULL)
675 : : {
9278 bruce@momjian.us 676 : 65646 : TupleConstr *constr1 = tupdesc1->constr;
677 : 65646 : TupleConstr *constr2 = tupdesc2->constr;
678 : :
9350 tgl@sss.pgh.pa.us 679 [ + + ]: 65646 : if (constr2 == NULL)
680 : 115 : return false;
9068 681 [ - + ]: 65531 : if (constr1->has_not_null != constr2->has_not_null)
9068 tgl@sss.pgh.pa.us 682 :UBC 0 : return false;
2352 peter@eisentraut.org 683 [ + + ]:CBC 65531 : if (constr1->has_generated_stored != constr2->has_generated_stored)
684 : 276 : return false;
211 685 [ + + ]: 65255 : if (constr1->has_generated_virtual != constr2->has_generated_virtual)
686 : 200 : return false;
9068 tgl@sss.pgh.pa.us 687 : 65055 : n = constr1->num_defval;
688 [ - + ]: 65055 : if (n != (int) constr2->num_defval)
9350 tgl@sss.pgh.pa.us 689 :UBC 0 : return false;
690 : : /* We assume here that both AttrDefault arrays are in adnum order */
9068 tgl@sss.pgh.pa.us 691 [ + + ]:CBC 73876 : for (i = 0; i < n; i++)
692 : : {
9278 bruce@momjian.us 693 : 8821 : AttrDefault *defval1 = constr1->defval + i;
1614 tgl@sss.pgh.pa.us 694 : 8821 : AttrDefault *defval2 = constr2->defval + i;
695 : :
696 [ - + ]: 8821 : if (defval1->adnum != defval2->adnum)
9350 tgl@sss.pgh.pa.us 697 :UBC 0 : return false;
9350 tgl@sss.pgh.pa.us 698 [ - + ]:CBC 8821 : if (strcmp(defval1->adbin, defval2->adbin) != 0)
9350 tgl@sss.pgh.pa.us 699 :UBC 0 : return false;
700 : : }
2719 andrew@dunslane.net 701 [ + + ]:CBC 65055 : if (constr1->missing)
702 : : {
703 [ + + ]: 351 : if (!constr2->missing)
704 : 42 : return false;
705 [ + + ]: 1870 : for (i = 0; i < tupdesc1->natts; i++)
706 : : {
707 : 1634 : AttrMissing *missval1 = constr1->missing + i;
708 : 1634 : AttrMissing *missval2 = constr2->missing + i;
709 : :
2628 akapila@postgresql.o 710 [ + + ]: 1634 : if (missval1->am_present != missval2->am_present)
2719 andrew@dunslane.net 711 : 73 : return false;
2628 akapila@postgresql.o 712 [ + + ]: 1561 : if (missval1->am_present)
713 : : {
260 drowley@postgresql.o 714 : 524 : CompactAttribute *missatt1 = TupleDescCompactAttr(tupdesc1, i);
715 : :
2628 akapila@postgresql.o 716 [ - + ]: 524 : if (!datumIsEqual(missval1->am_value, missval2->am_value,
2719 andrew@dunslane.net 717 : 524 : missatt1->attbyval, missatt1->attlen))
2719 andrew@dunslane.net 718 :UBC 0 : return false;
719 : : }
720 : : }
721 : : }
2719 andrew@dunslane.net 722 [ + + ]:CBC 64704 : else if (constr2->missing)
723 : 180 : return false;
9068 tgl@sss.pgh.pa.us 724 : 64760 : n = constr1->num_check;
725 [ + + ]: 64760 : if (n != (int) constr2->num_check)
9350 726 : 734 : return false;
727 : :
728 : : /*
729 : : * Similarly, we rely here on the ConstrCheck entries being sorted by
730 : : * name. If there are duplicate names, the outcome of the comparison
731 : : * is uncertain, but that should not happen.
732 : : */
9068 733 [ + + ]: 65622 : for (i = 0; i < n; i++)
734 : : {
9278 bruce@momjian.us 735 : 1647 : ConstrCheck *check1 = constr1->check + i;
1614 tgl@sss.pgh.pa.us 736 : 1647 : ConstrCheck *check2 = constr2->check + i;
737 : :
738 [ + - ]: 1647 : if (!(strcmp(check1->ccname, check2->ccname) == 0 &&
739 [ + - ]: 1647 : strcmp(check1->ccbin, check2->ccbin) == 0 &&
238 peter@eisentraut.org 740 [ + + ]: 1647 : check1->ccenforced == check2->ccenforced &&
1614 tgl@sss.pgh.pa.us 741 [ + + ]: 1638 : check1->ccvalid == check2->ccvalid &&
742 [ - + ]: 1596 : check1->ccnoinherit == check2->ccnoinherit))
9350 743 : 51 : return false;
744 : : }
745 : : }
746 [ + + ]: 119693 : else if (tupdesc2->constr != NULL)
747 : 897 : return false;
748 : 182771 : return true;
749 : : }
750 : :
751 : : /*
752 : : * equalRowTypes
753 : : *
754 : : * This determines whether two tuple descriptors have equal row types. This
755 : : * only checks those fields in pg_attribute that are applicable for row types,
756 : : * while ignoring those fields that define the physical row storage or those
757 : : * that define table column metadata.
758 : : *
759 : : * Specifically, this checks:
760 : : *
761 : : * - same number of attributes
762 : : * - same composite type ID (but could both be zero)
763 : : * - corresponding attributes (in order) have same the name, type, typmod,
764 : : * collation
765 : : *
766 : : * This is used to check whether two record types are compatible, whether
767 : : * function return row types are the same, and other similar situations.
768 : : *
769 : : * (XXX There was some discussion whether attndims should be checked here, but
770 : : * for now it has been decided not to.)
771 : : *
772 : : * Note: We deliberately do not check the tdtypmod field. This allows
773 : : * typcache.c to use this routine to see if a cached record type matches a
774 : : * requested type.
775 : : */
776 : : bool
538 peter@eisentraut.org 777 : 178117 : equalRowTypes(TupleDesc tupdesc1, TupleDesc tupdesc2)
778 : : {
779 [ + + ]: 178117 : if (tupdesc1->natts != tupdesc2->natts)
780 : 85 : return false;
781 [ + + ]: 178032 : if (tupdesc1->tdtypeid != tupdesc2->tdtypeid)
782 : 899 : return false;
783 : :
784 [ + + ]: 2806781 : for (int i = 0; i < tupdesc1->natts; i++)
785 : : {
786 : 2633872 : Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i);
787 : 2633872 : Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i);
788 : :
789 [ + + ]: 2633872 : if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0)
790 : 4211 : return false;
791 [ + + ]: 2629661 : if (attr1->atttypid != attr2->atttypid)
792 : 11 : return false;
793 [ + + ]: 2629650 : if (attr1->atttypmod != attr2->atttypmod)
794 : 2 : return false;
795 [ - + ]: 2629648 : if (attr1->attcollation != attr2->attcollation)
538 peter@eisentraut.org 796 :UBC 0 : return false;
797 : :
798 : : /* Record types derived from tables could have dropped fields. */
538 peter@eisentraut.org 799 [ - + ]:CBC 2629648 : if (attr1->attisdropped != attr2->attisdropped)
538 peter@eisentraut.org 800 :UBC 0 : return false;
801 : : }
802 : :
538 peter@eisentraut.org 803 :CBC 172909 : return true;
804 : : }
805 : :
806 : : /*
807 : : * hashRowType
808 : : *
809 : : * If two tuple descriptors would be considered equal by equalRowTypes()
810 : : * then their hash value will be equal according to this function.
811 : : */
812 : : uint32
813 : 186580 : hashRowType(TupleDesc desc)
814 : : {
815 : : uint32 s;
816 : : int i;
817 : :
32 peter@eisentraut.org 818 :GNC 186580 : s = hash_combine(0, hash_bytes_uint32(desc->natts));
819 : 186580 : s = hash_combine(s, hash_bytes_uint32(desc->tdtypeid));
2937 andres@anarazel.de 820 [ + + ]:CBC 2968657 : for (i = 0; i < desc->natts; ++i)
32 peter@eisentraut.org 821 :GNC 2782077 : s = hash_combine(s, hash_bytes_uint32(TupleDescAttr(desc, i)->atttypid));
822 : :
2937 andres@anarazel.de 823 :CBC 186580 : return s;
824 : : }
825 : :
826 : : /*
827 : : * TupleDescInitEntry
828 : : * This function initializes a single attribute structure in
829 : : * a previously allocated tuple descriptor.
830 : : *
831 : : * If attributeName is NULL, the attname field is set to an empty string
832 : : * (this is for cases where we don't know or need a name for the field).
833 : : * Also, some callers use this function to change the datatype-related fields
834 : : * in an existing tupdesc; they pass attributeName = NameStr(att->attname)
835 : : * to indicate that the attname field shouldn't be modified.
836 : : *
837 : : * Note that attcollation is set to the default for the specified datatype.
838 : : * If a nondefault collation is needed, insert it afterwards using
839 : : * TupleDescInitEntryCollation.
840 : : */
841 : : void
10651 scrappy@hub.org 842 : 5976280 : TupleDescInitEntry(TupleDesc desc,
843 : : AttrNumber attributeNumber,
844 : : const char *attributeName,
845 : : Oid oidtypeid,
846 : : int32 typmod,
847 : : int attdim)
848 : : {
849 : : HeapTuple tuple;
850 : : Form_pg_type typeForm;
851 : : Form_pg_attribute att;
852 : :
853 : : /*
854 : : * sanity checks
855 : : */
1044 peter@eisentraut.org 856 [ - + ]: 5976280 : Assert(PointerIsValid(desc));
857 [ - + ]: 5976280 : Assert(attributeNumber >= 1);
858 [ - + ]: 5976280 : Assert(attributeNumber <= desc->natts);
893 859 [ - + ]: 5976280 : Assert(attdim >= 0);
860 [ - + ]: 5976280 : Assert(attdim <= PG_INT16_MAX);
861 : :
862 : : /*
863 : : * initialize the attribute fields
864 : : */
2939 andres@anarazel.de 865 : 5976280 : att = TupleDescAttr(desc, attributeNumber - 1);
866 : :
10226 bruce@momjian.us 867 : 5976280 : att->attrelid = 0; /* dummy value */
868 : :
869 : : /*
870 : : * Note: attributeName can be NULL, because the planner doesn't always
871 : : * fill in valid resname values in targetlists, particularly for resjunk
872 : : * attributes. Also, do nothing if caller wants to re-use the old attname.
873 : : */
4331 tgl@sss.pgh.pa.us 874 [ + + ]: 5976280 : if (attributeName == NULL)
9435 bruce@momjian.us 875 [ + + + - : 9442777 : MemSet(NameStr(att->attname), 0, NAMEDATALEN);
+ - + - +
+ ]
4331 tgl@sss.pgh.pa.us 876 [ + + ]: 3975759 : else if (attributeName != NameStr(att->attname))
877 : 3974032 : namestrcpy(&(att->attname), attributeName);
878 : :
10070 bruce@momjian.us 879 : 5976280 : att->atttypmod = typmod;
880 : :
10226 881 : 5976280 : att->attnum = attributeNumber;
8888 tgl@sss.pgh.pa.us 882 : 5976280 : att->attndims = attdim;
883 : :
10226 bruce@momjian.us 884 : 5976280 : att->attnotnull = false;
885 : 5976280 : att->atthasdef = false;
2719 andrew@dunslane.net 886 : 5976280 : att->atthasmissing = false;
3075 peter_e@gmx.net 887 : 5976280 : att->attidentity = '\0';
2352 peter@eisentraut.org 888 : 5976280 : att->attgenerated = '\0';
8436 tgl@sss.pgh.pa.us 889 : 5976280 : att->attisdropped = false;
8385 890 : 5976280 : att->attislocal = true;
891 : 5976280 : att->attinhcount = 0;
892 : : /* variable-length fields are not present in tupledescs */
893 : :
5683 rhaas@postgresql.org 894 : 5976280 : tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid));
10226 bruce@momjian.us 895 [ - + ]: 5976280 : if (!HeapTupleIsValid(tuple))
8083 tgl@sss.pgh.pa.us 896 [ # # ]:UBC 0 : elog(ERROR, "cache lookup failed for type %u", oidtypeid);
9867 bruce@momjian.us 897 :CBC 5976280 : typeForm = (Form_pg_type) GETSTRUCT(tuple);
898 : :
7828 tgl@sss.pgh.pa.us 899 : 5976280 : att->atttypid = oidtypeid;
900 : 5976280 : att->attlen = typeForm->typlen;
901 : 5976280 : att->attbyval = typeForm->typbyval;
902 : 5976280 : att->attalign = typeForm->typalign;
903 : 5976280 : att->attstorage = typeForm->typstorage;
1563 904 : 5976280 : att->attcompression = InvalidCompressionMethod;
1567 905 : 5976280 : att->attcollation = typeForm->typcollation;
906 : :
260 drowley@postgresql.o 907 : 5976280 : populate_compact_attribute(desc, attributeNumber - 1);
908 : :
9060 tgl@sss.pgh.pa.us 909 : 5976280 : ReleaseSysCache(tuple);
10651 scrappy@hub.org 910 : 5976280 : }
911 : :
912 : : /*
913 : : * TupleDescInitBuiltinEntry
914 : : * Initialize a tuple descriptor without catalog access. Only
915 : : * a limited range of builtin types are supported.
916 : : */
917 : : void
3147 rhaas@postgresql.org 918 : 6532 : TupleDescInitBuiltinEntry(TupleDesc desc,
919 : : AttrNumber attributeNumber,
920 : : const char *attributeName,
921 : : Oid oidtypeid,
922 : : int32 typmod,
923 : : int attdim)
924 : : {
925 : : Form_pg_attribute att;
926 : :
927 : : /* sanity checks */
1044 peter@eisentraut.org 928 [ - + ]: 6532 : Assert(PointerIsValid(desc));
929 [ - + ]: 6532 : Assert(attributeNumber >= 1);
930 [ - + ]: 6532 : Assert(attributeNumber <= desc->natts);
893 931 [ - + ]: 6532 : Assert(attdim >= 0);
932 [ - + ]: 6532 : Assert(attdim <= PG_INT16_MAX);
933 : :
934 : : /* initialize the attribute fields */
2939 andres@anarazel.de 935 : 6532 : att = TupleDescAttr(desc, attributeNumber - 1);
3147 rhaas@postgresql.org 936 : 6532 : att->attrelid = 0; /* dummy value */
937 : :
938 : : /* unlike TupleDescInitEntry, we require an attribute name */
939 [ - + ]: 6532 : Assert(attributeName != NULL);
940 : 6532 : namestrcpy(&(att->attname), attributeName);
941 : :
942 : 6532 : att->atttypmod = typmod;
943 : :
944 : 6532 : att->attnum = attributeNumber;
945 : 6532 : att->attndims = attdim;
946 : :
947 : 6532 : att->attnotnull = false;
948 : 6532 : att->atthasdef = false;
2719 andrew@dunslane.net 949 : 6532 : att->atthasmissing = false;
3075 peter_e@gmx.net 950 : 6532 : att->attidentity = '\0';
2352 peter@eisentraut.org 951 : 6532 : att->attgenerated = '\0';
3147 rhaas@postgresql.org 952 : 6532 : att->attisdropped = false;
953 : 6532 : att->attislocal = true;
954 : 6532 : att->attinhcount = 0;
955 : : /* variable-length fields are not present in tupledescs */
956 : :
957 : 6532 : att->atttypid = oidtypeid;
958 : :
959 : : /*
960 : : * Our goal here is to support just enough types to let basic builtin
961 : : * commands work without catalog access - e.g. so that we can do certain
962 : : * things even in processes that are not connected to a database.
963 : : */
964 [ + - - + : 6532 : switch (oidtypeid)
+ - ]
965 : : {
966 : 5207 : case TEXTOID:
967 : : case TEXTARRAYOID:
968 : 5207 : att->attlen = -1;
969 : 5207 : att->attbyval = false;
2012 tgl@sss.pgh.pa.us 970 : 5207 : att->attalign = TYPALIGN_INT;
971 : 5207 : att->attstorage = TYPSTORAGE_EXTENDED;
1563 972 : 5207 : att->attcompression = InvalidCompressionMethod;
3147 rhaas@postgresql.org 973 : 5207 : att->attcollation = DEFAULT_COLLATION_OID;
974 : 5207 : break;
975 : :
3147 rhaas@postgresql.org 976 :UBC 0 : case BOOLOID:
977 : 0 : att->attlen = 1;
978 : 0 : att->attbyval = true;
2012 tgl@sss.pgh.pa.us 979 : 0 : att->attalign = TYPALIGN_CHAR;
980 : 0 : att->attstorage = TYPSTORAGE_PLAIN;
1567 981 : 0 : att->attcompression = InvalidCompressionMethod;
3147 rhaas@postgresql.org 982 : 0 : att->attcollation = InvalidOid;
983 : 0 : break;
984 : :
985 : 0 : case INT4OID:
986 : 0 : att->attlen = 4;
987 : 0 : att->attbyval = true;
2012 tgl@sss.pgh.pa.us 988 : 0 : att->attalign = TYPALIGN_INT;
989 : 0 : att->attstorage = TYPSTORAGE_PLAIN;
1567 990 : 0 : att->attcompression = InvalidCompressionMethod;
3147 rhaas@postgresql.org 991 : 0 : att->attcollation = InvalidOid;
3139 992 : 0 : break;
993 : :
3139 rhaas@postgresql.org 994 :CBC 1161 : case INT8OID:
995 : 1161 : att->attlen = 8;
24 tgl@sss.pgh.pa.us 996 :GNC 1161 : att->attbyval = true;
2012 tgl@sss.pgh.pa.us 997 :CBC 1161 : att->attalign = TYPALIGN_DOUBLE;
998 : 1161 : att->attstorage = TYPSTORAGE_PLAIN;
1567 999 : 1161 : att->attcompression = InvalidCompressionMethod;
3139 rhaas@postgresql.org 1000 : 1161 : att->attcollation = InvalidOid;
3147 1001 : 1161 : break;
1002 : :
1160 peter@eisentraut.org 1003 : 164 : case OIDOID:
1004 : 164 : att->attlen = 4;
1005 : 164 : att->attbyval = true;
1006 : 164 : att->attalign = TYPALIGN_INT;
1007 : 164 : att->attstorage = TYPSTORAGE_PLAIN;
1008 : 164 : att->attcompression = InvalidCompressionMethod;
1009 : 164 : att->attcollation = InvalidOid;
1010 : 164 : break;
1011 : :
2462 tgl@sss.pgh.pa.us 1012 :UBC 0 : default:
1013 [ # # ]: 0 : elog(ERROR, "unsupported type %u", oidtypeid);
1014 : : }
1015 : :
260 drowley@postgresql.o 1016 :CBC 6532 : populate_compact_attribute(desc, attributeNumber - 1);
3147 rhaas@postgresql.org 1017 : 6532 : }
1018 : :
1019 : : /*
1020 : : * TupleDescInitEntryCollation
1021 : : *
1022 : : * Assign a nondefault collation to a previously initialized tuple descriptor
1023 : : * entry.
1024 : : */
1025 : : void
5324 peter_e@gmx.net 1026 : 3129765 : TupleDescInitEntryCollation(TupleDesc desc,
1027 : : AttrNumber attributeNumber,
1028 : : Oid collationid)
1029 : : {
1030 : : /*
1031 : : * sanity checks
1032 : : */
1044 peter@eisentraut.org 1033 [ - + ]: 3129765 : Assert(PointerIsValid(desc));
1034 [ - + ]: 3129765 : Assert(attributeNumber >= 1);
1035 [ - + ]: 3129765 : Assert(attributeNumber <= desc->natts);
1036 : :
2939 andres@anarazel.de 1037 : 3129765 : TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid;
5324 peter_e@gmx.net 1038 : 3129765 : }
1039 : :
1040 : : /*
1041 : : * BuildDescFromLists
1042 : : *
1043 : : * Build a TupleDesc given lists of column names (as String nodes),
1044 : : * column type OIDs, typmods, and collation OIDs.
1045 : : *
1046 : : * No constraints are generated.
1047 : : *
1048 : : * This is for use with functions returning RECORD.
1049 : : */
1050 : : TupleDesc
711 peter@eisentraut.org 1051 : 714 : BuildDescFromLists(const List *names, const List *types, const List *typmods, const List *collations)
1052 : : {
1053 : : int natts;
1054 : : AttrNumber attnum;
1055 : : ListCell *l1;
1056 : : ListCell *l2;
1057 : : ListCell *l3;
1058 : : ListCell *l4;
1059 : : TupleDesc desc;
1060 : :
7114 tgl@sss.pgh.pa.us 1061 : 714 : natts = list_length(names);
1062 [ - + ]: 714 : Assert(natts == list_length(types));
1063 [ - + ]: 714 : Assert(natts == list_length(typmods));
5324 peter_e@gmx.net 1064 [ - + ]: 714 : Assert(natts == list_length(collations));
1065 : :
1066 : : /*
1067 : : * allocate a new tuple descriptor
1068 : : */
2482 andres@anarazel.de 1069 : 714 : desc = CreateTemplateTupleDesc(natts);
1070 : :
7114 tgl@sss.pgh.pa.us 1071 : 714 : attnum = 0;
2382 1072 [ + - + + : 2513 : forfour(l1, names, l2, types, l3, typmods, l4, collations)
+ - + + +
- + + + -
+ + + + +
- + - + -
+ + ]
1073 : : {
7114 1074 : 1799 : char *attname = strVal(lfirst(l1));
2382 1075 : 1799 : Oid atttypid = lfirst_oid(l2);
1076 : 1799 : int32 atttypmod = lfirst_int(l3);
1077 : 1799 : Oid attcollation = lfirst_oid(l4);
1078 : :
7114 1079 : 1799 : attnum++;
1080 : :
1081 : 1799 : TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0);
5324 peter_e@gmx.net 1082 : 1799 : TupleDescInitEntryCollation(desc, attnum, attcollation);
1083 : : }
1084 : :
7114 tgl@sss.pgh.pa.us 1085 : 714 : return desc;
1086 : : }
1087 : :
1088 : : /*
1089 : : * Get default expression (or NULL if none) for the given attribute number.
1090 : : */
1091 : : Node *
710 peter@eisentraut.org 1092 : 75336 : TupleDescGetDefault(TupleDesc tupdesc, AttrNumber attnum)
1093 : : {
1094 : 75336 : Node *result = NULL;
1095 : :
1096 [ + - ]: 75336 : if (tupdesc->constr)
1097 : : {
1098 : 75336 : AttrDefault *attrdef = tupdesc->constr->defval;
1099 : :
1100 [ + - ]: 113889 : for (int i = 0; i < tupdesc->constr->num_defval; i++)
1101 : : {
1102 [ + + ]: 113889 : if (attrdef[i].adnum == attnum)
1103 : : {
1104 : 75336 : result = stringToNode(attrdef[i].adbin);
1105 : 75336 : break;
1106 : : }
1107 : : }
1108 : : }
1109 : :
1110 : 75336 : return result;
1111 : : }
1112 : :
1113 : : /* ResourceOwner callbacks */
1114 : :
1115 : : static void
668 heikki.linnakangas@i 1116 : 7714 : ResOwnerReleaseTupleDesc(Datum res)
1117 : : {
1118 : 7714 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1119 : :
1120 : : /* Like DecrTupleDescRefCount, but don't call ResourceOwnerForget() */
1121 [ - + ]: 7714 : Assert(tupdesc->tdrefcount > 0);
1122 [ + + ]: 7714 : if (--tupdesc->tdrefcount == 0)
1123 : 247 : FreeTupleDesc(tupdesc);
1124 : 7714 : }
1125 : :
1126 : : static char *
668 heikki.linnakangas@i 1127 :UBC 0 : ResOwnerPrintTupleDesc(Datum res)
1128 : : {
1129 : 0 : TupleDesc tupdesc = (TupleDesc) DatumGetPointer(res);
1130 : :
1131 : 0 : return psprintf("TupleDesc %p (%u,%d)",
1132 : : tupdesc, tupdesc->tdtypeid, tupdesc->tdtypmod);
1133 : : }
|