LCOV - code coverage report
Current view: top level - src/backend/parser - parse_type.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12devel Lines: 224 271 82.7 %
Date: 2018-10-17 03:20:55 Functions: 22 24 91.7 %
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-2018, 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     1330094 : 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     1330094 :     if (typeName->names == NIL)
      65             :     {
      66             :         /* We have the OID already if it's an internally generated TypeName */
      67      363140 :         typoid = typeName->typeOid;
      68             :     }
      69      966954 :     else if (typeName->pct_type)
      70             :     {
      71             :         /* Handle %TYPE reference to type of an existing field */
      72          16 :         RangeVar   *rel = makeRangeVar(NULL, NULL, typeName->location);
      73          16 :         char       *field = NULL;
      74             :         Oid         relid;
      75             :         AttrNumber  attnum;
      76             : 
      77             :         /* deconstruct the name list */
      78          16 :         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          16 :                 rel->relname = strVal(linitial(typeName->names));
      89          16 :                 field = strVal(lsecond(typeName->names));
      90          16 :                 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          16 :         relid = RangeVarGetRelid(rel, NoLock, missing_ok);
     119          16 :         attnum = get_attnum(relid, field);
     120          16 :         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          16 :             typoid = get_atttype(relid, attnum);
     134             : 
     135             :             /* this construct should never have an array indicator */
     136             :             Assert(typeName->arrayBounds == NIL);
     137             : 
     138             :             /* emit nuisance notice (intentionally not errposition'd) */
     139          16 :             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      966938 :         DeconstructQualifiedName(typeName->names, &schemaname, &typname);
     153             : 
     154      966938 :         if (schemaname)
     155             :         {
     156             :             /* Look in specific schema only */
     157             :             Oid         namespaceId;
     158             :             ParseCallbackState pcbstate;
     159             : 
     160      387310 :             setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
     161             : 
     162      387310 :             namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
     163      387306 :             if (OidIsValid(namespaceId))
     164      387242 :                 typoid = GetSysCacheOid2(TYPENAMENSP,
     165             :                                          PointerGetDatum(typname),
     166             :                                          ObjectIdGetDatum(namespaceId));
     167             :             else
     168          64 :                 typoid = InvalidOid;
     169             : 
     170      387306 :             cancel_parser_errposition_callback(&pcbstate);
     171             :         }
     172             :         else
     173             :         {
     174             :             /* Unqualified type name, so search the search path */
     175      579628 :             typoid = TypenameGetTypid(typname);
     176             :         }
     177             : 
     178             :         /* If an array reference, return the array type instead */
     179      966934 :         if (typeName->arrayBounds != NIL)
     180        7794 :             typoid = get_array_type(typoid);
     181             :     }
     182             : 
     183     1330090 :     if (!OidIsValid(typoid))
     184             :     {
     185       49792 :         if (typmod_p)
     186          22 :             *typmod_p = -1;
     187       49792 :         return NULL;
     188             :     }
     189             : 
     190     1280298 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
     191     1280298 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     192           0 :         elog(ERROR, "cache lookup failed for type %u", typoid);
     193             : 
     194     1280298 :     typmod = typenameTypeMod(pstate, typeName, (Type) tup);
     195             : 
     196     1280294 :     if (typmod_p)
     197      724718 :         *typmod_p = typmod;
     198             : 
     199     1280294 :     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      215158 : LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
     216             : {
     217             :     Oid         typoid;
     218             :     Type        tup;
     219             : 
     220      215158 :     tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
     221      215158 :     if (tup == NULL)
     222             :     {
     223         122 :         if (!missing_ok)
     224          22 :             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         100 :         return InvalidOid;
     231             :     }
     232             : 
     233      215036 :     typoid = HeapTupleGetOid(tup);
     234      215036 :     ReleaseSysCache(tup);
     235             : 
     236      215036 :     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      766534 : typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
     248             : {
     249             :     Type        tup;
     250             : 
     251      766534 :     tup = LookupTypeName(pstate, typeName, typmod_p, false);
     252      766530 :     if (tup == NULL)
     253          16 :         ereport(ERROR,
     254             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     255             :                  errmsg("type \"%s\" does not exist",
     256             :                         TypeNameToString(typeName)),
     257             :                  parser_errposition(pstate, typeName->location)));
     258      766514 :     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      766514 :     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        6230 : typenameTypeId(ParseState *pstate, const TypeName *typeName)
     275             : {
     276             :     Oid         typoid;
     277             :     Type        tup;
     278             : 
     279        6230 :     tup = typenameType(pstate, typeName, NULL);
     280        6220 :     typoid = HeapTupleGetOid(tup);
     281        6220 :     ReleaseSysCache(tup);
     282             : 
     283        6220 :     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      718426 : typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
     294             :                      Oid *typeid_p, int32 *typmod_p)
     295             : {
     296             :     Type        tup;
     297             : 
     298      718426 :     tup = typenameType(pstate, typeName, typmod_p);
     299      718426 :     *typeid_p = HeapTupleGetOid(tup);
     300      718426 :     ReleaseSysCache(tup);
     301      718426 : }
     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     1280298 : 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     1280298 :     if (typeName->typmods == NIL)
     327     1275032 :         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        5266 :     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        5266 :     typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
     342             : 
     343        5266 :     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        5266 :     datums = (Datum *) palloc(list_length(typeName->typmods) * sizeof(Datum));
     356        5266 :     n = 0;
     357       12070 :     foreach(l, typeName->typmods)
     358             :     {
     359        6804 :         Node       *tm = (Node *) lfirst(l);
     360        6804 :         char       *cstr = NULL;
     361             : 
     362        6804 :         if (IsA(tm, A_Const))
     363             :         {
     364        6804 :             A_Const    *ac = (A_Const *) tm;
     365             : 
     366        6804 :             if (IsA(&ac->val, Integer))
     367             :             {
     368        6804 :                 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        6804 :         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        6804 :         datums[n++] = CStringGetDatum(cstr);
     391             :     }
     392             : 
     393             :     /* hardwired knowledge about cstring's representation details here */
     394        5266 :     arrtypmod = construct_array(datums, n, CSTRINGOID,
     395             :                                 -2, false, 'c');
     396             : 
     397             :     /* arrange to report location if type's typmodin function fails */
     398        5266 :     setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
     399             : 
     400        5266 :     result = DatumGetInt32(OidFunctionCall1(typmodin,
     401             :                                             PointerGetDatum(arrtypmod)));
     402             : 
     403        5262 :     cancel_parser_errposition_callback(&pcbstate);
     404             : 
     405        5262 :     pfree(datums);
     406        5262 :     pfree(arrtypmod);
     407             : 
     408        5262 :     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       11602 : appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
     421             : {
     422       11602 :     if (typeName->names != NIL)
     423             :     {
     424             :         /* Emit possibly-qualified name as-is */
     425             :         ListCell   *l;
     426             : 
     427       23340 :         foreach(l, typeName->names)
     428             :         {
     429       11738 :             if (l != list_head(typeName->names))
     430         136 :                 appendStringInfoChar(string, '.');
     431       11738 :             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       11602 :     if (typeName->pct_type)
     445          16 :         appendStringInfoString(string, "%TYPE");
     446             : 
     447       11602 :     if (typeName->arrayBounds != NIL)
     448           4 :         appendStringInfoString(string, "[]");
     449       11602 : }
     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       11584 : TypeNameToString(const TypeName *typeName)
     460             : {
     461             :     StringInfoData string;
     462             : 
     463       11584 :     initStringInfo(&string);
     464       11584 :     appendTypeNameToBuffer(typeName, &string);
     465       11584 :     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          18 : TypeNameListToString(List *typenames)
     474             : {
     475             :     StringInfoData string;
     476             :     ListCell   *l;
     477             : 
     478          18 :     initStringInfo(&string);
     479          36 :     foreach(l, typenames)
     480             :     {
     481          18 :         TypeName   *typeName = lfirst_node(TypeName, l);
     482             : 
     483          18 :         if (l != list_head(typenames))
     484           8 :             appendStringInfoChar(&string, ',');
     485          18 :         appendTypeNameToBuffer(typeName, &string);
     486             :     }
     487          18 :     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         748 : LookupCollation(ParseState *pstate, List *collnames, int location)
     497             : {
     498             :     Oid         colloid;
     499             :     ParseCallbackState pcbstate;
     500             : 
     501         748 :     if (pstate)
     502         636 :         setup_parser_errposition_callback(&pcbstate, pstate, location);
     503             : 
     504         748 :     colloid = get_collation_oid(collnames, false);
     505             : 
     506         748 :     if (pstate)
     507         636 :         cancel_parser_errposition_callback(&pcbstate);
     508             : 
     509         748 :     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      402888 : GetColumnDefCollation(ParseState *pstate, ColumnDef *coldef, Oid typeOid)
     522             : {
     523             :     Oid         result;
     524      402888 :     Oid         typcollation = get_typcollation(typeOid);
     525      402888 :     int         location = coldef->location;
     526             : 
     527      402888 :     if (coldef->collClause)
     528             :     {
     529             :         /* We have a raw COLLATE clause, so look up the collation */
     530         112 :         location = coldef->collClause->location;
     531         112 :         result = LookupCollation(pstate, coldef->collClause->collname,
     532             :                                  location);
     533             :     }
     534      402776 :     else if (OidIsValid(coldef->collOid))
     535             :     {
     536             :         /* Precooked collation spec, use that */
     537      191200 :         result = coldef->collOid;
     538             :     }
     539             :     else
     540             :     {
     541             :         /* Use the type's default collation if any */
     542      211576 :         result = typcollation;
     543             :     }
     544             : 
     545             :     /* Complain if COLLATE is applied to an uncollatable type */
     546      402888 :     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      402888 :     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      642172 : typeidType(Oid id)
     560             : {
     561             :     HeapTuple   tup;
     562             : 
     563      642172 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id));
     564      642172 :     if (!HeapTupleIsValid(tup))
     565           0 :         elog(ERROR, "cache lookup failed for type %u", id);
     566      642172 :     return (Type) tup;
     567             : }
     568             : 
     569             : /* given type (as type struct), return the type OID */
     570             : Oid
     571      295780 : typeTypeId(Type tp)
     572             : {
     573      295780 :     if (tp == NULL)             /* probably useless */
     574           0 :         elog(ERROR, "typeTypeId() called with NULL type struct");
     575      295780 :     return HeapTupleGetOid(tp);
     576             : }
     577             : 
     578             : /* given type (as type struct), return the length of type */
     579             : int16
     580      613066 : typeLen(Type t)
     581             : {
     582             :     Form_pg_type typ;
     583             : 
     584      613066 :     typ = (Form_pg_type) GETSTRUCT(t);
     585      613066 :     return typ->typlen;
     586             : }
     587             : 
     588             : /* given type (as type struct), return its 'byval' attribute */
     589             : bool
     590      613066 : typeByVal(Type t)
     591             : {
     592             :     Form_pg_type typ;
     593             : 
     594      613066 :     typ = (Form_pg_type) GETSTRUCT(t);
     595      613066 :     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         452 : typeTypeRelid(Type typ)
     612             : {
     613             :     Form_pg_type typtup;
     614             : 
     615         452 :     typtup = (Form_pg_type) GETSTRUCT(typ);
     616         452 :     return typtup->typrelid;
     617             : }
     618             : 
     619             : /* given type (as type struct), return its 'typcollation' attribute */
     620             : Oid
     621      613066 : typeTypeCollation(Type typ)
     622             : {
     623             :     Form_pg_type typtup;
     624             : 
     625      613066 :     typtup = (Form_pg_type) GETSTRUCT(typ);
     626      613066 :     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      613066 : stringTypeDatum(Type tp, char *string, int32 atttypmod)
     636             : {
     637      613066 :     Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
     638      613066 :     Oid         typinput = typform->typinput;
     639      613066 :     Oid         typioparam = getTypeIOParam(tp);
     640             : 
     641      613066 :     return OidInputFunctionCall(typinput, string, typioparam, atttypmod);
     642             : }
     643             : 
     644             : /*
     645             :  * Given a typeid, return the type's typrelid (associated relation), if any.
     646             :  * Returns InvalidOid if type is not a composite type.
     647             :  */
     648             : Oid
     649        6758 : typeidTypeRelid(Oid type_id)
     650             : {
     651             :     HeapTuple   typeTuple;
     652             :     Form_pg_type type;
     653             :     Oid         result;
     654             : 
     655        6758 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
     656        6758 :     if (!HeapTupleIsValid(typeTuple))
     657           0 :         elog(ERROR, "cache lookup failed for type %u", type_id);
     658        6758 :     type = (Form_pg_type) GETSTRUCT(typeTuple);
     659        6758 :     result = type->typrelid;
     660        6758 :     ReleaseSysCache(typeTuple);
     661        6758 :     return result;
     662             : }
     663             : 
     664             : /*
     665             :  * Given a typeid, return the type's typrelid (associated relation), if any.
     666             :  * Returns InvalidOid if type is not a composite type or a domain over one.
     667             :  * This is the same as typeidTypeRelid(getBaseType(type_id)), but faster.
     668             :  */
     669             : Oid
     670     1388000 : typeOrDomainTypeRelid(Oid type_id)
     671             : {
     672             :     HeapTuple   typeTuple;
     673             :     Form_pg_type type;
     674             :     Oid         result;
     675             : 
     676             :     for (;;)
     677             :     {
     678     1547476 :         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
     679     1388000 :         if (!HeapTupleIsValid(typeTuple))
     680           0 :             elog(ERROR, "cache lookup failed for type %u", type_id);
     681     1388000 :         type = (Form_pg_type) GETSTRUCT(typeTuple);
     682     1388000 :         if (type->typtype != TYPTYPE_DOMAIN)
     683             :         {
     684             :             /* Not a domain, so done looking through domains */
     685     1228524 :             break;
     686             :         }
     687             :         /* It is a domain, so examine the base type instead */
     688      159476 :         type_id = type->typbasetype;
     689      159476 :         ReleaseSysCache(typeTuple);
     690             :     }
     691     1228524 :     result = type->typrelid;
     692     1228524 :     ReleaseSysCache(typeTuple);
     693     1228524 :     return result;
     694             : }
     695             : 
     696             : /*
     697             :  * error context callback for parse failure during parseTypeString()
     698             :  */
     699             : static void
     700           0 : pts_error_callback(void *arg)
     701             : {
     702           0 :     const char *str = (const char *) arg;
     703             : 
     704           0 :     errcontext("invalid type name \"%s\"", str);
     705             : 
     706             :     /*
     707             :      * Currently we just suppress any syntax error position report, rather
     708             :      * than transforming to an "internal query" error.  It's unlikely that a
     709             :      * type name is complex enough to need positioning.
     710             :      */
     711           0 :     errposition(0);
     712           0 : }
     713             : 
     714             : /*
     715             :  * Given a string that is supposed to be a SQL-compatible type declaration,
     716             :  * such as "int4" or "integer" or "character varying(32)", parse
     717             :  * the string and return the result as a TypeName.
     718             :  * If the string cannot be parsed as a type, an error is raised.
     719             :  */
     720             : TypeName *
     721        3268 : typeStringToTypeName(const char *str)
     722             : {
     723             :     StringInfoData buf;
     724             :     List       *raw_parsetree_list;
     725             :     SelectStmt *stmt;
     726             :     ResTarget  *restarget;
     727             :     TypeCast   *typecast;
     728             :     TypeName   *typeName;
     729             :     ErrorContextCallback ptserrcontext;
     730             : 
     731             :     /* make sure we give useful error for empty input */
     732        3268 :     if (strspn(str, " \t\n\r\f") == strlen(str))
     733           0 :         goto fail;
     734             : 
     735        3268 :     initStringInfo(&buf);
     736        3268 :     appendStringInfo(&buf, "SELECT NULL::%s", str);
     737             : 
     738             :     /*
     739             :      * Setup error traceback support in case of ereport() during parse
     740             :      */
     741        3268 :     ptserrcontext.callback = pts_error_callback;
     742        3268 :     ptserrcontext.arg = (void *) str;
     743        3268 :     ptserrcontext.previous = error_context_stack;
     744        3268 :     error_context_stack = &ptserrcontext;
     745             : 
     746        3268 :     raw_parsetree_list = raw_parser(buf.data);
     747             : 
     748        3268 :     error_context_stack = ptserrcontext.previous;
     749             : 
     750             :     /*
     751             :      * Make sure we got back exactly what we expected and no more; paranoia is
     752             :      * justified since the string might contain anything.
     753             :      */
     754        3268 :     if (list_length(raw_parsetree_list) != 1)
     755           0 :         goto fail;
     756        3268 :     stmt = (SelectStmt *) linitial_node(RawStmt, raw_parsetree_list)->stmt;
     757        6536 :     if (stmt == NULL ||
     758        6536 :         !IsA(stmt, SelectStmt) ||
     759        6536 :         stmt->distinctClause != NIL ||
     760        6536 :         stmt->intoClause != NULL ||
     761        6536 :         stmt->fromClause != NIL ||
     762        6536 :         stmt->whereClause != NULL ||
     763        6536 :         stmt->groupClause != NIL ||
     764        6536 :         stmt->havingClause != NULL ||
     765        6536 :         stmt->windowClause != NIL ||
     766        6536 :         stmt->valuesLists != NIL ||
     767        6536 :         stmt->sortClause != NIL ||
     768        6536 :         stmt->limitOffset != NULL ||
     769        6536 :         stmt->limitCount != NULL ||
     770        6536 :         stmt->lockingClause != NIL ||
     771        6536 :         stmt->withClause != NULL ||
     772        3268 :         stmt->op != SETOP_NONE)
     773             :         goto fail;
     774        3268 :     if (list_length(stmt->targetList) != 1)
     775           0 :         goto fail;
     776        3268 :     restarget = (ResTarget *) linitial(stmt->targetList);
     777        6536 :     if (restarget == NULL ||
     778        6536 :         !IsA(restarget, ResTarget) ||
     779        6536 :         restarget->name != NULL ||
     780        3268 :         restarget->indirection != NIL)
     781             :         goto fail;
     782        3268 :     typecast = (TypeCast *) restarget->val;
     783        6536 :     if (typecast == NULL ||
     784        6536 :         !IsA(typecast, TypeCast) ||
     785        6536 :         typecast->arg == NULL ||
     786        3268 :         !IsA(typecast->arg, A_Const))
     787             :         goto fail;
     788             : 
     789        3268 :     typeName = typecast->typeName;
     790        6536 :     if (typeName == NULL ||
     791        3268 :         !IsA(typeName, TypeName))
     792             :         goto fail;
     793        3268 :     if (typeName->setof)
     794           0 :         goto fail;
     795             : 
     796        3268 :     pfree(buf.data);
     797             : 
     798        3268 :     return typeName;
     799             : 
     800             : fail:
     801           0 :     ereport(ERROR,
     802             :             (errcode(ERRCODE_SYNTAX_ERROR),
     803             :              errmsg("invalid type name \"%s\"", str)));
     804             :     return NULL;                /* keep compiler quiet */
     805             : }
     806             : 
     807             : /*
     808             :  * Given a string that is supposed to be a SQL-compatible type declaration,
     809             :  * such as "int4" or "integer" or "character varying(32)", parse
     810             :  * the string and convert it to a type OID and type modifier.
     811             :  * If missing_ok is true, InvalidOid is returned rather than raising an error
     812             :  * when the type name is not found.
     813             :  */
     814             : void
     815        2976 : parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok)
     816             : {
     817             :     TypeName   *typeName;
     818             :     Type        tup;
     819             : 
     820        2976 :     typeName = typeStringToTypeName(str);
     821             : 
     822        2976 :     tup = LookupTypeName(NULL, typeName, typmod_p, missing_ok);
     823        2972 :     if (tup == NULL)
     824             :     {
     825          22 :         if (!missing_ok)
     826          14 :             ereport(ERROR,
     827             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     828             :                      errmsg("type \"%s\" does not exist",
     829             :                             TypeNameToString(typeName)),
     830             :                      parser_errposition(NULL, typeName->location)));
     831           8 :         *typeid_p = InvalidOid;
     832             :     }
     833             :     else
     834             :     {
     835        2950 :         if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
     836           0 :             ereport(ERROR,
     837             :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     838             :                      errmsg("type \"%s\" is only a shell",
     839             :                             TypeNameToString(typeName)),
     840             :                      parser_errposition(NULL, typeName->location)));
     841        2950 :         *typeid_p = HeapTupleGetOid(tup);
     842        2950 :         ReleaseSysCache(tup);
     843             :     }
     844        2958 : }

Generated by: LCOV version 1.13