LCOV - code coverage report
Current view: top level - src/backend/parser - parse_type.c (source / functions) Coverage Total Hit
Test: PostgreSQL 19devel Lines: 83.3 % 246 205
Test Date: 2026-03-02 14:15:04 Functions: 96.0 % 25 24
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-2026, 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/parse_type.h"
      23              : #include "parser/parser.h"
      24              : #include "utils/array.h"
      25              : #include "utils/builtins.h"
      26              : #include "utils/lsyscache.h"
      27              : #include "utils/syscache.h"
      28              : 
      29              : static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
      30              :                              Type typ);
      31              : 
      32              : 
      33              : /*
      34              :  * LookupTypeName
      35              :  *      Wrapper for typical case.
      36              :  */
      37              : Type
      38       398955 : LookupTypeName(ParseState *pstate, const TypeName *typeName,
      39              :                int32 *typmod_p, bool missing_ok)
      40              : {
      41       398955 :     return LookupTypeNameExtended(pstate,
      42              :                                   typeName, typmod_p, true, missing_ok);
      43              : }
      44              : 
      45              : /*
      46              :  * LookupTypeNameExtended
      47              :  *      Given a TypeName object, lookup the pg_type syscache entry of the type.
      48              :  *      Returns NULL if no such type can be found.  If the type is found,
      49              :  *      the typmod value represented in the TypeName struct is computed and
      50              :  *      stored into *typmod_p.
      51              :  *
      52              :  * NB: on success, the caller must ReleaseSysCache the type tuple when done
      53              :  * with it.
      54              :  *
      55              :  * NB: direct callers of this function MUST check typisdefined before assuming
      56              :  * that the type is fully valid.  Most code should go through typenameType
      57              :  * or typenameTypeId instead.
      58              :  *
      59              :  * typmod_p can be passed as NULL if the caller does not care to know the
      60              :  * typmod value, but the typmod decoration (if any) will be validated anyway,
      61              :  * except in the case where the type is not found.  Note that if the type is
      62              :  * found but is a shell, and there is typmod decoration, an error will be
      63              :  * thrown --- this is intentional.
      64              :  *
      65              :  * If temp_ok is false, ignore types in the temporary namespace.  Pass false
      66              :  * when the caller will decide, using goodness of fit criteria, whether the
      67              :  * typeName is actually a type or something else.  If typeName always denotes
      68              :  * a type (or denotes nothing), pass true.
      69              :  *
      70              :  * pstate is only used for error location info, and may be NULL.
      71              :  */
      72              : Type
      73       431952 : LookupTypeNameExtended(ParseState *pstate,
      74              :                        const TypeName *typeName, int32 *typmod_p,
      75              :                        bool temp_ok, bool missing_ok)
      76              : {
      77              :     Oid         typoid;
      78              :     HeapTuple   tup;
      79              :     int32       typmod;
      80              : 
      81       431952 :     if (typeName->names == NIL)
      82              :     {
      83              :         /* We have the OID already if it's an internally generated TypeName */
      84       101349 :         typoid = typeName->typeOid;
      85              :     }
      86       330603 :     else if (typeName->pct_type)
      87              :     {
      88              :         /* Handle %TYPE reference to type of an existing field */
      89           12 :         RangeVar   *rel = makeRangeVar(NULL, NULL, typeName->location);
      90           12 :         char       *field = NULL;
      91              :         Oid         relid;
      92              :         AttrNumber  attnum;
      93              : 
      94              :         /* deconstruct the name list */
      95           12 :         switch (list_length(typeName->names))
      96              :         {
      97            0 :             case 1:
      98            0 :                 ereport(ERROR,
      99              :                         (errcode(ERRCODE_SYNTAX_ERROR),
     100              :                          errmsg("improper %%TYPE reference (too few dotted names): %s",
     101              :                                 NameListToString(typeName->names)),
     102              :                          parser_errposition(pstate, typeName->location)));
     103              :                 break;
     104            9 :             case 2:
     105            9 :                 rel->relname = strVal(linitial(typeName->names));
     106            9 :                 field = strVal(lsecond(typeName->names));
     107            9 :                 break;
     108            3 :             case 3:
     109            3 :                 rel->schemaname = strVal(linitial(typeName->names));
     110            3 :                 rel->relname = strVal(lsecond(typeName->names));
     111            3 :                 field = strVal(lthird(typeName->names));
     112            3 :                 break;
     113            0 :             case 4:
     114            0 :                 rel->catalogname = strVal(linitial(typeName->names));
     115            0 :                 rel->schemaname = strVal(lsecond(typeName->names));
     116            0 :                 rel->relname = strVal(lthird(typeName->names));
     117            0 :                 field = strVal(lfourth(typeName->names));
     118            0 :                 break;
     119            0 :             default:
     120            0 :                 ereport(ERROR,
     121              :                         (errcode(ERRCODE_SYNTAX_ERROR),
     122              :                          errmsg("improper %%TYPE reference (too many dotted names): %s",
     123              :                                 NameListToString(typeName->names)),
     124              :                          parser_errposition(pstate, typeName->location)));
     125              :                 break;
     126              :         }
     127              : 
     128              :         /*
     129              :          * Look up the field.
     130              :          *
     131              :          * XXX: As no lock is taken here, this might fail in the presence of
     132              :          * concurrent DDL.  But taking a lock would carry a performance
     133              :          * penalty and would also require a permissions check.
     134              :          */
     135           12 :         relid = RangeVarGetRelid(rel, NoLock, missing_ok);
     136           12 :         attnum = get_attnum(relid, field);
     137           12 :         if (attnum == InvalidAttrNumber)
     138              :         {
     139            0 :             if (missing_ok)
     140            0 :                 typoid = InvalidOid;
     141              :             else
     142            0 :                 ereport(ERROR,
     143              :                         (errcode(ERRCODE_UNDEFINED_COLUMN),
     144              :                          errmsg("column \"%s\" of relation \"%s\" does not exist",
     145              :                                 field, rel->relname),
     146              :                          parser_errposition(pstate, typeName->location)));
     147              :         }
     148              :         else
     149              :         {
     150           12 :             typoid = get_atttype(relid, attnum);
     151              : 
     152              :             /* this construct should never have an array indicator */
     153              :             Assert(typeName->arrayBounds == NIL);
     154              : 
     155              :             /* emit nuisance notice (intentionally not errposition'd) */
     156           12 :             ereport(NOTICE,
     157              :                     (errmsg("type reference %s converted to %s",
     158              :                             TypeNameToString(typeName),
     159              :                             format_type_be(typoid))));
     160              :         }
     161              :     }
     162              :     else
     163              :     {
     164              :         /* Normal reference to a type name */
     165              :         char       *schemaname;
     166              :         char       *typname;
     167              : 
     168              :         /* deconstruct the name list */
     169       330591 :         DeconstructQualifiedName(typeName->names, &schemaname, &typname);
     170              : 
     171       330585 :         if (schemaname)
     172              :         {
     173              :             /* Look in specific schema only */
     174              :             Oid         namespaceId;
     175              :             ParseCallbackState pcbstate;
     176              : 
     177       149903 :             setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
     178              : 
     179       149903 :             namespaceId = LookupExplicitNamespace(schemaname, missing_ok);
     180       149900 :             if (OidIsValid(namespaceId))
     181       149852 :                 typoid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
     182              :                                          PointerGetDatum(typname),
     183              :                                          ObjectIdGetDatum(namespaceId));
     184              :             else
     185           48 :                 typoid = InvalidOid;
     186              : 
     187       149900 :             cancel_parser_errposition_callback(&pcbstate);
     188              :         }
     189              :         else
     190              :         {
     191              :             /* Unqualified type name, so search the search path */
     192       180682 :             typoid = TypenameGetTypidExtended(typname, temp_ok);
     193              :         }
     194              : 
     195              :         /* If an array reference, return the array type instead */
     196       330582 :         if (typeName->arrayBounds != NIL)
     197         7895 :             typoid = get_array_type(typoid);
     198              :     }
     199              : 
     200       431943 :     if (!OidIsValid(typoid))
     201              :     {
     202        32816 :         if (typmod_p)
     203           28 :             *typmod_p = -1;
     204        32816 :         return NULL;
     205              :     }
     206              : 
     207       399127 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
     208       399127 :     if (!HeapTupleIsValid(tup)) /* should not happen */
     209            0 :         elog(ERROR, "cache lookup failed for type %u", typoid);
     210              : 
     211       399127 :     typmod = typenameTypeMod(pstate, typeName, (Type) tup);
     212              : 
     213       399121 :     if (typmod_p)
     214       309824 :         *typmod_p = typmod;
     215              : 
     216       399121 :     return (Type) tup;
     217              : }
     218              : 
     219              : /*
     220              :  * LookupTypeNameOid
     221              :  *      Given a TypeName object, lookup the pg_type syscache entry of the type.
     222              :  *      Returns InvalidOid if no such type can be found.  If the type is found,
     223              :  *      return its Oid.
     224              :  *
     225              :  * NB: direct callers of this function need to be aware that the type OID
     226              :  * returned may correspond to a shell type.  Most code should go through
     227              :  * typenameTypeId instead.
     228              :  *
     229              :  * pstate is only used for error location info, and may be NULL.
     230              :  */
     231              : Oid
     232        13190 : LookupTypeNameOid(ParseState *pstate, const TypeName *typeName, bool missing_ok)
     233              : {
     234              :     Oid         typoid;
     235              :     Type        tup;
     236              : 
     237        13190 :     tup = LookupTypeName(pstate, typeName, NULL, missing_ok);
     238        13190 :     if (tup == NULL)
     239              :     {
     240           90 :         if (!missing_ok)
     241           16 :             ereport(ERROR,
     242              :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     243              :                      errmsg("type \"%s\" does not exist",
     244              :                             TypeNameToString(typeName)),
     245              :                      parser_errposition(pstate, typeName->location)));
     246              : 
     247           74 :         return InvalidOid;
     248              :     }
     249              : 
     250        13100 :     typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
     251        13100 :     ReleaseSysCache(tup);
     252              : 
     253        13100 :     return typoid;
     254              : }
     255              : 
     256              : /*
     257              :  * typenameType - given a TypeName, return a Type structure and typmod
     258              :  *
     259              :  * This is equivalent to LookupTypeName, except that this will report
     260              :  * a suitable error message if the type cannot be found or is not defined.
     261              :  * Callers of this can therefore assume the result is a fully valid type.
     262              :  */
     263              : Type
     264       349347 : typenameType(ParseState *pstate, const TypeName *typeName, int32 *typmod_p)
     265              : {
     266              :     Type        tup;
     267              : 
     268       349347 :     tup = LookupTypeName(pstate, typeName, typmod_p, false);
     269       349344 :     if (tup == NULL)
     270           25 :         ereport(ERROR,
     271              :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     272              :                  errmsg("type \"%s\" does not exist",
     273              :                         TypeNameToString(typeName)),
     274              :                  parser_errposition(pstate, typeName->location)));
     275       349319 :     if (!((Form_pg_type) GETSTRUCT(tup))->typisdefined)
     276            3 :         ereport(ERROR,
     277              :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     278              :                  errmsg("type \"%s\" is only a shell",
     279              :                         TypeNameToString(typeName)),
     280              :                  parser_errposition(pstate, typeName->location)));
     281       349316 :     return tup;
     282              : }
     283              : 
     284              : /*
     285              :  * typenameTypeId - given a TypeName, return the type's OID
     286              :  *
     287              :  * This is similar to typenameType, but we only hand back the type OID
     288              :  * not the syscache entry.
     289              :  */
     290              : Oid
     291         5981 : typenameTypeId(ParseState *pstate, const TypeName *typeName)
     292              : {
     293              :     Oid         typoid;
     294              :     Type        tup;
     295              : 
     296         5981 :     tup = typenameType(pstate, typeName, NULL);
     297         5974 :     typoid = ((Form_pg_type) GETSTRUCT(tup))->oid;
     298         5974 :     ReleaseSysCache(tup);
     299              : 
     300         5974 :     return typoid;
     301              : }
     302              : 
     303              : /*
     304              :  * typenameTypeIdAndMod - given a TypeName, return the type's OID and typmod
     305              :  *
     306              :  * This is equivalent to typenameType, but we only hand back the type OID
     307              :  * and typmod, not the syscache entry.
     308              :  */
     309              : void
     310       306587 : typenameTypeIdAndMod(ParseState *pstate, const TypeName *typeName,
     311              :                      Oid *typeid_p, int32 *typmod_p)
     312              : {
     313              :     Type        tup;
     314              : 
     315       306587 :     tup = typenameType(pstate, typeName, typmod_p);
     316       306582 :     *typeid_p = ((Form_pg_type) GETSTRUCT(tup))->oid;
     317       306582 :     ReleaseSysCache(tup);
     318       306582 : }
     319              : 
     320              : /*
     321              :  * typenameTypeMod - given a TypeName, return the internal typmod value
     322              :  *
     323              :  * This will throw an error if the TypeName includes type modifiers that are
     324              :  * illegal for the data type.
     325              :  *
     326              :  * The actual type OID represented by the TypeName must already have been
     327              :  * looked up, and is passed as "typ".
     328              :  *
     329              :  * pstate is only used for error location info, and may be NULL.
     330              :  */
     331              : static int32
     332       399127 : typenameTypeMod(ParseState *pstate, const TypeName *typeName, Type typ)
     333              : {
     334              :     int32       result;
     335              :     Oid         typmodin;
     336              :     Datum      *datums;
     337              :     int         n;
     338              :     ListCell   *l;
     339              :     ArrayType  *arrtypmod;
     340              :     ParseCallbackState pcbstate;
     341              : 
     342              :     /* Return prespecified typmod if no typmod expressions */
     343       399127 :     if (typeName->typmods == NIL)
     344       394975 :         return typeName->typemod;
     345              : 
     346              :     /*
     347              :      * Else, type had better accept typmods.  We give a special error message
     348              :      * for the shell-type case, since a shell couldn't possibly have a
     349              :      * typmodin function.
     350              :      */
     351         4152 :     if (!((Form_pg_type) GETSTRUCT(typ))->typisdefined)
     352            0 :         ereport(ERROR,
     353              :                 (errcode(ERRCODE_SYNTAX_ERROR),
     354              :                  errmsg("type modifier cannot be specified for shell type \"%s\"",
     355              :                         TypeNameToString(typeName)),
     356              :                  parser_errposition(pstate, typeName->location)));
     357              : 
     358         4152 :     typmodin = ((Form_pg_type) GETSTRUCT(typ))->typmodin;
     359              : 
     360         4152 :     if (typmodin == InvalidOid)
     361            0 :         ereport(ERROR,
     362              :                 (errcode(ERRCODE_SYNTAX_ERROR),
     363              :                  errmsg("type modifier is not allowed for type \"%s\"",
     364              :                         TypeNameToString(typeName)),
     365              :                  parser_errposition(pstate, typeName->location)));
     366              : 
     367              :     /*
     368              :      * Convert the list of raw-grammar-output expressions to a cstring array.
     369              :      * Currently, we allow simple numeric constants, string literals, and
     370              :      * identifiers; possibly this list could be extended.
     371              :      */
     372         4152 :     datums = palloc_array(Datum, list_length(typeName->typmods));
     373         4152 :     n = 0;
     374         9277 :     foreach(l, typeName->typmods)
     375              :     {
     376         5125 :         Node       *tm = (Node *) lfirst(l);
     377         5125 :         char       *cstr = NULL;
     378              : 
     379         5125 :         if (IsA(tm, A_Const))
     380              :         {
     381         5125 :             A_Const    *ac = (A_Const *) tm;
     382              : 
     383         5125 :             if (IsA(&ac->val, Integer))
     384              :             {
     385         5125 :                 cstr = psprintf("%d", intVal(&ac->val));
     386              :             }
     387            0 :             else if (IsA(&ac->val, Float))
     388              :             {
     389              :                 /* we can just use the string representation directly. */
     390            0 :                 cstr = ac->val.fval.fval;
     391              :             }
     392            0 :             else if (IsA(&ac->val, String))
     393              :             {
     394              :                 /* we can just use the string representation directly. */
     395            0 :                 cstr = strVal(&ac->val);
     396              :             }
     397              :         }
     398            0 :         else if (IsA(tm, ColumnRef))
     399              :         {
     400            0 :             ColumnRef  *cr = (ColumnRef *) tm;
     401              : 
     402            0 :             if (list_length(cr->fields) == 1 &&
     403            0 :                 IsA(linitial(cr->fields), String))
     404            0 :                 cstr = strVal(linitial(cr->fields));
     405              :         }
     406         5125 :         if (!cstr)
     407            0 :             ereport(ERROR,
     408              :                     (errcode(ERRCODE_SYNTAX_ERROR),
     409              :                      errmsg("type modifiers must be simple constants or identifiers"),
     410              :                      parser_errposition(pstate, typeName->location)));
     411         5125 :         datums[n++] = CStringGetDatum(cstr);
     412              :     }
     413              : 
     414         4152 :     arrtypmod = construct_array_builtin(datums, n, CSTRINGOID);
     415              : 
     416              :     /* arrange to report location if type's typmodin function fails */
     417         4152 :     setup_parser_errposition_callback(&pcbstate, pstate, typeName->location);
     418              : 
     419         4152 :     result = DatumGetInt32(OidFunctionCall1(typmodin,
     420              :                                             PointerGetDatum(arrtypmod)));
     421              : 
     422         4146 :     cancel_parser_errposition_callback(&pcbstate);
     423              : 
     424         4146 :     pfree(datums);
     425         4146 :     pfree(arrtypmod);
     426              : 
     427         4146 :     return result;
     428              : }
     429              : 
     430              : /*
     431              :  * appendTypeNameToBuffer
     432              :  *      Append a string representing the name of a TypeName to a StringInfo.
     433              :  *      This is the shared guts of TypeNameToString and TypeNameListToString.
     434              :  *
     435              :  * NB: this must work on TypeNames that do not describe any actual type;
     436              :  * it is mostly used for reporting lookup errors.
     437              :  */
     438              : static void
     439         3486 : appendTypeNameToBuffer(const TypeName *typeName, StringInfo string)
     440              : {
     441         3486 :     if (typeName->names != NIL)
     442              :     {
     443              :         /* Emit possibly-qualified name as-is */
     444              :         ListCell   *l;
     445              : 
     446         7077 :         foreach(l, typeName->names)
     447              :         {
     448         3591 :             if (l != list_head(typeName->names))
     449          105 :                 appendStringInfoChar(string, '.');
     450         3591 :             appendStringInfoString(string, strVal(lfirst(l)));
     451              :         }
     452              :     }
     453              :     else
     454              :     {
     455              :         /* Look up internally-specified type */
     456            0 :         appendStringInfoString(string, format_type_be(typeName->typeOid));
     457              :     }
     458              : 
     459              :     /*
     460              :      * Add decoration as needed, but only for fields considered by
     461              :      * LookupTypeName
     462              :      */
     463         3486 :     if (typeName->pct_type)
     464           12 :         appendStringInfoString(string, "%TYPE");
     465              : 
     466         3486 :     if (typeName->arrayBounds != NIL)
     467            3 :         appendStringInfoString(string, "[]");
     468         3486 : }
     469              : 
     470              : /*
     471              :  * TypeNameToString
     472              :  *      Produce a string representing the name of a TypeName.
     473              :  *
     474              :  * NB: this must work on TypeNames that do not describe any actual type;
     475              :  * it is mostly used for reporting lookup errors.
     476              :  */
     477              : char *
     478         3474 : TypeNameToString(const TypeName *typeName)
     479              : {
     480              :     StringInfoData string;
     481              : 
     482         3474 :     initStringInfo(&string);
     483         3474 :     appendTypeNameToBuffer(typeName, &string);
     484         3474 :     return string.data;
     485              : }
     486              : 
     487              : /*
     488              :  * TypeNameListToString
     489              :  *      Produce a string representing the name(s) of a List of TypeNames
     490              :  */
     491              : char *
     492           20 : TypeNameListToString(List *typenames)
     493              : {
     494              :     StringInfoData string;
     495              :     ListCell   *l;
     496              : 
     497           20 :     initStringInfo(&string);
     498           32 :     foreach(l, typenames)
     499              :     {
     500           12 :         TypeName   *typeName = lfirst_node(TypeName, l);
     501              : 
     502           12 :         if (l != list_head(typenames))
     503            6 :             appendStringInfoChar(&string, ',');
     504           12 :         appendTypeNameToBuffer(typeName, &string);
     505              :     }
     506           20 :     return string.data;
     507              : }
     508              : 
     509              : /*
     510              :  * LookupCollation
     511              :  *
     512              :  * Look up collation by name, return OID, with support for error location.
     513              :  */
     514              : Oid
     515         5302 : LookupCollation(ParseState *pstate, List *collnames, int location)
     516              : {
     517              :     Oid         colloid;
     518              :     ParseCallbackState pcbstate;
     519              : 
     520         5302 :     if (pstate)
     521         5049 :         setup_parser_errposition_callback(&pcbstate, pstate, location);
     522              : 
     523         5302 :     colloid = get_collation_oid(collnames, false);
     524              : 
     525         5296 :     if (pstate)
     526         5043 :         cancel_parser_errposition_callback(&pcbstate);
     527              : 
     528         5296 :     return colloid;
     529              : }
     530              : 
     531              : /*
     532              :  * GetColumnDefCollation
     533              :  *
     534              :  * Get the collation to be used for a column being defined, given the
     535              :  * ColumnDef node and the previously-determined column type OID.
     536              :  *
     537              :  * pstate is only used for error location purposes, and can be NULL.
     538              :  */
     539              : Oid
     540       138074 : GetColumnDefCollation(ParseState *pstate, const ColumnDef *coldef, Oid typeOid)
     541              : {
     542              :     Oid         result;
     543       138074 :     Oid         typcollation = get_typcollation(typeOid);
     544       138074 :     int         location = coldef->location;
     545              : 
     546       138074 :     if (coldef->collClause)
     547              :     {
     548              :         /* We have a raw COLLATE clause, so look up the collation */
     549          259 :         location = coldef->collClause->location;
     550          259 :         result = LookupCollation(pstate, coldef->collClause->collname,
     551              :                                  location);
     552              :     }
     553       137815 :     else if (OidIsValid(coldef->collOid))
     554              :     {
     555              :         /* Precooked collation spec, use that */
     556        46213 :         result = coldef->collOid;
     557              :     }
     558              :     else
     559              :     {
     560              :         /* Use the type's default collation if any */
     561        91602 :         result = typcollation;
     562              :     }
     563              : 
     564              :     /* Complain if COLLATE is applied to an uncollatable type */
     565       138074 :     if (OidIsValid(result) && !OidIsValid(typcollation))
     566            3 :         ereport(ERROR,
     567              :                 (errcode(ERRCODE_DATATYPE_MISMATCH),
     568              :                  errmsg("collations are not supported by type %s",
     569              :                         format_type_be(typeOid)),
     570              :                  parser_errposition(pstate, location)));
     571              : 
     572       138071 :     return result;
     573              : }
     574              : 
     575              : /* return a Type structure, given a type id */
     576              : /* NB: caller must ReleaseSysCache the type tuple when done with it */
     577              : Type
     578       406378 : typeidType(Oid id)
     579              : {
     580              :     HeapTuple   tup;
     581              : 
     582       406378 :     tup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(id));
     583       406378 :     if (!HeapTupleIsValid(tup))
     584            0 :         elog(ERROR, "cache lookup failed for type %u", id);
     585       406378 :     return (Type) tup;
     586              : }
     587              : 
     588              : /* given type (as type struct), return the type OID */
     589              : Oid
     590        34813 : typeTypeId(Type tp)
     591              : {
     592        34813 :     if (tp == NULL)             /* probably useless */
     593            0 :         elog(ERROR, "typeTypeId() called with NULL type struct");
     594        34813 :     return ((Form_pg_type) GETSTRUCT(tp))->oid;
     595              : }
     596              : 
     597              : /* given type (as type struct), return the length of type */
     598              : int16
     599       395441 : typeLen(Type t)
     600              : {
     601              :     Form_pg_type typ;
     602              : 
     603       395441 :     typ = (Form_pg_type) GETSTRUCT(t);
     604       395441 :     return typ->typlen;
     605              : }
     606              : 
     607              : /* given type (as type struct), return its 'byval' attribute */
     608              : bool
     609       395441 : typeByVal(Type t)
     610              : {
     611              :     Form_pg_type typ;
     612              : 
     613       395441 :     typ = (Form_pg_type) GETSTRUCT(t);
     614       395441 :     return typ->typbyval;
     615              : }
     616              : 
     617              : /* given type (as type struct), return the type's name */
     618              : char *
     619            0 : typeTypeName(Type t)
     620              : {
     621              :     Form_pg_type typ;
     622              : 
     623            0 :     typ = (Form_pg_type) GETSTRUCT(t);
     624              :     /* pstrdup here because result may need to outlive the syscache entry */
     625            0 :     return pstrdup(NameStr(typ->typname));
     626              : }
     627              : 
     628              : /* given type (as type struct), return its 'typrelid' attribute */
     629              : Oid
     630          419 : typeTypeRelid(Type typ)
     631              : {
     632              :     Form_pg_type typtup;
     633              : 
     634          419 :     typtup = (Form_pg_type) GETSTRUCT(typ);
     635          419 :     return typtup->typrelid;
     636              : }
     637              : 
     638              : /* given type (as type struct), return its 'typcollation' attribute */
     639              : Oid
     640       395441 : typeTypeCollation(Type typ)
     641              : {
     642              :     Form_pg_type typtup;
     643              : 
     644       395441 :     typtup = (Form_pg_type) GETSTRUCT(typ);
     645       395441 :     return typtup->typcollation;
     646              : }
     647              : 
     648              : /*
     649              :  * Given a type structure and a string, returns the internal representation
     650              :  * of that string.  The "string" can be NULL to perform conversion of a NULL
     651              :  * (which might result in failure, if the input function rejects NULLs).
     652              :  */
     653              : Datum
     654       395441 : stringTypeDatum(Type tp, char *string, int32 atttypmod)
     655              : {
     656       395441 :     Form_pg_type typform = (Form_pg_type) GETSTRUCT(tp);
     657       395441 :     Oid         typinput = typform->typinput;
     658       395441 :     Oid         typioparam = getTypeIOParam(tp);
     659              : 
     660       395441 :     return OidInputFunctionCall(typinput, string, typioparam, atttypmod);
     661              : }
     662              : 
     663              : /*
     664              :  * Given a typeid, return the type's typrelid (associated relation), if any.
     665              :  * Returns InvalidOid if type is not a composite type.
     666              :  */
     667              : Oid
     668         7398 : typeidTypeRelid(Oid type_id)
     669              : {
     670              :     HeapTuple   typeTuple;
     671              :     Form_pg_type type;
     672              :     Oid         result;
     673              : 
     674         7398 :     typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
     675         7398 :     if (!HeapTupleIsValid(typeTuple))
     676            0 :         elog(ERROR, "cache lookup failed for type %u", type_id);
     677         7398 :     type = (Form_pg_type) GETSTRUCT(typeTuple);
     678         7398 :     result = type->typrelid;
     679         7398 :     ReleaseSysCache(typeTuple);
     680         7398 :     return result;
     681              : }
     682              : 
     683              : /*
     684              :  * Given a typeid, return the type's typrelid (associated relation), if any.
     685              :  * Returns InvalidOid if type is not a composite type or a domain over one.
     686              :  * This is the same as typeidTypeRelid(getBaseType(type_id)), but faster.
     687              :  */
     688              : Oid
     689       964018 : typeOrDomainTypeRelid(Oid type_id)
     690              : {
     691              :     HeapTuple   typeTuple;
     692              :     Form_pg_type type;
     693              :     Oid         result;
     694              : 
     695              :     for (;;)
     696              :     {
     697       995989 :         typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_id));
     698       995989 :         if (!HeapTupleIsValid(typeTuple))
     699            0 :             elog(ERROR, "cache lookup failed for type %u", type_id);
     700       995989 :         type = (Form_pg_type) GETSTRUCT(typeTuple);
     701       995989 :         if (type->typtype != TYPTYPE_DOMAIN)
     702              :         {
     703              :             /* Not a domain, so done looking through domains */
     704       964018 :             break;
     705              :         }
     706              :         /* It is a domain, so examine the base type instead */
     707        31971 :         type_id = type->typbasetype;
     708        31971 :         ReleaseSysCache(typeTuple);
     709              :     }
     710       964018 :     result = type->typrelid;
     711       964018 :     ReleaseSysCache(typeTuple);
     712       964018 :     return result;
     713              : }
     714              : 
     715              : /*
     716              :  * error context callback for parse failure during parseTypeString()
     717              :  */
     718              : static void
     719            3 : pts_error_callback(void *arg)
     720              : {
     721            3 :     const char *str = (const char *) arg;
     722              : 
     723            3 :     errcontext("invalid type name \"%s\"", str);
     724            3 : }
     725              : 
     726              : /*
     727              :  * Given a string that is supposed to be a SQL-compatible type declaration,
     728              :  * such as "int4" or "integer" or "character varying(32)", parse
     729              :  * the string and return the result as a TypeName.
     730              :  *
     731              :  * If the string cannot be parsed as a type, an error is raised,
     732              :  * unless escontext is an ErrorSaveContext node, in which case we may
     733              :  * fill that and return NULL.  But note that the ErrorSaveContext option
     734              :  * is mostly aspirational at present: errors detected by the main
     735              :  * grammar, rather than here, will still be thrown.
     736              :  */
     737              : TypeName *
     738         5163 : typeStringToTypeName(const char *str, Node *escontext)
     739              : {
     740              :     List       *raw_parsetree_list;
     741              :     TypeName   *typeName;
     742              :     ErrorContextCallback ptserrcontext;
     743              : 
     744              :     /* make sure we give useful error for empty input */
     745         5163 :     if (strspn(str, " \t\n\r\f\v") == strlen(str))
     746            0 :         goto fail;
     747              : 
     748              :     /*
     749              :      * Setup error traceback support in case of ereport() during parse
     750              :      */
     751         5163 :     ptserrcontext.callback = pts_error_callback;
     752         5163 :     ptserrcontext.arg = unconstify(char *, str);
     753         5163 :     ptserrcontext.previous = error_context_stack;
     754         5163 :     error_context_stack = &ptserrcontext;
     755              : 
     756         5163 :     raw_parsetree_list = raw_parser(str, RAW_PARSE_TYPE_NAME);
     757              : 
     758         5160 :     error_context_stack = ptserrcontext.previous;
     759              : 
     760              :     /* We should get back exactly one TypeName node. */
     761              :     Assert(list_length(raw_parsetree_list) == 1);
     762         5160 :     typeName = linitial_node(TypeName, raw_parsetree_list);
     763              : 
     764              :     /* The grammar allows SETOF in TypeName, but we don't want that here. */
     765         5160 :     if (typeName->setof)
     766            0 :         goto fail;
     767              : 
     768         5160 :     return typeName;
     769              : 
     770            0 : fail:
     771            0 :     ereturn(escontext, NULL,
     772              :             (errcode(ERRCODE_SYNTAX_ERROR),
     773              :              errmsg("invalid type name \"%s\"", str)));
     774              : }
     775              : 
     776              : /*
     777              :  * Given a string that is supposed to be a SQL-compatible type declaration,
     778              :  * such as "int4" or "integer" or "character varying(32)", parse
     779              :  * the string and convert it to a type OID and type modifier.
     780              :  *
     781              :  * If escontext is an ErrorSaveContext node, then errors are reported by
     782              :  * filling escontext and returning false, instead of throwing them.
     783              :  */
     784              : bool
     785         1947 : parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
     786              :                 Node *escontext)
     787              : {
     788              :     TypeName   *typeName;
     789              :     Type        tup;
     790              : 
     791         1947 :     typeName = typeStringToTypeName(str, escontext);
     792         1944 :     if (typeName == NULL)
     793            0 :         return false;
     794              : 
     795         1944 :     tup = LookupTypeName(NULL, typeName, typmod_p,
     796         1944 :                          (escontext && IsA(escontext, ErrorSaveContext)));
     797         1932 :     if (tup == NULL)
     798              :     {
     799           20 :         ereturn(escontext, false,
     800              :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
     801              :                  errmsg("type \"%s\" does not exist",
     802              :                         TypeNameToString(typeName))));
     803              :     }
     804              :     else
     805              :     {
     806         1912 :         Form_pg_type typ = (Form_pg_type) GETSTRUCT(tup);
     807              : 
     808         1912 :         if (!typ->typisdefined)
     809              :         {
     810            0 :             ReleaseSysCache(tup);
     811            0 :             ereturn(escontext, false,
     812              :                     (errcode(ERRCODE_UNDEFINED_OBJECT),
     813              :                      errmsg("type \"%s\" is only a shell",
     814              :                             TypeNameToString(typeName))));
     815              :         }
     816         1912 :         *typeid_p = typ->oid;
     817         1912 :         ReleaseSysCache(tup);
     818              :     }
     819              : 
     820         1912 :     return true;
     821              : }
        

Generated by: LCOV version 2.0-1