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