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

Generated by: LCOV version 1.16