1 /*-------------------------------------------------------------------------
2 *
3 * parse_type.c
4 * handle type operations for parser
5 *
6 * Portions Copyright (c) 1996-2017, 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
30 static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
31 Type typ);
32
33
34 /*
35 * LookupTypeName
36 * Wrapper for typical case.
37 */
38 Type
LookupTypeName(ParseState * pstate,const TypeName * typeName,int32 * typmod_p,bool missing_ok)39 LookupTypeName(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 */
73 Type
LookupTypeNameExtended(ParseState * pstate,const TypeName * typeName,int32 * typmod_p,bool temp_ok,bool missing_ok)74 LookupTypeNameExtended(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,
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 */
232 Oid
LookupTypeNameOid(ParseState * pstate,const TypeName * typeName,bool missing_ok)233 LookupTypeNameOid(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 = HeapTupleGetOid(tup);
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 */
264 Type
typenameType(ParseState * pstate,const TypeName * typeName,int32 * typmod_p)265 typenameType(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 */
291 Oid
typenameTypeId(ParseState * pstate,const TypeName * typeName)292 typenameTypeId(ParseState *pstate, const TypeName *typeName)
293 {
294 Oid typoid;
295 Type tup;
296
297 tup = typenameType(pstate, typeName, NULL);
298 typoid = HeapTupleGetOid(tup);
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 */
310 void
typenameTypeIdAndMod(ParseState * pstate,const TypeName * typeName,Oid * typeid_p,int32 * typmod_p)311 typenameTypeIdAndMod(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 = HeapTupleGetOid(tup);
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 */
332 static int32
typenameTypeMod(ParseState * pstate,const TypeName * typeName,Type typ)333 typenameTypeMod(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 */
437 static void
appendTypeNameToBuffer(const TypeName * typeName,StringInfo string)438 appendTypeNameToBuffer(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 */
476 char *
TypeNameToString(const TypeName * typeName)477 TypeNameToString(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 */
490 char *
TypeNameListToString(List * typenames)491 TypeNameListToString(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 */
513 Oid
LookupCollation(ParseState * pstate,List * collnames,int location)514 LookupCollation(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 */
538 Oid
GetColumnDefCollation(ParseState * pstate,ColumnDef * coldef,Oid typeOid)539 GetColumnDefCollation(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 */
576 Type
typeidType(Oid id)577 typeidType(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 */
588 Oid
typeTypeId(Type tp)589 typeTypeId(Type tp)
590 {
591 if (tp == NULL) /* probably useless */
592 elog(ERROR, "typeTypeId() called with NULL type struct");
593 return HeapTupleGetOid(tp);
594 }
595
596 /* given type (as type struct), return the length of type */
597 int16
typeLen(Type t)598 typeLen(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 */
607 bool
typeByVal(Type t)608 typeByVal(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 */
617 char *
typeTypeName(Type t)618 typeTypeName(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 */
628 Oid
typeTypeRelid(Type typ)629 typeTypeRelid(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 */
638 Oid
typeTypeCollation(Type typ)639 typeTypeCollation(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 */
652 Datum
stringTypeDatum(Type tp,char * string,int32 atttypmod)653 stringTypeDatum(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 /* given a typeid, return the type's typrelid (associated relation, if any) */
663 Oid
typeidTypeRelid(Oid type_id)664 typeidTypeRelid(Oid type_id)
665 {
666 HeapTuple typeTuple;
667 Form_pg_type type;
668 Oid result;
669
670 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
671 if (!HeapTupleIsValid(typeTuple))
672 elog(ERROR, "cache lookup failed for type %u", type_id);
673
674 type = (Form_pg_type) GETSTRUCT(typeTuple);
675 result = type->typrelid;
676 ReleaseSysCache(typeTuple);
677 return result;
678 }
679
680 /*
681 * error context callback for parse failure during parseTypeString()
682 */
683 static void
pts_error_callback(void * arg)684 pts_error_callback(void *arg)
685 {
686 const char *str = (const char *) arg;
687
688 errcontext("invalid type name \"%s\"", str);
689
690 /*
691 * Currently we just suppress any syntax error position report, rather
692 * than transforming to an "internal query" error. It's unlikely that a
693 * type name is complex enough to need positioning.
694 */
695 errposition(0);
696 }
697
698 /*
699 * Given a string that is supposed to be a SQL-compatible type declaration,
700 * such as "int4" or "integer" or "character varying(32)", parse
701 * the string and return the result as a TypeName.
702 * If the string cannot be parsed as a type, an error is raised.
703 */
704 TypeName *
typeStringToTypeName(const char * str)705 typeStringToTypeName(const char *str)
706 {
707 StringInfoData buf;
708 List *raw_parsetree_list;
709 SelectStmt *stmt;
710 ResTarget *restarget;
711 TypeCast *typecast;
712 TypeName *typeName;
713 ErrorContextCallback ptserrcontext;
714
715 /* make sure we give useful error for empty input */
716 if (strspn(str, " \t\n\r\f") == strlen(str))
717 goto fail;
718
719 initStringInfo(&buf);
720 appendStringInfo(&buf, "SELECT NULL::%s", str);
721
722 /*
723 * Setup error traceback support in case of ereport() during parse
724 */
725 ptserrcontext.callback = pts_error_callback;
726 ptserrcontext.arg = (void *) str;
727 ptserrcontext.previous = error_context_stack;
728 error_context_stack = &ptserrcontext;
729
730 raw_parsetree_list = raw_parser(buf.data);
731
732 error_context_stack = ptserrcontext.previous;
733
734 /*
735 * Make sure we got back exactly what we expected and no more; paranoia is
736 * justified since the string might contain anything.
737 */
738 if (list_length(raw_parsetree_list) != 1)
739 goto fail;
740 stmt = (SelectStmt *) linitial_node(RawStmt, raw_parsetree_list)->stmt;
741 if (stmt == NULL ||
742 !IsA(stmt, SelectStmt) ||
743 stmt->distinctClause != NIL ||
744 stmt->intoClause != NULL ||
745 stmt->fromClause != NIL ||
746 stmt->whereClause != NULL ||
747 stmt->groupClause != NIL ||
748 stmt->havingClause != NULL ||
749 stmt->windowClause != NIL ||
750 stmt->valuesLists != NIL ||
751 stmt->sortClause != NIL ||
752 stmt->limitOffset != NULL ||
753 stmt->limitCount != NULL ||
754 stmt->lockingClause != NIL ||
755 stmt->withClause != NULL ||
756 stmt->op != SETOP_NONE)
757 goto fail;
758 if (list_length(stmt->targetList) != 1)
759 goto fail;
760 restarget = (ResTarget *) linitial(stmt->targetList);
761 if (restarget == NULL ||
762 !IsA(restarget, ResTarget) ||
763 restarget->name != NULL ||
764 restarget->indirection != NIL)
765 goto fail;
766 typecast = (TypeCast *) restarget->val;
767 if (typecast == NULL ||
768 !IsA(typecast, TypeCast) ||
769 typecast->arg == NULL ||
770 !IsA(typecast->arg, A_Const))
771 goto fail;
772
773 typeName = typecast->typeName;
774 if (typeName == NULL ||
775 !IsA(typeName, TypeName))
776 goto fail;
777 if (typeName->setof)
778 goto fail;
779
780 pfree(buf.data);
781
782 return typeName;
783
784 fail:
785 ereport(ERROR,
786 (errcode(ERRCODE_SYNTAX_ERROR),
787 errmsg("invalid type name \"%s\"", str)));
788 return NULL; /* keep compiler quiet */
789 }
790
791 /*
792 * Given a string that is supposed to be a SQL-compatible type declaration,
793 * such as "int4" or "integer" or "character varying(32)", parse
794 * the string and convert it to a type OID and type modifier.
795 * If missing_ok is true, InvalidOid is returned rather than raising an error
796 * when the type name is not found.
797 */
798 void
parseTypeString(const char * str,Oid * typeid_p,int32 * typmod_p,bool missing_ok)799 parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok)
800 {
801 TypeName *typeName;
802 Type tup;
803
804 typeName = typeStringToTypeName(str);
805
806 tup = LookupTypeName(NULL, typeName, typmod_p, missing_ok);
807 if (tup == NULL)
808 {
809 if (!missing_ok)
810 ereport(ERROR,
811 (errcode(ERRCODE_UNDEFINED_OBJECT),
812 errmsg("type \"%s\" does not exist",
813 TypeNameToString(typeName)),
814 parser_errposition(NULL, typeName->location)));
815 *typeid_p = InvalidOid;
816 }
817 else
818 {
819 if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
820 ereport(ERROR,
821 (errcode(ERRCODE_UNDEFINED_OBJECT),
822 errmsg("type \"%s\" is only a shell",
823 TypeNameToString(typeName)),
824 parser_errposition(NULL, typeName->location)));
825 *typeid_p = HeapTupleGetOid(tup);
826 ReleaseSysCache(tup);
827 }
828 }
829