LCOV - code coverage report
Current view: top level - src/backend/parser - parse_type.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 214 260 82.3 %
Date: 2017-09-29 15:12:54 Functions: 21 23 91.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11