LCOV - code coverage report
Current view: top level - src/backend/utils/adt - regproc.c (source / functions) Hit Total Coverage
Test: PostgreSQL 19devel Lines: 516 665 77.6 %
Date: 2025-10-15 15:17:24 Functions: 46 72 63.9 %
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-2025, 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      970212 : regprocin(PG_FUNCTION_ARGS)
      68             : {
      69      970212 :     char       *pro_name_or_oid = PG_GETARG_CSTRING(0);
      70      970212 :     Node       *escontext = fcinfo->context;
      71             :     RegProcedure result;
      72             :     List       *names;
      73             :     FuncCandidateList clist;
      74             :     int         fgc_flags;
      75             : 
      76             :     /* Handle "-" or numeric OID */
      77      970212 :     if (parseDashOrOid(pro_name_or_oid, &result, escontext))
      78      969482 :         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         730 :     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         730 :     names = stringToQualifiedNameList(pro_name_or_oid, escontext);
      94         730 :     if (names == NIL)
      95           0 :         PG_RETURN_NULL();
      96             : 
      97         730 :     clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true,
      98             :                                   &fgc_flags);
      99             : 
     100         730 :     if (clist == NULL)
     101          30 :         ereturn(escontext, (Datum) 0,
     102             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     103             :                  errmsg("function \"%s\" does not exist", pro_name_or_oid)));
     104         700 :     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         700 :     result = clist->oid;
     111             : 
     112         700 :     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          30 : to_regproc(PG_FUNCTION_ARGS)
     122             : {
     123          30 :     char       *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
     124             :     Datum       result;
     125          30 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
     126             : 
     127          30 :     if (!DirectInputFunctionCallSafe(regprocin, pro_name,
     128             :                                      InvalidOid, -1,
     129             :                                      (Node *) &escontext,
     130             :                                      &result))
     131          12 :         PG_RETURN_NULL();
     132          18 :     PG_RETURN_DATUM(result);
     133             : }
     134             : 
     135             : /*
     136             :  * regprocout       - converts proc OID to "pro_name"
     137             :  */
     138             : Datum
     139      165774 : regprocout(PG_FUNCTION_ARGS)
     140             : {
     141      165774 :     RegProcedure proid = PG_GETARG_OID(0);
     142             :     char       *result;
     143             :     HeapTuple   proctup;
     144             : 
     145      165774 :     if (proid == InvalidOid)
     146             :     {
     147       74390 :         result = pstrdup("-");
     148       74390 :         PG_RETURN_CSTRING(result);
     149             :     }
     150             : 
     151       91384 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
     152             : 
     153       91384 :     if (HeapTupleIsValid(proctup))
     154             :     {
     155       91384 :         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
     156       91384 :         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       91384 :         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       91384 :             clist = FuncnameGetCandidates(list_make1(makeString(proname)),
     176             :                                           -1, NIL, false, false, false, false,
     177             :                                           &fgc_flags);
     178       91384 :             if (clist != NULL && clist->next == NULL &&
     179       88206 :                 clist->oid == proid)
     180       88206 :                 nspname = NULL;
     181             :             else
     182        3178 :                 nspname = get_namespace_name(procform->pronamespace);
     183             : 
     184       91384 :             result = quote_qualified_identifier(nspname, proname);
     185             :         }
     186             : 
     187       91384 :         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       91384 :     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         514 : regprocedurein(PG_FUNCTION_ARGS)
     230             : {
     231         514 :     char       *pro_name_or_oid = PG_GETARG_CSTRING(0);
     232         514 :     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         514 :     if (parseDashOrOid(pro_name_or_oid, &result, escontext))
     242          14 :         PG_RETURN_OID(result);
     243             : 
     244             :     /* The rest of this wouldn't work in bootstrap mode */
     245         500 :     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         500 :     if (!parseNameAndArgTypes(pro_name_or_oid, false,
     255             :                               &names, &nargs, argtypes,
     256             :                               escontext))
     257           6 :         PG_RETURN_NULL();
     258             : 
     259         494 :     clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true,
     260             :                                   &fgc_flags);
     261             : 
     262         494 :     for (; clist; clist = clist->next)
     263             :     {
     264         464 :         if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
     265         464 :             break;
     266             :     }
     267             : 
     268         494 :     if (clist == NULL)
     269          30 :         ereturn(escontext, (Datum) 0,
     270             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     271             :                  errmsg("function \"%s\" does not exist", pro_name_or_oid)));
     272             : 
     273         464 :     result = clist->oid;
     274             : 
     275         464 :     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          30 : to_regprocedure(PG_FUNCTION_ARGS)
     285             : {
     286          30 :     char       *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
     287             :     Datum       result;
     288          30 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
     289             : 
     290          30 :     if (!DirectInputFunctionCallSafe(regprocedurein, pro_name,
     291             :                                      InvalidOid, -1,
     292             :                                      (Node *) &escontext,
     293             :                                      &result))
     294          12 :         PG_RETURN_NULL();
     295          18 :     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       23648 : format_procedure(Oid procedure_oid)
     306             : {
     307       23648 :     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       28778 : format_procedure_extended(Oid procedure_oid, bits16 flags)
     333             : {
     334             :     char       *result;
     335             :     HeapTuple   proctup;
     336             : 
     337       28778 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
     338             : 
     339       28778 :     if (HeapTupleIsValid(proctup))
     340             :     {
     341       28760 :         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
     342       28760 :         char       *proname = NameStr(procform->proname);
     343       28760 :         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       28760 :         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       57216 :         if ((flags & FORMAT_PROC_FORCE_QUALIFY) == 0 &&
     358       28456 :             FunctionIsVisible(procedure_oid))
     359       27636 :             nspname = NULL;
     360             :         else
     361        1124 :             nspname = get_namespace_name(procform->pronamespace);
     362             : 
     363       28760 :         appendStringInfo(&buf, "%s(",
     364             :                          quote_qualified_identifier(nspname, proname));
     365       87650 :         for (i = 0; i < nargs; i++)
     366             :         {
     367       58890 :             Oid         thisargtype = procform->proargtypes.values[i];
     368             : 
     369       58890 :             if (i > 0)
     370       36470 :                 appendStringInfoChar(&buf, ',');
     371       58890 :             appendStringInfoString(&buf,
     372       58890 :                                    (flags & FORMAT_PROC_FORCE_QUALIFY) != 0 ?
     373         348 :                                    format_type_be_qualified(thisargtype) :
     374       58542 :                                    format_type_be(thisargtype));
     375             :         }
     376       28760 :         appendStringInfoChar(&buf, ')');
     377             : 
     378       28760 :         result = buf.data;
     379             : 
     380       28760 :         ReleaseSysCache(proctup);
     381             :     }
     382          18 :     else if ((flags & FORMAT_PROC_INVALID_AS_NULL) != 0)
     383             :     {
     384             :         /* If object is undefined, return NULL as wanted by caller */
     385          18 :         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       28778 :     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         136 : 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         136 :     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
     413             : 
     414         136 :     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         136 :     procform = (Form_pg_proc) GETSTRUCT(proctup);
     422         136 :     nargs = procform->pronargs;
     423             : 
     424         136 :     *objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace),
     425             :                            pstrdup(NameStr(procform->proname)));
     426         136 :     *objargs = NIL;
     427         256 :     for (i = 0; i < nargs; i++)
     428             :     {
     429         120 :         Oid         thisargtype = procform->proargtypes.values[i];
     430             : 
     431         120 :         *objargs = lappend(*objargs, format_type_be_qualified(thisargtype));
     432             :     }
     433             : 
     434         136 :     ReleaseSysCache(proctup);
     435             : }
     436             : 
     437             : /*
     438             :  * regprocedureout      - converts proc OID to "pro_name(args)"
     439             :  */
     440             : Datum
     441       17606 : regprocedureout(PG_FUNCTION_ARGS)
     442             : {
     443       17606 :     RegProcedure proid = PG_GETARG_OID(0);
     444             :     char       *result;
     445             : 
     446       17606 :     if (proid == InvalidOid)
     447        3904 :         result = pstrdup("-");
     448             :     else
     449       13702 :         result = format_procedure(proid);
     450             : 
     451       17606 :     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          60 : regoperin(PG_FUNCTION_ARGS)
     485             : {
     486          60 :     char       *opr_name_or_oid = PG_GETARG_CSTRING(0);
     487          60 :     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          60 :     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          60 :     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          60 :     names = stringToQualifiedNameList(opr_name_or_oid, escontext);
     508          60 :     if (names == NIL)
     509           0 :         PG_RETURN_NULL();
     510             : 
     511          60 :     clist = OpernameGetCandidates(names, '\0', true, &fgc_flags);
     512             : 
     513          60 :     if (clist == NULL)
     514          30 :         ereturn(escontext, (Datum) 0,
     515             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     516             :                  errmsg("operator does not exist: %s", opr_name_or_oid)));
     517          30 :     else if (clist->next != NULL)
     518           6 :         ereturn(escontext, (Datum) 0,
     519             :                 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
     520             :                  errmsg("more than one operator named %s",
     521             :                         opr_name_or_oid)));
     522             : 
     523          24 :     result = clist->oid;
     524             : 
     525          24 :     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          24 : to_regoper(PG_FUNCTION_ARGS)
     535             : {
     536          24 :     char       *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
     537             :     Datum       result;
     538          24 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
     539             : 
     540          24 :     if (!DirectInputFunctionCallSafe(regoperin, opr_name,
     541             :                                      InvalidOid, -1,
     542             :                                      (Node *) &escontext,
     543             :                                      &result))
     544          12 :         PG_RETURN_NULL();
     545          12 :     PG_RETURN_DATUM(result);
     546             : }
     547             : 
     548             : /*
     549             :  * regoperout       - converts operator OID to "opr_name"
     550             :  */
     551             : Datum
     552          24 : regoperout(PG_FUNCTION_ARGS)
     553             : {
     554          24 :     Oid         oprid = PG_GETARG_OID(0);
     555             :     char       *result;
     556             :     HeapTuple   opertup;
     557             : 
     558          24 :     if (oprid == InvalidOid)
     559             :     {
     560           0 :         result = pstrdup("0");
     561           0 :         PG_RETURN_CSTRING(result);
     562             :     }
     563             : 
     564          24 :     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
     565             : 
     566          24 :     if (HeapTupleIsValid(opertup))
     567             :     {
     568          24 :         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
     569          24 :         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          24 :         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          24 :             clist = OpernameGetCandidates(list_make1(makeString(oprname)),
     588             :                                           '\0', false, &fgc_flags);
     589          24 :             if (clist != NULL && clist->next == NULL &&
     590          24 :                 clist->oid == oprid)
     591          24 :                 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          24 :         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          24 :     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          84 : regoperatorin(PG_FUNCTION_ARGS)
     648             : {
     649          84 :     char       *opr_name_or_oid = PG_GETARG_CSTRING(0);
     650          84 :     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          84 :     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          84 :     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          84 :     if (!parseNameAndArgTypes(opr_name_or_oid, true,
     671             :                               &names, &nargs, argtypes,
     672             :                               escontext))
     673           6 :         PG_RETURN_NULL();
     674             : 
     675          78 :     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          78 :     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          78 :     result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
     687             : 
     688          78 :     if (!OidIsValid(result))
     689          30 :         ereturn(escontext, (Datum) 0,
     690             :                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
     691             :                  errmsg("operator does not exist: %s", opr_name_or_oid)));
     692             : 
     693          48 :     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          18 : to_regoperator(PG_FUNCTION_ARGS)
     703             : {
     704          18 :     char       *opr_name_or_oid = text_to_cstring(PG_GETARG_TEXT_PP(0));
     705             :     Datum       result;
     706          18 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
     707             : 
     708          18 :     if (!DirectInputFunctionCallSafe(regoperatorin, opr_name_or_oid,
     709             :                                      InvalidOid, -1,
     710             :                                      (Node *) &escontext,
     711             :                                      &result))
     712          12 :         PG_RETURN_NULL();
     713           6 :     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        3950 : format_operator_extended(Oid operator_oid, bits16 flags)
     731             : {
     732             :     char       *result;
     733             :     HeapTuple   opertup;
     734             : 
     735        3950 :     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
     736             : 
     737        3950 :     if (HeapTupleIsValid(opertup))
     738             :     {
     739        3932 :         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
     740        3932 :         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        3932 :         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        3932 :         if ((flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ||
     754        3886 :             !OperatorIsVisible(operator_oid))
     755             :         {
     756         364 :             nspname = get_namespace_name(operform->oprnamespace);
     757         364 :             appendStringInfo(&buf, "%s.",
     758             :                              quote_identifier(nspname));
     759             :         }
     760             : 
     761        3932 :         appendStringInfo(&buf, "%s(", oprname);
     762             : 
     763        3932 :         if (operform->oprleft)
     764        3920 :             appendStringInfo(&buf, "%s,",
     765        3920 :                              (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
     766          46 :                              format_type_be_qualified(operform->oprleft) :
     767        3874 :                              format_type_be(operform->oprleft));
     768             :         else
     769          12 :             appendStringInfoString(&buf, "NONE,");
     770             : 
     771        3932 :         if (operform->oprright)
     772        3932 :             appendStringInfo(&buf, "%s)",
     773        3932 :                              (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ?
     774          46 :                              format_type_be_qualified(operform->oprright) :
     775        3886 :                              format_type_be(operform->oprright));
     776             :         else
     777           0 :             appendStringInfoString(&buf, "NONE)");
     778             : 
     779        3932 :         result = buf.data;
     780             : 
     781        3932 :         ReleaseSysCache(opertup);
     782             :     }
     783          18 :     else if ((flags & FORMAT_OPERATOR_INVALID_AS_NULL) != 0)
     784             :     {
     785             :         /* If object is undefined, return NULL as wanted by caller */
     786          18 :         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        3950 :     return result;
     798             : }
     799             : 
     800             : char *
     801        3120 : format_operator(Oid operator_oid)
     802             : {
     803        3120 :     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           6 : 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           6 :     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
     821           6 :     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           6 :     oprForm = (Form_pg_operator) GETSTRUCT(opertup);
     830           6 :     *objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace),
     831             :                            pstrdup(NameStr(oprForm->oprname)));
     832           6 :     *objargs = NIL;
     833           6 :     if (oprForm->oprleft)
     834           6 :         *objargs = lappend(*objargs,
     835           6 :                            format_type_be_qualified(oprForm->oprleft));
     836           6 :     if (oprForm->oprright)
     837           6 :         *objargs = lappend(*objargs,
     838           6 :                            format_type_be_qualified(oprForm->oprright));
     839             : 
     840           6 :     ReleaseSysCache(opertup);
     841             : }
     842             : 
     843             : /*
     844             :  * regoperatorout       - converts operator OID to "opr_name(args)"
     845             :  */
     846             : Datum
     847        1042 : regoperatorout(PG_FUNCTION_ARGS)
     848             : {
     849        1042 :     Oid         oprid = PG_GETARG_OID(0);
     850             :     char       *result;
     851             : 
     852        1042 :     if (oprid == InvalidOid)
     853           0 :         result = pstrdup("0");
     854             :     else
     855        1042 :         result = format_operator(oprid);
     856             : 
     857        1042 :     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       47244 : regclassin(PG_FUNCTION_ARGS)
     891             : {
     892       47244 :     char       *class_name_or_oid = PG_GETARG_CSTRING(0);
     893       47244 :     Node       *escontext = fcinfo->context;
     894             :     Oid         result;
     895             :     List       *names;
     896             : 
     897             :     /* Handle "-" or numeric OID */
     898       47244 :     if (parseDashOrOid(class_name_or_oid, &result, escontext))
     899       15110 :         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       32134 :     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       32134 :     names = stringToQualifiedNameList(class_name_or_oid, escontext);
     912       32134 :     if (names == NIL)
     913           0 :         PG_RETURN_NULL();
     914             : 
     915             :     /* We might not even have permissions on this relation; don't lock it. */
     916       32134 :     result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
     917             : 
     918       32134 :     if (!OidIsValid(result))
     919          40 :         ereturn(escontext, (Datum) 0,
     920             :                 (errcode(ERRCODE_UNDEFINED_TABLE),
     921             :                  errmsg("relation \"%s\" does not exist",
     922             :                         NameListToString(names))));
     923             : 
     924       32094 :     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          30 : to_regclass(PG_FUNCTION_ARGS)
     934             : {
     935          30 :     char       *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
     936             :     Datum       result;
     937          30 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
     938             : 
     939          30 :     if (!DirectInputFunctionCallSafe(regclassin, class_name,
     940             :                                      InvalidOid, -1,
     941             :                                      (Node *) &escontext,
     942             :                                      &result))
     943          12 :         PG_RETURN_NULL();
     944          18 :     PG_RETURN_DATUM(result);
     945             : }
     946             : 
     947             : /*
     948             :  * regclassout      - converts class OID to "class_name"
     949             :  */
     950             : Datum
     951      209990 : regclassout(PG_FUNCTION_ARGS)
     952             : {
     953      209990 :     Oid         classid = PG_GETARG_OID(0);
     954             :     char       *result;
     955             :     HeapTuple   classtup;
     956             : 
     957      209990 :     if (classid == InvalidOid)
     958             :     {
     959         534 :         result = pstrdup("-");
     960         534 :         PG_RETURN_CSTRING(result);
     961             :     }
     962             : 
     963      209456 :     classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
     964             : 
     965      209456 :     if (HeapTupleIsValid(classtup))
     966             :     {
     967      209038 :         Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
     968      209038 :         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      209038 :         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      209038 :             if (RelationIsVisible(classid))
     985      135932 :                 nspname = NULL;
     986             :             else
     987       73106 :                 nspname = get_namespace_name(classform->relnamespace);
     988             : 
     989      209038 :             result = quote_qualified_identifier(nspname, classname);
     990             :         }
     991             : 
     992      209038 :         ReleaseSysCache(classtup);
     993             :     }
     994             :     else
     995             :     {
     996             :         /* If OID doesn't match any pg_class entry, return it numerically */
     997         418 :         result = (char *) palloc(NAMEDATALEN);
     998         418 :         snprintf(result, NAMEDATALEN, "%u", classid);
     999             :     }
    1000             : 
    1001      209456 :     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          60 : regcollationin(PG_FUNCTION_ARGS)
    1035             : {
    1036          60 :     char       *collation_name_or_oid = PG_GETARG_CSTRING(0);
    1037          60 :     Node       *escontext = fcinfo->context;
    1038             :     Oid         result;
    1039             :     List       *names;
    1040             : 
    1041             :     /* Handle "-" or numeric OID */
    1042          60 :     if (parseDashOrOid(collation_name_or_oid, &result, escontext))
    1043          12 :         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          48 :     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          48 :     names = stringToQualifiedNameList(collation_name_or_oid, escontext);
    1056          48 :     if (names == NIL)
    1057           0 :         PG_RETURN_NULL();
    1058             : 
    1059          48 :     result = get_collation_oid(names, true);
    1060             : 
    1061          48 :     if (!OidIsValid(result))
    1062          24 :         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          24 :     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          30 : to_regcollation(PG_FUNCTION_ARGS)
    1077             : {
    1078          30 :     char       *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1079             :     Datum       result;
    1080          30 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
    1081             : 
    1082          30 :     if (!DirectInputFunctionCallSafe(regcollationin, collation_name,
    1083             :                                      InvalidOid, -1,
    1084             :                                      (Node *) &escontext,
    1085             :                                      &result))
    1086          12 :         PG_RETURN_NULL();
    1087          18 :     PG_RETURN_DATUM(result);
    1088             : }
    1089             : 
    1090             : /*
    1091             :  * regcollationout      - converts collation OID to "collation_name"
    1092             :  */
    1093             : Datum
    1094          24 : regcollationout(PG_FUNCTION_ARGS)
    1095             : {
    1096          24 :     Oid         collationid = PG_GETARG_OID(0);
    1097             :     char       *result;
    1098             :     HeapTuple   collationtup;
    1099             : 
    1100          24 :     if (collationid == InvalidOid)
    1101             :     {
    1102           0 :         result = pstrdup("-");
    1103           0 :         PG_RETURN_CSTRING(result);
    1104             :     }
    1105             : 
    1106          24 :     collationtup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationid));
    1107             : 
    1108          24 :     if (HeapTupleIsValid(collationtup))
    1109             :     {
    1110          24 :         Form_pg_collation collationform = (Form_pg_collation) GETSTRUCT(collationtup);
    1111          24 :         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          24 :         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          24 :             if (CollationIsVisible(collationid))
    1129          24 :                 nspname = NULL;
    1130             :             else
    1131           0 :                 nspname = get_namespace_name(collationform->collnamespace);
    1132             : 
    1133          24 :             result = quote_qualified_identifier(nspname, collationname);
    1134             :         }
    1135             : 
    1136          24 :         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          24 :     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        1118 : regtypein(PG_FUNCTION_ARGS)
    1185             : {
    1186        1118 :     char       *typ_name_or_oid = PG_GETARG_CSTRING(0);
    1187        1118 :     Node       *escontext = fcinfo->context;
    1188             :     Oid         result;
    1189             :     int32       typmod;
    1190             : 
    1191             :     /* Handle "-" or numeric OID */
    1192        1118 :     if (parseDashOrOid(typ_name_or_oid, &result, escontext))
    1193          32 :         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        1086 :     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        1086 :     (void) parseTypeString(typ_name_or_oid, &result, &typmod, escontext);
    1207             : 
    1208        1050 :     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          48 : to_regtype(PG_FUNCTION_ARGS)
    1218             : {
    1219          48 :     char       *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1220             :     Datum       result;
    1221          48 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
    1222             : 
    1223          48 :     if (!DirectInputFunctionCallSafe(regtypein, typ_name,
    1224             :                                      InvalidOid, -1,
    1225             :                                      (Node *) &escontext,
    1226             :                                      &result))
    1227          12 :         PG_RETURN_NULL();
    1228          36 :     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          36 : to_regtypemod(PG_FUNCTION_ARGS)
    1238             : {
    1239          36 :     char       *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1240             :     Oid         typid;
    1241             :     int32       typmod;
    1242          36 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
    1243             : 
    1244             :     /* We rely on parseTypeString to parse the input. */
    1245          36 :     if (!parseTypeString(typ_name, &typid, &typmod, (Node *) &escontext))
    1246           6 :         PG_RETURN_NULL();
    1247             : 
    1248          30 :     PG_RETURN_INT32(typmod);
    1249             : }
    1250             : 
    1251             : /*
    1252             :  * regtypeout       - converts type OID to "typ_name"
    1253             :  */
    1254             : Datum
    1255       17572 : regtypeout(PG_FUNCTION_ARGS)
    1256             : {
    1257       17572 :     Oid         typid = PG_GETARG_OID(0);
    1258             :     char       *result;
    1259             :     HeapTuple   typetup;
    1260             : 
    1261       17572 :     if (typid == InvalidOid)
    1262             :     {
    1263        1624 :         result = pstrdup("-");
    1264        1624 :         PG_RETURN_CSTRING(result);
    1265             :     }
    1266             : 
    1267       15948 :     typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
    1268             : 
    1269       15948 :     if (HeapTupleIsValid(typetup))
    1270             :     {
    1271       15948 :         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       15948 :         if (IsBootstrapProcessingMode())
    1279             :         {
    1280           0 :             char       *typname = NameStr(typeform->typname);
    1281             : 
    1282           0 :             result = pstrdup(typname);
    1283             :         }
    1284             :         else
    1285       15948 :             result = format_type_be(typid);
    1286             : 
    1287       15948 :         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       15948 :     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        1940 : regconfigin(PG_FUNCTION_ARGS)
    1330             : {
    1331        1940 :     char       *cfg_name_or_oid = PG_GETARG_CSTRING(0);
    1332        1940 :     Node       *escontext = fcinfo->context;
    1333             :     Oid         result;
    1334             :     List       *names;
    1335             : 
    1336             :     /* Handle "-" or numeric OID */
    1337        1940 :     if (parseDashOrOid(cfg_name_or_oid, &result, escontext))
    1338           6 :         PG_RETURN_OID(result);
    1339             : 
    1340             :     /* The rest of this wouldn't work in bootstrap mode */
    1341        1934 :     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        1934 :     names = stringToQualifiedNameList(cfg_name_or_oid, escontext);
    1349        1934 :     if (names == NIL)
    1350           0 :         PG_RETURN_NULL();
    1351             : 
    1352        1934 :     result = get_ts_config_oid(names, true);
    1353             : 
    1354        1934 :     if (!OidIsValid(result))
    1355           6 :         ereturn(escontext, (Datum) 0,
    1356             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1357             :                  errmsg("text search configuration \"%s\" does not exist",
    1358             :                         NameListToString(names))));
    1359             : 
    1360        1928 :     PG_RETURN_OID(result);
    1361             : }
    1362             : 
    1363             : /*
    1364             :  * regconfigout     - converts tsconfig OID to "tsconfigname"
    1365             :  */
    1366             : Datum
    1367          10 : regconfigout(PG_FUNCTION_ARGS)
    1368             : {
    1369          10 :     Oid         cfgid = PG_GETARG_OID(0);
    1370             :     char       *result;
    1371             :     HeapTuple   cfgtup;
    1372             : 
    1373          10 :     if (cfgid == InvalidOid)
    1374             :     {
    1375           0 :         result = pstrdup("-");
    1376           0 :         PG_RETURN_CSTRING(result);
    1377             :     }
    1378             : 
    1379          10 :     cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
    1380             : 
    1381          10 :     if (HeapTupleIsValid(cfgtup))
    1382             :     {
    1383          10 :         Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
    1384          10 :         char       *cfgname = NameStr(cfgform->cfgname);
    1385             :         char       *nspname;
    1386             : 
    1387             :         /*
    1388             :          * Would this config be found by regconfigin? If not, qualify it.
    1389             :          */
    1390          10 :         if (TSConfigIsVisible(cfgid))
    1391           6 :             nspname = NULL;
    1392             :         else
    1393           4 :             nspname = get_namespace_name(cfgform->cfgnamespace);
    1394             : 
    1395          10 :         result = quote_qualified_identifier(nspname, cfgname);
    1396             : 
    1397          10 :         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          10 :     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         642 : regdictionaryin(PG_FUNCTION_ARGS)
    1440             : {
    1441         642 :     char       *dict_name_or_oid = PG_GETARG_CSTRING(0);
    1442         642 :     Node       *escontext = fcinfo->context;
    1443             :     Oid         result;
    1444             :     List       *names;
    1445             : 
    1446             :     /* Handle "-" or numeric OID */
    1447         642 :     if (parseDashOrOid(dict_name_or_oid, &result, escontext))
    1448           6 :         PG_RETURN_OID(result);
    1449             : 
    1450             :     /* The rest of this wouldn't work in bootstrap mode */
    1451         636 :     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         636 :     names = stringToQualifiedNameList(dict_name_or_oid, escontext);
    1459         636 :     if (names == NIL)
    1460           0 :         PG_RETURN_NULL();
    1461             : 
    1462         636 :     result = get_ts_dict_oid(names, true);
    1463             : 
    1464         636 :     if (!OidIsValid(result))
    1465           6 :         ereturn(escontext, (Datum) 0,
    1466             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1467             :                  errmsg("text search dictionary \"%s\" does not exist",
    1468             :                         NameListToString(names))));
    1469             : 
    1470         630 :     PG_RETURN_OID(result);
    1471             : }
    1472             : 
    1473             : /*
    1474             :  * regdictionaryout     - converts tsdictionary OID to "tsdictionaryname"
    1475             :  */
    1476             : Datum
    1477        6098 : regdictionaryout(PG_FUNCTION_ARGS)
    1478             : {
    1479        6098 :     Oid         dictid = PG_GETARG_OID(0);
    1480             :     char       *result;
    1481             :     HeapTuple   dicttup;
    1482             : 
    1483        6098 :     if (dictid == InvalidOid)
    1484             :     {
    1485           0 :         result = pstrdup("-");
    1486           0 :         PG_RETURN_CSTRING(result);
    1487             :     }
    1488             : 
    1489        6098 :     dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
    1490             : 
    1491        6098 :     if (HeapTupleIsValid(dicttup))
    1492             :     {
    1493        6098 :         Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
    1494        6098 :         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        6098 :         if (TSDictionaryIsVisible(dictid))
    1502        5828 :             nspname = NULL;
    1503             :         else
    1504         270 :             nspname = get_namespace_name(dictform->dictnamespace);
    1505             : 
    1506        6098 :         result = quote_qualified_identifier(nspname, dictname);
    1507             : 
    1508        6098 :         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        6098 :     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         242 : regrolein(PG_FUNCTION_ARGS)
    1550             : {
    1551         242 :     char       *role_name_or_oid = PG_GETARG_CSTRING(0);
    1552         242 :     Node       *escontext = fcinfo->context;
    1553             :     Oid         result;
    1554             :     List       *names;
    1555             : 
    1556             :     /* Handle "-" or numeric OID */
    1557         242 :     if (parseDashOrOid(role_name_or_oid, &result, escontext))
    1558          12 :         PG_RETURN_OID(result);
    1559             : 
    1560             :     /* The rest of this wouldn't work in bootstrap mode */
    1561         230 :     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         230 :     names = stringToQualifiedNameList(role_name_or_oid, escontext);
    1566         230 :     if (names == NIL)
    1567           0 :         PG_RETURN_NULL();
    1568             : 
    1569         230 :     if (list_length(names) != 1)
    1570          18 :         ereturn(escontext, (Datum) 0,
    1571             :                 (errcode(ERRCODE_INVALID_NAME),
    1572             :                  errmsg("invalid name syntax")));
    1573             : 
    1574         212 :     result = get_role_oid(strVal(linitial(names)), true);
    1575             : 
    1576         212 :     if (!OidIsValid(result))
    1577          54 :         ereturn(escontext, (Datum) 0,
    1578             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1579             :                  errmsg("role \"%s\" does not exist",
    1580             :                         strVal(linitial(names)))));
    1581             : 
    1582         158 :     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          54 : to_regrole(PG_FUNCTION_ARGS)
    1592             : {
    1593          54 :     char       *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1594             :     Datum       result;
    1595          54 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
    1596             : 
    1597          54 :     if (!DirectInputFunctionCallSafe(regrolein, role_name,
    1598             :                                      InvalidOid, -1,
    1599             :                                      (Node *) &escontext,
    1600             :                                      &result))
    1601          36 :         PG_RETURN_NULL();
    1602          18 :     PG_RETURN_DATUM(result);
    1603             : }
    1604             : 
    1605             : /*
    1606             :  * regroleout       - converts role OID to "role_name"
    1607             :  */
    1608             : Datum
    1609        1552 : regroleout(PG_FUNCTION_ARGS)
    1610             : {
    1611        1552 :     Oid         roleoid = PG_GETARG_OID(0);
    1612             :     char       *result;
    1613             : 
    1614        1552 :     if (roleoid == InvalidOid)
    1615             :     {
    1616         140 :         result = pstrdup("-");
    1617         140 :         PG_RETURN_CSTRING(result);
    1618             :     }
    1619             : 
    1620        1412 :     result = GetUserNameFromId(roleoid, true);
    1621             : 
    1622        1412 :     if (result)
    1623             :     {
    1624             :         /* pstrdup is not really necessary, but it avoids a compiler warning */
    1625        1412 :         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        1412 :     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         692 : regnamespacein(PG_FUNCTION_ARGS)
    1667             : {
    1668         692 :     char       *nsp_name_or_oid = PG_GETARG_CSTRING(0);
    1669         692 :     Node       *escontext = fcinfo->context;
    1670             :     Oid         result;
    1671             :     List       *names;
    1672             : 
    1673             :     /* Handle "-" or numeric OID */
    1674         692 :     if (parseDashOrOid(nsp_name_or_oid, &result, escontext))
    1675          12 :         PG_RETURN_OID(result);
    1676             : 
    1677             :     /* The rest of this wouldn't work in bootstrap mode */
    1678         680 :     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         680 :     names = stringToQualifiedNameList(nsp_name_or_oid, escontext);
    1683         680 :     if (names == NIL)
    1684           0 :         PG_RETURN_NULL();
    1685             : 
    1686         680 :     if (list_length(names) != 1)
    1687          12 :         ereturn(escontext, (Datum) 0,
    1688             :                 (errcode(ERRCODE_INVALID_NAME),
    1689             :                  errmsg("invalid name syntax")));
    1690             : 
    1691         668 :     result = get_namespace_oid(strVal(linitial(names)), true);
    1692             : 
    1693         668 :     if (!OidIsValid(result))
    1694          30 :         ereturn(escontext, (Datum) 0,
    1695             :                 (errcode(ERRCODE_UNDEFINED_SCHEMA),
    1696             :                  errmsg("schema \"%s\" does not exist",
    1697             :                         strVal(linitial(names)))));
    1698             : 
    1699         638 :     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          36 : to_regnamespace(PG_FUNCTION_ARGS)
    1709             : {
    1710          36 :     char       *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1711             :     Datum       result;
    1712          36 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
    1713             : 
    1714          36 :     if (!DirectInputFunctionCallSafe(regnamespacein, nsp_name,
    1715             :                                      InvalidOid, -1,
    1716             :                                      (Node *) &escontext,
    1717             :                                      &result))
    1718          18 :         PG_RETURN_NULL();
    1719          18 :     PG_RETURN_DATUM(result);
    1720             : }
    1721             : 
    1722             : /*
    1723             :  * regnamespaceout      - converts namespace OID to "nsp_name"
    1724             :  */
    1725             : Datum
    1726        1212 : regnamespaceout(PG_FUNCTION_ARGS)
    1727             : {
    1728        1212 :     Oid         nspid = PG_GETARG_OID(0);
    1729             :     char       *result;
    1730             : 
    1731        1212 :     if (nspid == InvalidOid)
    1732             :     {
    1733           0 :         result = pstrdup("-");
    1734           0 :         PG_RETURN_CSTRING(result);
    1735             :     }
    1736             : 
    1737        1212 :     result = get_namespace_name(nspid);
    1738             : 
    1739        1212 :     if (result)
    1740             :     {
    1741             :         /* pstrdup is not really necessary, but it avoids a compiler warning */
    1742        1212 :         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        1212 :     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          90 : regdatabasein(PG_FUNCTION_ARGS)
    1784             : {
    1785          90 :     char       *db_name_or_oid = PG_GETARG_CSTRING(0);
    1786          90 :     Node       *escontext = fcinfo->context;
    1787             :     Oid         result;
    1788             :     List       *names;
    1789             : 
    1790             :     /* Handle "-" or numeric OID */
    1791          90 :     if (parseDashOrOid(db_name_or_oid, &result, escontext))
    1792          12 :         PG_RETURN_OID(result);
    1793             : 
    1794             :     /* The rest of this wouldn't work in bootstrap mode */
    1795          78 :     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          78 :     names = stringToQualifiedNameList(db_name_or_oid, escontext);
    1800          78 :     if (names == NIL)
    1801           0 :         PG_RETURN_NULL();
    1802             : 
    1803          78 :     if (list_length(names) != 1)
    1804          12 :         ereturn(escontext, (Datum) 0,
    1805             :                 (errcode(ERRCODE_INVALID_NAME),
    1806             :                  errmsg("invalid name syntax")));
    1807             : 
    1808          66 :     result = get_database_oid(strVal(linitial(names)), true);
    1809             : 
    1810          66 :     if (!OidIsValid(result))
    1811          30 :         ereturn(escontext, (Datum) 0,
    1812             :                 (errcode(ERRCODE_UNDEFINED_OBJECT),
    1813             :                  errmsg("database \"%s\" does not exist",
    1814             :                         strVal(linitial(names)))));
    1815             : 
    1816          36 :     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          36 : to_regdatabase(PG_FUNCTION_ARGS)
    1826             : {
    1827          36 :     char       *db_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
    1828             :     Datum       result;
    1829          36 :     ErrorSaveContext escontext = {T_ErrorSaveContext};
    1830             : 
    1831          36 :     if (!DirectInputFunctionCallSafe(regdatabasein, db_name,
    1832             :                                      InvalidOid, -1,
    1833             :                                      (Node *) &escontext,
    1834             :                                      &result))
    1835          18 :         PG_RETURN_NULL();
    1836          18 :     PG_RETURN_DATUM(result);
    1837             : }
    1838             : 
    1839             : /*
    1840             :  * regdatabaseout - converts database OID to database name
    1841             :  */
    1842             : Datum
    1843          32 : regdatabaseout(PG_FUNCTION_ARGS)
    1844             : {
    1845          32 :     Oid         dboid = PG_GETARG_OID(0);
    1846             :     char       *result;
    1847             : 
    1848          32 :     if (dboid == InvalidOid)
    1849             :     {
    1850           0 :         result = pstrdup("-");
    1851           0 :         PG_RETURN_CSTRING(result);
    1852             :     }
    1853             : 
    1854          32 :     result = get_database_name(dboid);
    1855             : 
    1856          32 :     if (result)
    1857             :     {
    1858             :         /* pstrdup is not really necessary, but it avoids a compiler warning */
    1859          32 :         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          32 :     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        4024 : text_regclass(PG_FUNCTION_ARGS)
    1900             : {
    1901        4024 :     text       *relname = PG_GETARG_TEXT_PP(0);
    1902             :     Oid         result;
    1903             :     RangeVar   *rv;
    1904             : 
    1905        4024 :     rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
    1906             : 
    1907             :     /* We might not even have permissions on this relation; don't lock it. */
    1908        4024 :     result = RangeVarGetRelid(rv, NoLock, false);
    1909             : 
    1910        4018 :     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       42716 : stringToQualifiedNameList(const char *string, Node *escontext)
    1923             : {
    1924             :     char       *rawname;
    1925       42716 :     List       *result = NIL;
    1926             :     List       *namelist;
    1927             :     ListCell   *l;
    1928             : 
    1929             :     /* We need a modifiable copy of the input string. */
    1930       42716 :     rawname = pstrdup(string);
    1931             : 
    1932       42716 :     if (!SplitIdentifierString(rawname, '.', &namelist))
    1933           0 :         ereturn(escontext, NIL,
    1934             :                 (errcode(ERRCODE_INVALID_NAME),
    1935             :                  errmsg("invalid name syntax")));
    1936             : 
    1937       42716 :     if (namelist == NIL)
    1938           0 :         ereturn(escontext, NIL,
    1939             :                 (errcode(ERRCODE_INVALID_NAME),
    1940             :                  errmsg("invalid name syntax")));
    1941             : 
    1942      108914 :     foreach(l, namelist)
    1943             :     {
    1944       66198 :         char       *curname = (char *) lfirst(l);
    1945             : 
    1946       66198 :         result = lappend(result, makeString(pstrdup(curname)));
    1947             :     }
    1948             : 
    1949       42716 :     pfree(rawname);
    1950       42716 :     list_free(namelist);
    1951             : 
    1952       42716 :     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      830890 : parseNumericOid(char *string, Oid *result, Node *escontext)
    1969             : {
    1970      830890 :     if (string[0] >= '0' && string[0] <= '9' &&
    1971      792690 :         strspn(string, "0123456789") == strlen(string))
    1972             :     {
    1973             :         Datum       oid_datum;
    1974             : 
    1975             :         /* We need not care here whether oidin() fails or not. */
    1976      792690 :         (void) DirectInputFunctionCallSafe(oidin, string,
    1977             :                                            InvalidOid, -1,
    1978             :                                            escontext,
    1979             :                                            &oid_datum);
    1980      792690 :         *result = DatumGetObjectId(oid_datum);
    1981      792690 :         return true;
    1982             :     }
    1983             : 
    1984             :     /* Prevent uninitialized-variable warnings from stupider compilers. */
    1985       38200 :     *result = InvalidOid;
    1986       38200 :     return false;
    1987             : }
    1988             : 
    1989             : /*
    1990             :  * As above, but also accept "-" as meaning 0 (InvalidOid).
    1991             :  */
    1992             : static bool
    1993     1022754 : parseDashOrOid(char *string, Oid *result, Node *escontext)
    1994             : {
    1995             :     /* '-' ? */
    1996     1022754 :     if (strcmp(string, "-") == 0)
    1997             :     {
    1998      192008 :         *result = InvalidOid;
    1999      192008 :         return true;
    2000             :     }
    2001             : 
    2002             :     /* Numeric OID? */
    2003      830746 :     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         584 : 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         584 :     rawname = pstrdup(string);
    2036             : 
    2037             :     /* Scan to find the expected left paren; mustn't be quoted */
    2038         584 :     in_quote = false;
    2039       10280 :     for (ptr = rawname; *ptr; ptr++)
    2040             :     {
    2041       10274 :         if (*ptr == '"')
    2042           0 :             in_quote = !in_quote;
    2043       10274 :         else if (*ptr == '(' && !in_quote)
    2044         578 :             break;
    2045             :     }
    2046         584 :     if (*ptr == '\0')
    2047           6 :         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         578 :     *ptr++ = '\0';
    2053         578 :     *names = stringToQualifiedNameList(rawname, escontext);
    2054         578 :     if (*names == NIL)
    2055           0 :         return false;
    2056             : 
    2057             :     /* Check for the trailing right parenthesis and remove it */
    2058         578 :     ptr2 = ptr + strlen(ptr);
    2059         596 :     while (--ptr2 > ptr)
    2060             :     {
    2061         502 :         if (!scanner_isspace(*ptr2))
    2062         484 :             break;
    2063             :     }
    2064         578 :     if (*ptr2 != ')')
    2065           6 :         ereturn(escontext, false,
    2066             :                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    2067             :                  errmsg("expected a right parenthesis")));
    2068             : 
    2069         572 :     *ptr2 = '\0';
    2070             : 
    2071             :     /* Separate the remaining string into comma-separated type names */
    2072         572 :     *nargs = 0;
    2073         572 :     had_comma = false;
    2074             : 
    2075             :     for (;;)
    2076             :     {
    2077             :         /* allow leading whitespace */
    2078        1188 :         while (scanner_isspace(*ptr))
    2079          30 :             ptr++;
    2080        1158 :         if (*ptr == '\0')
    2081             :         {
    2082             :             /* End of string.  Okay unless we had a comma before. */
    2083         572 :             if (had_comma)
    2084           0 :                 ereturn(escontext, false,
    2085             :                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    2086             :                          errmsg("expected a type name")));
    2087         572 :             break;
    2088             :         }
    2089         586 :         typename = ptr;
    2090             :         /* Find end of type name --- end of string or comma */
    2091             :         /* ... but not a quoted or parenthesized comma */
    2092         586 :         in_quote = false;
    2093         586 :         paren_count = 0;
    2094        5280 :         for (; *ptr; ptr++)
    2095             :         {
    2096        4802 :             if (*ptr == '"')
    2097           0 :                 in_quote = !in_quote;
    2098        4802 :             else if (*ptr == ',' && !in_quote && paren_count == 0)
    2099             :                 break;
    2100        4694 :             else if (!in_quote)
    2101             :             {
    2102        4694 :                 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         586 :         if (in_quote || paren_count != 0)
    2116           0 :             ereturn(escontext, false,
    2117             :                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
    2118             :                      errmsg("improper type name")));
    2119             : 
    2120         586 :         ptr2 = ptr;
    2121         586 :         if (*ptr == ',')
    2122             :         {
    2123         108 :             had_comma = true;
    2124         108 :             *ptr++ = '\0';
    2125             :         }
    2126             :         else
    2127             :         {
    2128         478 :             had_comma = false;
    2129             :             Assert(*ptr == '\0');
    2130             :         }
    2131             :         /* Lop off trailing whitespace */
    2132         586 :         while (--ptr2 >= typename)
    2133             :         {
    2134         586 :             if (!scanner_isspace(*ptr2))
    2135         586 :                 break;
    2136           0 :             *ptr2 = '\0';
    2137             :         }
    2138             : 
    2139         586 :         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         586 :             if (!parseTypeString(typename, &typeid, &typmod, escontext))
    2149           0 :                 return false;
    2150             :         }
    2151         586 :         if (*nargs >= FUNC_MAX_ARGS)
    2152           0 :             ereturn(escontext, false,
    2153             :                     (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
    2154             :                      errmsg("too many arguments")));
    2155             : 
    2156         586 :         argtypes[*nargs] = typeid;
    2157         586 :         (*nargs)++;
    2158             :     }
    2159             : 
    2160         572 :     pfree(rawname);
    2161             : 
    2162         572 :     return true;
    2163             : }

Generated by: LCOV version 1.16