1 | /*------------------------------------------------------------------------- |
2 | * |
3 | * tupdesc.c |
4 | * POSTGRES tuple descriptor support code |
5 | * |
6 | * Portions Copyright (c) 1996-2019, 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/tupdesc_details.h" |
24 | #include "catalog/pg_collation.h" |
25 | #include "catalog/pg_type.h" |
26 | #include "miscadmin.h" |
27 | #include "parser/parse_type.h" |
28 | #include "utils/acl.h" |
29 | #include "utils/builtins.h" |
30 | #include "utils/datum.h" |
31 | #include "utils/hashutils.h" |
32 | #include "utils/resowner_private.h" |
33 | #include "utils/syscache.h" |
34 | |
35 | |
36 | /* |
37 | * CreateTemplateTupleDesc |
38 | * This function allocates an empty tuple descriptor structure. |
39 | * |
40 | * Tuple type ID information is initially set for an anonymous record type; |
41 | * caller can overwrite this if needed. |
42 | */ |
43 | TupleDesc |
44 | CreateTemplateTupleDesc(int natts) |
45 | { |
46 | TupleDesc desc; |
47 | |
48 | /* |
49 | * sanity checks |
50 | */ |
51 | AssertArg(natts >= 0); |
52 | |
53 | /* |
54 | * Allocate enough memory for the tuple descriptor, including the |
55 | * attribute rows. |
56 | * |
57 | * Note: the attribute array stride is sizeof(FormData_pg_attribute), |
58 | * since we declare the array elements as FormData_pg_attribute for |
59 | * notational convenience. However, we only guarantee that the first |
60 | * ATTRIBUTE_FIXED_PART_SIZE bytes of each entry are valid; most code that |
61 | * copies tupdesc entries around copies just that much. In principle that |
62 | * could be less due to trailing padding, although with the current |
63 | * definition of pg_attribute there probably isn't any padding. |
64 | */ |
65 | desc = (TupleDesc) palloc(offsetof(struct TupleDescData, attrs) + |
66 | natts * sizeof(FormData_pg_attribute)); |
67 | |
68 | /* |
69 | * Initialize other fields of the tupdesc. |
70 | */ |
71 | desc->natts = natts; |
72 | desc->constr = NULL; |
73 | desc->tdtypeid = RECORDOID; |
74 | desc->tdtypmod = -1; |
75 | desc->tdrefcount = -1; /* assume not reference-counted */ |
76 | |
77 | return desc; |
78 | } |
79 | |
80 | /* |
81 | * CreateTupleDesc |
82 | * This function allocates a new TupleDesc by copying a given |
83 | * Form_pg_attribute array. |
84 | * |
85 | * Tuple type ID information is initially set for an anonymous record type; |
86 | * caller can overwrite this if needed. |
87 | */ |
88 | TupleDesc |
89 | CreateTupleDesc(int natts, Form_pg_attribute *attrs) |
90 | { |
91 | TupleDesc desc; |
92 | int i; |
93 | |
94 | desc = CreateTemplateTupleDesc(natts); |
95 | |
96 | for (i = 0; i < natts; ++i) |
97 | memcpy(TupleDescAttr(desc, i), attrs[i], ATTRIBUTE_FIXED_PART_SIZE); |
98 | |
99 | return desc; |
100 | } |
101 | |
102 | /* |
103 | * CreateTupleDescCopy |
104 | * This function creates a new TupleDesc by copying from an existing |
105 | * TupleDesc. |
106 | * |
107 | * !!! Constraints and defaults are not copied !!! |
108 | */ |
109 | TupleDesc |
110 | CreateTupleDescCopy(TupleDesc tupdesc) |
111 | { |
112 | TupleDesc desc; |
113 | int i; |
114 | |
115 | desc = CreateTemplateTupleDesc(tupdesc->natts); |
116 | |
117 | /* Flat-copy the attribute array */ |
118 | memcpy(TupleDescAttr(desc, 0), |
119 | TupleDescAttr(tupdesc, 0), |
120 | desc->natts * sizeof(FormData_pg_attribute)); |
121 | |
122 | /* |
123 | * Since we're not copying constraints and defaults, clear fields |
124 | * associated with them. |
125 | */ |
126 | for (i = 0; i < desc->natts; i++) |
127 | { |
128 | Form_pg_attribute att = TupleDescAttr(desc, i); |
129 | |
130 | att->attnotnull = false; |
131 | att->atthasdef = false; |
132 | att->atthasmissing = false; |
133 | att->attidentity = '\0'; |
134 | att->attgenerated = '\0'; |
135 | } |
136 | |
137 | /* We can copy the tuple type identification, too */ |
138 | desc->tdtypeid = tupdesc->tdtypeid; |
139 | desc->tdtypmod = tupdesc->tdtypmod; |
140 | |
141 | return desc; |
142 | } |
143 | |
144 | /* |
145 | * CreateTupleDescCopyConstr |
146 | * This function creates a new TupleDesc by copying from an existing |
147 | * TupleDesc (including its constraints and defaults). |
148 | */ |
149 | TupleDesc |
150 | CreateTupleDescCopyConstr(TupleDesc tupdesc) |
151 | { |
152 | TupleDesc desc; |
153 | TupleConstr *constr = tupdesc->constr; |
154 | int i; |
155 | |
156 | desc = CreateTemplateTupleDesc(tupdesc->natts); |
157 | |
158 | /* Flat-copy the attribute array */ |
159 | memcpy(TupleDescAttr(desc, 0), |
160 | TupleDescAttr(tupdesc, 0), |
161 | desc->natts * sizeof(FormData_pg_attribute)); |
162 | |
163 | /* Copy the TupleConstr data structure, if any */ |
164 | if (constr) |
165 | { |
166 | TupleConstr *cpy = (TupleConstr *) palloc0(sizeof(TupleConstr)); |
167 | |
168 | cpy->has_not_null = constr->has_not_null; |
169 | cpy->has_generated_stored = constr->has_generated_stored; |
170 | |
171 | if ((cpy->num_defval = constr->num_defval) > 0) |
172 | { |
173 | cpy->defval = (AttrDefault *) palloc(cpy->num_defval * sizeof(AttrDefault)); |
174 | memcpy(cpy->defval, constr->defval, cpy->num_defval * sizeof(AttrDefault)); |
175 | for (i = cpy->num_defval - 1; i >= 0; i--) |
176 | { |
177 | if (constr->defval[i].adbin) |
178 | cpy->defval[i].adbin = pstrdup(constr->defval[i].adbin); |
179 | } |
180 | } |
181 | |
182 | if (constr->missing) |
183 | { |
184 | cpy->missing = (AttrMissing *) palloc(tupdesc->natts * sizeof(AttrMissing)); |
185 | memcpy(cpy->missing, constr->missing, tupdesc->natts * sizeof(AttrMissing)); |
186 | for (i = tupdesc->natts - 1; i >= 0; i--) |
187 | { |
188 | if (constr->missing[i].am_present) |
189 | { |
190 | Form_pg_attribute attr = TupleDescAttr(tupdesc, i); |
191 | |
192 | cpy->missing[i].am_value = datumCopy(constr->missing[i].am_value, |
193 | attr->attbyval, |
194 | attr->attlen); |
195 | } |
196 | } |
197 | } |
198 | |
199 | if ((cpy->num_check = constr->num_check) > 0) |
200 | { |
201 | cpy->check = (ConstrCheck *) palloc(cpy->num_check * sizeof(ConstrCheck)); |
202 | memcpy(cpy->check, constr->check, cpy->num_check * sizeof(ConstrCheck)); |
203 | for (i = cpy->num_check - 1; i >= 0; i--) |
204 | { |
205 | if (constr->check[i].ccname) |
206 | cpy->check[i].ccname = pstrdup(constr->check[i].ccname); |
207 | if (constr->check[i].ccbin) |
208 | cpy->check[i].ccbin = pstrdup(constr->check[i].ccbin); |
209 | cpy->check[i].ccvalid = constr->check[i].ccvalid; |
210 | cpy->check[i].ccnoinherit = constr->check[i].ccnoinherit; |
211 | } |
212 | } |
213 | |
214 | desc->constr = cpy; |
215 | } |
216 | |
217 | /* We can copy the tuple type identification, too */ |
218 | desc->tdtypeid = tupdesc->tdtypeid; |
219 | desc->tdtypmod = tupdesc->tdtypmod; |
220 | |
221 | return desc; |
222 | } |
223 | |
224 | /* |
225 | * TupleDescCopy |
226 | * Copy a tuple descriptor into caller-supplied memory. |
227 | * The memory may be shared memory mapped at any address, and must |
228 | * be sufficient to hold TupleDescSize(src) bytes. |
229 | * |
230 | * !!! Constraints and defaults are not copied !!! |
231 | */ |
232 | void |
233 | TupleDescCopy(TupleDesc dst, TupleDesc src) |
234 | { |
235 | int i; |
236 | |
237 | /* Flat-copy the header and attribute array */ |
238 | memcpy(dst, src, TupleDescSize(src)); |
239 | |
240 | /* |
241 | * Since we're not copying constraints and defaults, clear fields |
242 | * associated with them. |
243 | */ |
244 | for (i = 0; i < dst->natts; i++) |
245 | { |
246 | Form_pg_attribute att = TupleDescAttr(dst, i); |
247 | |
248 | att->attnotnull = false; |
249 | att->atthasdef = false; |
250 | att->atthasmissing = false; |
251 | att->attidentity = '\0'; |
252 | att->attgenerated = '\0'; |
253 | } |
254 | dst->constr = NULL; |
255 | |
256 | /* |
257 | * Also, assume the destination is not to be ref-counted. (Copying the |
258 | * source's refcount would be wrong in any case.) |
259 | */ |
260 | dst->tdrefcount = -1; |
261 | } |
262 | |
263 | /* |
264 | * TupleDescCopyEntry |
265 | * This function copies a single attribute structure from one tuple |
266 | * descriptor to another. |
267 | * |
268 | * !!! Constraints and defaults are not copied !!! |
269 | */ |
270 | void |
271 | TupleDescCopyEntry(TupleDesc dst, AttrNumber dstAttno, |
272 | TupleDesc src, AttrNumber srcAttno) |
273 | { |
274 | Form_pg_attribute dstAtt = TupleDescAttr(dst, dstAttno - 1); |
275 | Form_pg_attribute srcAtt = TupleDescAttr(src, srcAttno - 1); |
276 | |
277 | /* |
278 | * sanity checks |
279 | */ |
280 | AssertArg(PointerIsValid(src)); |
281 | AssertArg(PointerIsValid(dst)); |
282 | AssertArg(srcAttno >= 1); |
283 | AssertArg(srcAttno <= src->natts); |
284 | AssertArg(dstAttno >= 1); |
285 | AssertArg(dstAttno <= dst->natts); |
286 | |
287 | memcpy(dstAtt, srcAtt, ATTRIBUTE_FIXED_PART_SIZE); |
288 | |
289 | /* |
290 | * Aside from updating the attno, we'd better reset attcacheoff. |
291 | * |
292 | * XXX Actually, to be entirely safe we'd need to reset the attcacheoff of |
293 | * all following columns in dst as well. Current usage scenarios don't |
294 | * require that though, because all following columns will get initialized |
295 | * by other uses of this function or TupleDescInitEntry. So we cheat a |
296 | * bit to avoid a useless O(N^2) penalty. |
297 | */ |
298 | dstAtt->attnum = dstAttno; |
299 | dstAtt->attcacheoff = -1; |
300 | |
301 | /* since we're not copying constraints or defaults, clear these */ |
302 | dstAtt->attnotnull = false; |
303 | dstAtt->atthasdef = false; |
304 | dstAtt->atthasmissing = false; |
305 | dstAtt->attidentity = '\0'; |
306 | dstAtt->attgenerated = '\0'; |
307 | } |
308 | |
309 | /* |
310 | * Free a TupleDesc including all substructure |
311 | */ |
312 | void |
313 | FreeTupleDesc(TupleDesc tupdesc) |
314 | { |
315 | int i; |
316 | |
317 | /* |
318 | * Possibly this should assert tdrefcount == 0, to disallow explicit |
319 | * freeing of un-refcounted tupdescs? |
320 | */ |
321 | Assert(tupdesc->tdrefcount <= 0); |
322 | |
323 | if (tupdesc->constr) |
324 | { |
325 | if (tupdesc->constr->num_defval > 0) |
326 | { |
327 | AttrDefault *attrdef = tupdesc->constr->defval; |
328 | |
329 | for (i = tupdesc->constr->num_defval - 1; i >= 0; i--) |
330 | { |
331 | if (attrdef[i].adbin) |
332 | pfree(attrdef[i].adbin); |
333 | } |
334 | pfree(attrdef); |
335 | } |
336 | if (tupdesc->constr->missing) |
337 | { |
338 | AttrMissing *attrmiss = tupdesc->constr->missing; |
339 | |
340 | for (i = tupdesc->natts - 1; i >= 0; i--) |
341 | { |
342 | if (attrmiss[i].am_present |
343 | && !TupleDescAttr(tupdesc, i)->attbyval) |
344 | pfree(DatumGetPointer(attrmiss[i].am_value)); |
345 | } |
346 | pfree(attrmiss); |
347 | } |
348 | if (tupdesc->constr->num_check > 0) |
349 | { |
350 | ConstrCheck *check = tupdesc->constr->check; |
351 | |
352 | for (i = tupdesc->constr->num_check - 1; i >= 0; i--) |
353 | { |
354 | if (check[i].ccname) |
355 | pfree(check[i].ccname); |
356 | if (check[i].ccbin) |
357 | pfree(check[i].ccbin); |
358 | } |
359 | pfree(check); |
360 | } |
361 | pfree(tupdesc->constr); |
362 | } |
363 | |
364 | pfree(tupdesc); |
365 | } |
366 | |
367 | /* |
368 | * Increment the reference count of a tupdesc, and log the reference in |
369 | * CurrentResourceOwner. |
370 | * |
371 | * Do not apply this to tupdescs that are not being refcounted. (Use the |
372 | * macro PinTupleDesc for tupdescs of uncertain status.) |
373 | */ |
374 | void |
375 | IncrTupleDescRefCount(TupleDesc tupdesc) |
376 | { |
377 | Assert(tupdesc->tdrefcount >= 0); |
378 | |
379 | ResourceOwnerEnlargeTupleDescs(CurrentResourceOwner); |
380 | tupdesc->tdrefcount++; |
381 | ResourceOwnerRememberTupleDesc(CurrentResourceOwner, tupdesc); |
382 | } |
383 | |
384 | /* |
385 | * Decrement the reference count of a tupdesc, remove the corresponding |
386 | * reference from CurrentResourceOwner, and free the tupdesc if no more |
387 | * references remain. |
388 | * |
389 | * Do not apply this to tupdescs that are not being refcounted. (Use the |
390 | * macro ReleaseTupleDesc for tupdescs of uncertain status.) |
391 | */ |
392 | void |
393 | DecrTupleDescRefCount(TupleDesc tupdesc) |
394 | { |
395 | Assert(tupdesc->tdrefcount > 0); |
396 | |
397 | ResourceOwnerForgetTupleDesc(CurrentResourceOwner, tupdesc); |
398 | if (--tupdesc->tdrefcount == 0) |
399 | FreeTupleDesc(tupdesc); |
400 | } |
401 | |
402 | /* |
403 | * Compare two TupleDesc structures for logical equality |
404 | * |
405 | * Note: we deliberately do not check the attrelid and tdtypmod fields. |
406 | * This allows typcache.c to use this routine to see if a cached record type |
407 | * matches a requested type, and is harmless for relcache.c's uses. |
408 | * We don't compare tdrefcount, either. |
409 | */ |
410 | bool |
411 | equalTupleDescs(TupleDesc tupdesc1, TupleDesc tupdesc2) |
412 | { |
413 | int i, |
414 | j, |
415 | n; |
416 | |
417 | if (tupdesc1->natts != tupdesc2->natts) |
418 | return false; |
419 | if (tupdesc1->tdtypeid != tupdesc2->tdtypeid) |
420 | return false; |
421 | |
422 | for (i = 0; i < tupdesc1->natts; i++) |
423 | { |
424 | Form_pg_attribute attr1 = TupleDescAttr(tupdesc1, i); |
425 | Form_pg_attribute attr2 = TupleDescAttr(tupdesc2, i); |
426 | |
427 | /* |
428 | * We do not need to check every single field here: we can disregard |
429 | * attrelid and attnum (which were used to place the row in the attrs |
430 | * array in the first place). It might look like we could dispense |
431 | * with checking attlen/attbyval/attalign, since these are derived |
432 | * from atttypid; but in the case of dropped columns we must check |
433 | * them (since atttypid will be zero for all dropped columns) and in |
434 | * general it seems safer to check them always. |
435 | * |
436 | * attcacheoff must NOT be checked since it's possibly not set in both |
437 | * copies. |
438 | */ |
439 | if (strcmp(NameStr(attr1->attname), NameStr(attr2->attname)) != 0) |
440 | return false; |
441 | if (attr1->atttypid != attr2->atttypid) |
442 | return false; |
443 | if (attr1->attstattarget != attr2->attstattarget) |
444 | return false; |
445 | if (attr1->attlen != attr2->attlen) |
446 | return false; |
447 | if (attr1->attndims != attr2->attndims) |
448 | return false; |
449 | if (attr1->atttypmod != attr2->atttypmod) |
450 | return false; |
451 | if (attr1->attbyval != attr2->attbyval) |
452 | return false; |
453 | if (attr1->attstorage != attr2->attstorage) |
454 | return false; |
455 | if (attr1->attalign != attr2->attalign) |
456 | return false; |
457 | if (attr1->attnotnull != attr2->attnotnull) |
458 | return false; |
459 | if (attr1->atthasdef != attr2->atthasdef) |
460 | return false; |
461 | if (attr1->attidentity != attr2->attidentity) |
462 | return false; |
463 | if (attr1->attgenerated != attr2->attgenerated) |
464 | return false; |
465 | if (attr1->attisdropped != attr2->attisdropped) |
466 | return false; |
467 | if (attr1->attislocal != attr2->attislocal) |
468 | return false; |
469 | if (attr1->attinhcount != attr2->attinhcount) |
470 | return false; |
471 | if (attr1->attcollation != attr2->attcollation) |
472 | return false; |
473 | /* attacl, attoptions and attfdwoptions are not even present... */ |
474 | } |
475 | |
476 | if (tupdesc1->constr != NULL) |
477 | { |
478 | TupleConstr *constr1 = tupdesc1->constr; |
479 | TupleConstr *constr2 = tupdesc2->constr; |
480 | |
481 | if (constr2 == NULL) |
482 | return false; |
483 | if (constr1->has_not_null != constr2->has_not_null) |
484 | return false; |
485 | if (constr1->has_generated_stored != constr2->has_generated_stored) |
486 | return false; |
487 | n = constr1->num_defval; |
488 | if (n != (int) constr2->num_defval) |
489 | return false; |
490 | for (i = 0; i < n; i++) |
491 | { |
492 | AttrDefault *defval1 = constr1->defval + i; |
493 | AttrDefault *defval2 = constr2->defval; |
494 | |
495 | /* |
496 | * We can't assume that the items are always read from the system |
497 | * catalogs in the same order; so use the adnum field to identify |
498 | * the matching item to compare. |
499 | */ |
500 | for (j = 0; j < n; defval2++, j++) |
501 | { |
502 | if (defval1->adnum == defval2->adnum) |
503 | break; |
504 | } |
505 | if (j >= n) |
506 | return false; |
507 | if (strcmp(defval1->adbin, defval2->adbin) != 0) |
508 | return false; |
509 | } |
510 | if (constr1->missing) |
511 | { |
512 | if (!constr2->missing) |
513 | return false; |
514 | for (i = 0; i < tupdesc1->natts; i++) |
515 | { |
516 | AttrMissing *missval1 = constr1->missing + i; |
517 | AttrMissing *missval2 = constr2->missing + i; |
518 | |
519 | if (missval1->am_present != missval2->am_present) |
520 | return false; |
521 | if (missval1->am_present) |
522 | { |
523 | Form_pg_attribute missatt1 = TupleDescAttr(tupdesc1, i); |
524 | |
525 | if (!datumIsEqual(missval1->am_value, missval2->am_value, |
526 | missatt1->attbyval, missatt1->attlen)) |
527 | return false; |
528 | } |
529 | } |
530 | } |
531 | else if (constr2->missing) |
532 | return false; |
533 | n = constr1->num_check; |
534 | if (n != (int) constr2->num_check) |
535 | return false; |
536 | for (i = 0; i < n; i++) |
537 | { |
538 | ConstrCheck *check1 = constr1->check + i; |
539 | ConstrCheck *check2 = constr2->check; |
540 | |
541 | /* |
542 | * Similarly, don't assume that the checks are always read in the |
543 | * same order; match them up by name and contents. (The name |
544 | * *should* be unique, but...) |
545 | */ |
546 | for (j = 0; j < n; check2++, j++) |
547 | { |
548 | if (strcmp(check1->ccname, check2->ccname) == 0 && |
549 | strcmp(check1->ccbin, check2->ccbin) == 0 && |
550 | check1->ccvalid == check2->ccvalid && |
551 | check1->ccnoinherit == check2->ccnoinherit) |
552 | break; |
553 | } |
554 | if (j >= n) |
555 | return false; |
556 | } |
557 | } |
558 | else if (tupdesc2->constr != NULL) |
559 | return false; |
560 | return true; |
561 | } |
562 | |
563 | /* |
564 | * hashTupleDesc |
565 | * Compute a hash value for a tuple descriptor. |
566 | * |
567 | * If two tuple descriptors would be considered equal by equalTupleDescs() |
568 | * then their hash value will be equal according to this function. |
569 | * |
570 | * Note that currently contents of constraint are not hashed - it'd be a bit |
571 | * painful to do so, and conflicts just due to constraints are unlikely. |
572 | */ |
573 | uint32 |
574 | hashTupleDesc(TupleDesc desc) |
575 | { |
576 | uint32 s; |
577 | int i; |
578 | |
579 | s = hash_combine(0, hash_uint32(desc->natts)); |
580 | s = hash_combine(s, hash_uint32(desc->tdtypeid)); |
581 | for (i = 0; i < desc->natts; ++i) |
582 | s = hash_combine(s, hash_uint32(TupleDescAttr(desc, i)->atttypid)); |
583 | |
584 | return s; |
585 | } |
586 | |
587 | /* |
588 | * TupleDescInitEntry |
589 | * This function initializes a single attribute structure in |
590 | * a previously allocated tuple descriptor. |
591 | * |
592 | * If attributeName is NULL, the attname field is set to an empty string |
593 | * (this is for cases where we don't know or need a name for the field). |
594 | * Also, some callers use this function to change the datatype-related fields |
595 | * in an existing tupdesc; they pass attributeName = NameStr(att->attname) |
596 | * to indicate that the attname field shouldn't be modified. |
597 | * |
598 | * Note that attcollation is set to the default for the specified datatype. |
599 | * If a nondefault collation is needed, insert it afterwards using |
600 | * TupleDescInitEntryCollation. |
601 | */ |
602 | void |
603 | TupleDescInitEntry(TupleDesc desc, |
604 | AttrNumber attributeNumber, |
605 | const char *attributeName, |
606 | Oid oidtypeid, |
607 | int32 typmod, |
608 | int attdim) |
609 | { |
610 | HeapTuple tuple; |
611 | Form_pg_type typeForm; |
612 | Form_pg_attribute att; |
613 | |
614 | /* |
615 | * sanity checks |
616 | */ |
617 | AssertArg(PointerIsValid(desc)); |
618 | AssertArg(attributeNumber >= 1); |
619 | AssertArg(attributeNumber <= desc->natts); |
620 | |
621 | /* |
622 | * initialize the attribute fields |
623 | */ |
624 | att = TupleDescAttr(desc, attributeNumber - 1); |
625 | |
626 | att->attrelid = 0; /* dummy value */ |
627 | |
628 | /* |
629 | * Note: attributeName can be NULL, because the planner doesn't always |
630 | * fill in valid resname values in targetlists, particularly for resjunk |
631 | * attributes. Also, do nothing if caller wants to re-use the old attname. |
632 | */ |
633 | if (attributeName == NULL) |
634 | MemSet(NameStr(att->attname), 0, NAMEDATALEN); |
635 | else if (attributeName != NameStr(att->attname)) |
636 | namestrcpy(&(att->attname), attributeName); |
637 | |
638 | att->attstattarget = -1; |
639 | att->attcacheoff = -1; |
640 | att->atttypmod = typmod; |
641 | |
642 | att->attnum = attributeNumber; |
643 | att->attndims = attdim; |
644 | |
645 | att->attnotnull = false; |
646 | att->atthasdef = false; |
647 | att->atthasmissing = false; |
648 | att->attidentity = '\0'; |
649 | att->attgenerated = '\0'; |
650 | att->attisdropped = false; |
651 | att->attislocal = true; |
652 | att->attinhcount = 0; |
653 | /* attacl, attoptions and attfdwoptions are not present in tupledescs */ |
654 | |
655 | tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(oidtypeid)); |
656 | if (!HeapTupleIsValid(tuple)) |
657 | elog(ERROR, "cache lookup failed for type %u" , oidtypeid); |
658 | typeForm = (Form_pg_type) GETSTRUCT(tuple); |
659 | |
660 | att->atttypid = oidtypeid; |
661 | att->attlen = typeForm->typlen; |
662 | att->attbyval = typeForm->typbyval; |
663 | att->attalign = typeForm->typalign; |
664 | att->attstorage = typeForm->typstorage; |
665 | att->attcollation = typeForm->typcollation; |
666 | |
667 | ReleaseSysCache(tuple); |
668 | } |
669 | |
670 | /* |
671 | * TupleDescInitBuiltinEntry |
672 | * Initialize a tuple descriptor without catalog access. Only |
673 | * a limited range of builtin types are supported. |
674 | */ |
675 | void |
676 | TupleDescInitBuiltinEntry(TupleDesc desc, |
677 | AttrNumber attributeNumber, |
678 | const char *attributeName, |
679 | Oid oidtypeid, |
680 | int32 typmod, |
681 | int attdim) |
682 | { |
683 | Form_pg_attribute att; |
684 | |
685 | /* sanity checks */ |
686 | AssertArg(PointerIsValid(desc)); |
687 | AssertArg(attributeNumber >= 1); |
688 | AssertArg(attributeNumber <= desc->natts); |
689 | |
690 | /* initialize the attribute fields */ |
691 | att = TupleDescAttr(desc, attributeNumber - 1); |
692 | att->attrelid = 0; /* dummy value */ |
693 | |
694 | /* unlike TupleDescInitEntry, we require an attribute name */ |
695 | Assert(attributeName != NULL); |
696 | namestrcpy(&(att->attname), attributeName); |
697 | |
698 | att->attstattarget = -1; |
699 | att->attcacheoff = -1; |
700 | att->atttypmod = typmod; |
701 | |
702 | att->attnum = attributeNumber; |
703 | att->attndims = attdim; |
704 | |
705 | att->attnotnull = false; |
706 | att->atthasdef = false; |
707 | att->atthasmissing = false; |
708 | att->attidentity = '\0'; |
709 | att->attgenerated = '\0'; |
710 | att->attisdropped = false; |
711 | att->attislocal = true; |
712 | att->attinhcount = 0; |
713 | /* attacl, attoptions and attfdwoptions are not present in tupledescs */ |
714 | |
715 | att->atttypid = oidtypeid; |
716 | |
717 | /* |
718 | * Our goal here is to support just enough types to let basic builtin |
719 | * commands work without catalog access - e.g. so that we can do certain |
720 | * things even in processes that are not connected to a database. |
721 | */ |
722 | switch (oidtypeid) |
723 | { |
724 | case TEXTOID: |
725 | case TEXTARRAYOID: |
726 | att->attlen = -1; |
727 | att->attbyval = false; |
728 | att->attalign = 'i'; |
729 | att->attstorage = 'x'; |
730 | att->attcollation = DEFAULT_COLLATION_OID; |
731 | break; |
732 | |
733 | case BOOLOID: |
734 | att->attlen = 1; |
735 | att->attbyval = true; |
736 | att->attalign = 'c'; |
737 | att->attstorage = 'p'; |
738 | att->attcollation = InvalidOid; |
739 | break; |
740 | |
741 | case INT4OID: |
742 | att->attlen = 4; |
743 | att->attbyval = true; |
744 | att->attalign = 'i'; |
745 | att->attstorage = 'p'; |
746 | att->attcollation = InvalidOid; |
747 | break; |
748 | |
749 | case INT8OID: |
750 | att->attlen = 8; |
751 | att->attbyval = FLOAT8PASSBYVAL; |
752 | att->attalign = 'd'; |
753 | att->attstorage = 'p'; |
754 | att->attcollation = InvalidOid; |
755 | break; |
756 | |
757 | default: |
758 | elog(ERROR, "unsupported type %u" , oidtypeid); |
759 | } |
760 | } |
761 | |
762 | /* |
763 | * TupleDescInitEntryCollation |
764 | * |
765 | * Assign a nondefault collation to a previously initialized tuple descriptor |
766 | * entry. |
767 | */ |
768 | void |
769 | TupleDescInitEntryCollation(TupleDesc desc, |
770 | AttrNumber attributeNumber, |
771 | Oid collationid) |
772 | { |
773 | /* |
774 | * sanity checks |
775 | */ |
776 | AssertArg(PointerIsValid(desc)); |
777 | AssertArg(attributeNumber >= 1); |
778 | AssertArg(attributeNumber <= desc->natts); |
779 | |
780 | TupleDescAttr(desc, attributeNumber - 1)->attcollation = collationid; |
781 | } |
782 | |
783 | |
784 | /* |
785 | * BuildDescForRelation |
786 | * |
787 | * Given a relation schema (list of ColumnDef nodes), build a TupleDesc. |
788 | * |
789 | * Note: the default assumption is no OIDs; caller may modify the returned |
790 | * TupleDesc if it wants OIDs. Also, tdtypeid will need to be filled in |
791 | * later on. |
792 | */ |
793 | TupleDesc |
794 | BuildDescForRelation(List *schema) |
795 | { |
796 | int natts; |
797 | AttrNumber attnum; |
798 | ListCell *l; |
799 | TupleDesc desc; |
800 | bool has_not_null; |
801 | char *attname; |
802 | Oid atttypid; |
803 | int32 atttypmod; |
804 | Oid attcollation; |
805 | int attdim; |
806 | |
807 | /* |
808 | * allocate a new tuple descriptor |
809 | */ |
810 | natts = list_length(schema); |
811 | desc = CreateTemplateTupleDesc(natts); |
812 | has_not_null = false; |
813 | |
814 | attnum = 0; |
815 | |
816 | foreach(l, schema) |
817 | { |
818 | ColumnDef *entry = lfirst(l); |
819 | AclResult aclresult; |
820 | Form_pg_attribute att; |
821 | |
822 | /* |
823 | * for each entry in the list, get the name and type information from |
824 | * the list and have TupleDescInitEntry fill in the attribute |
825 | * information we need. |
826 | */ |
827 | attnum++; |
828 | |
829 | attname = entry->colname; |
830 | typenameTypeIdAndMod(NULL, entry->typeName, &atttypid, &atttypmod); |
831 | |
832 | aclresult = pg_type_aclcheck(atttypid, GetUserId(), ACL_USAGE); |
833 | if (aclresult != ACLCHECK_OK) |
834 | aclcheck_error_type(aclresult, atttypid); |
835 | |
836 | attcollation = GetColumnDefCollation(NULL, entry, atttypid); |
837 | attdim = list_length(entry->typeName->arrayBounds); |
838 | |
839 | if (entry->typeName->setof) |
840 | ereport(ERROR, |
841 | (errcode(ERRCODE_INVALID_TABLE_DEFINITION), |
842 | errmsg("column \"%s\" cannot be declared SETOF" , |
843 | attname))); |
844 | |
845 | TupleDescInitEntry(desc, attnum, attname, |
846 | atttypid, atttypmod, attdim); |
847 | att = TupleDescAttr(desc, attnum - 1); |
848 | |
849 | /* Override TupleDescInitEntry's settings as requested */ |
850 | TupleDescInitEntryCollation(desc, attnum, attcollation); |
851 | if (entry->storage) |
852 | att->attstorage = entry->storage; |
853 | |
854 | /* Fill in additional stuff not handled by TupleDescInitEntry */ |
855 | att->attnotnull = entry->is_not_null; |
856 | has_not_null |= entry->is_not_null; |
857 | att->attislocal = entry->is_local; |
858 | att->attinhcount = entry->inhcount; |
859 | } |
860 | |
861 | if (has_not_null) |
862 | { |
863 | TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr)); |
864 | |
865 | constr->has_not_null = true; |
866 | constr->has_generated_stored = false; |
867 | constr->defval = NULL; |
868 | constr->missing = NULL; |
869 | constr->num_defval = 0; |
870 | constr->check = NULL; |
871 | constr->num_check = 0; |
872 | desc->constr = constr; |
873 | } |
874 | else |
875 | { |
876 | desc->constr = NULL; |
877 | } |
878 | |
879 | return desc; |
880 | } |
881 | |
882 | /* |
883 | * BuildDescFromLists |
884 | * |
885 | * Build a TupleDesc given lists of column names (as String nodes), |
886 | * column type OIDs, typmods, and collation OIDs. |
887 | * |
888 | * No constraints are generated. |
889 | * |
890 | * This is essentially a cut-down version of BuildDescForRelation for use |
891 | * with functions returning RECORD. |
892 | */ |
893 | TupleDesc |
894 | BuildDescFromLists(List *names, List *types, List *typmods, List *collations) |
895 | { |
896 | int natts; |
897 | AttrNumber attnum; |
898 | ListCell *l1; |
899 | ListCell *l2; |
900 | ListCell *l3; |
901 | ListCell *l4; |
902 | TupleDesc desc; |
903 | |
904 | natts = list_length(names); |
905 | Assert(natts == list_length(types)); |
906 | Assert(natts == list_length(typmods)); |
907 | Assert(natts == list_length(collations)); |
908 | |
909 | /* |
910 | * allocate a new tuple descriptor |
911 | */ |
912 | desc = CreateTemplateTupleDesc(natts); |
913 | |
914 | attnum = 0; |
915 | forfour(l1, names, l2, types, l3, typmods, l4, collations) |
916 | { |
917 | char *attname = strVal(lfirst(l1)); |
918 | Oid atttypid = lfirst_oid(l2); |
919 | int32 atttypmod = lfirst_int(l3); |
920 | Oid attcollation = lfirst_oid(l4); |
921 | |
922 | attnum++; |
923 | |
924 | TupleDescInitEntry(desc, attnum, attname, atttypid, atttypmod, 0); |
925 | TupleDescInitEntryCollation(desc, attnum, attcollation); |
926 | } |
927 | |
928 | return desc; |
929 | } |
930 | |