LCOV - code coverage report
Current view: top level - src/backend/utils/adt - regproc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 12beta2 Lines: 424 583 72.7 %
Date: 2019-06-19 16:07:09 Functions: 38 59 64.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * regproc.c
       4             :  *    Functions for the built-in types regproc, regclass, regtype, etc.
       5             :  *
       6             :  * These types are all binary-compatible with type Oid, and rely on Oid
       7             :  * for comparison and so forth.  Their only interesting behavior is in
       8             :  * special I/O conversion routines.
       9             :  *
      10             :  *
      11             :  * Portions Copyright (c) 1996-2019, PostgreSQL Global Development Group
      12             :  * Portions Copyright (c) 1994, Regents of the University of California
      13             :  *
      14             :  *
      15             :  * IDENTIFICATION
      16             :  *    src/backend/utils/adt/regproc.c
      17             :  *
      18             :  *-------------------------------------------------------------------------
      19             :  */
      20             : #include "postgres.h"
      21             : 
      22             : #include <ctype.h>
      23             : 
      24             : #include "access/htup_details.h"
      25             : #include "catalog/namespace.h"
      26             : #include "catalog/pg_class.h"
      27             : #include "catalog/pg_operator.h"
      28             : #include "catalog/pg_proc.h"
      29             : #include "catalog/pg_ts_config.h"
      30             : #include "catalog/pg_ts_dict.h"
      31             : #include "catalog/pg_type.h"
      32             : #include "lib/stringinfo.h"
      33             : #include "miscadmin.h"
      34             : #include "parser/parse_type.h"
      35             : #include "parser/scansup.h"
      36             : #include "utils/builtins.h"
      37             : #include "utils/lsyscache.h"
      38             : #include "utils/syscache.h"
      39             : #include "utils/acl.h"
      40             : #include "utils/regproc.h"
      41             : #include "utils/varlena.h"
      42             : 
      43             : static char *format_operator_internal(Oid operator_oid, bool force_qualify);
      44             : static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
      45             : static void parseNameAndArgTypes(const char *string, bool allowNone,
      46             :                                  List **names, int *nargs, Oid *argtypes);
      47             : 
      48             : 
      49             : /*****************************************************************************
      50             :  *   USER I/O ROUTINES                                                       *
      51             :  *****************************************************************************/
      52             : 
      53             : /*
      54             :  * regprocin        - converts "proname" to proc OID
      55             :  *
      56             :  * We also accept a numeric OID, for symmetry with the output routine.
      57             :  *
      58             :  * '-' signifies unknown (OID 0).  In all other cases, the input must
      59             :  * match an existing pg_proc entry.
      60             :  */
      61             : Datum
      62     2618828 : regprocin(PG_FUNCTION_ARGS)
      63             : {
      64     2618828 :     char       *pro_name_or_oid = PG_GETARG_CSTRING(0);
      65     2618828 :     RegProcedure result = InvalidOid;
      66             :     List       *names;
      67             :     FuncCandidateList clist;
      68             : 
      69             :     /* '-' ? */
      70     2618828 :     if (strcmp(pro_name_or_oid, "-") == 0)
      71      512616 :         PG_RETURN_OID(InvalidOid);
      72             : 
      73             :     /* Numeric OID? */
      74     4212424 :     if (pro_name_or_oid[0] >= '0' &&
      75     4212228 :         pro_name_or_oid[0] <= '9' &&
      76     2106016 :         strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
      77             :     {
      78     2106016 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
      79             :                                                       CStringGetDatum(pro_name_or_oid)));
      80     2106016 :         PG_RETURN_OID(result);
      81             :     }
      82             : 
      83             :     /* Else it's a name, possibly schema-qualified */
      84             : 
      85             :     /*
      86             :      * We should never get here in bootstrap mode, as all references should
      87             :      * have been resolved by genbki.pl.
      88             :      */
      89         196 :     if (IsBootstrapProcessingMode())
      90           0 :         elog(ERROR, "regproc values must be OIDs in bootstrap mode");
      91             : 
      92             :     /*
      93             :      * Normal case: parse the name into components and see if it matches any
      94             :      * pg_proc entries in the current search path.
      95             :      */
      96         196 :     names = stringToQualifiedNameList(pro_name_or_oid);
      97         196 :     clist = FuncnameGetCandidates(names, -1, NIL, false, false, false);
      98             : 
      99         192 :     if (clist == NULL)
     100           4 :         ereport(ERROR,
     101             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     102             :                  errmsg("function \"%s\" does not exist", pro_name_or_oid)));
     103         188 :     else if (clist->next != NULL)
     104           0 :         ereport(ERROR,
     105             :                 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
     106             :                  errmsg("more than one function named \"%s\"",
     107             :                         pro_name_or_oid)));
     108             : 
     109         188 :     result = clist->oid;
     110             : 
     111         188 :     PG_RETURN_OID(result);
     112             : }
     113             : 
     114             : /*
     115             :  * to_regproc   - converts "proname" to proc OID
     116             :  *
     117             :  * If the name is not found, we return NULL.
     118             :  */
     119             : Datum
     120          16 : to_regproc(PG_FUNCTION_ARGS)
     121             : {
     122          16 :     char       *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
     123             :     List       *names;
     124             :     FuncCandidateList clist;
     125             : 
     126             :     /*
     127             :      * Parse the name into components and see if it matches any pg_proc
     128             :      * entries in the current search path.
     129             :      */
     130          16 :     names = stringToQualifiedNameList(pro_name);
     131          16 :     clist = FuncnameGetCandidates(names, -1, NIL, false, false, true);
     132             : 
     133          16 :     if (clist == NULL || clist->next != NULL)
     134           8 :         PG_RETURN_NULL();
     135             : 
     136           8 :     PG_RETURN_OID(clist->oid);
     137             : }
     138             : 
     139             : /*
     140             :  * regprocout       - converts proc OID to "pro_name"
     141             :  */
     142             : Datum
     143        8062 : regprocout(PG_FUNCTION_ARGS)
     144             : {
     145        8062 :     RegProcedure proid = PG_GETARG_OID(0);
     146             :     char       *result;
     147             :     HeapTuple   proctup;
     148             : 
     149        8062 :     if (proid == InvalidOid)
     150             :     {
     151        4876 :         result = pstrdup("-");
     152        4876 :         PG_RETURN_CSTRING(result);
     153             :     }
     154             : 
     155        3186 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
     156             : 
     157        3186 :     if (HeapTupleIsValid(proctup))
     158             :     {
     159        3186 :         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
     160        3186 :         char       *proname = NameStr(procform->proname);
     161             : 
     162             :         /*
     163             :          * In bootstrap mode, skip the fancy namespace stuff and just return
     164             :          * the proc name.  (This path is only needed for debugging output
     165             :          * anyway.)
     166             :          */
     167        3186 :         if (IsBootstrapProcessingMode())
     168           0 :             result = pstrdup(proname);
     169             :         else
     170             :         {
     171             :             char       *nspname;
     172             :             FuncCandidateList clist;
     173             : 
     174             :             /*
     175             :              * Would this proc be found (uniquely!) by regprocin? If not,
     176             :              * qualify it.
     177             :              */
     178        3186 :             clist = FuncnameGetCandidates(list_make1(makeString(proname)),
     179             :                                           -1, NIL, false, false, false);
     180        5384 :             if (clist != NULL && clist->next == NULL &&
     181        2198 :                 clist->oid == proid)
     182        2198 :                 nspname = NULL;
     183             :             else
     184         988 :                 nspname = get_namespace_name(procform->pronamespace);
     185             : 
     186        3186 :             result = quote_qualified_identifier(nspname, proname);
     187             :         }
     188             : 
     189        3186 :         ReleaseSysCache(proctup);
     190             :     }
     191             :     else
     192             :     {
     193             :         /* If OID doesn't match any pg_proc entry, return it numerically */
     194           0 :         result = (char *) palloc(NAMEDATALEN);
     195           0 :         snprintf(result, NAMEDATALEN, "%u", proid);
     196             :     }
     197             : 
     198        3186 :     PG_RETURN_CSTRING(result);
     199             : }
     200             : 
     201             : /*
     202             :  *      regprocrecv         - converts external binary format to regproc
     203             :  */
     204             : Datum
     205           0 : regprocrecv(PG_FUNCTION_ARGS)
     206             : {
     207             :     /* Exactly the same as oidrecv, so share code */
     208           0 :     return oidrecv(fcinfo);
     209             : }
     210             : 
     211             : /*
     212             :  *      regprocsend         - converts regproc to binary format
     213             :  */
     214             : Datum
     215           0 : regprocsend(PG_FUNCTION_ARGS)
     216             : {
     217             :     /* Exactly the same as oidsend, so share code */
     218           0 :     return oidsend(fcinfo);
     219             : }
     220             : 
     221             : 
     222             : /*
     223             :  * regprocedurein       - converts "proname(args)" to proc OID
     224             :  *
     225             :  * We also accept a numeric OID, for symmetry with the output routine.
     226             :  *
     227             :  * '-' signifies unknown (OID 0).  In all other cases, the input must
     228             :  * match an existing pg_proc entry.
     229             :  */
     230             : Datum
     231         112 : regprocedurein(PG_FUNCTION_ARGS)
     232             : {
     233         112 :     char       *pro_name_or_oid = PG_GETARG_CSTRING(0);
     234         112 :     RegProcedure result = InvalidOid;
     235             :     List       *names;
     236             :     int         nargs;
     237             :     Oid         argtypes[FUNC_MAX_ARGS];
     238             :     FuncCandidateList clist;
     239             : 
     240             :     /* '-' ? */
     241         112 :     if (strcmp(pro_name_or_oid, "-") == 0)
     242           0 :         PG_RETURN_OID(InvalidOid);
     243             : 
     244             :     /* Numeric OID? */
     245         224 :     if (pro_name_or_oid[0] >= '0' &&
     246         112 :         pro_name_or_oid[0] <= '9' &&
     247           0 :         strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
     248             :     {
     249           0 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
     250             :                                                       CStringGetDatum(pro_name_or_oid)));
     251           0 :         PG_RETURN_OID(result);
     252             :     }
     253             : 
     254             :     /* The rest of this wouldn't work in bootstrap mode */
     255         112 :     if (IsBootstrapProcessingMode())
     256           0 :         elog(ERROR, "regprocedure values must be OIDs in bootstrap mode");
     257             : 
     258             :     /*
     259             :      * Else it's a name and arguments.  Parse the name and arguments, look up
     260             :      * potential matches in the current namespace search list, and scan to see
     261             :      * which one exactly matches the given argument types.  (There will not be
     262             :      * more than one match.)
     263             :      */
     264         112 :     parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
     265             : 
     266         112 :     clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false);
     267             : 
     268         108 :     for (; clist; clist = clist->next)
     269             :     {
     270         104 :         if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
     271         104 :             break;
     272             :     }
     273             : 
     274         108 :     if (clist == NULL)
     275           4 :         ereport(ERROR,
     276             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     277             :                  errmsg("function \"%s\" does not exist", pro_name_or_oid)));
     278             : 
     279         104 :     result = clist->oid;
     280             : 
     281         104 :     PG_RETURN_OID(result);
     282             : }
     283             : 
     284             : /*
     285             :  * to_regprocedure  - converts "proname(args)" to proc OID
     286             :  *
     287             :  * If the name is not found, we return NULL.
     288             :  */
     289             : Datum
     290          16 : to_regprocedure(PG_FUNCTION_ARGS)
     291             : {
     292          16 :     char       *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
     293             :     List       *names;
     294             :     int         nargs;
     295             :     Oid         argtypes[FUNC_MAX_ARGS];
     296             :     FuncCandidateList clist;
     297             : 
     298             :     /*
     299             :      * Parse the name and arguments, look up potential matches in the current
     300             :      * namespace search list, and scan to see which one exactly matches the
     301             :      * given argument types.    (There will not be more than one match.)
     302             :      */
     303          16 :     parseNameAndArgTypes(pro_name, false, &names, &nargs, argtypes);
     304             : 
     305          16 :     clist = FuncnameGetCandidates(names, nargs, NIL, false, false, true);
     306             : 
     307          16 :     for (; clist; clist = clist->next)
     308             :     {
     309           8 :         if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
     310           8 :             PG_RETURN_OID(clist->oid);
     311             :     }
     312             : 
     313           8 :     PG_RETURN_NULL();
     314             : }
     315             : 
     316             : /*
     317             :  * format_procedure     - converts proc OID to "pro_name(args)"
     318             :  *
     319             :  * This exports the useful functionality of regprocedureout for use
     320             :  * in other backend modules.  The result is a palloc'd string.
     321             :  */
     322             : char *
     323        6826 : format_procedure(Oid procedure_oid)
     324             : {
     325        6826 :     return format_procedure_internal(procedure_oid, false);
     326             : }
     327             : 
     328             : char *
     329         170 : format_procedure_qualified(Oid procedure_oid)
     330             : {
     331         170 :     return format_procedure_internal(procedure_oid, true);
     332             : }
     333             : 
     334             : /*
     335             :  * Routine to produce regprocedure names; see format_procedure above.
     336             :  *
     337             :  * force_qualify says whether to schema-qualify; if true, the name is always
     338             :  * qualified regardless of search_path visibility.  Otherwise the name is only
     339             :  * qualified if the function is not in path.
     340             :  */
     341             : static char *
     342        6996 : format_procedure_internal(Oid procedure_oid, bool force_qualify)
     343             : {
     344             :     char       *result;
     345             :     HeapTuple   proctup;
     346             : 
     347        6996 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
     348             : 
     349        6996 :     if (HeapTupleIsValid(proctup))
     350             :     {
     351        6996 :         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
     352        6996 :         char       *proname = NameStr(procform->proname);
     353        6996 :         int         nargs = procform->pronargs;
     354             :         int         i;
     355             :         char       *nspname;
     356             :         StringInfoData buf;
     357             : 
     358             :         /* XXX no support here for bootstrap mode */
     359             :         Assert(!IsBootstrapProcessingMode());
     360             : 
     361        6996 :         initStringInfo(&buf);
     362             : 
     363             :         /*
     364             :          * Would this proc be found (given the right args) by regprocedurein?
     365             :          * If not, or if caller requests it, we need to qualify it.
     366             :          */
     367        6996 :         if (!force_qualify && FunctionIsVisible(procedure_oid))
     368        6412 :             nspname = NULL;
     369             :         else
     370         584 :             nspname = get_namespace_name(procform->pronamespace);
     371             : 
     372        6996 :         appendStringInfo(&buf, "%s(",
     373             :                          quote_qualified_identifier(nspname, proname));
     374       15080 :         for (i = 0; i < nargs; i++)
     375             :         {
     376        8084 :             Oid         thisargtype = procform->proargtypes.values[i];
     377             : 
     378        8084 :             if (i > 0)
     379        3564 :                 appendStringInfoChar(&buf, ',');
     380        8084 :             appendStringInfoString(&buf,
     381             :                                    force_qualify ?
     382             :                                    format_type_be_qualified(thisargtype) :
     383             :                                    format_type_be(thisargtype));
     384             :         }
     385        6996 :         appendStringInfoChar(&buf, ')');
     386             : 
     387        6996 :         result = buf.data;
     388             : 
     389        6996 :         ReleaseSysCache(proctup);
     390             :     }
     391             :     else
     392             :     {
     393             :         /* If OID doesn't match any pg_proc entry, return it numerically */
     394           0 :         result = (char *) palloc(NAMEDATALEN);
     395           0 :         snprintf(result, NAMEDATALEN, "%u", procedure_oid);
     396             :     }
     397             : 
     398        6996 :     return result;
     399             : }
     400             : 
     401             : /*
     402             :  * Output an objname/objargs representation for the procedure with the
     403             :  * given OID.  If it doesn't exist, an error is thrown.
     404             :  *
     405             :  * This can be used to feed get_object_address.
     406             :  */
     407             : void
     408          66 : format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs)
     409             : {
     410             :     HeapTuple   proctup;
     411             :     Form_pg_proc procform;
     412             :     int         nargs;
     413             :     int         i;
     414             : 
     415          66 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
     416             : 
     417          66 :     if (!HeapTupleIsValid(proctup))
     418           0 :         elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid);
     419             : 
     420          66 :     procform = (Form_pg_proc) GETSTRUCT(proctup);
     421          66 :     nargs = procform->pronargs;
     422             : 
     423          66 :     *objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
     424             :                            pstrdup(NameStr(procform->proname)));
     425          66 :     *objargs = NIL;
     426         130 :     for (i = 0; i < nargs; i++)
     427             :     {
     428          64 :         Oid         thisargtype = procform->proargtypes.values[i];
     429             : 
     430          64 :         *objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
     431             :     }
     432             : 
     433          66 :     ReleaseSysCache(proctup);
     434          66 : }
     435             : 
     436             : /*
     437             :  * regprocedureout      - converts proc OID to "pro_name(args)"
     438             :  */
     439             : Datum
     440        1562 : regprocedureout(PG_FUNCTION_ARGS)
     441             : {
     442        1562 :     RegProcedure proid = PG_GETARG_OID(0);
     443             :     char       *result;
     444             : 
     445        1562 :     if (proid == InvalidOid)
     446         108 :         result = pstrdup("-");
     447             :     else
     448        1454 :         result = format_procedure(proid);
     449             : 
     450        1562 :     PG_RETURN_CSTRING(result);
     451             : }
     452             : 
     453             : /*
     454             :  *      regprocedurerecv            - converts external binary format to regprocedure
     455             :  */
     456             : Datum
     457           0 : regprocedurerecv(PG_FUNCTION_ARGS)
     458             : {
     459             :     /* Exactly the same as oidrecv, so share code */
     460           0 :     return oidrecv(fcinfo);
     461             : }
     462             : 
     463             : /*
     464             :  *      regproceduresend            - converts regprocedure to binary format
     465             :  */
     466             : Datum
     467           0 : regproceduresend(PG_FUNCTION_ARGS)
     468             : {
     469             :     /* Exactly the same as oidsend, so share code */
     470           0 :     return oidsend(fcinfo);
     471             : }
     472             : 
     473             : 
     474             : /*
     475             :  * regoperin        - converts "oprname" to operator OID
     476             :  *
     477             :  * We also accept a numeric OID, for symmetry with the output routine.
     478             :  *
     479             :  * '0' signifies unknown (OID 0).  In all other cases, the input must
     480             :  * match an existing pg_operator entry.
     481             :  */
     482             : Datum
     483          16 : regoperin(PG_FUNCTION_ARGS)
     484             : {
     485          16 :     char       *opr_name_or_oid = PG_GETARG_CSTRING(0);
     486          16 :     Oid         result = InvalidOid;
     487             :     List       *names;
     488             :     FuncCandidateList clist;
     489             : 
     490             :     /* '0' ? */
     491          16 :     if (strcmp(opr_name_or_oid, "0") == 0)
     492           0 :         PG_RETURN_OID(InvalidOid);
     493             : 
     494             :     /* Numeric OID? */
     495          32 :     if (opr_name_or_oid[0] >= '0' &&
     496          16 :         opr_name_or_oid[0] <= '9' &&
     497           0 :         strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
     498             :     {
     499           0 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
     500             :                                                       CStringGetDatum(opr_name_or_oid)));
     501           0 :         PG_RETURN_OID(result);
     502             :     }
     503             : 
     504             :     /* Else it's a name, possibly schema-qualified */
     505             : 
     506             :     /* The rest of this wouldn't work in bootstrap mode */
     507          16 :     if (IsBootstrapProcessingMode())
     508           0 :         elog(ERROR, "regoper values must be OIDs in bootstrap mode");
     509             : 
     510             :     /*
     511             :      * Normal case: parse the name into components and see if it matches any
     512             :      * pg_operator entries in the current search path.
     513             :      */
     514          16 :     names = stringToQualifiedNameList(opr_name_or_oid);
     515          16 :     clist = OpernameGetCandidates(names, '\0', false);
     516             : 
     517          12 :     if (clist == NULL)
     518           4 :         ereport(ERROR,
     519             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     520             :                  errmsg("operator does not exist: %s", opr_name_or_oid)));
     521           8 :     else if (clist->next != NULL)
     522           0 :         ereport(ERROR,
     523             :                 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
     524             :                  errmsg("more than one operator named %s",
     525             :                         opr_name_or_oid)));
     526             : 
     527           8 :     result = clist->oid;
     528             : 
     529           8 :     PG_RETURN_OID(result);
     530             : }
     531             : 
     532             : /*
     533             :  * to_regoper       - converts "oprname" to operator OID
     534             :  *
     535             :  * If the name is not found, we return NULL.
     536             :  */
     537             : Datum
     538          16 : to_regoper(PG_FUNCTION_ARGS)
     539             : {
     540          16 :     char       *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
     541             :     List       *names;
     542             :     FuncCandidateList clist;
     543             : 
     544             :     /*
     545             :      * Parse the name into components and see if it matches any pg_operator
     546             :      * entries in the current search path.
     547             :      */
     548          16 :     names = stringToQualifiedNameList(opr_name);
     549          16 :     clist = OpernameGetCandidates(names, '\0', true);
     550             : 
     551          16 :     if (clist == NULL || clist->next != NULL)
     552           8 :         PG_RETURN_NULL();
     553             : 
     554           8 :     PG_RETURN_OID(clist->oid);
     555             : }
     556             : 
     557             : /*
     558             :  * regoperout       - converts operator OID to "opr_name"
     559             :  */
     560             : Datum
     561          16 : regoperout(PG_FUNCTION_ARGS)
     562             : {
     563          16 :     Oid         oprid = PG_GETARG_OID(0);
     564             :     char       *result;
     565             :     HeapTuple   opertup;
     566             : 
     567          16 :     if (oprid == InvalidOid)
     568             :     {
     569           0 :         result = pstrdup("0");
     570           0 :         PG_RETURN_CSTRING(result);
     571             :     }
     572             : 
     573          16 :     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
     574             : 
     575          16 :     if (HeapTupleIsValid(opertup))
     576             :     {
     577          16 :         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
     578          16 :         char       *oprname = NameStr(operform->oprname);
     579             : 
     580             :         /*
     581             :          * In bootstrap mode, skip the fancy namespace stuff and just return
     582             :          * the oper name.  (This path is only needed for debugging output
     583             :          * anyway.)
     584             :          */
     585          16 :         if (IsBootstrapProcessingMode())
     586           0 :             result = pstrdup(oprname);
     587             :         else
     588             :         {
     589             :             FuncCandidateList clist;
     590             : 
     591             :             /*
     592             :              * Would this oper be found (uniquely!) by regoperin? If not,
     593             :              * qualify it.
     594             :              */
     595          16 :             clist = OpernameGetCandidates(list_make1(makeString(oprname)),
     596             :                                           '\0', false);
     597          32 :             if (clist != NULL && clist->next == NULL &&
     598          16 :                 clist->oid == oprid)
     599          16 :                 result = pstrdup(oprname);
     600             :             else
     601             :             {
     602             :                 const char *nspname;
     603             : 
     604           0 :                 nspname = get_namespace_name(operform->oprnamespace);
     605           0 :                 nspname = quote_identifier(nspname);
     606           0 :                 result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
     607           0 :                 sprintf(result, "%s.%s", nspname, oprname);
     608             :             }
     609             :         }
     610             : 
     611          16 :         ReleaseSysCache(opertup);
     612             :     }
     613             :     else
     614             :     {
     615             :         /*
     616             :          * If OID doesn't match any pg_operator entry, return it numerically
     617             :          */
     618           0 :         result = (char *) palloc(NAMEDATALEN);
     619           0 :         snprintf(result, NAMEDATALEN, "%u", oprid);
     620             :     }
     621             : 
     622          16 :     PG_RETURN_CSTRING(result);
     623             : }
     624             : 
     625             : /*
     626             :  *      regoperrecv         - converts external binary format to regoper
     627             :  */
     628             : Datum
     629           0 : regoperrecv(PG_FUNCTION_ARGS)
     630             : {
     631             :     /* Exactly the same as oidrecv, so share code */
     632           0 :     return oidrecv(fcinfo);
     633             : }
     634             : 
     635             : /*
     636             :  *      regopersend         - converts regoper to binary format
     637             :  */
     638             : Datum
     639           0 : regopersend(PG_FUNCTION_ARGS)
     640             : {
     641             :     /* Exactly the same as oidsend, so share code */
     642           0 :     return oidsend(fcinfo);
     643             : }
     644             : 
     645             : 
     646             : /*
     647             :  * regoperatorin        - converts "oprname(args)" to operator OID
     648             :  *
     649             :  * We also accept a numeric OID, for symmetry with the output routine.
     650             :  *
     651             :  * '0' signifies unknown (OID 0).  In all other cases, the input must
     652             :  * match an existing pg_operator entry.
     653             :  */
     654             : Datum
     655          36 : regoperatorin(PG_FUNCTION_ARGS)
     656             : {
     657          36 :     char       *opr_name_or_oid = PG_GETARG_CSTRING(0);
     658             :     Oid         result;
     659             :     List       *names;
     660             :     int         nargs;
     661             :     Oid         argtypes[FUNC_MAX_ARGS];
     662             : 
     663             :     /* '0' ? */
     664          36 :     if (strcmp(opr_name_or_oid, "0") == 0)
     665           0 :         PG_RETURN_OID(InvalidOid);
     666             : 
     667             :     /* Numeric OID? */
     668          64 :     if (opr_name_or_oid[0] >= '0' &&
     669          28 :         opr_name_or_oid[0] <= '9' &&
     670           0 :         strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
     671             :     {
     672           0 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
     673             :                                                       CStringGetDatum(opr_name_or_oid)));
     674           0 :         PG_RETURN_OID(result);
     675             :     }
     676             : 
     677             :     /* The rest of this wouldn't work in bootstrap mode */
     678          36 :     if (IsBootstrapProcessingMode())
     679           0 :         elog(ERROR, "regoperator values must be OIDs in bootstrap mode");
     680             : 
     681             :     /*
     682             :      * Else it's a name and arguments.  Parse the name and arguments, look up
     683             :      * potential matches in the current namespace search list, and scan to see
     684             :      * which one exactly matches the given argument types.  (There will not be
     685             :      * more than one match.)
     686             :      */
     687          36 :     parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
     688          36 :     if (nargs == 1)
     689           0 :         ereport(ERROR,
     690             :                 (errcode(ERRCODE_UNDEFINED_PARAMETER),
     691             :                  errmsg("missing argument"),
     692             :                  errhint("Use NONE to denote the missing argument of a unary operator.")));
     693          36 :     if (nargs != 2)
     694           0 :         ereport(ERROR,
     695             :                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
     696             :                  errmsg("too many arguments"),
     697             :                  errhint("Provide two argument types for operator.")));
     698             : 
     699          36 :     result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
     700             : 
     701          36 :     if (!OidIsValid(result))
     702           8 :         ereport(ERROR,
     703             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     704             :                  errmsg("operator does not exist: %s", opr_name_or_oid)));
     705             : 
     706          28 :     PG_RETURN_OID(result);
     707             : }
     708             : 
     709             : /*
     710             :  * to_regoperator   - converts "oprname(args)" to operator OID
     711             :  *
     712             :  * If the name is not found, we return NULL.
     713             :  */
     714             : Datum
     715          12 : to_regoperator(PG_FUNCTION_ARGS)
     716             : {
     717          12 :     char       *opr_name_or_oid = text_to_cstring(PG_GETARG_TEXT_PP(0));
     718             :     Oid         result;
     719             :     List       *names;
     720             :     int         nargs;
     721             :     Oid         argtypes[FUNC_MAX_ARGS];
     722             : 
     723             :     /*
     724             :      * Parse the name and arguments, look up potential matches in the current
     725             :      * namespace search list, and scan to see which one exactly matches the
     726             :      * given argument types.    (There will not be more than one match.)
     727             :      */
     728          12 :     parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
     729          12 :     if (nargs == 1)
     730           0 :         ereport(ERROR,
     731             :                 (errcode(ERRCODE_UNDEFINED_PARAMETER),
     732             :                  errmsg("missing argument"),
     733             :                  errhint("Use NONE to denote the missing argument of a unary operator.")));
     734          12 :     if (nargs != 2)
     735           0 :         ereport(ERROR,
     736             :                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
     737             :                  errmsg("too many arguments"),
     738             :                  errhint("Provide two argument types for operator.")));
     739             : 
     740          12 :     result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
     741             : 
     742          12 :     if (!OidIsValid(result))
     743           8 :         PG_RETURN_NULL();
     744             : 
     745           4 :     PG_RETURN_OID(result);
     746             : }
     747             : 
     748             : /*
     749             :  * format_operator      - converts operator OID to "opr_name(args)"
     750             :  *
     751             :  * This exports the useful functionality of regoperatorout for use
     752             :  * in other backend modules.  The result is a palloc'd string.
     753             :  */
     754             : static char *
     755        2008 : format_operator_internal(Oid operator_oid, bool force_qualify)
     756             : {
     757             :     char       *result;
     758             :     HeapTuple   opertup;
     759             : 
     760        2008 :     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
     761             : 
     762        2008 :     if (HeapTupleIsValid(opertup))
     763             :     {
     764        2008 :         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
     765        2008 :         char       *oprname = NameStr(operform->oprname);
     766             :         char       *nspname;
     767             :         StringInfoData buf;
     768             : 
     769             :         /* XXX no support here for bootstrap mode */
     770             :         Assert(!IsBootstrapProcessingMode());
     771             : 
     772        2008 :         initStringInfo(&buf);
     773             : 
     774             :         /*
     775             :          * Would this oper be found (given the right args) by regoperatorin?
     776             :          * If not, or if caller explicitly requests it, we need to qualify it.
     777             :          */
     778        2008 :         if (force_qualify || !OperatorIsVisible(operator_oid))
     779             :         {
     780         230 :             nspname = get_namespace_name(operform->oprnamespace);
     781         230 :             appendStringInfo(&buf, "%s.",
     782             :                              quote_identifier(nspname));
     783             :         }
     784             : 
     785        2008 :         appendStringInfo(&buf, "%s(", oprname);
     786             : 
     787        2008 :         if (operform->oprleft)
     788        3992 :             appendStringInfo(&buf, "%s,",
     789             :                              force_qualify ?
     790          32 :                              format_type_be_qualified(operform->oprleft) :
     791        1964 :                              format_type_be(operform->oprleft));
     792             :         else
     793          12 :             appendStringInfoString(&buf, "NONE,");
     794             : 
     795        2008 :         if (operform->oprright)
     796        4016 :             appendStringInfo(&buf, "%s)",
     797             :                              force_qualify ?
     798          32 :                              format_type_be_qualified(operform->oprright) :
     799        1976 :                              format_type_be(operform->oprright));
     800             :         else
     801           0 :             appendStringInfoString(&buf, "NONE)");
     802             : 
     803        2008 :         result = buf.data;
     804             : 
     805        2008 :         ReleaseSysCache(opertup);
     806             :     }
     807             :     else
     808             :     {
     809             :         /*
     810             :          * If OID doesn't match any pg_operator entry, return it numerically
     811             :          */
     812           0 :         result = (char *) palloc(NAMEDATALEN);
     813           0 :         snprintf(result, NAMEDATALEN, "%u", operator_oid);
     814             :     }
     815             : 
     816        2008 :     return result;
     817             : }
     818             : 
     819             : char *
     820        1976 : format_operator(Oid operator_oid)
     821             : {
     822        1976 :     return format_operator_internal(operator_oid, false);
     823             : }
     824             : 
     825             : char *
     826          32 : format_operator_qualified(Oid operator_oid)
     827             : {
     828          32 :     return format_operator_internal(operator_oid, true);
     829             : }
     830             : 
     831             : void
     832           4 : format_operator_parts(Oid operator_oid, List **objnames, List **objargs)
     833             : {
     834             :     HeapTuple   opertup;
     835             :     Form_pg_operator oprForm;
     836             : 
     837           4 :     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
     838           4 :     if (!HeapTupleIsValid(opertup))
     839           0 :         elog(ERROR, "cache lookup failed for operator with OID %u",
     840             :              operator_oid);
     841             : 
     842           4 :     oprForm = (Form_pg_operator) GETSTRUCT(opertup);
     843           4 :     *objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
     844             :                            pstrdup(NameStr(oprForm->oprname)));
     845           4 :     *objargs = NIL;
     846           4 :     if (oprForm->oprleft)
     847           4 :         *objargs = lappend(*objargs,
     848           4 :                            format_type_be_qualified(oprForm->oprleft));
     849           4 :     if (oprForm->oprright)
     850           4 :         *objargs = lappend(*objargs,
     851           4 :                            format_type_be_qualified(oprForm->oprright));
     852             : 
     853           4 :     ReleaseSysCache(opertup);
     854           4 : }
     855             : 
     856             : /*
     857             :  * regoperatorout       - converts operator OID to "opr_name(args)"
     858             :  */
     859             : Datum
     860         464 : regoperatorout(PG_FUNCTION_ARGS)
     861             : {
     862         464 :     Oid         oprid = PG_GETARG_OID(0);
     863             :     char       *result;
     864             : 
     865         464 :     if (oprid == InvalidOid)
     866           0 :         result = pstrdup("0");
     867             :     else
     868         464 :         result = format_operator(oprid);
     869             : 
     870         464 :     PG_RETURN_CSTRING(result);
     871             : }
     872             : 
     873             : /*
     874             :  *      regoperatorrecv         - converts external binary format to regoperator
     875             :  */
     876             : Datum
     877           0 : regoperatorrecv(PG_FUNCTION_ARGS)
     878             : {
     879             :     /* Exactly the same as oidrecv, so share code */
     880           0 :     return oidrecv(fcinfo);
     881             : }
     882             : 
     883             : /*
     884             :  *      regoperatorsend         - converts regoperator to binary format
     885             :  */
     886             : Datum
     887           0 : regoperatorsend(PG_FUNCTION_ARGS)
     888             : {
     889             :     /* Exactly the same as oidsend, so share code */
     890           0 :     return oidsend(fcinfo);
     891             : }
     892             : 
     893             : 
     894             : /*
     895             :  * regclassin       - converts "classname" to class OID
     896             :  *
     897             :  * We also accept a numeric OID, for symmetry with the output routine.
     898             :  *
     899             :  * '-' signifies unknown (OID 0).  In all other cases, the input must
     900             :  * match an existing pg_class entry.
     901             :  */
     902             : Datum
     903       22684 : regclassin(PG_FUNCTION_ARGS)
     904             : {
     905       22684 :     char       *class_name_or_oid = PG_GETARG_CSTRING(0);
     906       22684 :     Oid         result = InvalidOid;
     907             :     List       *names;
     908             : 
     909             :     /* '-' ? */
     910       22684 :     if (strcmp(class_name_or_oid, "-") == 0)
     911           0 :         PG_RETURN_OID(InvalidOid);
     912             : 
     913             :     /* Numeric OID? */
     914       43292 :     if (class_name_or_oid[0] >= '0' &&
     915       22300 :         class_name_or_oid[0] <= '9' &&
     916        1692 :         strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
     917             :     {
     918        1692 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
     919             :                                                       CStringGetDatum(class_name_or_oid)));
     920        1692 :         PG_RETURN_OID(result);
     921             :     }
     922             : 
     923             :     /* Else it's a name, possibly schema-qualified */
     924             : 
     925             :     /* The rest of this wouldn't work in bootstrap mode */
     926       20992 :     if (IsBootstrapProcessingMode())
     927           0 :         elog(ERROR, "regclass values must be OIDs in bootstrap mode");
     928             : 
     929             :     /*
     930             :      * Normal case: parse the name into components and see if it matches any
     931             :      * pg_class entries in the current search path.
     932             :      */
     933       20992 :     names = stringToQualifiedNameList(class_name_or_oid);
     934             : 
     935             :     /* We might not even have permissions on this relation; don't lock it. */
     936       20992 :     result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false);
     937             : 
     938       20976 :     PG_RETURN_OID(result);
     939             : }
     940             : 
     941             : /*
     942             :  * to_regclass      - converts "classname" to class OID
     943             :  *
     944             :  * If the name is not found, we return NULL.
     945             :  */
     946             : Datum
     947          16 : to_regclass(PG_FUNCTION_ARGS)
     948             : {
     949          16 :     char       *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
     950             :     Oid         result;
     951             :     List       *names;
     952             : 
     953             :     /*
     954             :      * Parse the name into components and see if it matches any pg_class
     955             :      * entries in the current search path.
     956             :      */
     957          16 :     names = stringToQualifiedNameList(class_name);
     958             : 
     959             :     /* We might not even have permissions on this relation; don't lock it. */
     960          16 :     result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
     961             : 
     962          16 :     if (OidIsValid(result))
     963           8 :         PG_RETURN_OID(result);
     964             :     else
     965           8 :         PG_RETURN_NULL();
     966             : }
     967             : 
     968             : /*
     969             :  * regclassout      - converts class OID to "class_name"
     970             :  */
     971             : Datum
     972       80276 : regclassout(PG_FUNCTION_ARGS)
     973             : {
     974       80276 :     Oid         classid = PG_GETARG_OID(0);
     975             :     char       *result;
     976             :     HeapTuple   classtup;
     977             : 
     978       80276 :     if (classid == InvalidOid)
     979             :     {
     980         116 :         result = pstrdup("-");
     981         116 :         PG_RETURN_CSTRING(result);
     982             :     }
     983             : 
     984       80160 :     classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
     985             : 
     986       80160 :     if (HeapTupleIsValid(classtup))
     987             :     {
     988       80160 :         Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
     989       80160 :         char       *classname = NameStr(classform->relname);
     990             : 
     991             :         /*
     992             :          * In bootstrap mode, skip the fancy namespace stuff and just return
     993             :          * the class name.  (This path is only needed for debugging output
     994             :          * anyway.)
     995             :          */
     996       80160 :         if (IsBootstrapProcessingMode())
     997           0 :             result = pstrdup(classname);
     998             :         else
     999             :         {
    1000             :             char       *nspname;
    1001             : 
    1002             :             /*
    1003             :              * Would this class be found by regclassin? If not, qualify it.
    1004             :              */
    1005       80160 :             if (RelationIsVisible(classid))
    1006       51638 :                 nspname = NULL;
    1007             :             else
    1008       28522 :                 nspname = get_namespace_name(classform->relnamespace);
    1009             : 
    1010       80160 :             result = quote_qualified_identifier(nspname, classname);
    1011             :         }
    1012             : 
    1013       80160 :         ReleaseSysCache(classtup);
    1014             :     }
    1015             :     else
    1016             :     {
    1017             :         /* If OID doesn't match any pg_class entry, return it numerically */
    1018           0 :         result = (char *) palloc(NAMEDATALEN);
    1019           0 :         snprintf(result, NAMEDATALEN, "%u", classid);
    1020             :     }
    1021             : 
    1022       80160 :     PG_RETURN_CSTRING(result);
    1023             : }
    1024             : 
    1025             : /*
    1026             :  *      regclassrecv            - converts external binary format to regclass
    1027             :  */
    1028             : Datum
    1029           0 : regclassrecv(PG_FUNCTION_ARGS)
    1030             : {
    1031             :     /* Exactly the same as oidrecv, so share code */
    1032           0 :     return oidrecv(fcinfo);
    1033             : }
    1034             : 
    1035             : /*
    1036             :  *      regclasssend            - converts regclass to binary format
    1037             :  */
    1038             : Datum
    1039           0 : regclasssend(PG_FUNCTION_ARGS)
    1040             : {
    1041             :     /* Exactly the same as oidsend, so share code */
    1042           0 :     return oidsend(fcinfo);
    1043             : }
    1044             : 
    1045             : 
    1046             : /*
    1047             :  * regtypein        - converts "typename" to type OID
    1048             :  *
    1049             :  * The type name can be specified using the full type syntax recognized by
    1050             :  * the parser; for example, DOUBLE PRECISION and INTEGER[] will work and be
    1051             :  * translated to the correct type names.  (We ignore any typmod info
    1052             :  * generated by the parser, however.)
    1053             :  *
    1054             :  * We also accept a numeric OID, for symmetry with the output routine,
    1055             :  * and for possible use in bootstrap mode.
    1056             :  *
    1057             :  * '-' signifies unknown (OID 0).  In all other cases, the input must
    1058             :  * match an existing pg_type entry.
    1059             :  */
    1060             : Datum
    1061         480 : regtypein(PG_FUNCTION_ARGS)
    1062             : {
    1063         480 :     char       *typ_name_or_oid = PG_GETARG_CSTRING(0);
    1064         480 :     Oid         result = InvalidOid;
    1065             :     int32       typmod;
    1066             : 
    1067             :     /* '-' ? */
    1068         480 :     if (strcmp(typ_name_or_oid, "-") == 0)
    1069           0 :         PG_RETURN_OID(InvalidOid);
    1070             : 
    1071             :     /* Numeric OID? */
    1072         960 :     if (typ_name_or_oid[0] >= '0' &&
    1073         500 :         typ_name_or_oid[0] <= '9' &&
    1074          20 :         strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
    1075             :     {
    1076          20 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
    1077             :                                                       CStringGetDatum(typ_name_or_oid)));
    1078          20 :         PG_RETURN_OID(result);
    1079             :     }
    1080             : 
    1081             :     /* Else it's a type name, possibly schema-qualified or decorated */
    1082             : 
    1083             :     /* The rest of this wouldn't work in bootstrap mode */
    1084         460 :     if (IsBootstrapProcessingMode())
    1085           0 :         elog(ERROR, "regtype values must be OIDs in bootstrap mode");
    1086             : 
    1087             :     /*
    1088             :      * Normal case: invoke the full parser to deal with special cases such as
    1089             :      * array syntax.
    1090             :      */
    1091         460 :     parseTypeString(typ_name_or_oid, &result, &typmod, false);
    1092             : 
    1093         452 :     PG_RETURN_OID(result);
    1094             : }
    1095             : 
    1096             : /*
    1097             :  * to_regtype       - converts "typename" to type OID
    1098             :  *
    1099             :  * If the name is not found, we return NULL.
    1100             :  */
    1101             : Datum
    1102          16 : to_regtype(PG_FUNCTION_ARGS)
    1103             : {
    1104          16 :     char       *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1105             :     Oid         result;
    1106             :     int32       typmod;
    1107             : 
    1108             :     /*
    1109             :      * Invoke the full parser to deal with special cases such as array syntax.
    1110             :      */
    1111          16 :     parseTypeString(typ_name, &result, &typmod, true);
    1112             : 
    1113          16 :     if (OidIsValid(result))
    1114           8 :         PG_RETURN_OID(result);
    1115             :     else
    1116           8 :         PG_RETURN_NULL();
    1117             : }
    1118             : 
    1119             : /*
    1120             :  * regtypeout       - converts type OID to "typ_name"
    1121             :  */
    1122             : Datum
    1123        1874 : regtypeout(PG_FUNCTION_ARGS)
    1124             : {
    1125        1874 :     Oid         typid = PG_GETARG_OID(0);
    1126             :     char       *result;
    1127             :     HeapTuple   typetup;
    1128             : 
    1129        1874 :     if (typid == InvalidOid)
    1130             :     {
    1131         450 :         result = pstrdup("-");
    1132         450 :         PG_RETURN_CSTRING(result);
    1133             :     }
    1134             : 
    1135        1424 :     typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    1136             : 
    1137        1424 :     if (HeapTupleIsValid(typetup))
    1138             :     {
    1139        1424 :         Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
    1140             : 
    1141             :         /*
    1142             :          * In bootstrap mode, skip the fancy namespace stuff and just return
    1143             :          * the type name.  (This path is only needed for debugging output
    1144             :          * anyway.)
    1145             :          */
    1146        1424 :         if (IsBootstrapProcessingMode())
    1147             :         {
    1148           0 :             char       *typname = NameStr(typeform->typname);
    1149             : 
    1150           0 :             result = pstrdup(typname);
    1151             :         }
    1152             :         else
    1153        1424 :             result = format_type_be(typid);
    1154             : 
    1155        1424 :         ReleaseSysCache(typetup);
    1156             :     }
    1157             :     else
    1158             :     {
    1159             :         /* If OID doesn't match any pg_type entry, return it numerically */
    1160           0 :         result = (char *) palloc(NAMEDATALEN);
    1161           0 :         snprintf(result, NAMEDATALEN, "%u", typid);
    1162             :     }
    1163             : 
    1164        1424 :     PG_RETURN_CSTRING(result);
    1165             : }
    1166             : 
    1167             : /*
    1168             :  *      regtyperecv         - converts external binary format to regtype
    1169             :  */
    1170             : Datum
    1171           0 : regtyperecv(PG_FUNCTION_ARGS)
    1172             : {
    1173             :     /* Exactly the same as oidrecv, so share code */
    1174           0 :     return oidrecv(fcinfo);
    1175             : }
    1176             : 
    1177             : /*
    1178             :  *      regtypesend         - converts regtype to binary format
    1179             :  */
    1180             : Datum
    1181           0 : regtypesend(PG_FUNCTION_ARGS)
    1182             : {
    1183             :     /* Exactly the same as oidsend, so share code */
    1184           0 :     return oidsend(fcinfo);
    1185             : }
    1186             : 
    1187             : 
    1188             : /*
    1189             :  * regconfigin      - converts "tsconfigname" to tsconfig OID
    1190             :  *
    1191             :  * We also accept a numeric OID, for symmetry with the output routine.
    1192             :  *
    1193             :  * '-' signifies unknown (OID 0).  In all other cases, the input must
    1194             :  * match an existing pg_ts_config entry.
    1195             :  */
    1196             : Datum
    1197        1116 : regconfigin(PG_FUNCTION_ARGS)
    1198             : {
    1199        1116 :     char       *cfg_name_or_oid = PG_GETARG_CSTRING(0);
    1200             :     Oid         result;
    1201             :     List       *names;
    1202             : 
    1203             :     /* '-' ? */
    1204        1116 :     if (strcmp(cfg_name_or_oid, "-") == 0)
    1205           0 :         PG_RETURN_OID(InvalidOid);
    1206             : 
    1207             :     /* Numeric OID? */
    1208        2232 :     if (cfg_name_or_oid[0] >= '0' &&
    1209        1116 :         cfg_name_or_oid[0] <= '9' &&
    1210           0 :         strspn(cfg_name_or_oid, "0123456789") == strlen(cfg_name_or_oid))
    1211             :     {
    1212           0 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
    1213             :                                                       CStringGetDatum(cfg_name_or_oid)));
    1214           0 :         PG_RETURN_OID(result);
    1215             :     }
    1216             : 
    1217             :     /* The rest of this wouldn't work in bootstrap mode */
    1218        1116 :     if (IsBootstrapProcessingMode())
    1219           0 :         elog(ERROR, "regconfig values must be OIDs in bootstrap mode");
    1220             : 
    1221             :     /*
    1222             :      * Normal case: parse the name into components and see if it matches any
    1223             :      * pg_ts_config entries in the current search path.
    1224             :      */
    1225        1116 :     names = stringToQualifiedNameList(cfg_name_or_oid);
    1226             : 
    1227        1116 :     result = get_ts_config_oid(names, false);
    1228             : 
    1229        1116 :     PG_RETURN_OID(result);
    1230             : }
    1231             : 
    1232             : /*
    1233             :  * regconfigout     - converts tsconfig OID to "tsconfigname"
    1234             :  */
    1235             : Datum
    1236           0 : regconfigout(PG_FUNCTION_ARGS)
    1237             : {
    1238           0 :     Oid         cfgid = PG_GETARG_OID(0);
    1239             :     char       *result;
    1240             :     HeapTuple   cfgtup;
    1241             : 
    1242           0 :     if (cfgid == InvalidOid)
    1243             :     {
    1244           0 :         result = pstrdup("-");
    1245           0 :         PG_RETURN_CSTRING(result);
    1246             :     }
    1247             : 
    1248           0 :     cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
    1249             : 
    1250           0 :     if (HeapTupleIsValid(cfgtup))
    1251             :     {
    1252           0 :         Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
    1253           0 :         char       *cfgname = NameStr(cfgform->cfgname);
    1254             :         char       *nspname;
    1255             : 
    1256             :         /*
    1257             :          * Would this config be found by regconfigin? If not, qualify it.
    1258             :          */
    1259           0 :         if (TSConfigIsVisible(cfgid))
    1260           0 :             nspname = NULL;
    1261             :         else
    1262           0 :             nspname = get_namespace_name(cfgform->cfgnamespace);
    1263             : 
    1264           0 :         result = quote_qualified_identifier(nspname, cfgname);
    1265             : 
    1266           0 :         ReleaseSysCache(cfgtup);
    1267             :     }
    1268             :     else
    1269             :     {
    1270             :         /* If OID doesn't match any pg_ts_config row, return it numerically */
    1271           0 :         result = (char *) palloc(NAMEDATALEN);
    1272           0 :         snprintf(result, NAMEDATALEN, "%u", cfgid);
    1273             :     }
    1274             : 
    1275           0 :     PG_RETURN_CSTRING(result);
    1276             : }
    1277             : 
    1278             : /*
    1279             :  *      regconfigrecv           - converts external binary format to regconfig
    1280             :  */
    1281             : Datum
    1282           0 : regconfigrecv(PG_FUNCTION_ARGS)
    1283             : {
    1284             :     /* Exactly the same as oidrecv, so share code */
    1285           0 :     return oidrecv(fcinfo);
    1286             : }
    1287             : 
    1288             : /*
    1289             :  *      regconfigsend           - converts regconfig to binary format
    1290             :  */
    1291             : Datum
    1292           0 : regconfigsend(PG_FUNCTION_ARGS)
    1293             : {
    1294             :     /* Exactly the same as oidsend, so share code */
    1295           0 :     return oidsend(fcinfo);
    1296             : }
    1297             : 
    1298             : 
    1299             : /*
    1300             :  * regdictionaryin      - converts "tsdictionaryname" to tsdictionary OID
    1301             :  *
    1302             :  * We also accept a numeric OID, for symmetry with the output routine.
    1303             :  *
    1304             :  * '-' signifies unknown (OID 0).  In all other cases, the input must
    1305             :  * match an existing pg_ts_dict entry.
    1306             :  */
    1307             : Datum
    1308         446 : regdictionaryin(PG_FUNCTION_ARGS)
    1309             : {
    1310         446 :     char       *dict_name_or_oid = PG_GETARG_CSTRING(0);
    1311             :     Oid         result;
    1312             :     List       *names;
    1313             : 
    1314             :     /* '-' ? */
    1315         446 :     if (strcmp(dict_name_or_oid, "-") == 0)
    1316           0 :         PG_RETURN_OID(InvalidOid);
    1317             : 
    1318             :     /* Numeric OID? */
    1319         892 :     if (dict_name_or_oid[0] >= '0' &&
    1320         446 :         dict_name_or_oid[0] <= '9' &&
    1321           0 :         strspn(dict_name_or_oid, "0123456789") == strlen(dict_name_or_oid))
    1322             :     {
    1323           0 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
    1324             :                                                       CStringGetDatum(dict_name_or_oid)));
    1325           0 :         PG_RETURN_OID(result);
    1326             :     }
    1327             : 
    1328             :     /* The rest of this wouldn't work in bootstrap mode */
    1329         446 :     if (IsBootstrapProcessingMode())
    1330           0 :         elog(ERROR, "regdictionary values must be OIDs in bootstrap mode");
    1331             : 
    1332             :     /*
    1333             :      * Normal case: parse the name into components and see if it matches any
    1334             :      * pg_ts_dict entries in the current search path.
    1335             :      */
    1336         446 :     names = stringToQualifiedNameList(dict_name_or_oid);
    1337             : 
    1338         446 :     result = get_ts_dict_oid(names, false);
    1339             : 
    1340         446 :     PG_RETURN_OID(result);
    1341             : }
    1342             : 
    1343             : /*
    1344             :  * regdictionaryout     - converts tsdictionary OID to "tsdictionaryname"
    1345             :  */
    1346             : Datum
    1347        1590 : regdictionaryout(PG_FUNCTION_ARGS)
    1348             : {
    1349        1590 :     Oid         dictid = PG_GETARG_OID(0);
    1350             :     char       *result;
    1351             :     HeapTuple   dicttup;
    1352             : 
    1353        1590 :     if (dictid == InvalidOid)
    1354             :     {
    1355           0 :         result = pstrdup("-");
    1356           0 :         PG_RETURN_CSTRING(result);
    1357             :     }
    1358             : 
    1359        1590 :     dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
    1360             : 
    1361        1590 :     if (HeapTupleIsValid(dicttup))
    1362             :     {
    1363        1590 :         Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
    1364        1590 :         char       *dictname = NameStr(dictform->dictname);
    1365             :         char       *nspname;
    1366             : 
    1367             :         /*
    1368             :          * Would this dictionary be found by regdictionaryin? If not, qualify
    1369             :          * it.
    1370             :          */
    1371        1590 :         if (TSDictionaryIsVisible(dictid))
    1372        1428 :             nspname = NULL;
    1373             :         else
    1374         162 :             nspname = get_namespace_name(dictform->dictnamespace);
    1375             : 
    1376        1590 :         result = quote_qualified_identifier(nspname, dictname);
    1377             : 
    1378        1590 :         ReleaseSysCache(dicttup);
    1379             :     }
    1380             :     else
    1381             :     {
    1382             :         /* If OID doesn't match any pg_ts_dict row, return it numerically */
    1383           0 :         result = (char *) palloc(NAMEDATALEN);
    1384           0 :         snprintf(result, NAMEDATALEN, "%u", dictid);
    1385             :     }
    1386             : 
    1387        1590 :     PG_RETURN_CSTRING(result);
    1388             : }
    1389             : 
    1390             : /*
    1391             :  *      regdictionaryrecv   - converts external binary format to regdictionary
    1392             :  */
    1393             : Datum
    1394           0 : regdictionaryrecv(PG_FUNCTION_ARGS)
    1395             : {
    1396             :     /* Exactly the same as oidrecv, so share code */
    1397           0 :     return oidrecv(fcinfo);
    1398             : }
    1399             : 
    1400             : /*
    1401             :  *      regdictionarysend   - converts regdictionary to binary format
    1402             :  */
    1403             : Datum
    1404           0 : regdictionarysend(PG_FUNCTION_ARGS)
    1405             : {
    1406             :     /* Exactly the same as oidsend, so share code */
    1407           0 :     return oidsend(fcinfo);
    1408             : }
    1409             : 
    1410             : /*
    1411             :  * regrolein    - converts "rolename" to role OID
    1412             :  *
    1413             :  * We also accept a numeric OID, for symmetry with the output routine.
    1414             :  *
    1415             :  * '-' signifies unknown (OID 0).  In all other cases, the input must
    1416             :  * match an existing pg_authid entry.
    1417             :  */
    1418             : Datum
    1419          36 : regrolein(PG_FUNCTION_ARGS)
    1420             : {
    1421          36 :     char       *role_name_or_oid = PG_GETARG_CSTRING(0);
    1422             :     Oid         result;
    1423             :     List       *names;
    1424             : 
    1425             :     /* '-' ? */
    1426          36 :     if (strcmp(role_name_or_oid, "-") == 0)
    1427           0 :         PG_RETURN_OID(InvalidOid);
    1428             : 
    1429             :     /* Numeric OID? */
    1430          60 :     if (role_name_or_oid[0] >= '0' &&
    1431          24 :         role_name_or_oid[0] <= '9' &&
    1432           0 :         strspn(role_name_or_oid, "0123456789") == strlen(role_name_or_oid))
    1433             :     {
    1434           0 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
    1435             :                                                       CStringGetDatum(role_name_or_oid)));
    1436           0 :         PG_RETURN_OID(result);
    1437             :     }
    1438             : 
    1439             :     /* The rest of this wouldn't work in bootstrap mode */
    1440          36 :     if (IsBootstrapProcessingMode())
    1441           0 :         elog(ERROR, "regrole values must be OIDs in bootstrap mode");
    1442             : 
    1443             :     /* Normal case: see if the name matches any pg_authid entry. */
    1444          36 :     names = stringToQualifiedNameList(role_name_or_oid);
    1445             : 
    1446          36 :     if (list_length(names) != 1)
    1447           4 :         ereport(ERROR,
    1448             :                 (errcode(ERRCODE_INVALID_NAME),
    1449             :                  errmsg("invalid name syntax")));
    1450             : 
    1451          32 :     result = get_role_oid(strVal(linitial(names)), false);
    1452             : 
    1453          16 :     PG_RETURN_OID(result);
    1454             : }
    1455             : 
    1456             : /*
    1457             :  * to_regrole       - converts "rolename" to role OID
    1458             :  *
    1459             :  * If the name is not found, we return NULL.
    1460             :  */
    1461             : Datum
    1462          32 : to_regrole(PG_FUNCTION_ARGS)
    1463             : {
    1464          32 :     char       *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1465             :     Oid         result;
    1466             :     List       *names;
    1467             : 
    1468          32 :     names = stringToQualifiedNameList(role_name);
    1469             : 
    1470          32 :     if (list_length(names) != 1)
    1471           8 :         ereport(ERROR,
    1472             :                 (errcode(ERRCODE_INVALID_NAME),
    1473             :                  errmsg("invalid name syntax")));
    1474             : 
    1475          24 :     result = get_role_oid(strVal(linitial(names)), true);
    1476             : 
    1477          24 :     if (OidIsValid(result))
    1478           8 :         PG_RETURN_OID(result);
    1479             :     else
    1480          16 :         PG_RETURN_NULL();
    1481             : }
    1482             : 
    1483             : /*
    1484             :  * regroleout       - converts role OID to "role_name"
    1485             :  */
    1486             : Datum
    1487          16 : regroleout(PG_FUNCTION_ARGS)
    1488             : {
    1489          16 :     Oid         roleoid = PG_GETARG_OID(0);
    1490             :     char       *result;
    1491             : 
    1492          16 :     if (roleoid == InvalidOid)
    1493             :     {
    1494           0 :         result = pstrdup("-");
    1495           0 :         PG_RETURN_CSTRING(result);
    1496             :     }
    1497             : 
    1498          16 :     result = GetUserNameFromId(roleoid, true);
    1499             : 
    1500          16 :     if (result)
    1501             :     {
    1502             :         /* pstrdup is not really necessary, but it avoids a compiler warning */
    1503          16 :         result = pstrdup(quote_identifier(result));
    1504             :     }
    1505             :     else
    1506             :     {
    1507             :         /* If OID doesn't match any role, return it numerically */
    1508           0 :         result = (char *) palloc(NAMEDATALEN);
    1509           0 :         snprintf(result, NAMEDATALEN, "%u", roleoid);
    1510             :     }
    1511             : 
    1512          16 :     PG_RETURN_CSTRING(result);
    1513             : }
    1514             : 
    1515             : /*
    1516             :  *      regrolerecv - converts external binary format to regrole
    1517             :  */
    1518             : Datum
    1519           0 : regrolerecv(PG_FUNCTION_ARGS)
    1520             : {
    1521             :     /* Exactly the same as oidrecv, so share code */
    1522           0 :     return oidrecv(fcinfo);
    1523             : }
    1524             : 
    1525             : /*
    1526             :  *      regrolesend - converts regrole to binary format
    1527             :  */
    1528             : Datum
    1529           0 : regrolesend(PG_FUNCTION_ARGS)
    1530             : {
    1531             :     /* Exactly the same as oidsend, so share code */
    1532           0 :     return oidsend(fcinfo);
    1533             : }
    1534             : 
    1535             : /*
    1536             :  * regnamespacein       - converts "nspname" to namespace OID
    1537             :  *
    1538             :  * We also accept a numeric OID, for symmetry with the output routine.
    1539             :  *
    1540             :  * '-' signifies unknown (OID 0).  In all other cases, the input must
    1541             :  * match an existing pg_namespace entry.
    1542             :  */
    1543             : Datum
    1544         656 : regnamespacein(PG_FUNCTION_ARGS)
    1545             : {
    1546         656 :     char       *nsp_name_or_oid = PG_GETARG_CSTRING(0);
    1547             :     Oid         result;
    1548             :     List       *names;
    1549             : 
    1550             :     /* '-' ? */
    1551         656 :     if (strcmp(nsp_name_or_oid, "-") == 0)
    1552           0 :         PG_RETURN_OID(InvalidOid);
    1553             : 
    1554             :     /* Numeric OID? */
    1555        1304 :     if (nsp_name_or_oid[0] >= '0' &&
    1556         648 :         nsp_name_or_oid[0] <= '9' &&
    1557           0 :         strspn(nsp_name_or_oid, "0123456789") == strlen(nsp_name_or_oid))
    1558             :     {
    1559           0 :         result = DatumGetObjectId(DirectFunctionCall1(oidin,
    1560             :                                                       CStringGetDatum(nsp_name_or_oid)));
    1561           0 :         PG_RETURN_OID(result);
    1562             :     }
    1563             : 
    1564             :     /* The rest of this wouldn't work in bootstrap mode */
    1565         656 :     if (IsBootstrapProcessingMode())
    1566           0 :         elog(ERROR, "regnamespace values must be OIDs in bootstrap mode");
    1567             : 
    1568             :     /* Normal case: see if the name matches any pg_namespace entry. */
    1569         656 :     names = stringToQualifiedNameList(nsp_name_or_oid);
    1570             : 
    1571         656 :     if (list_length(names) != 1)
    1572           4 :         ereport(ERROR,
    1573             :                 (errcode(ERRCODE_INVALID_NAME),
    1574             :                  errmsg("invalid name syntax")));
    1575             : 
    1576         652 :     result = get_namespace_oid(strVal(linitial(names)), false);
    1577             : 
    1578         644 :     PG_RETURN_OID(result);
    1579             : }
    1580             : 
    1581             : /*
    1582             :  * to_regnamespace      - converts "nspname" to namespace OID
    1583             :  *
    1584             :  * If the name is not found, we return NULL.
    1585             :  */
    1586             : Datum
    1587          20 : to_regnamespace(PG_FUNCTION_ARGS)
    1588             : {
    1589          20 :     char       *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1590             :     Oid         result;
    1591             :     List       *names;
    1592             : 
    1593          20 :     names = stringToQualifiedNameList(nsp_name);
    1594             : 
    1595          20 :     if (list_length(names) != 1)
    1596           4 :         ereport(ERROR,
    1597             :                 (errcode(ERRCODE_INVALID_NAME),
    1598             :                  errmsg("invalid name syntax")));
    1599             : 
    1600          16 :     result = get_namespace_oid(strVal(linitial(names)), true);
    1601             : 
    1602          16 :     if (OidIsValid(result))
    1603           8 :         PG_RETURN_OID(result);
    1604             :     else
    1605           8 :         PG_RETURN_NULL();
    1606             : }
    1607             : 
    1608             : /*
    1609             :  * regnamespaceout      - converts namespace OID to "nsp_name"
    1610             :  */
    1611             : Datum
    1612          38 : regnamespaceout(PG_FUNCTION_ARGS)
    1613             : {
    1614          38 :     Oid         nspid = PG_GETARG_OID(0);
    1615             :     char       *result;
    1616             : 
    1617          38 :     if (nspid == InvalidOid)
    1618             :     {
    1619           0 :         result = pstrdup("-");
    1620           0 :         PG_RETURN_CSTRING(result);
    1621             :     }
    1622             : 
    1623          38 :     result = get_namespace_name(nspid);
    1624             : 
    1625          38 :     if (result)
    1626             :     {
    1627             :         /* pstrdup is not really necessary, but it avoids a compiler warning */
    1628          38 :         result = pstrdup(quote_identifier(result));
    1629             :     }
    1630             :     else
    1631             :     {
    1632             :         /* If OID doesn't match any namespace, return it numerically */
    1633           0 :         result = (char *) palloc(NAMEDATALEN);
    1634           0 :         snprintf(result, NAMEDATALEN, "%u", nspid);
    1635             :     }
    1636             : 
    1637          38 :     PG_RETURN_CSTRING(result);
    1638             : }
    1639             : 
    1640             : /*
    1641             :  *      regnamespacerecv    - converts external binary format to regnamespace
    1642             :  */
    1643             : Datum
    1644           0 : regnamespacerecv(PG_FUNCTION_ARGS)
    1645             : {
    1646             :     /* Exactly the same as oidrecv, so share code */
    1647           0 :     return oidrecv(fcinfo);
    1648             : }
    1649             : 
    1650             : /*
    1651             :  *      regnamespacesend        - converts regnamespace to binary format
    1652             :  */
    1653             : Datum
    1654           0 : regnamespacesend(PG_FUNCTION_ARGS)
    1655             : {
    1656             :     /* Exactly the same as oidsend, so share code */
    1657           0 :     return oidsend(fcinfo);
    1658             : }
    1659             : 
    1660             : /*
    1661             :  * text_regclass: convert text to regclass
    1662             :  *
    1663             :  * This could be replaced by CoerceViaIO, except that we need to treat
    1664             :  * text-to-regclass as an implicit cast to support legacy forms of nextval()
    1665             :  * and related functions.
    1666             :  */
    1667             : Datum
    1668          32 : text_regclass(PG_FUNCTION_ARGS)
    1669             : {
    1670          32 :     text       *relname = PG_GETARG_TEXT_PP(0);
    1671             :     Oid         result;
    1672             :     RangeVar   *rv;
    1673             : 
    1674          32 :     rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
    1675             : 
    1676             :     /* We might not even have permissions on this relation; don't lock it. */
    1677          32 :     result = RangeVarGetRelid(rv, NoLock, false);
    1678             : 
    1679          28 :     PG_RETURN_OID(result);
    1680             : }
    1681             : 
    1682             : 
    1683             : /*
    1684             :  * Given a C string, parse it into a qualified-name list.
    1685             :  */
    1686             : List *
    1687       27098 : stringToQualifiedNameList(const char *string)
    1688             : {
    1689             :     char       *rawname;
    1690       27098 :     List       *result = NIL;
    1691             :     List       *namelist;
    1692             :     ListCell   *l;
    1693             : 
    1694             :     /* We need a modifiable copy of the input string. */
    1695       27098 :     rawname = pstrdup(string);
    1696             : 
    1697       27098 :     if (!SplitIdentifierString(rawname, '.', &namelist))
    1698           0 :         ereport(ERROR,
    1699             :                 (errcode(ERRCODE_INVALID_NAME),
    1700             :                  errmsg("invalid name syntax")));
    1701             : 
    1702       27098 :     if (namelist == NIL)
    1703           0 :         ereport(ERROR,
    1704             :                 (errcode(ERRCODE_INVALID_NAME),
    1705             :                  errmsg("invalid name syntax")));
    1706             : 
    1707       70102 :     foreach(l, namelist)
    1708             :     {
    1709       43004 :         char       *curname = (char *) lfirst(l);
    1710             : 
    1711       43004 :         result = lappend(result, makeString(pstrdup(curname)));
    1712             :     }
    1713             : 
    1714       27098 :     pfree(rawname);
    1715       27098 :     list_free(namelist);
    1716             : 
    1717       27098 :     return result;
    1718             : }
    1719             : 
    1720             : /*****************************************************************************
    1721             :  *   SUPPORT ROUTINES                                                        *
    1722             :  *****************************************************************************/
    1723             : 
    1724             : /*
    1725             :  * Given a C string, parse it into a qualified function or operator name
    1726             :  * followed by a parenthesized list of type names.  Reduce the
    1727             :  * type names to an array of OIDs (returned into *nargs and *argtypes;
    1728             :  * the argtypes array should be of size FUNC_MAX_ARGS).  The function or
    1729             :  * operator name is returned to *names as a List of Strings.
    1730             :  *
    1731             :  * If allowNone is true, accept "NONE" and return it as InvalidOid (this is
    1732             :  * for unary operators).
    1733             :  */
    1734             : static void
    1735         176 : parseNameAndArgTypes(const char *string, bool allowNone, List **names,
    1736             :                      int *nargs, Oid *argtypes)
    1737             : {
    1738             :     char       *rawname;
    1739             :     char       *ptr;
    1740             :     char       *ptr2;
    1741             :     char       *typename;
    1742             :     bool        in_quote;
    1743             :     bool        had_comma;
    1744             :     int         paren_count;
    1745             :     Oid         typeid;
    1746             :     int32       typmod;
    1747             : 
    1748             :     /* We need a modifiable copy of the input string. */
    1749         176 :     rawname = pstrdup(string);
    1750             : 
    1751             :     /* Scan to find the expected left paren; mustn't be quoted */
    1752         176 :     in_quote = false;
    1753        2208 :     for (ptr = rawname; *ptr; ptr++)
    1754             :     {
    1755        2208 :         if (*ptr == '"')
    1756           0 :             in_quote = !in_quote;
    1757        2208 :         else if (*ptr == '(' && !in_quote)
    1758         176 :             break;
    1759             :     }
    1760         176 :     if (*ptr == '\0')
    1761           0 :         ereport(ERROR,
    1762             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1763             :                  errmsg("expected a left parenthesis")));
    1764             : 
    1765             :     /* Separate the name and parse it into a list */
    1766         176 :     *ptr++ = '\0';
    1767         176 :     *names = stringToQualifiedNameList(rawname);
    1768             : 
    1769             :     /* Check for the trailing right parenthesis and remove it */
    1770         176 :     ptr2 = ptr + strlen(ptr);
    1771         352 :     while (--ptr2 > ptr)
    1772             :     {
    1773         152 :         if (!scanner_isspace(*ptr2))
    1774         152 :             break;
    1775             :     }
    1776         176 :     if (*ptr2 != ')')
    1777           0 :         ereport(ERROR,
    1778             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1779             :                  errmsg("expected a right parenthesis")));
    1780             : 
    1781         176 :     *ptr2 = '\0';
    1782             : 
    1783             :     /* Separate the remaining string into comma-separated type names */
    1784         176 :     *nargs = 0;
    1785         176 :     had_comma = false;
    1786             : 
    1787             :     for (;;)
    1788             :     {
    1789             :         /* allow leading whitespace */
    1790         952 :         while (scanner_isspace(*ptr))
    1791           0 :             ptr++;
    1792         376 :         if (*ptr == '\0')
    1793             :         {
    1794             :             /* End of string.  Okay unless we had a comma before. */
    1795         176 :             if (had_comma)
    1796           0 :                 ereport(ERROR,
    1797             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1798             :                          errmsg("expected a type name")));
    1799         176 :             break;
    1800             :         }
    1801         200 :         typename = ptr;
    1802             :         /* Find end of type name --- end of string or comma */
    1803             :         /* ... but not a quoted or parenthesized comma */
    1804         200 :         in_quote = false;
    1805         200 :         paren_count = 0;
    1806        1308 :         for (; *ptr; ptr++)
    1807             :         {
    1808        1156 :             if (*ptr == '"')
    1809           0 :                 in_quote = !in_quote;
    1810        1156 :             else if (*ptr == ',' && !in_quote && paren_count == 0)
    1811             :                 break;
    1812        1108 :             else if (!in_quote)
    1813             :             {
    1814        1108 :                 switch (*ptr)
    1815             :                 {
    1816             :                     case '(':
    1817             :                     case '[':
    1818           0 :                         paren_count++;
    1819           0 :                         break;
    1820             :                     case ')':
    1821             :                     case ']':
    1822           0 :                         paren_count--;
    1823           0 :                         break;
    1824             :                 }
    1825             :             }
    1826             :         }
    1827         200 :         if (in_quote || paren_count != 0)
    1828           0 :             ereport(ERROR,
    1829             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    1830             :                      errmsg("improper type name")));
    1831             : 
    1832         200 :         ptr2 = ptr;
    1833         200 :         if (*ptr == ',')
    1834             :         {
    1835          48 :             had_comma = true;
    1836          48 :             *ptr++ = '\0';
    1837             :         }
    1838             :         else
    1839             :         {
    1840         152 :             had_comma = false;
    1841             :             Assert(*ptr == '\0');
    1842             :         }
    1843             :         /* Lop off trailing whitespace */
    1844         400 :         while (--ptr2 >= typename)
    1845             :         {
    1846         200 :             if (!scanner_isspace(*ptr2))
    1847         200 :                 break;
    1848           0 :             *ptr2 = '\0';
    1849             :         }
    1850             : 
    1851         200 :         if (allowNone && pg_strcasecmp(typename, "none") == 0)
    1852             :         {
    1853             :             /* Special case for NONE */
    1854           0 :             typeid = InvalidOid;
    1855           0 :             typmod = -1;
    1856             :         }
    1857             :         else
    1858             :         {
    1859             :             /* Use full parser to resolve the type name */
    1860         200 :             parseTypeString(typename, &typeid, &typmod, false);
    1861             :         }
    1862         200 :         if (*nargs >= FUNC_MAX_ARGS)
    1863           0 :             ereport(ERROR,
    1864             :                     (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
    1865             :                      errmsg("too many arguments")));
    1866             : 
    1867         200 :         argtypes[*nargs] = typeid;
    1868         200 :         (*nargs)++;
    1869             :     }
    1870             : 
    1871         176 :     pfree(rawname);
    1872         176 : }

Generated by: LCOV version 1.13