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