1 /*-------------------------------------------------------------------------
2 *
3 * parse_type.c
4 * handle type operations for parser
5 *
6 * Portions Copyright (c) 1996-2021, 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
LookupTypeName(ParseState * pstate,const TypeName * typeName,int32 * typmod_p,bool missing_ok)38 LookupTypeName(ParseState *pstate, const TypeName *typeName,
39 int32 *typmod_p, bool missing_ok)
40 {
41 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
LookupTypeNameExtended(ParseState * pstate,const TypeName * typeName,int32 * typmod_p,bool temp_ok,bool missing_ok)73 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 if (typeName->names == NIL)
82 {
83 /* We have the OID already if it's an internally generated TypeName */
84 typoid = typeName->typeOid;
85 }
86 else if (typeName->pct_type)
87 {
88 /* Handle %TYPE reference to type of an existing field */
89 RangeVar *rel = makeRangeVar(NULL, NULL, typeName->location);
90 char *field = NULL;
91 Oid relid;
92 AttrNumber attnum;
93
94 /* deconstruct the name list */
95 switch (list_length(typeName->names))
96 {
97 case 1:
98 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 case 2:
105 rel->relname = strVal(linitial(typeName->names));
106 field = strVal(lsecond(typeName->names));
107 break;
108 case 3:
109 rel->schemaname = strVal(linitial(typeName->names));
110 rel->relname = strVal(lsecond(typeName->names));
111 field = strVal(lthird(typeName->names));
112 break;
113 case 4:
114 rel->catalogname = strVal(linitial(typeName->names));
115 rel->schemaname = strVal(lsecond(typeName->names));
116 rel->relname = strVal(lthird(typeName->names));
117 field = strVal(lfourth(typeName->names));
118 break;
119 default:
120 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 relid = RangeVarGetRelid(rel, NoLock, missing_ok);
136 attnum = get_attnum(relid, field);
137 if (attnum == InvalidAttrNumber)
138 {
139 if (missing_ok)
140 typoid = InvalidOid;
141 else
142 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 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 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 DeconstructQualifiedName(typeName->names, &schemaname, &typname);
170
171 if (schemaname)
172 {
173 /* Look in specific schema only */
174 Oid namespaceId;
175 ParseCallbackState pcbstate;
176
177 setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
178
179 namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
180 if (OidIsValid(namespaceId))
181 typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
182 PointerGetDatum(typname),
183 ObjectIdGetDatum(namespaceId));
184 else
185 typoid = InvalidOid;
186
187 cancel_parser_errposition_callback(&pcbstate);
188 }
189 else
190 {
191 /* Unqualified type name, so search the search path */
192 typoid = TypenameGetTypidExtended(typname, temp_ok);
193 }
194
195 /* If an array reference, return the array type instead */
196 if (typeName->arrayBounds != NIL)
197 typoid = get_array_type(typoid);
198 }
199
200 if (!OidIsValid(typoid))
201 {
202 if (typmod_p)
203 *typmod_p = -1;
204 return NULL;
205 }
206
207 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
208 if (!HeapTupleIsValid(tup)) /* should not happen */
209 elog(ERROR, "cache lookup failed for type %u", typoid);
210
211 typmod = typenameTypeMod(pstate, typeName, (Type) tup);
212
213 if (typmod_p)
214 *typmod_p = typmod;
215
216 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
LookupTypeNameOid(ParseState * pstate,const TypeName * typeName,bool missing_ok)232 LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
233 {
234 Oid typoid;
235 Type tup;
236
237 tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
238 if (tup == NULL)
239 {
240 if (!missing_ok)
241 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 return InvalidOid;
248 }
249
250 typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
251 ReleaseSysCache(tup);
252
253 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
typenameType(ParseState * pstate,const TypeName * typeName,int32 * typmod_p)264 typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
265 {
266 Type tup;
267
268 tup = LookupTypeName(pstate, typeName, typmod_p, false);
269 if (tup == NULL)
270 ereport(ERROR,
271 (errcode(ERRCODE_UNDEFINED_OBJECT),
272 errmsg("type \"%s\" does not exist",
273 TypeNameToString(typeName)),
274 parser_errposition(pstate, typeName->location)));
275 if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
276 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 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
typenameTypeId(ParseState * pstate,const TypeName * typeName)291 typenameTypeId(ParseState *pstate, const TypeName *typeName)
292 {
293 Oid typoid;
294 Type tup;
295
296 tup = typenameType(pstate, typeName, NULL);
297 typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
298 ReleaseSysCache(tup);
299
300 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
typenameTypeIdAndMod(ParseState * pstate,const TypeName * typeName,Oid * typeid_p,int32 * typmod_p)310 typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
311 Oid *typeid_p, int32 *typmod_p)
312 {
313 Type tup;
314
315 tup = typenameType(pstate, typeName, typmod_p);
316 *typeid_p = ((Form_pg_type) GETSTRUCT(tup))->oid;
317 ReleaseSysCache(tup);
318 }
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
typenameTypeMod(ParseState * pstate,const TypeName * typeName,Type typ)332 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 if (typeName->typmods == NIL)
344 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 if (!((Form_pg_type) GETSTRUCT(typ))->typisdefined)
352 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 typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
359
360 if (typmodin == InvalidOid)
361 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 datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum));
373 n = 0;
374 foreach(l, typeName->typmods)
375 {
376 Node *tm = (Node *) lfirst(l);
377 char *cstr = NULL;
378
379 if (IsA(tm, A_Const))
380 {
381 A_Const *ac = (A_Const *) tm;
382
383 if (IsA(&ac->val, Integer))
384 {
385 cstr = psprintf("%ld", (long) ac->val.val.ival);
386 }
387 else if (IsA(&ac->val, Float) ||
388 IsA(&ac->val, String))
389 {
390 /* we can just use the str field directly. */
391 cstr = ac->val.val.str;
392 }
393 }
394 else if (IsA(tm, ColumnRef))
395 {
396 ColumnRef *cr = (ColumnRef *) tm;
397
398 if (list_length(cr->fields) == 1 &&
399 IsA(linitial(cr->fields), String))
400 cstr = strVal(linitial(cr->fields));
401 }
402 if (!cstr)
403 ereport(ERROR,
404 (errcode(ERRCODE_SYNTAX_ERROR),
405 errmsg("type modifiers must be simple constants or identifiers"),
406 parser_errposition(pstate, typeName->location)));
407 datums[n++] = CStringGetDatum(cstr);
408 }
409
410 /* hardwired knowledge about cstring's representation details here */
411 arrtypmod = construct_array(datums, n, CSTRINGOID,
412 -2, false, TYPALIGN_CHAR);
413
414 /* arrange to report location if type's typmodin function fails */
415 setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
416
417 result = DatumGetInt32(OidFunctionCall1(typmodin,
418 PointerGetDatum(arrtypmod)));
419
420 cancel_parser_errposition_callback(&pcbstate);
421
422 pfree(datums);
423 pfree(arrtypmod);
424
425 return result;
426 }
427
428 /*
429 * appendTypeNameToBuffer
430 * Append a string representing the name of a TypeName to a StringInfo.
431 * This is the shared guts of TypeNameToString and TypeNameListToString.
432 *
433 * NB: this must work on TypeNames that do not describe any actual type;
434 * it is mostly used for reporting lookup errors.
435 */
436 static void
appendTypeNameToBuffer(const TypeName * typeName,StringInfo string)437 appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
438 {
439 if (typeName->names != NIL)
440 {
441 /* Emit possibly-qualified name as-is */
442 ListCell *l;
443
444 foreach(l, typeName->names)
445 {
446 if (l != list_head(typeName->names))
447 appendStringInfoChar(string, '.');
448 appendStringInfoString(string, strVal(lfirst(l)));
449 }
450 }
451 else
452 {
453 /* Look up internally-specified type */
454 appendStringInfoString(string, format_type_be(typeName->typeOid));
455 }
456
457 /*
458 * Add decoration as needed, but only for fields considered by
459 * LookupTypeName
460 */
461 if (typeName->pct_type)
462 appendStringInfoString(string, "%TYPE");
463
464 if (typeName->arrayBounds != NIL)
465 appendStringInfoString(string, "[]");
466 }
467
468 /*
469 * TypeNameToString
470 * Produce a string representing the name of a TypeName.
471 *
472 * NB: this must work on TypeNames that do not describe any actual type;
473 * it is mostly used for reporting lookup errors.
474 */
475 char *
TypeNameToString(const TypeName * typeName)476 TypeNameToString(const TypeName *typeName)
477 {
478 StringInfoData string;
479
480 initStringInfo(&string);
481 appendTypeNameToBuffer(typeName, &string);
482 return string.data;
483 }
484
485 /*
486 * TypeNameListToString
487 * Produce a string representing the name(s) of a List of TypeNames
488 */
489 char *
TypeNameListToString(List * typenames)490 TypeNameListToString(List *typenames)
491 {
492 StringInfoData string;
493 ListCell *l;
494
495 initStringInfo(&string);
496 foreach(l, typenames)
497 {
498 TypeName *typeName = lfirst_node(TypeName, l);
499
500 if (l != list_head(typenames))
501 appendStringInfoChar(&string, ',');
502 appendTypeNameToBuffer(typeName, &string);
503 }
504 return string.data;
505 }
506
507 /*
508 * LookupCollation
509 *
510 * Look up collation by name, return OID, with support for error location.
511 */
512 Oid
LookupCollation(ParseState * pstate,List * collnames,int location)513 LookupCollation(ParseState *pstate, List *collnames, int location)
514 {
515 Oid colloid;
516 ParseCallbackState pcbstate;
517
518 if (pstate)
519 setup_parser_errposition_callback(&pcbstate, pstate, location);
520
521 colloid = get_collation_oid(collnames, false);
522
523 if (pstate)
524 cancel_parser_errposition_callback(&pcbstate);
525
526 return colloid;
527 }
528
529 /*
530 * GetColumnDefCollation
531 *
532 * Get the collation to be used for a column being defined, given the
533 * ColumnDef node and the previously-determined column type OID.
534 *
535 * pstate is only used for error location purposes, and can be NULL.
536 */
537 Oid
GetColumnDefCollation(ParseState * pstate,ColumnDef * coldef,Oid typeOid)538 GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
539 {
540 Oid result;
541 Oid typcollation = get_typcollation(typeOid);
542 int location = coldef->location;
543
544 if (coldef->collClause)
545 {
546 /* We have a raw COLLATE clause, so look up the collation */
547 location = coldef->collClause->location;
548 result = LookupCollation(pstate, coldef->collClause->collname,
549 location);
550 }
551 else if (OidIsValid(coldef->collOid))
552 {
553 /* Precooked collation spec, use that */
554 result = coldef->collOid;
555 }
556 else
557 {
558 /* Use the type's default collation if any */
559 result = typcollation;
560 }
561
562 /* Complain if COLLATE is applied to an uncollatable type */
563 if (OidIsValid(result) && !OidIsValid(typcollation))
564 ereport(ERROR,
565 (errcode(ERRCODE_DATATYPE_MISMATCH),
566 errmsg("collations are not supported by type %s",
567 format_type_be(typeOid)),
568 parser_errposition(pstate, location)));
569
570 return result;
571 }
572
573 /* return a Type structure, given a type id */
574 /* NB: caller must ReleaseSysCache the type tuple when done with it */
575 Type
typeidType(Oid id)576 typeidType(Oid id)
577 {
578 HeapTuple tup;
579
580 tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id));
581 if (!HeapTupleIsValid(tup))
582 elog(ERROR, "cache lookup failed for type %u", id);
583 return (Type) tup;
584 }
585
586 /* given type (as type struct), return the type OID */
587 Oid
typeTypeId(Type tp)588 typeTypeId(Type tp)
589 {
590 if (tp == NULL) /* probably useless */
591 elog(ERROR, "typeTypeId() called with NULL type struct");
592 return ((Form_pg_type) GETSTRUCT(tp))->oid;
593 }
594
595 /* given type (as type struct), return the length of type */
596 int16
typeLen(Type t)597 typeLen(Type t)
598 {
599 Form_pg_type typ;
600
601 typ = (Form_pg_type) GETSTRUCT(t);
602 return typ->typlen;
603 }
604
605 /* given type (as type struct), return its 'byval' attribute */
606 bool
typeByVal(Type t)607 typeByVal(Type t)
608 {
609 Form_pg_type typ;
610
611 typ = (Form_pg_type) GETSTRUCT(t);
612 return typ->typbyval;
613 }
614
615 /* given type (as type struct), return the type's name */
616 char *
typeTypeName(Type t)617 typeTypeName(Type t)
618 {
619 Form_pg_type typ;
620
621 typ = (Form_pg_type) GETSTRUCT(t);
622 /* pstrdup here because result may need to outlive the syscache entry */
623 return pstrdup(NameStr(typ->typname));
624 }
625
626 /* given type (as type struct), return its 'typrelid' attribute */
627 Oid
typeTypeRelid(Type typ)628 typeTypeRelid(Type typ)
629 {
630 Form_pg_type typtup;
631
632 typtup = (Form_pg_type) GETSTRUCT(typ);
633 return typtup->typrelid;
634 }
635
636 /* given type (as type struct), return its 'typcollation' attribute */
637 Oid
typeTypeCollation(Type typ)638 typeTypeCollation(Type typ)
639 {
640 Form_pg_type typtup;
641
642 typtup = (Form_pg_type) GETSTRUCT(typ);
643 return typtup->typcollation;
644 }
645
646 /*
647 * Given a type structure and a string, returns the internal representation
648 * of that string. The "string" can be NULL to perform conversion of a NULL
649 * (which might result in failure, if the input function rejects NULLs).
650 */
651 Datum
stringTypeDatum(Type tp,char * string,int32 atttypmod)652 stringTypeDatum(Type tp, char *string, int32 atttypmod)
653 {
654 Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
655 Oid typinput = typform->typinput;
656 Oid typioparam = getTypeIOParam(tp);
657
658 return OidInputFunctionCall(typinput, string, typioparam, atttypmod);
659 }
660
661 /*
662 * Given a typeid, return the type's typrelid (associated relation), if any.
663 * Returns InvalidOid if type is not a composite type.
664 */
665 Oid
typeidTypeRelid(Oid type_id)666 typeidTypeRelid(Oid type_id)
667 {
668 HeapTuple typeTuple;
669 Form_pg_type type;
670 Oid result;
671
672 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
673 if (!HeapTupleIsValid(typeTuple))
674 elog(ERROR, "cache lookup failed for type %u", type_id);
675 type = (Form_pg_type) GETSTRUCT(typeTuple);
676 result = type->typrelid;
677 ReleaseSysCache(typeTuple);
678 return result;
679 }
680
681 /*
682 * Given a typeid, return the type's typrelid (associated relation), if any.
683 * Returns InvalidOid if type is not a composite type or a domain over one.
684 * This is the same as typeidTypeRelid(getBaseType(type_id)), but faster.
685 */
686 Oid
typeOrDomainTypeRelid(Oid type_id)687 typeOrDomainTypeRelid(Oid type_id)
688 {
689 HeapTuple typeTuple;
690 Form_pg_type type;
691 Oid result;
692
693 for (;;)
694 {
695 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
696 if (!HeapTupleIsValid(typeTuple))
697 elog(ERROR, "cache lookup failed for type %u", type_id);
698 type = (Form_pg_type) GETSTRUCT(typeTuple);
699 if (type->typtype != TYPTYPE_DOMAIN)
700 {
701 /* Not a domain, so done looking through domains */
702 break;
703 }
704 /* It is a domain, so examine the base type instead */
705 type_id = type->typbasetype;
706 ReleaseSysCache(typeTuple);
707 }
708 result = type->typrelid;
709 ReleaseSysCache(typeTuple);
710 return result;
711 }
712
713 /*
714 * error context callback for parse failure during parseTypeString()
715 */
716 static void
pts_error_callback(void * arg)717 pts_error_callback(void *arg)
718 {
719 const char *str = (const char *) arg;
720
721 errcontext("invalid type name \"%s\"", str);
722 }
723
724 /*
725 * Given a string that is supposed to be a SQL-compatible type declaration,
726 * such as "int4" or "integer" or "character varying(32)", parse
727 * the string and return the result as a TypeName.
728 * If the string cannot be parsed as a type, an error is raised.
729 */
730 TypeName *
typeStringToTypeName(const char * str)731 typeStringToTypeName(const char *str)
732 {
733 List *raw_parsetree_list;
734 TypeName *typeName;
735 ErrorContextCallback ptserrcontext;
736
737 /* make sure we give useful error for empty input */
738 if (strspn(str, " \t\n\r\f") == strlen(str))
739 goto fail;
740
741 /*
742 * Setup error traceback support in case of ereport() during parse
743 */
744 ptserrcontext.callback = pts_error_callback;
745 ptserrcontext.arg = unconstify(char *, str);
746 ptserrcontext.previous = error_context_stack;
747 error_context_stack = &ptserrcontext;
748
749 raw_parsetree_list = raw_parser(str, RAW_PARSE_TYPE_NAME);
750
751 error_context_stack = ptserrcontext.previous;
752
753 /* We should get back exactly one TypeName node. */
754 Assert(list_length(raw_parsetree_list) == 1);
755 typeName = linitial_node(TypeName, raw_parsetree_list);
756
757 /* The grammar allows SETOF in TypeName, but we don't want that here. */
758 if (typeName->setof)
759 goto fail;
760
761 return typeName;
762
763 fail:
764 ereport(ERROR,
765 (errcode(ERRCODE_SYNTAX_ERROR),
766 errmsg("invalid type name \"%s\"", str)));
767 return NULL; /* keep compiler quiet */
768 }
769
770 /*
771 * Given a string that is supposed to be a SQL-compatible type declaration,
772 * such as "int4" or "integer" or "character varying(32)", parse
773 * the string and convert it to a type OID and type modifier.
774 * If missing_ok is true, InvalidOid is returned rather than raising an error
775 * when the type name is not found.
776 */
777 void
parseTypeString(const char * str,Oid * typeid_p,int32 * typmod_p,bool missing_ok)778 parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok)
779 {
780 TypeName *typeName;
781 Type tup;
782
783 typeName = typeStringToTypeName(str);
784
785 tup = LookupTypeName(NULL, typeName, typmod_p, missing_ok);
786 if (tup == NULL)
787 {
788 if (!missing_ok)
789 ereport(ERROR,
790 (errcode(ERRCODE_UNDEFINED_OBJECT),
791 errmsg("type \"%s\" does not exist",
792 TypeNameToString(typeName)),
793 parser_errposition(NULL, typeName->location)));
794 *typeid_p = InvalidOid;
795 }
796 else
797 {
798 Form_pg_type typ = (Form_pg_type) GETSTRUCT(tup);
799
800 if (!typ->typisdefined)
801 ereport(ERROR,
802 (errcode(ERRCODE_UNDEFINED_OBJECT),
803 errmsg("type \"%s\" is only a shell",
804 TypeNameToString(typeName)),
805 parser_errposition(NULL, typeName->location)));
806 *typeid_p = typ->oid;
807 ReleaseSysCache(tup);
808 }
809 }
810