Header And Logo

PostgreSQL
| The world's most advanced open source database.

regproc.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * regproc.c
00004  *    Functions for the built-in types regproc, regclass, regtype, etc.
00005  *
00006  * These types are all binary-compatible with type Oid, and rely on Oid
00007  * for comparison and so forth.  Their only interesting behavior is in
00008  * special I/O conversion routines.
00009  *
00010  *
00011  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00012  * Portions Copyright (c) 1994, Regents of the University of California
00013  *
00014  *
00015  * IDENTIFICATION
00016  *    src/backend/utils/adt/regproc.c
00017  *
00018  *-------------------------------------------------------------------------
00019  */
00020 #include "postgres.h"
00021 
00022 #include <ctype.h>
00023 
00024 #include "access/genam.h"
00025 #include "access/heapam.h"
00026 #include "access/htup_details.h"
00027 #include "catalog/indexing.h"
00028 #include "catalog/namespace.h"
00029 #include "catalog/pg_class.h"
00030 #include "catalog/pg_operator.h"
00031 #include "catalog/pg_proc.h"
00032 #include "catalog/pg_ts_config.h"
00033 #include "catalog/pg_ts_dict.h"
00034 #include "catalog/pg_type.h"
00035 #include "lib/stringinfo.h"
00036 #include "miscadmin.h"
00037 #include "parser/parse_type.h"
00038 #include "utils/builtins.h"
00039 #include "utils/fmgroids.h"
00040 #include "utils/lsyscache.h"
00041 #include "utils/syscache.h"
00042 #include "utils/tqual.h"
00043 
00044 static char *format_operator_internal(Oid operator_oid, bool force_qualify);
00045 static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
00046 static void parseNameAndArgTypes(const char *string, bool allowNone,
00047                      List **names, int *nargs, Oid *argtypes);
00048 
00049 
00050 /*****************************************************************************
00051  *   USER I/O ROUTINES                                                       *
00052  *****************************************************************************/
00053 
00054 /*
00055  * regprocin        - converts "proname" to proc OID
00056  *
00057  * We also accept a numeric OID, for symmetry with the output routine.
00058  *
00059  * '-' signifies unknown (OID 0).  In all other cases, the input must
00060  * match an existing pg_proc entry.
00061  */
00062 Datum
00063 regprocin(PG_FUNCTION_ARGS)
00064 {
00065     char       *pro_name_or_oid = PG_GETARG_CSTRING(0);
00066     RegProcedure result = InvalidOid;
00067     List       *names;
00068     FuncCandidateList clist;
00069 
00070     /* '-' ? */
00071     if (strcmp(pro_name_or_oid, "-") == 0)
00072         PG_RETURN_OID(InvalidOid);
00073 
00074     /* Numeric OID? */
00075     if (pro_name_or_oid[0] >= '0' &&
00076         pro_name_or_oid[0] <= '9' &&
00077         strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
00078     {
00079         result = DatumGetObjectId(DirectFunctionCall1(oidin,
00080                                           CStringGetDatum(pro_name_or_oid)));
00081         PG_RETURN_OID(result);
00082     }
00083 
00084     /* Else it's a name, possibly schema-qualified */
00085 
00086     /*
00087      * In bootstrap mode we assume the given name is not schema-qualified, and
00088      * just search pg_proc for a unique match.  This is needed for
00089      * initializing other system catalogs (pg_namespace may not exist yet, and
00090      * certainly there are no schemas other than pg_catalog).
00091      */
00092     if (IsBootstrapProcessingMode())
00093     {
00094         int         matches = 0;
00095         Relation    hdesc;
00096         ScanKeyData skey[1];
00097         SysScanDesc sysscan;
00098         HeapTuple   tuple;
00099 
00100         ScanKeyInit(&skey[0],
00101                     Anum_pg_proc_proname,
00102                     BTEqualStrategyNumber, F_NAMEEQ,
00103                     CStringGetDatum(pro_name_or_oid));
00104 
00105         hdesc = heap_open(ProcedureRelationId, AccessShareLock);
00106         sysscan = systable_beginscan(hdesc, ProcedureNameArgsNspIndexId, true,
00107                                      SnapshotNow, 1, skey);
00108 
00109         while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
00110         {
00111             result = (RegProcedure) HeapTupleGetOid(tuple);
00112             if (++matches > 1)
00113                 break;
00114         }
00115 
00116         systable_endscan(sysscan);
00117         heap_close(hdesc, AccessShareLock);
00118 
00119         if (matches == 0)
00120             ereport(ERROR,
00121                     (errcode(ERRCODE_UNDEFINED_FUNCTION),
00122                  errmsg("function \"%s\" does not exist", pro_name_or_oid)));
00123 
00124         else if (matches > 1)
00125             ereport(ERROR,
00126                     (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
00127                      errmsg("more than one function named \"%s\"",
00128                             pro_name_or_oid)));
00129 
00130         PG_RETURN_OID(result);
00131     }
00132 
00133     /*
00134      * Normal case: parse the name into components and see if it matches any
00135      * pg_proc entries in the current search path.
00136      */
00137     names = stringToQualifiedNameList(pro_name_or_oid);
00138     clist = FuncnameGetCandidates(names, -1, NIL, false, false);
00139 
00140     if (clist == NULL)
00141         ereport(ERROR,
00142                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
00143                  errmsg("function \"%s\" does not exist", pro_name_or_oid)));
00144     else if (clist->next != NULL)
00145         ereport(ERROR,
00146                 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
00147                  errmsg("more than one function named \"%s\"",
00148                         pro_name_or_oid)));
00149 
00150     result = clist->oid;
00151 
00152     PG_RETURN_OID(result);
00153 }
00154 
00155 /*
00156  * regprocout       - converts proc OID to "pro_name"
00157  */
00158 Datum
00159 regprocout(PG_FUNCTION_ARGS)
00160 {
00161     RegProcedure proid = PG_GETARG_OID(0);
00162     char       *result;
00163     HeapTuple   proctup;
00164 
00165     if (proid == InvalidOid)
00166     {
00167         result = pstrdup("-");
00168         PG_RETURN_CSTRING(result);
00169     }
00170 
00171     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid));
00172 
00173     if (HeapTupleIsValid(proctup))
00174     {
00175         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
00176         char       *proname = NameStr(procform->proname);
00177 
00178         /*
00179          * In bootstrap mode, skip the fancy namespace stuff and just return
00180          * the proc name.  (This path is only needed for debugging output
00181          * anyway.)
00182          */
00183         if (IsBootstrapProcessingMode())
00184             result = pstrdup(proname);
00185         else
00186         {
00187             char       *nspname;
00188             FuncCandidateList clist;
00189 
00190             /*
00191              * Would this proc be found (uniquely!) by regprocin? If not,
00192              * qualify it.
00193              */
00194             clist = FuncnameGetCandidates(list_make1(makeString(proname)),
00195                                           -1, NIL, false, false);
00196             if (clist != NULL && clist->next == NULL &&
00197                 clist->oid == proid)
00198                 nspname = NULL;
00199             else
00200                 nspname = get_namespace_name(procform->pronamespace);
00201 
00202             result = quote_qualified_identifier(nspname, proname);
00203         }
00204 
00205         ReleaseSysCache(proctup);
00206     }
00207     else
00208     {
00209         /* If OID doesn't match any pg_proc entry, return it numerically */
00210         result = (char *) palloc(NAMEDATALEN);
00211         snprintf(result, NAMEDATALEN, "%u", proid);
00212     }
00213 
00214     PG_RETURN_CSTRING(result);
00215 }
00216 
00217 /*
00218  *      regprocrecv         - converts external binary format to regproc
00219  */
00220 Datum
00221 regprocrecv(PG_FUNCTION_ARGS)
00222 {
00223     /* Exactly the same as oidrecv, so share code */
00224     return oidrecv(fcinfo);
00225 }
00226 
00227 /*
00228  *      regprocsend         - converts regproc to binary format
00229  */
00230 Datum
00231 regprocsend(PG_FUNCTION_ARGS)
00232 {
00233     /* Exactly the same as oidsend, so share code */
00234     return oidsend(fcinfo);
00235 }
00236 
00237 
00238 /*
00239  * regprocedurein       - converts "proname(args)" to proc OID
00240  *
00241  * We also accept a numeric OID, for symmetry with the output routine.
00242  *
00243  * '-' signifies unknown (OID 0).  In all other cases, the input must
00244  * match an existing pg_proc entry.
00245  */
00246 Datum
00247 regprocedurein(PG_FUNCTION_ARGS)
00248 {
00249     char       *pro_name_or_oid = PG_GETARG_CSTRING(0);
00250     RegProcedure result = InvalidOid;
00251     List       *names;
00252     int         nargs;
00253     Oid         argtypes[FUNC_MAX_ARGS];
00254     FuncCandidateList clist;
00255 
00256     /* '-' ? */
00257     if (strcmp(pro_name_or_oid, "-") == 0)
00258         PG_RETURN_OID(InvalidOid);
00259 
00260     /* Numeric OID? */
00261     if (pro_name_or_oid[0] >= '0' &&
00262         pro_name_or_oid[0] <= '9' &&
00263         strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid))
00264     {
00265         result = DatumGetObjectId(DirectFunctionCall1(oidin,
00266                                           CStringGetDatum(pro_name_or_oid)));
00267         PG_RETURN_OID(result);
00268     }
00269 
00270     /*
00271      * Else it's a name and arguments.  Parse the name and arguments, look up
00272      * potential matches in the current namespace search list, and scan to see
00273      * which one exactly matches the given argument types.  (There will not be
00274      * more than one match.)
00275      *
00276      * XXX at present, this code will not work in bootstrap mode, hence this
00277      * datatype cannot be used for any system column that needs to receive
00278      * data during bootstrap.
00279      */
00280     parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes);
00281 
00282     clist = FuncnameGetCandidates(names, nargs, NIL, false, false);
00283 
00284     for (; clist; clist = clist->next)
00285     {
00286         if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0)
00287             break;
00288     }
00289 
00290     if (clist == NULL)
00291         ereport(ERROR,
00292                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
00293                  errmsg("function \"%s\" does not exist", pro_name_or_oid)));
00294 
00295     result = clist->oid;
00296 
00297     PG_RETURN_OID(result);
00298 }
00299 
00300 /*
00301  * format_procedure     - converts proc OID to "pro_name(args)"
00302  *
00303  * This exports the useful functionality of regprocedureout for use
00304  * in other backend modules.  The result is a palloc'd string.
00305  */
00306 char *
00307 format_procedure(Oid procedure_oid)
00308 {
00309     return format_procedure_internal(procedure_oid, false);
00310 }
00311 
00312 char *
00313 format_procedure_qualified(Oid procedure_oid)
00314 {
00315     return format_procedure_internal(procedure_oid, true);
00316 }
00317 
00318 /*
00319  * Routine to produce regprocedure names; see format_procedure above.
00320  *
00321  * force_qualify says whether to schema-qualify; if true, the name is always
00322  * qualified regardless of search_path visibility.  Otherwise the name is only
00323  * qualified if the function is not in path.
00324  */
00325 static char *
00326 format_procedure_internal(Oid procedure_oid, bool force_qualify)
00327 {
00328     char       *result;
00329     HeapTuple   proctup;
00330 
00331     proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid));
00332 
00333     if (HeapTupleIsValid(proctup))
00334     {
00335         Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup);
00336         char       *proname = NameStr(procform->proname);
00337         int         nargs = procform->pronargs;
00338         int         i;
00339         char       *nspname;
00340         StringInfoData buf;
00341 
00342         /* XXX no support here for bootstrap mode */
00343 
00344         initStringInfo(&buf);
00345 
00346         /*
00347          * Would this proc be found (given the right args) by regprocedurein?
00348          * If not, or if caller requests it, we need to qualify it.
00349          */
00350         if (!force_qualify && FunctionIsVisible(procedure_oid))
00351             nspname = NULL;
00352         else
00353             nspname = get_namespace_name(procform->pronamespace);
00354 
00355         appendStringInfo(&buf, "%s(",
00356                          quote_qualified_identifier(nspname, proname));
00357         for (i = 0; i < nargs; i++)
00358         {
00359             Oid         thisargtype = procform->proargtypes.values[i];
00360 
00361             if (i > 0)
00362                 appendStringInfoChar(&buf, ',');
00363             appendStringInfoString(&buf,
00364                                    force_qualify ?
00365                                    format_type_be_qualified(thisargtype) :
00366                                    format_type_be(thisargtype));
00367         }
00368         appendStringInfoChar(&buf, ')');
00369 
00370         result = buf.data;
00371 
00372         ReleaseSysCache(proctup);
00373     }
00374     else
00375     {
00376         /* If OID doesn't match any pg_proc entry, return it numerically */
00377         result = (char *) palloc(NAMEDATALEN);
00378         snprintf(result, NAMEDATALEN, "%u", procedure_oid);
00379     }
00380 
00381     return result;
00382 }
00383 
00384 /*
00385  * regprocedureout      - converts proc OID to "pro_name(args)"
00386  */
00387 Datum
00388 regprocedureout(PG_FUNCTION_ARGS)
00389 {
00390     RegProcedure proid = PG_GETARG_OID(0);
00391     char       *result;
00392 
00393     if (proid == InvalidOid)
00394         result = pstrdup("-");
00395     else
00396         result = format_procedure(proid);
00397 
00398     PG_RETURN_CSTRING(result);
00399 }
00400 
00401 /*
00402  *      regprocedurerecv            - converts external binary format to regprocedure
00403  */
00404 Datum
00405 regprocedurerecv(PG_FUNCTION_ARGS)
00406 {
00407     /* Exactly the same as oidrecv, so share code */
00408     return oidrecv(fcinfo);
00409 }
00410 
00411 /*
00412  *      regproceduresend            - converts regprocedure to binary format
00413  */
00414 Datum
00415 regproceduresend(PG_FUNCTION_ARGS)
00416 {
00417     /* Exactly the same as oidsend, so share code */
00418     return oidsend(fcinfo);
00419 }
00420 
00421 
00422 /*
00423  * regoperin        - converts "oprname" to operator OID
00424  *
00425  * We also accept a numeric OID, for symmetry with the output routine.
00426  *
00427  * '0' signifies unknown (OID 0).  In all other cases, the input must
00428  * match an existing pg_operator entry.
00429  */
00430 Datum
00431 regoperin(PG_FUNCTION_ARGS)
00432 {
00433     char       *opr_name_or_oid = PG_GETARG_CSTRING(0);
00434     Oid         result = InvalidOid;
00435     List       *names;
00436     FuncCandidateList clist;
00437 
00438     /* '0' ? */
00439     if (strcmp(opr_name_or_oid, "0") == 0)
00440         PG_RETURN_OID(InvalidOid);
00441 
00442     /* Numeric OID? */
00443     if (opr_name_or_oid[0] >= '0' &&
00444         opr_name_or_oid[0] <= '9' &&
00445         strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
00446     {
00447         result = DatumGetObjectId(DirectFunctionCall1(oidin,
00448                                           CStringGetDatum(opr_name_or_oid)));
00449         PG_RETURN_OID(result);
00450     }
00451 
00452     /* Else it's a name, possibly schema-qualified */
00453 
00454     /*
00455      * In bootstrap mode we assume the given name is not schema-qualified, and
00456      * just search pg_operator for a unique match.  This is needed for
00457      * initializing other system catalogs (pg_namespace may not exist yet, and
00458      * certainly there are no schemas other than pg_catalog).
00459      */
00460     if (IsBootstrapProcessingMode())
00461     {
00462         int         matches = 0;
00463         Relation    hdesc;
00464         ScanKeyData skey[1];
00465         SysScanDesc sysscan;
00466         HeapTuple   tuple;
00467 
00468         ScanKeyInit(&skey[0],
00469                     Anum_pg_operator_oprname,
00470                     BTEqualStrategyNumber, F_NAMEEQ,
00471                     CStringGetDatum(opr_name_or_oid));
00472 
00473         hdesc = heap_open(OperatorRelationId, AccessShareLock);
00474         sysscan = systable_beginscan(hdesc, OperatorNameNspIndexId, true,
00475                                      SnapshotNow, 1, skey);
00476 
00477         while (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
00478         {
00479             result = HeapTupleGetOid(tuple);
00480             if (++matches > 1)
00481                 break;
00482         }
00483 
00484         systable_endscan(sysscan);
00485         heap_close(hdesc, AccessShareLock);
00486 
00487         if (matches == 0)
00488             ereport(ERROR,
00489                     (errcode(ERRCODE_UNDEFINED_FUNCTION),
00490                      errmsg("operator does not exist: %s", opr_name_or_oid)));
00491         else if (matches > 1)
00492             ereport(ERROR,
00493                     (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
00494                      errmsg("more than one operator named %s",
00495                             opr_name_or_oid)));
00496 
00497         PG_RETURN_OID(result);
00498     }
00499 
00500     /*
00501      * Normal case: parse the name into components and see if it matches any
00502      * pg_operator entries in the current search path.
00503      */
00504     names = stringToQualifiedNameList(opr_name_or_oid);
00505     clist = OpernameGetCandidates(names, '\0');
00506 
00507     if (clist == NULL)
00508         ereport(ERROR,
00509                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
00510                  errmsg("operator does not exist: %s", opr_name_or_oid)));
00511     else if (clist->next != NULL)
00512         ereport(ERROR,
00513                 (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
00514                  errmsg("more than one operator named %s",
00515                         opr_name_or_oid)));
00516 
00517     result = clist->oid;
00518 
00519     PG_RETURN_OID(result);
00520 }
00521 
00522 /*
00523  * regoperout       - converts operator OID to "opr_name"
00524  */
00525 Datum
00526 regoperout(PG_FUNCTION_ARGS)
00527 {
00528     Oid         oprid = PG_GETARG_OID(0);
00529     char       *result;
00530     HeapTuple   opertup;
00531 
00532     if (oprid == InvalidOid)
00533     {
00534         result = pstrdup("0");
00535         PG_RETURN_CSTRING(result);
00536     }
00537 
00538     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
00539 
00540     if (HeapTupleIsValid(opertup))
00541     {
00542         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
00543         char       *oprname = NameStr(operform->oprname);
00544 
00545         /*
00546          * In bootstrap mode, skip the fancy namespace stuff and just return
00547          * the oper name.  (This path is only needed for debugging output
00548          * anyway.)
00549          */
00550         if (IsBootstrapProcessingMode())
00551             result = pstrdup(oprname);
00552         else
00553         {
00554             FuncCandidateList clist;
00555 
00556             /*
00557              * Would this oper be found (uniquely!) by regoperin? If not,
00558              * qualify it.
00559              */
00560             clist = OpernameGetCandidates(list_make1(makeString(oprname)),
00561                                           '\0');
00562             if (clist != NULL && clist->next == NULL &&
00563                 clist->oid == oprid)
00564                 result = pstrdup(oprname);
00565             else
00566             {
00567                 const char *nspname;
00568 
00569                 nspname = get_namespace_name(operform->oprnamespace);
00570                 nspname = quote_identifier(nspname);
00571                 result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2);
00572                 sprintf(result, "%s.%s", nspname, oprname);
00573             }
00574         }
00575 
00576         ReleaseSysCache(opertup);
00577     }
00578     else
00579     {
00580         /*
00581          * If OID doesn't match any pg_operator entry, return it numerically
00582          */
00583         result = (char *) palloc(NAMEDATALEN);
00584         snprintf(result, NAMEDATALEN, "%u", oprid);
00585     }
00586 
00587     PG_RETURN_CSTRING(result);
00588 }
00589 
00590 /*
00591  *      regoperrecv         - converts external binary format to regoper
00592  */
00593 Datum
00594 regoperrecv(PG_FUNCTION_ARGS)
00595 {
00596     /* Exactly the same as oidrecv, so share code */
00597     return oidrecv(fcinfo);
00598 }
00599 
00600 /*
00601  *      regopersend         - converts regoper to binary format
00602  */
00603 Datum
00604 regopersend(PG_FUNCTION_ARGS)
00605 {
00606     /* Exactly the same as oidsend, so share code */
00607     return oidsend(fcinfo);
00608 }
00609 
00610 
00611 /*
00612  * regoperatorin        - converts "oprname(args)" to operator OID
00613  *
00614  * We also accept a numeric OID, for symmetry with the output routine.
00615  *
00616  * '0' signifies unknown (OID 0).  In all other cases, the input must
00617  * match an existing pg_operator entry.
00618  */
00619 Datum
00620 regoperatorin(PG_FUNCTION_ARGS)
00621 {
00622     char       *opr_name_or_oid = PG_GETARG_CSTRING(0);
00623     Oid         result;
00624     List       *names;
00625     int         nargs;
00626     Oid         argtypes[FUNC_MAX_ARGS];
00627 
00628     /* '0' ? */
00629     if (strcmp(opr_name_or_oid, "0") == 0)
00630         PG_RETURN_OID(InvalidOid);
00631 
00632     /* Numeric OID? */
00633     if (opr_name_or_oid[0] >= '0' &&
00634         opr_name_or_oid[0] <= '9' &&
00635         strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid))
00636     {
00637         result = DatumGetObjectId(DirectFunctionCall1(oidin,
00638                                           CStringGetDatum(opr_name_or_oid)));
00639         PG_RETURN_OID(result);
00640     }
00641 
00642     /*
00643      * Else it's a name and arguments.  Parse the name and arguments, look up
00644      * potential matches in the current namespace search list, and scan to see
00645      * which one exactly matches the given argument types.  (There will not be
00646      * more than one match.)
00647      *
00648      * XXX at present, this code will not work in bootstrap mode, hence this
00649      * datatype cannot be used for any system column that needs to receive
00650      * data during bootstrap.
00651      */
00652     parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes);
00653     if (nargs == 1)
00654         ereport(ERROR,
00655                 (errcode(ERRCODE_UNDEFINED_PARAMETER),
00656                  errmsg("missing argument"),
00657                  errhint("Use NONE to denote the missing argument of a unary operator.")));
00658     if (nargs != 2)
00659         ereport(ERROR,
00660                 (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
00661                  errmsg("too many arguments"),
00662                  errhint("Provide two argument types for operator.")));
00663 
00664     result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
00665 
00666     if (!OidIsValid(result))
00667         ereport(ERROR,
00668                 (errcode(ERRCODE_UNDEFINED_FUNCTION),
00669                  errmsg("operator does not exist: %s", opr_name_or_oid)));
00670 
00671     PG_RETURN_OID(result);
00672 }
00673 
00674 /*
00675  * format_operator      - converts operator OID to "opr_name(args)"
00676  *
00677  * This exports the useful functionality of regoperatorout for use
00678  * in other backend modules.  The result is a palloc'd string.
00679  */
00680 static char *
00681 format_operator_internal(Oid operator_oid, bool force_qualify)
00682 {
00683     char       *result;
00684     HeapTuple   opertup;
00685 
00686     opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid));
00687 
00688     if (HeapTupleIsValid(opertup))
00689     {
00690         Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup);
00691         char       *oprname = NameStr(operform->oprname);
00692         char       *nspname;
00693         StringInfoData buf;
00694 
00695         /* XXX no support here for bootstrap mode */
00696 
00697         initStringInfo(&buf);
00698 
00699         /*
00700          * Would this oper be found (given the right args) by regoperatorin?
00701          * If not, or if caller explicitely requests it, we need to qualify it.
00702          */
00703         if (force_qualify || !OperatorIsVisible(operator_oid))
00704         {
00705             nspname = get_namespace_name(operform->oprnamespace);
00706             appendStringInfo(&buf, "%s.",
00707                              quote_identifier(nspname));
00708         }
00709 
00710         appendStringInfo(&buf, "%s(", oprname);
00711 
00712         if (operform->oprleft)
00713             appendStringInfo(&buf, "%s,",
00714                              force_qualify ?
00715                              format_type_be_qualified(operform->oprleft) :
00716                              format_type_be(operform->oprleft));
00717         else
00718             appendStringInfo(&buf, "NONE,");
00719 
00720         if (operform->oprright)
00721             appendStringInfo(&buf, "%s)",
00722                              force_qualify ?
00723                              format_type_be_qualified(operform->oprright) :
00724                              format_type_be(operform->oprright));
00725         else
00726             appendStringInfo(&buf, "NONE)");
00727 
00728         result = buf.data;
00729 
00730         ReleaseSysCache(opertup);
00731     }
00732     else
00733     {
00734         /*
00735          * If OID doesn't match any pg_operator entry, return it numerically
00736          */
00737         result = (char *) palloc(NAMEDATALEN);
00738         snprintf(result, NAMEDATALEN, "%u", operator_oid);
00739     }
00740 
00741     return result;
00742 }
00743 
00744 char *
00745 format_operator(Oid operator_oid)
00746 {
00747     return format_operator_internal(operator_oid, false);
00748 }
00749 
00750 char *
00751 format_operator_qualified(Oid operator_oid)
00752 {
00753     return format_operator_internal(operator_oid, true);
00754 }
00755 
00756 /*
00757  * regoperatorout       - converts operator OID to "opr_name(args)"
00758  */
00759 Datum
00760 regoperatorout(PG_FUNCTION_ARGS)
00761 {
00762     Oid         oprid = PG_GETARG_OID(0);
00763     char       *result;
00764 
00765     if (oprid == InvalidOid)
00766         result = pstrdup("0");
00767     else
00768         result = format_operator(oprid);
00769 
00770     PG_RETURN_CSTRING(result);
00771 }
00772 
00773 /*
00774  *      regoperatorrecv         - converts external binary format to regoperator
00775  */
00776 Datum
00777 regoperatorrecv(PG_FUNCTION_ARGS)
00778 {
00779     /* Exactly the same as oidrecv, so share code */
00780     return oidrecv(fcinfo);
00781 }
00782 
00783 /*
00784  *      regoperatorsend         - converts regoperator to binary format
00785  */
00786 Datum
00787 regoperatorsend(PG_FUNCTION_ARGS)
00788 {
00789     /* Exactly the same as oidsend, so share code */
00790     return oidsend(fcinfo);
00791 }
00792 
00793 
00794 /*
00795  * regclassin       - converts "classname" to class OID
00796  *
00797  * We also accept a numeric OID, for symmetry with the output routine.
00798  *
00799  * '-' signifies unknown (OID 0).  In all other cases, the input must
00800  * match an existing pg_class entry.
00801  */
00802 Datum
00803 regclassin(PG_FUNCTION_ARGS)
00804 {
00805     char       *class_name_or_oid = PG_GETARG_CSTRING(0);
00806     Oid         result = InvalidOid;
00807     List       *names;
00808 
00809     /* '-' ? */
00810     if (strcmp(class_name_or_oid, "-") == 0)
00811         PG_RETURN_OID(InvalidOid);
00812 
00813     /* Numeric OID? */
00814     if (class_name_or_oid[0] >= '0' &&
00815         class_name_or_oid[0] <= '9' &&
00816         strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid))
00817     {
00818         result = DatumGetObjectId(DirectFunctionCall1(oidin,
00819                                         CStringGetDatum(class_name_or_oid)));
00820         PG_RETURN_OID(result);
00821     }
00822 
00823     /* Else it's a name, possibly schema-qualified */
00824 
00825     /*
00826      * In bootstrap mode we assume the given name is not schema-qualified, and
00827      * just search pg_class for a match.  This is needed for initializing
00828      * other system catalogs (pg_namespace may not exist yet, and certainly
00829      * there are no schemas other than pg_catalog).
00830      */
00831     if (IsBootstrapProcessingMode())
00832     {
00833         Relation    hdesc;
00834         ScanKeyData skey[1];
00835         SysScanDesc sysscan;
00836         HeapTuple   tuple;
00837 
00838         ScanKeyInit(&skey[0],
00839                     Anum_pg_class_relname,
00840                     BTEqualStrategyNumber, F_NAMEEQ,
00841                     CStringGetDatum(class_name_or_oid));
00842 
00843         hdesc = heap_open(RelationRelationId, AccessShareLock);
00844         sysscan = systable_beginscan(hdesc, ClassNameNspIndexId, true,
00845                                      SnapshotNow, 1, skey);
00846 
00847         if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
00848             result = HeapTupleGetOid(tuple);
00849         else
00850             ereport(ERROR,
00851                     (errcode(ERRCODE_UNDEFINED_TABLE),
00852                errmsg("relation \"%s\" does not exist", class_name_or_oid)));
00853 
00854         /* We assume there can be only one match */
00855 
00856         systable_endscan(sysscan);
00857         heap_close(hdesc, AccessShareLock);
00858 
00859         PG_RETURN_OID(result);
00860     }
00861 
00862     /*
00863      * Normal case: parse the name into components and see if it matches any
00864      * pg_class entries in the current search path.
00865      */
00866     names = stringToQualifiedNameList(class_name_or_oid);
00867 
00868     /* We might not even have permissions on this relation; don't lock it. */
00869     result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false);
00870 
00871     PG_RETURN_OID(result);
00872 }
00873 
00874 /*
00875  * regclassout      - converts class OID to "class_name"
00876  */
00877 Datum
00878 regclassout(PG_FUNCTION_ARGS)
00879 {
00880     Oid         classid = PG_GETARG_OID(0);
00881     char       *result;
00882     HeapTuple   classtup;
00883 
00884     if (classid == InvalidOid)
00885     {
00886         result = pstrdup("-");
00887         PG_RETURN_CSTRING(result);
00888     }
00889 
00890     classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid));
00891 
00892     if (HeapTupleIsValid(classtup))
00893     {
00894         Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup);
00895         char       *classname = NameStr(classform->relname);
00896 
00897         /*
00898          * In bootstrap mode, skip the fancy namespace stuff and just return
00899          * the class name.  (This path is only needed for debugging output
00900          * anyway.)
00901          */
00902         if (IsBootstrapProcessingMode())
00903             result = pstrdup(classname);
00904         else
00905         {
00906             char       *nspname;
00907 
00908             /*
00909              * Would this class be found by regclassin? If not, qualify it.
00910              */
00911             if (RelationIsVisible(classid))
00912                 nspname = NULL;
00913             else
00914                 nspname = get_namespace_name(classform->relnamespace);
00915 
00916             result = quote_qualified_identifier(nspname, classname);
00917         }
00918 
00919         ReleaseSysCache(classtup);
00920     }
00921     else
00922     {
00923         /* If OID doesn't match any pg_class entry, return it numerically */
00924         result = (char *) palloc(NAMEDATALEN);
00925         snprintf(result, NAMEDATALEN, "%u", classid);
00926     }
00927 
00928     PG_RETURN_CSTRING(result);
00929 }
00930 
00931 /*
00932  *      regclassrecv            - converts external binary format to regclass
00933  */
00934 Datum
00935 regclassrecv(PG_FUNCTION_ARGS)
00936 {
00937     /* Exactly the same as oidrecv, so share code */
00938     return oidrecv(fcinfo);
00939 }
00940 
00941 /*
00942  *      regclasssend            - converts regclass to binary format
00943  */
00944 Datum
00945 regclasssend(PG_FUNCTION_ARGS)
00946 {
00947     /* Exactly the same as oidsend, so share code */
00948     return oidsend(fcinfo);
00949 }
00950 
00951 
00952 /*
00953  * regtypein        - converts "typename" to type OID
00954  *
00955  * We also accept a numeric OID, for symmetry with the output routine.
00956  *
00957  * '-' signifies unknown (OID 0).  In all other cases, the input must
00958  * match an existing pg_type entry.
00959  *
00960  * In bootstrap mode the name must just equal some existing name in pg_type.
00961  * In normal mode the type name can be specified using the full type syntax
00962  * recognized by the parser; for example, DOUBLE PRECISION and INTEGER[] will
00963  * work and be translated to the correct type names.  (We ignore any typmod
00964  * info generated by the parser, however.)
00965  */
00966 Datum
00967 regtypein(PG_FUNCTION_ARGS)
00968 {
00969     char       *typ_name_or_oid = PG_GETARG_CSTRING(0);
00970     Oid         result = InvalidOid;
00971     int32       typmod;
00972 
00973     /* '-' ? */
00974     if (strcmp(typ_name_or_oid, "-") == 0)
00975         PG_RETURN_OID(InvalidOid);
00976 
00977     /* Numeric OID? */
00978     if (typ_name_or_oid[0] >= '0' &&
00979         typ_name_or_oid[0] <= '9' &&
00980         strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid))
00981     {
00982         result = DatumGetObjectId(DirectFunctionCall1(oidin,
00983                                           CStringGetDatum(typ_name_or_oid)));
00984         PG_RETURN_OID(result);
00985     }
00986 
00987     /* Else it's a type name, possibly schema-qualified or decorated */
00988 
00989     /*
00990      * In bootstrap mode we assume the given name is not schema-qualified, and
00991      * just search pg_type for a match.  This is needed for initializing other
00992      * system catalogs (pg_namespace may not exist yet, and certainly there
00993      * are no schemas other than pg_catalog).
00994      */
00995     if (IsBootstrapProcessingMode())
00996     {
00997         Relation    hdesc;
00998         ScanKeyData skey[1];
00999         SysScanDesc sysscan;
01000         HeapTuple   tuple;
01001 
01002         ScanKeyInit(&skey[0],
01003                     Anum_pg_type_typname,
01004                     BTEqualStrategyNumber, F_NAMEEQ,
01005                     CStringGetDatum(typ_name_or_oid));
01006 
01007         hdesc = heap_open(TypeRelationId, AccessShareLock);
01008         sysscan = systable_beginscan(hdesc, TypeNameNspIndexId, true,
01009                                      SnapshotNow, 1, skey);
01010 
01011         if (HeapTupleIsValid(tuple = systable_getnext(sysscan)))
01012             result = HeapTupleGetOid(tuple);
01013         else
01014             ereport(ERROR,
01015                     (errcode(ERRCODE_UNDEFINED_OBJECT),
01016                      errmsg("type \"%s\" does not exist", typ_name_or_oid)));
01017 
01018         /* We assume there can be only one match */
01019 
01020         systable_endscan(sysscan);
01021         heap_close(hdesc, AccessShareLock);
01022 
01023         PG_RETURN_OID(result);
01024     }
01025 
01026     /*
01027      * Normal case: invoke the full parser to deal with special cases such as
01028      * array syntax.
01029      */
01030     parseTypeString(typ_name_or_oid, &result, &typmod);
01031 
01032     PG_RETURN_OID(result);
01033 }
01034 
01035 /*
01036  * regtypeout       - converts type OID to "typ_name"
01037  */
01038 Datum
01039 regtypeout(PG_FUNCTION_ARGS)
01040 {
01041     Oid         typid = PG_GETARG_OID(0);
01042     char       *result;
01043     HeapTuple   typetup;
01044 
01045     if (typid == InvalidOid)
01046     {
01047         result = pstrdup("-");
01048         PG_RETURN_CSTRING(result);
01049     }
01050 
01051     typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
01052 
01053     if (HeapTupleIsValid(typetup))
01054     {
01055         Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup);
01056 
01057         /*
01058          * In bootstrap mode, skip the fancy namespace stuff and just return
01059          * the type name.  (This path is only needed for debugging output
01060          * anyway.)
01061          */
01062         if (IsBootstrapProcessingMode())
01063         {
01064             char       *typname = NameStr(typeform->typname);
01065 
01066             result = pstrdup(typname);
01067         }
01068         else
01069             result = format_type_be(typid);
01070 
01071         ReleaseSysCache(typetup);
01072     }
01073     else
01074     {
01075         /* If OID doesn't match any pg_type entry, return it numerically */
01076         result = (char *) palloc(NAMEDATALEN);
01077         snprintf(result, NAMEDATALEN, "%u", typid);
01078     }
01079 
01080     PG_RETURN_CSTRING(result);
01081 }
01082 
01083 /*
01084  *      regtyperecv         - converts external binary format to regtype
01085  */
01086 Datum
01087 regtyperecv(PG_FUNCTION_ARGS)
01088 {
01089     /* Exactly the same as oidrecv, so share code */
01090     return oidrecv(fcinfo);
01091 }
01092 
01093 /*
01094  *      regtypesend         - converts regtype to binary format
01095  */
01096 Datum
01097 regtypesend(PG_FUNCTION_ARGS)
01098 {
01099     /* Exactly the same as oidsend, so share code */
01100     return oidsend(fcinfo);
01101 }
01102 
01103 
01104 /*
01105  * regconfigin      - converts "tsconfigname" to tsconfig OID
01106  *
01107  * We also accept a numeric OID, for symmetry with the output routine.
01108  *
01109  * '-' signifies unknown (OID 0).  In all other cases, the input must
01110  * match an existing pg_ts_config entry.
01111  *
01112  * This function is not needed in bootstrap mode, so we don't worry about
01113  * making it work then.
01114  */
01115 Datum
01116 regconfigin(PG_FUNCTION_ARGS)
01117 {
01118     char       *cfg_name_or_oid = PG_GETARG_CSTRING(0);
01119     Oid         result;
01120     List       *names;
01121 
01122     /* '-' ? */
01123     if (strcmp(cfg_name_or_oid, "-") == 0)
01124         PG_RETURN_OID(InvalidOid);
01125 
01126     /* Numeric OID? */
01127     if (cfg_name_or_oid[0] >= '0' &&
01128         cfg_name_or_oid[0] <= '9' &&
01129         strspn(cfg_name_or_oid, "0123456789") == strlen(cfg_name_or_oid))
01130     {
01131         result = DatumGetObjectId(DirectFunctionCall1(oidin,
01132                                           CStringGetDatum(cfg_name_or_oid)));
01133         PG_RETURN_OID(result);
01134     }
01135 
01136     /*
01137      * Normal case: parse the name into components and see if it matches any
01138      * pg_ts_config entries in the current search path.
01139      */
01140     names = stringToQualifiedNameList(cfg_name_or_oid);
01141 
01142     result = get_ts_config_oid(names, false);
01143 
01144     PG_RETURN_OID(result);
01145 }
01146 
01147 /*
01148  * regconfigout     - converts tsconfig OID to "tsconfigname"
01149  */
01150 Datum
01151 regconfigout(PG_FUNCTION_ARGS)
01152 {
01153     Oid         cfgid = PG_GETARG_OID(0);
01154     char       *result;
01155     HeapTuple   cfgtup;
01156 
01157     if (cfgid == InvalidOid)
01158     {
01159         result = pstrdup("-");
01160         PG_RETURN_CSTRING(result);
01161     }
01162 
01163     cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
01164 
01165     if (HeapTupleIsValid(cfgtup))
01166     {
01167         Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup);
01168         char       *cfgname = NameStr(cfgform->cfgname);
01169         char       *nspname;
01170 
01171         /*
01172          * Would this config be found by regconfigin? If not, qualify it.
01173          */
01174         if (TSConfigIsVisible(cfgid))
01175             nspname = NULL;
01176         else
01177             nspname = get_namespace_name(cfgform->cfgnamespace);
01178 
01179         result = quote_qualified_identifier(nspname, cfgname);
01180 
01181         ReleaseSysCache(cfgtup);
01182     }
01183     else
01184     {
01185         /* If OID doesn't match any pg_ts_config row, return it numerically */
01186         result = (char *) palloc(NAMEDATALEN);
01187         snprintf(result, NAMEDATALEN, "%u", cfgid);
01188     }
01189 
01190     PG_RETURN_CSTRING(result);
01191 }
01192 
01193 /*
01194  *      regconfigrecv           - converts external binary format to regconfig
01195  */
01196 Datum
01197 regconfigrecv(PG_FUNCTION_ARGS)
01198 {
01199     /* Exactly the same as oidrecv, so share code */
01200     return oidrecv(fcinfo);
01201 }
01202 
01203 /*
01204  *      regconfigsend           - converts regconfig to binary format
01205  */
01206 Datum
01207 regconfigsend(PG_FUNCTION_ARGS)
01208 {
01209     /* Exactly the same as oidsend, so share code */
01210     return oidsend(fcinfo);
01211 }
01212 
01213 
01214 /*
01215  * regdictionaryin      - converts "tsdictionaryname" to tsdictionary OID
01216  *
01217  * We also accept a numeric OID, for symmetry with the output routine.
01218  *
01219  * '-' signifies unknown (OID 0).  In all other cases, the input must
01220  * match an existing pg_ts_dict entry.
01221  *
01222  * This function is not needed in bootstrap mode, so we don't worry about
01223  * making it work then.
01224  */
01225 Datum
01226 regdictionaryin(PG_FUNCTION_ARGS)
01227 {
01228     char       *dict_name_or_oid = PG_GETARG_CSTRING(0);
01229     Oid         result;
01230     List       *names;
01231 
01232     /* '-' ? */
01233     if (strcmp(dict_name_or_oid, "-") == 0)
01234         PG_RETURN_OID(InvalidOid);
01235 
01236     /* Numeric OID? */
01237     if (dict_name_or_oid[0] >= '0' &&
01238         dict_name_or_oid[0] <= '9' &&
01239         strspn(dict_name_or_oid, "0123456789") == strlen(dict_name_or_oid))
01240     {
01241         result = DatumGetObjectId(DirectFunctionCall1(oidin,
01242                                          CStringGetDatum(dict_name_or_oid)));
01243         PG_RETURN_OID(result);
01244     }
01245 
01246     /*
01247      * Normal case: parse the name into components and see if it matches any
01248      * pg_ts_dict entries in the current search path.
01249      */
01250     names = stringToQualifiedNameList(dict_name_or_oid);
01251 
01252     result = get_ts_dict_oid(names, false);
01253 
01254     PG_RETURN_OID(result);
01255 }
01256 
01257 /*
01258  * regdictionaryout     - converts tsdictionary OID to "tsdictionaryname"
01259  */
01260 Datum
01261 regdictionaryout(PG_FUNCTION_ARGS)
01262 {
01263     Oid         dictid = PG_GETARG_OID(0);
01264     char       *result;
01265     HeapTuple   dicttup;
01266 
01267     if (dictid == InvalidOid)
01268     {
01269         result = pstrdup("-");
01270         PG_RETURN_CSTRING(result);
01271     }
01272 
01273     dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid));
01274 
01275     if (HeapTupleIsValid(dicttup))
01276     {
01277         Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup);
01278         char       *dictname = NameStr(dictform->dictname);
01279         char       *nspname;
01280 
01281         /*
01282          * Would this dictionary be found by regdictionaryin? If not, qualify
01283          * it.
01284          */
01285         if (TSDictionaryIsVisible(dictid))
01286             nspname = NULL;
01287         else
01288             nspname = get_namespace_name(dictform->dictnamespace);
01289 
01290         result = quote_qualified_identifier(nspname, dictname);
01291 
01292         ReleaseSysCache(dicttup);
01293     }
01294     else
01295     {
01296         /* If OID doesn't match any pg_ts_dict row, return it numerically */
01297         result = (char *) palloc(NAMEDATALEN);
01298         snprintf(result, NAMEDATALEN, "%u", dictid);
01299     }
01300 
01301     PG_RETURN_CSTRING(result);
01302 }
01303 
01304 /*
01305  *      regdictionaryrecv   - converts external binary format to regdictionary
01306  */
01307 Datum
01308 regdictionaryrecv(PG_FUNCTION_ARGS)
01309 {
01310     /* Exactly the same as oidrecv, so share code */
01311     return oidrecv(fcinfo);
01312 }
01313 
01314 /*
01315  *      regdictionarysend   - converts regdictionary to binary format
01316  */
01317 Datum
01318 regdictionarysend(PG_FUNCTION_ARGS)
01319 {
01320     /* Exactly the same as oidsend, so share code */
01321     return oidsend(fcinfo);
01322 }
01323 
01324 
01325 /*
01326  * text_regclass: convert text to regclass
01327  *
01328  * This could be replaced by CoerceViaIO, except that we need to treat
01329  * text-to-regclass as an implicit cast to support legacy forms of nextval()
01330  * and related functions.
01331  */
01332 Datum
01333 text_regclass(PG_FUNCTION_ARGS)
01334 {
01335     text       *relname = PG_GETARG_TEXT_P(0);
01336     Oid         result;
01337     RangeVar   *rv;
01338 
01339     rv = makeRangeVarFromNameList(textToQualifiedNameList(relname));
01340 
01341     /* We might not even have permissions on this relation; don't lock it. */
01342     result = RangeVarGetRelid(rv, NoLock, false);
01343 
01344     PG_RETURN_OID(result);
01345 }
01346 
01347 
01348 /*
01349  * Given a C string, parse it into a qualified-name list.
01350  */
01351 List *
01352 stringToQualifiedNameList(const char *string)
01353 {
01354     char       *rawname;
01355     List       *result = NIL;
01356     List       *namelist;
01357     ListCell   *l;
01358 
01359     /* We need a modifiable copy of the input string. */
01360     rawname = pstrdup(string);
01361 
01362     if (!SplitIdentifierString(rawname, '.', &namelist))
01363         ereport(ERROR,
01364                 (errcode(ERRCODE_INVALID_NAME),
01365                  errmsg("invalid name syntax")));
01366 
01367     if (namelist == NIL)
01368         ereport(ERROR,
01369                 (errcode(ERRCODE_INVALID_NAME),
01370                  errmsg("invalid name syntax")));
01371 
01372     foreach(l, namelist)
01373     {
01374         char       *curname = (char *) lfirst(l);
01375 
01376         result = lappend(result, makeString(pstrdup(curname)));
01377     }
01378 
01379     pfree(rawname);
01380     list_free(namelist);
01381 
01382     return result;
01383 }
01384 
01385 /*****************************************************************************
01386  *   SUPPORT ROUTINES                                                        *
01387  *****************************************************************************/
01388 
01389 /*
01390  * Given a C string, parse it into a qualified function or operator name
01391  * followed by a parenthesized list of type names.  Reduce the
01392  * type names to an array of OIDs (returned into *nargs and *argtypes;
01393  * the argtypes array should be of size FUNC_MAX_ARGS).  The function or
01394  * operator name is returned to *names as a List of Strings.
01395  *
01396  * If allowNone is TRUE, accept "NONE" and return it as InvalidOid (this is
01397  * for unary operators).
01398  */
01399 static void
01400 parseNameAndArgTypes(const char *string, bool allowNone, List **names,
01401                      int *nargs, Oid *argtypes)
01402 {
01403     char       *rawname;
01404     char       *ptr;
01405     char       *ptr2;
01406     char       *typename;
01407     bool        in_quote;
01408     bool        had_comma;
01409     int         paren_count;
01410     Oid         typeid;
01411     int32       typmod;
01412 
01413     /* We need a modifiable copy of the input string. */
01414     rawname = pstrdup(string);
01415 
01416     /* Scan to find the expected left paren; mustn't be quoted */
01417     in_quote = false;
01418     for (ptr = rawname; *ptr; ptr++)
01419     {
01420         if (*ptr == '"')
01421             in_quote = !in_quote;
01422         else if (*ptr == '(' && !in_quote)
01423             break;
01424     }
01425     if (*ptr == '\0')
01426         ereport(ERROR,
01427                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01428                  errmsg("expected a left parenthesis")));
01429 
01430     /* Separate the name and parse it into a list */
01431     *ptr++ = '\0';
01432     *names = stringToQualifiedNameList(rawname);
01433 
01434     /* Check for the trailing right parenthesis and remove it */
01435     ptr2 = ptr + strlen(ptr);
01436     while (--ptr2 > ptr)
01437     {
01438         if (!isspace((unsigned char) *ptr2))
01439             break;
01440     }
01441     if (*ptr2 != ')')
01442         ereport(ERROR,
01443                 (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01444                  errmsg("expected a right parenthesis")));
01445 
01446     *ptr2 = '\0';
01447 
01448     /* Separate the remaining string into comma-separated type names */
01449     *nargs = 0;
01450     had_comma = false;
01451 
01452     for (;;)
01453     {
01454         /* allow leading whitespace */
01455         while (isspace((unsigned char) *ptr))
01456             ptr++;
01457         if (*ptr == '\0')
01458         {
01459             /* End of string.  Okay unless we had a comma before. */
01460             if (had_comma)
01461                 ereport(ERROR,
01462                         (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01463                          errmsg("expected a type name")));
01464             break;
01465         }
01466         typename = ptr;
01467         /* Find end of type name --- end of string or comma */
01468         /* ... but not a quoted or parenthesized comma */
01469         in_quote = false;
01470         paren_count = 0;
01471         for (; *ptr; ptr++)
01472         {
01473             if (*ptr == '"')
01474                 in_quote = !in_quote;
01475             else if (*ptr == ',' && !in_quote && paren_count == 0)
01476                 break;
01477             else if (!in_quote)
01478             {
01479                 switch (*ptr)
01480                 {
01481                     case '(':
01482                     case '[':
01483                         paren_count++;
01484                         break;
01485                     case ')':
01486                     case ']':
01487                         paren_count--;
01488                         break;
01489                 }
01490             }
01491         }
01492         if (in_quote || paren_count != 0)
01493             ereport(ERROR,
01494                     (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
01495                      errmsg("improper type name")));
01496 
01497         ptr2 = ptr;
01498         if (*ptr == ',')
01499         {
01500             had_comma = true;
01501             *ptr++ = '\0';
01502         }
01503         else
01504         {
01505             had_comma = false;
01506             Assert(*ptr == '\0');
01507         }
01508         /* Lop off trailing whitespace */
01509         while (--ptr2 >= typename)
01510         {
01511             if (!isspace((unsigned char) *ptr2))
01512                 break;
01513             *ptr2 = '\0';
01514         }
01515 
01516         if (allowNone && pg_strcasecmp(typename, "none") == 0)
01517         {
01518             /* Special case for NONE */
01519             typeid = InvalidOid;
01520             typmod = -1;
01521         }
01522         else
01523         {
01524             /* Use full parser to resolve the type name */
01525             parseTypeString(typename, &typeid, &typmod);
01526         }
01527         if (*nargs >= FUNC_MAX_ARGS)
01528             ereport(ERROR,
01529                     (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
01530                      errmsg("too many arguments")));
01531 
01532         argtypes[*nargs] = typeid;
01533         (*nargs)++;
01534     }
01535 
01536     pfree(rawname);
01537 }