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

Generated by: LCOV version 2.0-1