Header And Logo

PostgreSQL
| The world's most advanced open source database.

parse_type.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * parse_type.c
00004  *      handle type operations for parser
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/parser/parse_type.c
00012  *
00013  *-------------------------------------------------------------------------
00014  */
00015 #include "postgres.h"
00016 
00017 #include "access/htup_details.h"
00018 #include "catalog/namespace.h"
00019 #include "catalog/pg_type.h"
00020 #include "lib/stringinfo.h"
00021 #include "nodes/makefuncs.h"
00022 #include "parser/parser.h"
00023 #include "parser/parse_type.h"
00024 #include "utils/array.h"
00025 #include "utils/builtins.h"
00026 #include "utils/datum.h"
00027 #include "utils/lsyscache.h"
00028 #include "utils/syscache.h"
00029 
00030 
00031 static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
00032                 Type typ);
00033 
00034 
00035 /*
00036  * LookupTypeName
00037  *      Given a TypeName object, lookup the pg_type syscache entry of the type.
00038  *      Returns NULL if no such type can be found.  If the type is found,
00039  *      the typmod value represented in the TypeName struct is computed and
00040  *      stored into *typmod_p.
00041  *
00042  * NB: on success, the caller must ReleaseSysCache the type tuple when done
00043  * with it.
00044  *
00045  * NB: direct callers of this function MUST check typisdefined before assuming
00046  * that the type is fully valid.  Most code should go through typenameType
00047  * or typenameTypeId instead.
00048  *
00049  * typmod_p can be passed as NULL if the caller does not care to know the
00050  * typmod value, but the typmod decoration (if any) will be validated anyway,
00051  * except in the case where the type is not found.  Note that if the type is
00052  * found but is a shell, and there is typmod decoration, an error will be
00053  * thrown --- this is intentional.
00054  *
00055  * pstate is only used for error location info, and may be NULL.
00056  */
00057 Type
00058 LookupTypeName(ParseState *pstate, const TypeName *typeName,
00059                int32 *typmod_p)
00060 {
00061     Oid         typoid;
00062     HeapTuple   tup;
00063     int32       typmod;
00064 
00065     if (typeName->names == NIL)
00066     {
00067         /* We have the OID already if it's an internally generated TypeName */
00068         typoid = typeName->typeOid;
00069     }
00070     else if (typeName->pct_type)
00071     {
00072         /* Handle %TYPE reference to type of an existing field */
00073         RangeVar   *rel = makeRangeVar(NULL, NULL, typeName->location);
00074         char       *field = NULL;
00075         Oid         relid;
00076         AttrNumber  attnum;
00077 
00078         /* deconstruct the name list */
00079         switch (list_length(typeName->names))
00080         {
00081             case 1:
00082                 ereport(ERROR,
00083                         (errcode(ERRCODE_SYNTAX_ERROR),
00084                 errmsg("improper %%TYPE reference (too few dotted names): %s",
00085                        NameListToString(typeName->names)),
00086                          parser_errposition(pstate, typeName->location)));
00087                 break;
00088             case 2:
00089                 rel->relname = strVal(linitial(typeName->names));
00090                 field = strVal(lsecond(typeName->names));
00091                 break;
00092             case 3:
00093                 rel->schemaname = strVal(linitial(typeName->names));
00094                 rel->relname = strVal(lsecond(typeName->names));
00095                 field = strVal(lthird(typeName->names));
00096                 break;
00097             case 4:
00098                 rel->catalogname = strVal(linitial(typeName->names));
00099                 rel->schemaname = strVal(lsecond(typeName->names));
00100                 rel->relname = strVal(lthird(typeName->names));
00101                 field = strVal(lfourth(typeName->names));
00102                 break;
00103             default:
00104                 ereport(ERROR,
00105                         (errcode(ERRCODE_SYNTAX_ERROR),
00106                          errmsg("improper %%TYPE reference (too many dotted names): %s",
00107                                 NameListToString(typeName->names)),
00108                          parser_errposition(pstate, typeName->location)));
00109                 break;
00110         }
00111 
00112         /*
00113          * Look up the field.
00114          *
00115          * XXX: As no lock is taken here, this might fail in the presence of
00116          * concurrent DDL.  But taking a lock would carry a performance
00117          * penalty and would also require a permissions check.
00118          */
00119         relid = RangeVarGetRelid(rel, NoLock, false);
00120         attnum = get_attnum(relid, field);
00121         if (attnum == InvalidAttrNumber)
00122             ereport(ERROR,
00123                     (errcode(ERRCODE_UNDEFINED_COLUMN),
00124                      errmsg("column \"%s\" of relation \"%s\" does not exist",
00125                             field, rel->relname),
00126                      parser_errposition(pstate, typeName->location)));
00127         typoid = get_atttype(relid, attnum);
00128 
00129         /* this construct should never have an array indicator */
00130         Assert(typeName->arrayBounds == NIL);
00131 
00132         /* emit nuisance notice (intentionally not errposition'd) */
00133         ereport(NOTICE,
00134                 (errmsg("type reference %s converted to %s",
00135                         TypeNameToString(typeName),
00136                         format_type_be(typoid))));
00137     }
00138     else
00139     {
00140         /* Normal reference to a type name */
00141         char       *schemaname;
00142         char       *typname;
00143 
00144         /* deconstruct the name list */
00145         DeconstructQualifiedName(typeName->names, &schemaname, &typname);
00146 
00147         if (schemaname)
00148         {
00149             /* Look in specific schema only */
00150             Oid         namespaceId;
00151 
00152             namespaceId = LookupExplicitNamespace(schemaname, false);
00153             typoid = GetSysCacheOid2(TYPENAMENSP,
00154                                      PointerGetDatum(typname),
00155                                      ObjectIdGetDatum(namespaceId));
00156         }
00157         else
00158         {
00159             /* Unqualified type name, so search the search path */
00160             typoid = TypenameGetTypid(typname);
00161         }
00162 
00163         /* If an array reference, return the array type instead */
00164         if (typeName->arrayBounds != NIL)
00165             typoid = get_array_type(typoid);
00166     }
00167 
00168     if (!OidIsValid(typoid))
00169     {
00170         if (typmod_p)
00171             *typmod_p = -1;
00172         return NULL;
00173     }
00174 
00175     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
00176     if (!HeapTupleIsValid(tup)) /* should not happen */
00177         elog(ERROR, "cache lookup failed for type %u", typoid);
00178 
00179     typmod = typenameTypeMod(pstate, typeName, (Type) tup);
00180 
00181     if (typmod_p)
00182         *typmod_p = typmod;
00183 
00184     return (Type) tup;
00185 }
00186 
00187 /*
00188  * typenameType - given a TypeName, return a Type structure and typmod
00189  *
00190  * This is equivalent to LookupTypeName, except that this will report
00191  * a suitable error message if the type cannot be found or is not defined.
00192  * Callers of this can therefore assume the result is a fully valid type.
00193  */
00194 Type
00195 typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
00196 {
00197     Type        tup;
00198 
00199     tup = LookupTypeName(pstate, typeName, typmod_p);
00200     if (tup == NULL)
00201         ereport(ERROR,
00202                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00203                  errmsg("type \"%s\" does not exist",
00204                         TypeNameToString(typeName)),
00205                  parser_errposition(pstate, typeName->location)));
00206     if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
00207         ereport(ERROR,
00208                 (errcode(ERRCODE_UNDEFINED_OBJECT),
00209                  errmsg("type \"%s\" is only a shell",
00210                         TypeNameToString(typeName)),
00211                  parser_errposition(pstate, typeName->location)));
00212     return tup;
00213 }
00214 
00215 /*
00216  * typenameTypeId - given a TypeName, return the type's OID
00217  *
00218  * This is similar to typenameType, but we only hand back the type OID
00219  * not the syscache entry.
00220  */
00221 Oid
00222 typenameTypeId(ParseState *pstate, const TypeName *typeName)
00223 {
00224     Oid         typoid;
00225     Type        tup;
00226 
00227     tup = typenameType(pstate, typeName, NULL);
00228     typoid = HeapTupleGetOid(tup);
00229     ReleaseSysCache(tup);
00230 
00231     return typoid;
00232 }
00233 
00234 /*
00235  * typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
00236  *
00237  * This is equivalent to typenameType, but we only hand back the type OID
00238  * and typmod, not the syscache entry.
00239  */
00240 void
00241 typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
00242                      Oid *typeid_p, int32 *typmod_p)
00243 {
00244     Type        tup;
00245 
00246     tup = typenameType(pstate, typeName, typmod_p);
00247     *typeid_p = HeapTupleGetOid(tup);
00248     ReleaseSysCache(tup);
00249 }
00250 
00251 /*
00252  * typenameTypeMod - given a TypeName, return the internal typmod value
00253  *
00254  * This will throw an error if the TypeName includes type modifiers that are
00255  * illegal for the data type.
00256  *
00257  * The actual type OID represented by the TypeName must already have been
00258  * looked up, and is passed as "typ".
00259  *
00260  * pstate is only used for error location info, and may be NULL.
00261  */
00262 static int32
00263 typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
00264 {
00265     int32       result;
00266     Oid         typmodin;
00267     Datum      *datums;
00268     int         n;
00269     ListCell   *l;
00270     ArrayType  *arrtypmod;
00271     ParseCallbackState pcbstate;
00272 
00273     /* Return prespecified typmod if no typmod expressions */
00274     if (typeName->typmods == NIL)
00275         return typeName->typemod;
00276 
00277     /*
00278      * Else, type had better accept typmods.  We give a special error message
00279      * for the shell-type case, since a shell couldn't possibly have a
00280      * typmodin function.
00281      */
00282     if (!((Form_pg_type) GETSTRUCT(typ))->typisdefined)
00283         ereport(ERROR,
00284                 (errcode(ERRCODE_SYNTAX_ERROR),
00285             errmsg("type modifier cannot be specified for shell type \"%s\"",
00286                    TypeNameToString(typeName)),
00287                  parser_errposition(pstate, typeName->location)));
00288 
00289     typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
00290 
00291     if (typmodin == InvalidOid)
00292         ereport(ERROR,
00293                 (errcode(ERRCODE_SYNTAX_ERROR),
00294                  errmsg("type modifier is not allowed for type \"%s\"",
00295                         TypeNameToString(typeName)),
00296                  parser_errposition(pstate, typeName->location)));
00297 
00298     /*
00299      * Convert the list of raw-grammar-output expressions to a cstring array.
00300      * Currently, we allow simple numeric constants, string literals, and
00301      * identifiers; possibly this list could be extended.
00302      */
00303     datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum));
00304     n = 0;
00305     foreach(l, typeName->typmods)
00306     {
00307         Node       *tm = (Node *) lfirst(l);
00308         char       *cstr = NULL;
00309 
00310         if (IsA(tm, A_Const))
00311         {
00312             A_Const    *ac = (A_Const *) tm;
00313 
00314             if (IsA(&ac->val, Integer))
00315             {
00316                 cstr = (char *) palloc(32);
00317                 snprintf(cstr, 32, "%ld", (long) ac->val.val.ival);
00318             }
00319             else if (IsA(&ac->val, Float) ||
00320                      IsA(&ac->val, String))
00321             {
00322                 /* we can just use the str field directly. */
00323                 cstr = ac->val.val.str;
00324             }
00325         }
00326         else if (IsA(tm, ColumnRef))
00327         {
00328             ColumnRef  *cr = (ColumnRef *) tm;
00329 
00330             if (list_length(cr->fields) == 1 &&
00331                 IsA(linitial(cr->fields), String))
00332                 cstr = strVal(linitial(cr->fields));
00333         }
00334         if (!cstr)
00335             ereport(ERROR,
00336                     (errcode(ERRCODE_SYNTAX_ERROR),
00337             errmsg("type modifiers must be simple constants or identifiers"),
00338                      parser_errposition(pstate, typeName->location)));
00339         datums[n++] = CStringGetDatum(cstr);
00340     }
00341 
00342     /* hardwired knowledge about cstring's representation details here */
00343     arrtypmod = construct_array(datums, n, CSTRINGOID,
00344                                 -2, false, 'c');
00345 
00346     /* arrange to report location if type's typmodin function fails */
00347     setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
00348 
00349     result = DatumGetInt32(OidFunctionCall1(typmodin,
00350                                             PointerGetDatum(arrtypmod)));
00351 
00352     cancel_parser_errposition_callback(&pcbstate);
00353 
00354     pfree(datums);
00355     pfree(arrtypmod);
00356 
00357     return result;
00358 }
00359 
00360 /*
00361  * appendTypeNameToBuffer
00362  *      Append a string representing the name of a TypeName to a StringInfo.
00363  *      This is the shared guts of TypeNameToString and TypeNameListToString.
00364  *
00365  * NB: this must work on TypeNames that do not describe any actual type;
00366  * it is mostly used for reporting lookup errors.
00367  */
00368 static void
00369 appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
00370 {
00371     if (typeName->names != NIL)
00372     {
00373         /* Emit possibly-qualified name as-is */
00374         ListCell   *l;
00375 
00376         foreach(l, typeName->names)
00377         {
00378             if (l != list_head(typeName->names))
00379                 appendStringInfoChar(string, '.');
00380             appendStringInfoString(string, strVal(lfirst(l)));
00381         }
00382     }
00383     else
00384     {
00385         /* Look up internally-specified type */
00386         appendStringInfoString(string, format_type_be(typeName->typeOid));
00387     }
00388 
00389     /*
00390      * Add decoration as needed, but only for fields considered by
00391      * LookupTypeName
00392      */
00393     if (typeName->pct_type)
00394         appendStringInfoString(string, "%TYPE");
00395 
00396     if (typeName->arrayBounds != NIL)
00397         appendStringInfoString(string, "[]");
00398 }
00399 
00400 /*
00401  * TypeNameToString
00402  *      Produce a string representing the name of a TypeName.
00403  *
00404  * NB: this must work on TypeNames that do not describe any actual type;
00405  * it is mostly used for reporting lookup errors.
00406  */
00407 char *
00408 TypeNameToString(const TypeName *typeName)
00409 {
00410     StringInfoData string;
00411 
00412     initStringInfo(&string);
00413     appendTypeNameToBuffer(typeName, &string);
00414     return string.data;
00415 }
00416 
00417 /*
00418  * TypeNameListToString
00419  *      Produce a string representing the name(s) of a List of TypeNames
00420  */
00421 char *
00422 TypeNameListToString(List *typenames)
00423 {
00424     StringInfoData string;
00425     ListCell   *l;
00426 
00427     initStringInfo(&string);
00428     foreach(l, typenames)
00429     {
00430         TypeName   *typeName = (TypeName *) lfirst(l);
00431 
00432         Assert(IsA(typeName, TypeName));
00433         if (l != list_head(typenames))
00434             appendStringInfoChar(&string, ',');
00435         appendTypeNameToBuffer(typeName, &string);
00436     }
00437     return string.data;
00438 }
00439 
00440 /*
00441  * LookupCollation
00442  *
00443  * Look up collation by name, return OID, with support for error location.
00444  */
00445 Oid
00446 LookupCollation(ParseState *pstate, List *collnames, int location)
00447 {
00448     Oid         colloid;
00449     ParseCallbackState pcbstate;
00450 
00451     if (pstate)
00452         setup_parser_errposition_callback(&pcbstate, pstate, location);
00453 
00454     colloid = get_collation_oid(collnames, false);
00455 
00456     if (pstate)
00457         cancel_parser_errposition_callback(&pcbstate);
00458 
00459     return colloid;
00460 }
00461 
00462 /*
00463  * GetColumnDefCollation
00464  *
00465  * Get the collation to be used for a column being defined, given the
00466  * ColumnDef node and the previously-determined column type OID.
00467  *
00468  * pstate is only used for error location purposes, and can be NULL.
00469  */
00470 Oid
00471 GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
00472 {
00473     Oid         result;
00474     Oid         typcollation = get_typcollation(typeOid);
00475     int         location = -1;
00476 
00477     if (coldef->collClause)
00478     {
00479         /* We have a raw COLLATE clause, so look up the collation */
00480         location = coldef->collClause->location;
00481         result = LookupCollation(pstate, coldef->collClause->collname,
00482                                  location);
00483     }
00484     else if (OidIsValid(coldef->collOid))
00485     {
00486         /* Precooked collation spec, use that */
00487         result = coldef->collOid;
00488     }
00489     else
00490     {
00491         /* Use the type's default collation if any */
00492         result = typcollation;
00493     }
00494 
00495     /* Complain if COLLATE is applied to an uncollatable type */
00496     if (OidIsValid(result) && !OidIsValid(typcollation))
00497         ereport(ERROR,
00498                 (errcode(ERRCODE_DATATYPE_MISMATCH),
00499                  errmsg("collations are not supported by type %s",
00500                         format_type_be(typeOid)),
00501                  parser_errposition(pstate, location)));
00502 
00503     return result;
00504 }
00505 
00506 /* return a Type structure, given a type id */
00507 /* NB: caller must ReleaseSysCache the type tuple when done with it */
00508 Type
00509 typeidType(Oid id)
00510 {
00511     HeapTuple   tup;
00512 
00513     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id));
00514     if (!HeapTupleIsValid(tup))
00515         elog(ERROR, "cache lookup failed for type %u", id);
00516     return (Type) tup;
00517 }
00518 
00519 /* given type (as type struct), return the type OID */
00520 Oid
00521 typeTypeId(Type tp)
00522 {
00523     if (tp == NULL)             /* probably useless */
00524         elog(ERROR, "typeTypeId() called with NULL type struct");
00525     return HeapTupleGetOid(tp);
00526 }
00527 
00528 /* given type (as type struct), return the length of type */
00529 int16
00530 typeLen(Type t)
00531 {
00532     Form_pg_type typ;
00533 
00534     typ = (Form_pg_type) GETSTRUCT(t);
00535     return typ->typlen;
00536 }
00537 
00538 /* given type (as type struct), return its 'byval' attribute */
00539 bool
00540 typeByVal(Type t)
00541 {
00542     Form_pg_type typ;
00543 
00544     typ = (Form_pg_type) GETSTRUCT(t);
00545     return typ->typbyval;
00546 }
00547 
00548 /* given type (as type struct), return the type's name */
00549 char *
00550 typeTypeName(Type t)
00551 {
00552     Form_pg_type typ;
00553 
00554     typ = (Form_pg_type) GETSTRUCT(t);
00555     /* pstrdup here because result may need to outlive the syscache entry */
00556     return pstrdup(NameStr(typ->typname));
00557 }
00558 
00559 /* given type (as type struct), return its 'typrelid' attribute */
00560 Oid
00561 typeTypeRelid(Type typ)
00562 {
00563     Form_pg_type typtup;
00564 
00565     typtup = (Form_pg_type) GETSTRUCT(typ);
00566     return typtup->typrelid;
00567 }
00568 
00569 /* given type (as type struct), return its 'typcollation' attribute */
00570 Oid
00571 typeTypeCollation(Type typ)
00572 {
00573     Form_pg_type typtup;
00574 
00575     typtup = (Form_pg_type) GETSTRUCT(typ);
00576     return typtup->typcollation;
00577 }
00578 
00579 /*
00580  * Given a type structure and a string, returns the internal representation
00581  * of that string.  The "string" can be NULL to perform conversion of a NULL
00582  * (which might result in failure, if the input function rejects NULLs).
00583  */
00584 Datum
00585 stringTypeDatum(Type tp, char *string, int32 atttypmod)
00586 {
00587     Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
00588     Oid         typinput = typform->typinput;
00589     Oid         typioparam = getTypeIOParam(tp);
00590     Datum       result;
00591 
00592     result = OidInputFunctionCall(typinput, string,
00593                                   typioparam, atttypmod);
00594 
00595 #ifdef RANDOMIZE_ALLOCATED_MEMORY
00596 
00597     /*
00598      * For pass-by-reference data types, repeat the conversion to see if the
00599      * input function leaves any uninitialized bytes in the result.  We can
00600      * only detect that reliably if RANDOMIZE_ALLOCATED_MEMORY is enabled, so
00601      * we don't bother testing otherwise.  The reason we don't want any
00602      * instability in the input function is that comparison of Const nodes
00603      * relies on bytewise comparison of the datums, so if the input function
00604      * leaves garbage then subexpressions that should be identical may not get
00605      * recognized as such.  See pgsql-hackers discussion of 2008-04-04.
00606      */
00607     if (string && !typform->typbyval)
00608     {
00609         Datum       result2;
00610 
00611         result2 = OidInputFunctionCall(typinput, string,
00612                                        typioparam, atttypmod);
00613         if (!datumIsEqual(result, result2, typform->typbyval, typform->typlen))
00614             elog(WARNING, "type %s has unstable input conversion for \"%s\"",
00615                  NameStr(typform->typname), string);
00616     }
00617 #endif
00618 
00619     return result;
00620 }
00621 
00622 /* given a typeid, return the type's typrelid (associated relation, if any) */
00623 Oid
00624 typeidTypeRelid(Oid type_id)
00625 {
00626     HeapTuple   typeTuple;
00627     Form_pg_type type;
00628     Oid         result;
00629 
00630     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
00631     if (!HeapTupleIsValid(typeTuple))
00632         elog(ERROR, "cache lookup failed for type %u", type_id);
00633 
00634     type = (Form_pg_type) GETSTRUCT(typeTuple);
00635     result = type->typrelid;
00636     ReleaseSysCache(typeTuple);
00637     return result;
00638 }
00639 
00640 /*
00641  * error context callback for parse failure during parseTypeString()
00642  */
00643 static void
00644 pts_error_callback(void *arg)
00645 {
00646     const char *str = (const char *) arg;
00647 
00648     errcontext("invalid type name \"%s\"", str);
00649 
00650     /*
00651      * Currently we just suppress any syntax error position report, rather
00652      * than transforming to an "internal query" error.  It's unlikely that a
00653      * type name is complex enough to need positioning.
00654      */
00655     errposition(0);
00656 }
00657 
00658 /*
00659  * Given a string that is supposed to be a SQL-compatible type declaration,
00660  * such as "int4" or "integer" or "character varying(32)", parse
00661  * the string and convert it to a type OID and type modifier.
00662  */
00663 void
00664 parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p)
00665 {
00666     StringInfoData buf;
00667     List       *raw_parsetree_list;
00668     SelectStmt *stmt;
00669     ResTarget  *restarget;
00670     TypeCast   *typecast;
00671     TypeName   *typeName;
00672     ErrorContextCallback ptserrcontext;
00673 
00674     /* make sure we give useful error for empty input */
00675     if (strspn(str, " \t\n\r\f") == strlen(str))
00676         goto fail;
00677 
00678     initStringInfo(&buf);
00679     appendStringInfo(&buf, "SELECT NULL::%s", str);
00680 
00681     /*
00682      * Setup error traceback support in case of ereport() during parse
00683      */
00684     ptserrcontext.callback = pts_error_callback;
00685     ptserrcontext.arg = (void *) str;
00686     ptserrcontext.previous = error_context_stack;
00687     error_context_stack = &ptserrcontext;
00688 
00689     raw_parsetree_list = raw_parser(buf.data);
00690 
00691     error_context_stack = ptserrcontext.previous;
00692 
00693     /*
00694      * Make sure we got back exactly what we expected and no more; paranoia is
00695      * justified since the string might contain anything.
00696      */
00697     if (list_length(raw_parsetree_list) != 1)
00698         goto fail;
00699     stmt = (SelectStmt *) linitial(raw_parsetree_list);
00700     if (stmt == NULL ||
00701         !IsA(stmt, SelectStmt) ||
00702         stmt->distinctClause != NIL ||
00703         stmt->intoClause != NULL ||
00704         stmt->fromClause != NIL ||
00705         stmt->whereClause != NULL ||
00706         stmt->groupClause != NIL ||
00707         stmt->havingClause != NULL ||
00708         stmt->windowClause != NIL ||
00709         stmt->valuesLists != NIL ||
00710         stmt->sortClause != NIL ||
00711         stmt->limitOffset != NULL ||
00712         stmt->limitCount != NULL ||
00713         stmt->lockingClause != NIL ||
00714         stmt->withClause != NULL ||
00715         stmt->op != SETOP_NONE)
00716         goto fail;
00717     if (list_length(stmt->targetList) != 1)
00718         goto fail;
00719     restarget = (ResTarget *) linitial(stmt->targetList);
00720     if (restarget == NULL ||
00721         !IsA(restarget, ResTarget) ||
00722         restarget->name != NULL ||
00723         restarget->indirection != NIL)
00724         goto fail;
00725     typecast = (TypeCast *) restarget->val;
00726     if (typecast == NULL ||
00727         !IsA(typecast, TypeCast) ||
00728         typecast->arg == NULL ||
00729         !IsA(typecast->arg, A_Const))
00730         goto fail;
00731     typeName = typecast->typeName;
00732     if (typeName == NULL ||
00733         !IsA(typeName, TypeName))
00734         goto fail;
00735     if (typeName->setof)
00736         goto fail;
00737 
00738     typenameTypeIdAndMod(NULL, typeName, typeid_p, typmod_p);
00739 
00740     pfree(buf.data);
00741 
00742     return;
00743 
00744 fail:
00745     ereport(ERROR,
00746             (errcode(ERRCODE_SYNTAX_ERROR),
00747              errmsg("invalid type name \"%s\"", str)));
00748 }