Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * parse_type.c
4 : * handle type operations for parser
5 : *
6 : * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/parser/parse_type.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : #include "postgres.h"
16 :
17 : #include "access/htup_details.h"
18 : #include "catalog/namespace.h"
19 : #include "catalog/pg_type.h"
20 : #include "lib/stringinfo.h"
21 : #include "nodes/makefuncs.h"
22 : #include "parser/parse_type.h"
23 : #include "parser/parser.h"
24 : #include "utils/array.h"
25 : #include "utils/builtins.h"
26 : #include "utils/lsyscache.h"
27 : #include "utils/syscache.h"
28 :
29 : static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
30 : Type typ);
31 :
32 :
33 : /*
34 : * LookupTypeName
35 : * Wrapper for typical case.
36 : */
37 : Type
38 688128 : LookupTypeName(ParseState *pstate, const TypeName *typeName,
39 : int32 *typmod_p, bool missing_ok)
40 : {
41 688128 : return LookupTypeNameExtended(pstate,
42 : typeName, typmod_p, true, missing_ok);
43 : }
44 :
45 : /*
46 : * LookupTypeNameExtended
47 : * Given a TypeName object, lookup the pg_type syscache entry of the type.
48 : * Returns NULL if no such type can be found. If the type is found,
49 : * the typmod value represented in the TypeName struct is computed and
50 : * stored into *typmod_p.
51 : *
52 : * NB: on success, the caller must ReleaseSysCache the type tuple when done
53 : * with it.
54 : *
55 : * NB: direct callers of this function MUST check typisdefined before assuming
56 : * that the type is fully valid. Most code should go through typenameType
57 : * or typenameTypeId instead.
58 : *
59 : * typmod_p can be passed as NULL if the caller does not care to know the
60 : * typmod value, but the typmod decoration (if any) will be validated anyway,
61 : * except in the case where the type is not found. Note that if the type is
62 : * found but is a shell, and there is typmod decoration, an error will be
63 : * thrown --- this is intentional.
64 : *
65 : * If temp_ok is false, ignore types in the temporary namespace. Pass false
66 : * when the caller will decide, using goodness of fit criteria, whether the
67 : * typeName is actually a type or something else. If typeName always denotes
68 : * a type (or denotes nothing), pass true.
69 : *
70 : * pstate is only used for error location info, and may be NULL.
71 : */
72 : Type
73 744790 : LookupTypeNameExtended(ParseState *pstate,
74 : const TypeName *typeName, int32 *typmod_p,
75 : bool temp_ok, bool missing_ok)
76 : {
77 : Oid typoid;
78 : HeapTuple tup;
79 : int32 typmod;
80 :
81 744790 : if (typeName->names == NIL)
82 : {
83 : /* We have the OID already if it's an internally generated TypeName */
84 170292 : typoid = typeName->typeOid;
85 : }
86 574498 : else if (typeName->pct_type)
87 : {
88 : /* Handle %TYPE reference to type of an existing field */
89 24 : RangeVar *rel = makeRangeVar(NULL, NULL, typeName->location);
90 24 : char *field = NULL;
91 : Oid relid;
92 : AttrNumber attnum;
93 :
94 : /* deconstruct the name list */
95 24 : switch (list_length(typeName->names))
96 : {
97 0 : case 1:
98 0 : ereport(ERROR,
99 : (errcode(ERRCODE_SYNTAX_ERROR),
100 : errmsg("improper %%TYPE reference (too few dotted names): %s",
101 : NameListToString(typeName->names)),
102 : parser_errposition(pstate, typeName->location)));
103 : break;
104 18 : case 2:
105 18 : rel->relname = strVal(linitial(typeName->names));
106 18 : field = strVal(lsecond(typeName->names));
107 18 : break;
108 6 : case 3:
109 6 : rel->schemaname = strVal(linitial(typeName->names));
110 6 : rel->relname = strVal(lsecond(typeName->names));
111 6 : field = strVal(lthird(typeName->names));
112 6 : break;
113 0 : case 4:
114 0 : rel->catalogname = strVal(linitial(typeName->names));
115 0 : rel->schemaname = strVal(lsecond(typeName->names));
116 0 : rel->relname = strVal(lthird(typeName->names));
117 0 : field = strVal(lfourth(typeName->names));
118 0 : break;
119 0 : default:
120 0 : ereport(ERROR,
121 : (errcode(ERRCODE_SYNTAX_ERROR),
122 : errmsg("improper %%TYPE reference (too many dotted names): %s",
123 : NameListToString(typeName->names)),
124 : parser_errposition(pstate, typeName->location)));
125 : break;
126 : }
127 :
128 : /*
129 : * Look up the field.
130 : *
131 : * XXX: As no lock is taken here, this might fail in the presence of
132 : * concurrent DDL. But taking a lock would carry a performance
133 : * penalty and would also require a permissions check.
134 : */
135 24 : relid = RangeVarGetRelid(rel, NoLock, missing_ok);
136 24 : attnum = get_attnum(relid, field);
137 24 : if (attnum == InvalidAttrNumber)
138 : {
139 0 : if (missing_ok)
140 0 : typoid = InvalidOid;
141 : else
142 0 : ereport(ERROR,
143 : (errcode(ERRCODE_UNDEFINED_COLUMN),
144 : errmsg("column \"%s\" of relation \"%s\" does not exist",
145 : field, rel->relname),
146 : parser_errposition(pstate, typeName->location)));
147 : }
148 : else
149 : {
150 24 : typoid = get_atttype(relid, attnum);
151 :
152 : /* this construct should never have an array indicator */
153 : Assert(typeName->arrayBounds == NIL);
154 :
155 : /* emit nuisance notice (intentionally not errposition'd) */
156 24 : ereport(NOTICE,
157 : (errmsg("type reference %s converted to %s",
158 : TypeNameToString(typeName),
159 : format_type_be(typoid))));
160 : }
161 : }
162 : else
163 : {
164 : /* Normal reference to a type name */
165 : char *schemaname;
166 : char *typname;
167 :
168 : /* deconstruct the name list */
169 574474 : DeconstructQualifiedName(typeName->names, &schemaname, &typname);
170 :
171 574462 : if (schemaname)
172 : {
173 : /* Look in specific schema only */
174 : Oid namespaceId;
175 : ParseCallbackState pcbstate;
176 :
177 245848 : setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
178 :
179 245848 : namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
180 245842 : if (OidIsValid(namespaceId))
181 245746 : typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
182 : PointerGetDatum(typname),
183 : ObjectIdGetDatum(namespaceId));
184 : else
185 96 : typoid = InvalidOid;
186 :
187 245842 : cancel_parser_errposition_callback(&pcbstate);
188 : }
189 : else
190 : {
191 : /* Unqualified type name, so search the search path */
192 328614 : typoid = TypenameGetTypidExtended(typname, temp_ok);
193 : }
194 :
195 : /* If an array reference, return the array type instead */
196 574456 : if (typeName->arrayBounds != NIL)
197 13100 : typoid = get_array_type(typoid);
198 : }
199 :
200 744772 : if (!OidIsValid(typoid))
201 : {
202 56420 : if (typmod_p)
203 44 : *typmod_p = -1;
204 56420 : return NULL;
205 : }
206 :
207 688352 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
208 688352 : if (!HeapTupleIsValid(tup)) /* should not happen */
209 0 : elog(ERROR, "cache lookup failed for type %u", typoid);
210 :
211 688352 : typmod = typenameTypeMod(pstate, typeName, (Type) tup);
212 :
213 688340 : if (typmod_p)
214 518800 : *typmod_p = typmod;
215 :
216 688340 : return (Type) tup;
217 : }
218 :
219 : /*
220 : * LookupTypeNameOid
221 : * Given a TypeName object, lookup the pg_type syscache entry of the type.
222 : * Returns InvalidOid if no such type can be found. If the type is found,
223 : * return its Oid.
224 : *
225 : * NB: direct callers of this function need to be aware that the type OID
226 : * returned may correspond to a shell type. Most code should go through
227 : * typenameTypeId instead.
228 : *
229 : * pstate is only used for error location info, and may be NULL.
230 : */
231 : Oid
232 21748 : LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
233 : {
234 : Oid typoid;
235 : Type tup;
236 :
237 21748 : tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
238 21748 : if (tup == NULL)
239 : {
240 180 : if (!missing_ok)
241 32 : ereport(ERROR,
242 : (errcode(ERRCODE_UNDEFINED_OBJECT),
243 : errmsg("type \"%s\" does not exist",
244 : TypeNameToString(typeName)),
245 : parser_errposition(pstate, typeName->location)));
246 :
247 148 : return InvalidOid;
248 : }
249 :
250 21568 : typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
251 21568 : ReleaseSysCache(tup);
252 :
253 21568 : return typoid;
254 : }
255 :
256 : /*
257 : * typenameType - given a TypeName, return a Type structure and typmod
258 : *
259 : * This is equivalent to LookupTypeName, except that this will report
260 : * a suitable error message if the type cannot be found or is not defined.
261 : * Callers of this can therefore assume the result is a fully valid type.
262 : */
263 : Type
264 589346 : typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
265 : {
266 : Type tup;
267 :
268 589346 : tup = LookupTypeName(pstate, typeName, typmod_p, false);
269 589340 : if (tup == NULL)
270 32 : ereport(ERROR,
271 : (errcode(ERRCODE_UNDEFINED_OBJECT),
272 : errmsg("type \"%s\" does not exist",
273 : TypeNameToString(typeName)),
274 : parser_errposition(pstate, typeName->location)));
275 589308 : if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
276 6 : ereport(ERROR,
277 : (errcode(ERRCODE_UNDEFINED_OBJECT),
278 : errmsg("type \"%s\" is only a shell",
279 : TypeNameToString(typeName)),
280 : parser_errposition(pstate, typeName->location)));
281 589302 : return tup;
282 : }
283 :
284 : /*
285 : * typenameTypeId - given a TypeName, return the type's OID
286 : *
287 : * This is similar to typenameType, but we only hand back the type OID
288 : * not the syscache entry.
289 : */
290 : Oid
291 10488 : typenameTypeId(ParseState *pstate, const TypeName *typeName)
292 : {
293 : Oid typoid;
294 : Type tup;
295 :
296 10488 : tup = typenameType(pstate, typeName, NULL);
297 10474 : typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
298 10474 : ReleaseSysCache(tup);
299 :
300 10474 : return typoid;
301 : }
302 :
303 : /*
304 : * typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
305 : *
306 : * This is equivalent to typenameType, but we only hand back the type OID
307 : * and typmod, not the syscache entry.
308 : */
309 : void
310 513308 : typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
311 : Oid *typeid_p, int32 *typmod_p)
312 : {
313 : Type tup;
314 :
315 513308 : tup = typenameType(pstate, typeName, typmod_p);
316 513304 : *typeid_p = ((Form_pg_type) GETSTRUCT(tup))->oid;
317 513304 : ReleaseSysCache(tup);
318 513304 : }
319 :
320 : /*
321 : * typenameTypeMod - given a TypeName, return the internal typmod value
322 : *
323 : * This will throw an error if the TypeName includes type modifiers that are
324 : * illegal for the data type.
325 : *
326 : * The actual type OID represented by the TypeName must already have been
327 : * looked up, and is passed as "typ".
328 : *
329 : * pstate is only used for error location info, and may be NULL.
330 : */
331 : static int32
332 688352 : typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
333 : {
334 : int32 result;
335 : Oid typmodin;
336 : Datum *datums;
337 : int n;
338 : ListCell *l;
339 : ArrayType *arrtypmod;
340 : ParseCallbackState pcbstate;
341 :
342 : /* Return prespecified typmod if no typmod expressions */
343 688352 : if (typeName->typmods == NIL)
344 680692 : return typeName->typemod;
345 :
346 : /*
347 : * Else, type had better accept typmods. We give a special error message
348 : * for the shell-type case, since a shell couldn't possibly have a
349 : * typmodin function.
350 : */
351 7660 : if (!((Form_pg_type) GETSTRUCT(typ))->typisdefined)
352 0 : ereport(ERROR,
353 : (errcode(ERRCODE_SYNTAX_ERROR),
354 : errmsg("type modifier cannot be specified for shell type \"%s\"",
355 : TypeNameToString(typeName)),
356 : parser_errposition(pstate, typeName->location)));
357 :
358 7660 : typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
359 :
360 7660 : if (typmodin == InvalidOid)
361 0 : ereport(ERROR,
362 : (errcode(ERRCODE_SYNTAX_ERROR),
363 : errmsg("type modifier is not allowed for type \"%s\"",
364 : TypeNameToString(typeName)),
365 : parser_errposition(pstate, typeName->location)));
366 :
367 : /*
368 : * Convert the list of raw-grammar-output expressions to a cstring array.
369 : * Currently, we allow simple numeric constants, string literals, and
370 : * identifiers; possibly this list could be extended.
371 : */
372 7660 : datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum));
373 7660 : n = 0;
374 17262 : foreach(l, typeName->typmods)
375 : {
376 9602 : Node *tm = (Node *) lfirst(l);
377 9602 : char *cstr = NULL;
378 :
379 9602 : if (IsA(tm, A_Const))
380 : {
381 9602 : A_Const *ac = (A_Const *) tm;
382 :
383 9602 : if (IsA(&ac->val, Integer))
384 : {
385 9602 : cstr = psprintf("%ld", (long) intVal(&ac->val));
386 : }
387 0 : else if (IsA(&ac->val, Float))
388 : {
389 : /* we can just use the string representation directly. */
390 0 : cstr = ac->val.fval.fval;
391 : }
392 0 : else if (IsA(&ac->val, String))
393 : {
394 : /* we can just use the string representation directly. */
395 0 : cstr = strVal(&ac->val);
396 : }
397 : }
398 0 : else if (IsA(tm, ColumnRef))
399 : {
400 0 : ColumnRef *cr = (ColumnRef *) tm;
401 :
402 0 : if (list_length(cr->fields) == 1 &&
403 0 : IsA(linitial(cr->fields), String))
404 0 : cstr = strVal(linitial(cr->fields));
405 : }
406 9602 : if (!cstr)
407 0 : ereport(ERROR,
408 : (errcode(ERRCODE_SYNTAX_ERROR),
409 : errmsg("type modifiers must be simple constants or identifiers"),
410 : parser_errposition(pstate, typeName->location)));
411 9602 : datums[n++] = CStringGetDatum(cstr);
412 : }
413 :
414 7660 : arrtypmod = construct_array_builtin(datums, n, CSTRINGOID);
415 :
416 : /* arrange to report location if type's typmodin function fails */
417 7660 : setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
418 :
419 7660 : result = DatumGetInt32(OidFunctionCall1(typmodin,
420 : PointerGetDatum(arrtypmod)));
421 :
422 7648 : cancel_parser_errposition_callback(&pcbstate);
423 :
424 7648 : pfree(datums);
425 7648 : pfree(arrtypmod);
426 :
427 7648 : return result;
428 : }
429 :
430 : /*
431 : * appendTypeNameToBuffer
432 : * Append a string representing the name of a TypeName to a StringInfo.
433 : * This is the shared guts of TypeNameToString and TypeNameListToString.
434 : *
435 : * NB: this must work on TypeNames that do not describe any actual type;
436 : * it is mostly used for reporting lookup errors.
437 : */
438 : static void
439 5994 : appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
440 : {
441 5994 : if (typeName->names != NIL)
442 : {
443 : /* Emit possibly-qualified name as-is */
444 : ListCell *l;
445 :
446 12198 : foreach(l, typeName->names)
447 : {
448 6204 : if (l != list_head(typeName->names))
449 210 : appendStringInfoChar(string, '.');
450 6204 : appendStringInfoString(string, strVal(lfirst(l)));
451 : }
452 : }
453 : else
454 : {
455 : /* Look up internally-specified type */
456 0 : appendStringInfoString(string, format_type_be(typeName->typeOid));
457 : }
458 :
459 : /*
460 : * Add decoration as needed, but only for fields considered by
461 : * LookupTypeName
462 : */
463 5994 : if (typeName->pct_type)
464 24 : appendStringInfoString(string, "%TYPE");
465 :
466 5994 : if (typeName->arrayBounds != NIL)
467 6 : appendStringInfoString(string, "[]");
468 5994 : }
469 :
470 : /*
471 : * TypeNameToString
472 : * Produce a string representing the name of a TypeName.
473 : *
474 : * NB: this must work on TypeNames that do not describe any actual type;
475 : * it is mostly used for reporting lookup errors.
476 : */
477 : char *
478 5970 : TypeNameToString(const TypeName *typeName)
479 : {
480 : StringInfoData string;
481 :
482 5970 : initStringInfo(&string);
483 5970 : appendTypeNameToBuffer(typeName, &string);
484 5970 : return string.data;
485 : }
486 :
487 : /*
488 : * TypeNameListToString
489 : * Produce a string representing the name(s) of a List of TypeNames
490 : */
491 : char *
492 40 : TypeNameListToString(List *typenames)
493 : {
494 : StringInfoData string;
495 : ListCell *l;
496 :
497 40 : initStringInfo(&string);
498 64 : foreach(l, typenames)
499 : {
500 24 : TypeName *typeName = lfirst_node(TypeName, l);
501 :
502 24 : if (l != list_head(typenames))
503 12 : appendStringInfoChar(&string, ',');
504 24 : appendTypeNameToBuffer(typeName, &string);
505 : }
506 40 : return string.data;
507 : }
508 :
509 : /*
510 : * LookupCollation
511 : *
512 : * Look up collation by name, return OID, with support for error location.
513 : */
514 : Oid
515 9164 : LookupCollation(ParseState *pstate, List *collnames, int location)
516 : {
517 : Oid colloid;
518 : ParseCallbackState pcbstate;
519 :
520 9164 : if (pstate)
521 8706 : setup_parser_errposition_callback(&pcbstate, pstate, location);
522 :
523 9164 : colloid = get_collation_oid(collnames, false);
524 :
525 9152 : if (pstate)
526 8694 : cancel_parser_errposition_callback(&pcbstate);
527 :
528 9152 : return colloid;
529 : }
530 :
531 : /*
532 : * GetColumnDefCollation
533 : *
534 : * Get the collation to be used for a column being defined, given the
535 : * ColumnDef node and the previously-determined column type OID.
536 : *
537 : * pstate is only used for error location purposes, and can be NULL.
538 : */
539 : Oid
540 235980 : GetColumnDefCollation(ParseState *pstate, const ColumnDef *coldef, Oid typeOid)
541 : {
542 : Oid result;
543 235980 : Oid typcollation = get_typcollation(typeOid);
544 235980 : int location = coldef->location;
545 :
546 235980 : if (coldef->collClause)
547 : {
548 : /* We have a raw COLLATE clause, so look up the collation */
549 458 : location = coldef->collClause->location;
550 458 : result = LookupCollation(pstate, coldef->collClause->collname,
551 : location);
552 : }
553 235522 : else if (OidIsValid(coldef->collOid))
554 : {
555 : /* Precooked collation spec, use that */
556 79048 : result = coldef->collOid;
557 : }
558 : else
559 : {
560 : /* Use the type's default collation if any */
561 156474 : result = typcollation;
562 : }
563 :
564 : /* Complain if COLLATE is applied to an uncollatable type */
565 235980 : if (OidIsValid(result) && !OidIsValid(typcollation))
566 0 : ereport(ERROR,
567 : (errcode(ERRCODE_DATATYPE_MISMATCH),
568 : errmsg("collations are not supported by type %s",
569 : format_type_be(typeOid)),
570 : parser_errposition(pstate, location)));
571 :
572 235980 : return result;
573 : }
574 :
575 : /* return a Type structure, given a type id */
576 : /* NB: caller must ReleaseSysCache the type tuple when done with it */
577 : Type
578 681998 : typeidType(Oid id)
579 : {
580 : HeapTuple tup;
581 :
582 681998 : tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id));
583 681998 : if (!HeapTupleIsValid(tup))
584 0 : elog(ERROR, "cache lookup failed for type %u", id);
585 681998 : return (Type) tup;
586 : }
587 :
588 : /* given type (as type struct), return the type OID */
589 : Oid
590 74224 : typeTypeId(Type tp)
591 : {
592 74224 : if (tp == NULL) /* probably useless */
593 0 : elog(ERROR, "typeTypeId() called with NULL type struct");
594 74224 : return ((Form_pg_type) GETSTRUCT(tp))->oid;
595 : }
596 :
597 : /* given type (as type struct), return the length of type */
598 : int16
599 663316 : typeLen(Type t)
600 : {
601 : Form_pg_type typ;
602 :
603 663316 : typ = (Form_pg_type) GETSTRUCT(t);
604 663316 : return typ->typlen;
605 : }
606 :
607 : /* given type (as type struct), return its 'byval' attribute */
608 : bool
609 663316 : typeByVal(Type t)
610 : {
611 : Form_pg_type typ;
612 :
613 663316 : typ = (Form_pg_type) GETSTRUCT(t);
614 663316 : return typ->typbyval;
615 : }
616 :
617 : /* given type (as type struct), return the type's name */
618 : char *
619 0 : typeTypeName(Type t)
620 : {
621 : Form_pg_type typ;
622 :
623 0 : typ = (Form_pg_type) GETSTRUCT(t);
624 : /* pstrdup here because result may need to outlive the syscache entry */
625 0 : return pstrdup(NameStr(typ->typname));
626 : }
627 :
628 : /* given type (as type struct), return its 'typrelid' attribute */
629 : Oid
630 672 : typeTypeRelid(Type typ)
631 : {
632 : Form_pg_type typtup;
633 :
634 672 : typtup = (Form_pg_type) GETSTRUCT(typ);
635 672 : return typtup->typrelid;
636 : }
637 :
638 : /* given type (as type struct), return its 'typcollation' attribute */
639 : Oid
640 663316 : typeTypeCollation(Type typ)
641 : {
642 : Form_pg_type typtup;
643 :
644 663316 : typtup = (Form_pg_type) GETSTRUCT(typ);
645 663316 : return typtup->typcollation;
646 : }
647 :
648 : /*
649 : * Given a type structure and a string, returns the internal representation
650 : * of that string. The "string" can be NULL to perform conversion of a NULL
651 : * (which might result in failure, if the input function rejects NULLs).
652 : */
653 : Datum
654 663316 : stringTypeDatum(Type tp, char *string, int32 atttypmod)
655 : {
656 663316 : Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
657 663316 : Oid typinput = typform->typinput;
658 663316 : Oid typioparam = getTypeIOParam(tp);
659 :
660 663316 : return OidInputFunctionCall(typinput, string, typioparam, atttypmod);
661 : }
662 :
663 : /*
664 : * Given a typeid, return the type's typrelid (associated relation), if any.
665 : * Returns InvalidOid if type is not a composite type.
666 : */
667 : Oid
668 13244 : typeidTypeRelid(Oid type_id)
669 : {
670 : HeapTuple typeTuple;
671 : Form_pg_type type;
672 : Oid result;
673 :
674 13244 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
675 13244 : if (!HeapTupleIsValid(typeTuple))
676 0 : elog(ERROR, "cache lookup failed for type %u", type_id);
677 13244 : type = (Form_pg_type) GETSTRUCT(typeTuple);
678 13244 : result = type->typrelid;
679 13244 : ReleaseSysCache(typeTuple);
680 13244 : return result;
681 : }
682 :
683 : /*
684 : * Given a typeid, return the type's typrelid (associated relation), if any.
685 : * Returns InvalidOid if type is not a composite type or a domain over one.
686 : * This is the same as typeidTypeRelid(getBaseType(type_id)), but faster.
687 : */
688 : Oid
689 1553438 : typeOrDomainTypeRelid(Oid type_id)
690 : {
691 : HeapTuple typeTuple;
692 : Form_pg_type type;
693 : Oid result;
694 :
695 : for (;;)
696 : {
697 1553438 : typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
698 1553438 : if (!HeapTupleIsValid(typeTuple))
699 0 : elog(ERROR, "cache lookup failed for type %u", type_id);
700 1553438 : type = (Form_pg_type) GETSTRUCT(typeTuple);
701 1553438 : if (type->typtype != TYPTYPE_DOMAIN)
702 : {
703 : /* Not a domain, so done looking through domains */
704 1496912 : break;
705 : }
706 : /* It is a domain, so examine the base type instead */
707 56526 : type_id = type->typbasetype;
708 56526 : ReleaseSysCache(typeTuple);
709 : }
710 1496912 : result = type->typrelid;
711 1496912 : ReleaseSysCache(typeTuple);
712 1496912 : return result;
713 : }
714 :
715 : /*
716 : * error context callback for parse failure during parseTypeString()
717 : */
718 : static void
719 6 : pts_error_callback(void *arg)
720 : {
721 6 : const char *str = (const char *) arg;
722 :
723 6 : errcontext("invalid type name \"%s\"", str);
724 6 : }
725 :
726 : /*
727 : * Given a string that is supposed to be a SQL-compatible type declaration,
728 : * such as "int4" or "integer" or "character varying(32)", parse
729 : * the string and return the result as a TypeName.
730 : *
731 : * If the string cannot be parsed as a type, an error is raised,
732 : * unless escontext is an ErrorSaveContext node, in which case we may
733 : * fill that and return NULL. But note that the ErrorSaveContext option
734 : * is mostly aspirational at present: errors detected by the main
735 : * grammar, rather than here, will still be thrown.
736 : */
737 : TypeName *
738 9538 : typeStringToTypeName(const char *str, Node *escontext)
739 : {
740 : List *raw_parsetree_list;
741 : TypeName *typeName;
742 : ErrorContextCallback ptserrcontext;
743 :
744 : /* make sure we give useful error for empty input */
745 9538 : if (strspn(str, " \t\n\r\f\v") == strlen(str))
746 0 : goto fail;
747 :
748 : /*
749 : * Setup error traceback support in case of ereport() during parse
750 : */
751 9538 : ptserrcontext.callback = pts_error_callback;
752 9538 : ptserrcontext.arg = unconstify(char *, str);
753 9538 : ptserrcontext.previous = error_context_stack;
754 9538 : error_context_stack = &ptserrcontext;
755 :
756 9538 : raw_parsetree_list = raw_parser(str, RAW_PARSE_TYPE_NAME);
757 :
758 9532 : error_context_stack = ptserrcontext.previous;
759 :
760 : /* We should get back exactly one TypeName node. */
761 : Assert(list_length(raw_parsetree_list) == 1);
762 9532 : typeName = linitial_node(TypeName, raw_parsetree_list);
763 :
764 : /* The grammar allows SETOF in TypeName, but we don't want that here. */
765 9532 : if (typeName->setof)
766 0 : goto fail;
767 :
768 9532 : return typeName;
769 :
770 0 : fail:
771 0 : ereturn(escontext, NULL,
772 : (errcode(ERRCODE_SYNTAX_ERROR),
773 : errmsg("invalid type name \"%s\"", str)));
774 : }
775 :
776 : /*
777 : * Given a string that is supposed to be a SQL-compatible type declaration,
778 : * such as "int4" or "integer" or "character varying(32)", parse
779 : * the string and convert it to a type OID and type modifier.
780 : *
781 : * If escontext is an ErrorSaveContext node, then errors are reported by
782 : * filling escontext and returning false, instead of throwing them.
783 : */
784 : bool
785 3352 : parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
786 : Node *escontext)
787 : {
788 : TypeName *typeName;
789 : Type tup;
790 :
791 3352 : typeName = typeStringToTypeName(str, escontext);
792 3346 : if (typeName == NULL)
793 0 : return false;
794 :
795 3346 : tup = LookupTypeName(NULL, typeName, typmod_p,
796 3346 : (escontext && IsA(escontext, ErrorSaveContext)));
797 3322 : if (tup == NULL)
798 : {
799 40 : ereturn(escontext, false,
800 : (errcode(ERRCODE_UNDEFINED_OBJECT),
801 : errmsg("type \"%s\" does not exist",
802 : TypeNameToString(typeName))));
803 : }
804 : else
805 : {
806 3282 : Form_pg_type typ = (Form_pg_type) GETSTRUCT(tup);
807 :
808 3282 : if (!typ->typisdefined)
809 : {
810 0 : ReleaseSysCache(tup);
811 0 : ereturn(escontext, false,
812 : (errcode(ERRCODE_UNDEFINED_OBJECT),
813 : errmsg("type \"%s\" is only a shell",
814 : TypeNameToString(typeName))));
815 : }
816 3282 : *typeid_p = typ->oid;
817 3282 : ReleaseSysCache(tup);
818 : }
819 :
820 3282 : return true;
821 : }
|