diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-04 12:15:05 +0000 |
commit | 46651ce6fe013220ed397add242004d764fc0153 (patch) | |
tree | 6e5299f990f88e60174a1d3ae6e48eedd2688b2b /src/backend/utils/adt/regproc.c | |
parent | Initial commit. (diff) | |
download | postgresql-14-46651ce6fe013220ed397add242004d764fc0153.tar.xz postgresql-14-46651ce6fe013220ed397add242004d764fc0153.zip |
Adding upstream version 14.5.upstream/14.5upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/backend/utils/adt/regproc.c')
-rw-r--r-- | src/backend/utils/adt/regproc.c | 2062 |
1 files changed, 2062 insertions, 0 deletions
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c new file mode 100644 index 0000000..e4fb9d3 --- /dev/null +++ b/src/backend/utils/adt/regproc.c @@ -0,0 +1,2062 @@ +/*------------------------------------------------------------------------- + * + * regproc.c + * Functions for the built-in types regproc, regclass, regtype, etc. + * + * These types are all binary-compatible with type Oid, and rely on Oid + * for comparison and so forth. Their only interesting behavior is in + * special I/O conversion routines. + * + * + * Portions Copyright (c) 1996-2021, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * src/backend/utils/adt/regproc.c + * + *------------------------------------------------------------------------- + */ +#include "postgres.h" + +#include <ctype.h> + +#include "access/htup_details.h" +#include "catalog/namespace.h" +#include "catalog/pg_class.h" +#include "catalog/pg_collation.h" +#include "catalog/pg_operator.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_ts_config.h" +#include "catalog/pg_ts_dict.h" +#include "catalog/pg_type.h" +#include "lib/stringinfo.h" +#include "miscadmin.h" +#include "parser/parse_type.h" +#include "parser/scansup.h" +#include "utils/acl.h" +#include "utils/builtins.h" +#include "utils/lsyscache.h" +#include "utils/regproc.h" +#include "utils/syscache.h" +#include "utils/varlena.h" + +static void parseNameAndArgTypes(const char *string, bool allowNone, + List **names, int *nargs, Oid *argtypes); + + +/***************************************************************************** + * USER I/O ROUTINES * + *****************************************************************************/ + +/* + * regprocin - converts "proname" to proc OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '-' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_proc entry. + */ +Datum +regprocin(PG_FUNCTION_ARGS) +{ + char *pro_name_or_oid = PG_GETARG_CSTRING(0); + RegProcedure result = InvalidOid; + List *names; + FuncCandidateList clist; + + /* '-' ? */ + if (strcmp(pro_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (pro_name_or_oid[0] >= '0' && + pro_name_or_oid[0] <= '9' && + strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(pro_name_or_oid))); + PG_RETURN_OID(result); + } + + /* Else it's a name, possibly schema-qualified */ + + /* + * We should never get here in bootstrap mode, as all references should + * have been resolved by genbki.pl. + */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regproc values must be OIDs in bootstrap mode"); + + /* + * Normal case: parse the name into components and see if it matches any + * pg_proc entries in the current search path. + */ + names = stringToQualifiedNameList(pro_name_or_oid); + clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, false); + + if (clist == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function \"%s\" does not exist", pro_name_or_oid))); + else if (clist->next != NULL) + ereport(ERROR, + (errcode(ERRCODE_AMBIGUOUS_FUNCTION), + errmsg("more than one function named \"%s\"", + pro_name_or_oid))); + + result = clist->oid; + + PG_RETURN_OID(result); +} + +/* + * to_regproc - converts "proname" to proc OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regproc(PG_FUNCTION_ARGS) +{ + char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + List *names; + FuncCandidateList clist; + + /* + * Parse the name into components and see if it matches any pg_proc + * entries in the current search path. + */ + names = stringToQualifiedNameList(pro_name); + clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true); + + if (clist == NULL || clist->next != NULL) + PG_RETURN_NULL(); + + PG_RETURN_OID(clist->oid); +} + +/* + * regprocout - converts proc OID to "pro_name" + */ +Datum +regprocout(PG_FUNCTION_ARGS) +{ + RegProcedure proid = PG_GETARG_OID(0); + char *result; + HeapTuple proctup; + + if (proid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(proid)); + + if (HeapTupleIsValid(proctup)) + { + Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); + char *proname = NameStr(procform->proname); + + /* + * In bootstrap mode, skip the fancy namespace stuff and just return + * the proc name. (This path is only needed for debugging output + * anyway.) + */ + if (IsBootstrapProcessingMode()) + result = pstrdup(proname); + else + { + char *nspname; + FuncCandidateList clist; + + /* + * Would this proc be found (uniquely!) by regprocin? If not, + * qualify it. + */ + clist = FuncnameGetCandidates(list_make1(makeString(proname)), + -1, NIL, false, false, false, false); + if (clist != NULL && clist->next == NULL && + clist->oid == proid) + nspname = NULL; + else + nspname = get_namespace_name(procform->pronamespace); + + result = quote_qualified_identifier(nspname, proname); + } + + ReleaseSysCache(proctup); + } + else + { + /* If OID doesn't match any pg_proc entry, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", proid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regprocrecv - converts external binary format to regproc + */ +Datum +regprocrecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regprocsend - converts regproc to binary format + */ +Datum +regprocsend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + + +/* + * regprocedurein - converts "proname(args)" to proc OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '-' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_proc entry. + */ +Datum +regprocedurein(PG_FUNCTION_ARGS) +{ + char *pro_name_or_oid = PG_GETARG_CSTRING(0); + RegProcedure result = InvalidOid; + List *names; + int nargs; + Oid argtypes[FUNC_MAX_ARGS]; + FuncCandidateList clist; + + /* '-' ? */ + if (strcmp(pro_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (pro_name_or_oid[0] >= '0' && + pro_name_or_oid[0] <= '9' && + strspn(pro_name_or_oid, "0123456789") == strlen(pro_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(pro_name_or_oid))); + PG_RETURN_OID(result); + } + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regprocedure values must be OIDs in bootstrap mode"); + + /* + * Else it's a name and arguments. Parse the name and arguments, look up + * potential matches in the current namespace search list, and scan to see + * which one exactly matches the given argument types. (There will not be + * more than one match.) + */ + parseNameAndArgTypes(pro_name_or_oid, false, &names, &nargs, argtypes); + + clist = FuncnameGetCandidates(names, nargs, NIL, false, false, + false, false); + + for (; clist; clist = clist->next) + { + if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0) + break; + } + + if (clist == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("function \"%s\" does not exist", pro_name_or_oid))); + + result = clist->oid; + + PG_RETURN_OID(result); +} + +/* + * to_regprocedure - converts "proname(args)" to proc OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regprocedure(PG_FUNCTION_ARGS) +{ + char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + List *names; + int nargs; + Oid argtypes[FUNC_MAX_ARGS]; + FuncCandidateList clist; + + /* + * Parse the name and arguments, look up potential matches in the current + * namespace search list, and scan to see which one exactly matches the + * given argument types. (There will not be more than one match.) + */ + parseNameAndArgTypes(pro_name, false, &names, &nargs, argtypes); + + clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true); + + for (; clist; clist = clist->next) + { + if (memcmp(clist->args, argtypes, nargs * sizeof(Oid)) == 0) + PG_RETURN_OID(clist->oid); + } + + PG_RETURN_NULL(); +} + +/* + * format_procedure - converts proc OID to "pro_name(args)" + * + * This exports the useful functionality of regprocedureout for use + * in other backend modules. The result is a palloc'd string. + */ +char * +format_procedure(Oid procedure_oid) +{ + return format_procedure_extended(procedure_oid, 0); +} + +char * +format_procedure_qualified(Oid procedure_oid) +{ + return format_procedure_extended(procedure_oid, FORMAT_PROC_FORCE_QUALIFY); +} + +/* + * format_procedure_extended - converts procedure OID to "pro_name(args)" + * + * This exports the useful functionality of regprocedureout for use + * in other backend modules. The result is a palloc'd string, or NULL. + * + * Routine to produce regprocedure names; see format_procedure above. + * + * The following bits in 'flags' modify the behavior: + * - FORMAT_PROC_INVALID_AS_NULL + * if the procedure OID is invalid or unknown, return NULL instead + * of the numeric OID. + * - FORMAT_PROC_FORCE_QUALIFY + * always schema-qualify procedure names, regardless of search_path + */ +char * +format_procedure_extended(Oid procedure_oid, bits16 flags) +{ + char *result; + HeapTuple proctup; + + proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid)); + + if (HeapTupleIsValid(proctup)) + { + Form_pg_proc procform = (Form_pg_proc) GETSTRUCT(proctup); + char *proname = NameStr(procform->proname); + int nargs = procform->pronargs; + int i; + char *nspname; + StringInfoData buf; + + /* XXX no support here for bootstrap mode */ + Assert(!IsBootstrapProcessingMode()); + + initStringInfo(&buf); + + /* + * Would this proc be found (given the right args) by regprocedurein? + * If not, or if caller requests it, we need to qualify it. + */ + if ((flags & FORMAT_PROC_FORCE_QUALIFY) == 0 && + FunctionIsVisible(procedure_oid)) + nspname = NULL; + else + nspname = get_namespace_name(procform->pronamespace); + + appendStringInfo(&buf, "%s(", + quote_qualified_identifier(nspname, proname)); + for (i = 0; i < nargs; i++) + { + Oid thisargtype = procform->proargtypes.values[i]; + + if (i > 0) + appendStringInfoChar(&buf, ','); + appendStringInfoString(&buf, + (flags & FORMAT_PROC_FORCE_QUALIFY) != 0 ? + format_type_be_qualified(thisargtype) : + format_type_be(thisargtype)); + } + appendStringInfoChar(&buf, ')'); + + result = buf.data; + + ReleaseSysCache(proctup); + } + else if ((flags & FORMAT_PROC_INVALID_AS_NULL) != 0) + { + /* If object is undefined, return NULL as wanted by caller */ + result = NULL; + } + else + { + /* If OID doesn't match any pg_proc entry, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", procedure_oid); + } + + return result; +} + +/* + * Output an objname/objargs representation for the procedure with the + * given OID. If it doesn't exist, an error is thrown. + * + * This can be used to feed get_object_address. + */ +void +format_procedure_parts(Oid procedure_oid, List **objnames, List **objargs, + bool missing_ok) +{ + HeapTuple proctup; + Form_pg_proc procform; + int nargs; + int i; + + proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(procedure_oid)); + + if (!HeapTupleIsValid(proctup)) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for procedure with OID %u", procedure_oid); + return; + } + + procform = (Form_pg_proc) GETSTRUCT(proctup); + nargs = procform->pronargs; + + *objnames = list_make2(get_namespace_name_or_temp(procform->pronamespace), + pstrdup(NameStr(procform->proname))); + *objargs = NIL; + for (i = 0; i < nargs; i++) + { + Oid thisargtype = procform->proargtypes.values[i]; + + *objargs = lappend(*objargs, format_type_be_qualified(thisargtype)); + } + + ReleaseSysCache(proctup); +} + +/* + * regprocedureout - converts proc OID to "pro_name(args)" + */ +Datum +regprocedureout(PG_FUNCTION_ARGS) +{ + RegProcedure proid = PG_GETARG_OID(0); + char *result; + + if (proid == InvalidOid) + result = pstrdup("-"); + else + result = format_procedure(proid); + + PG_RETURN_CSTRING(result); +} + +/* + * regprocedurerecv - converts external binary format to regprocedure + */ +Datum +regprocedurerecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regproceduresend - converts regprocedure to binary format + */ +Datum +regproceduresend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + + +/* + * regoperin - converts "oprname" to operator OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '0' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_operator entry. + */ +Datum +regoperin(PG_FUNCTION_ARGS) +{ + char *opr_name_or_oid = PG_GETARG_CSTRING(0); + Oid result = InvalidOid; + List *names; + FuncCandidateList clist; + + /* '0' ? */ + if (strcmp(opr_name_or_oid, "0") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (opr_name_or_oid[0] >= '0' && + opr_name_or_oid[0] <= '9' && + strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(opr_name_or_oid))); + PG_RETURN_OID(result); + } + + /* Else it's a name, possibly schema-qualified */ + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regoper values must be OIDs in bootstrap mode"); + + /* + * Normal case: parse the name into components and see if it matches any + * pg_operator entries in the current search path. + */ + names = stringToQualifiedNameList(opr_name_or_oid); + clist = OpernameGetCandidates(names, '\0', false); + + if (clist == NULL) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("operator does not exist: %s", opr_name_or_oid))); + else if (clist->next != NULL) + ereport(ERROR, + (errcode(ERRCODE_AMBIGUOUS_FUNCTION), + errmsg("more than one operator named %s", + opr_name_or_oid))); + + result = clist->oid; + + PG_RETURN_OID(result); +} + +/* + * to_regoper - converts "oprname" to operator OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regoper(PG_FUNCTION_ARGS) +{ + char *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + List *names; + FuncCandidateList clist; + + /* + * Parse the name into components and see if it matches any pg_operator + * entries in the current search path. + */ + names = stringToQualifiedNameList(opr_name); + clist = OpernameGetCandidates(names, '\0', true); + + if (clist == NULL || clist->next != NULL) + PG_RETURN_NULL(); + + PG_RETURN_OID(clist->oid); +} + +/* + * regoperout - converts operator OID to "opr_name" + */ +Datum +regoperout(PG_FUNCTION_ARGS) +{ + Oid oprid = PG_GETARG_OID(0); + char *result; + HeapTuple opertup; + + if (oprid == InvalidOid) + { + result = pstrdup("0"); + PG_RETURN_CSTRING(result); + } + + opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid)); + + if (HeapTupleIsValid(opertup)) + { + Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup); + char *oprname = NameStr(operform->oprname); + + /* + * In bootstrap mode, skip the fancy namespace stuff and just return + * the oper name. (This path is only needed for debugging output + * anyway.) + */ + if (IsBootstrapProcessingMode()) + result = pstrdup(oprname); + else + { + FuncCandidateList clist; + + /* + * Would this oper be found (uniquely!) by regoperin? If not, + * qualify it. + */ + clist = OpernameGetCandidates(list_make1(makeString(oprname)), + '\0', false); + if (clist != NULL && clist->next == NULL && + clist->oid == oprid) + result = pstrdup(oprname); + else + { + const char *nspname; + + nspname = get_namespace_name(operform->oprnamespace); + nspname = quote_identifier(nspname); + result = (char *) palloc(strlen(nspname) + strlen(oprname) + 2); + sprintf(result, "%s.%s", nspname, oprname); + } + } + + ReleaseSysCache(opertup); + } + else + { + /* + * If OID doesn't match any pg_operator entry, return it numerically + */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", oprid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regoperrecv - converts external binary format to regoper + */ +Datum +regoperrecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regopersend - converts regoper to binary format + */ +Datum +regopersend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + + +/* + * regoperatorin - converts "oprname(args)" to operator OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '0' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_operator entry. + */ +Datum +regoperatorin(PG_FUNCTION_ARGS) +{ + char *opr_name_or_oid = PG_GETARG_CSTRING(0); + Oid result; + List *names; + int nargs; + Oid argtypes[FUNC_MAX_ARGS]; + + /* '0' ? */ + if (strcmp(opr_name_or_oid, "0") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (opr_name_or_oid[0] >= '0' && + opr_name_or_oid[0] <= '9' && + strspn(opr_name_or_oid, "0123456789") == strlen(opr_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(opr_name_or_oid))); + PG_RETURN_OID(result); + } + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regoperator values must be OIDs in bootstrap mode"); + + /* + * Else it's a name and arguments. Parse the name and arguments, look up + * potential matches in the current namespace search list, and scan to see + * which one exactly matches the given argument types. (There will not be + * more than one match.) + */ + parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes); + if (nargs == 1) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_PARAMETER), + errmsg("missing argument"), + errhint("Use NONE to denote the missing argument of a unary operator."))); + if (nargs != 2) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ARGUMENTS), + errmsg("too many arguments"), + errhint("Provide two argument types for operator."))); + + result = OpernameGetOprid(names, argtypes[0], argtypes[1]); + + if (!OidIsValid(result)) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION), + errmsg("operator does not exist: %s", opr_name_or_oid))); + + PG_RETURN_OID(result); +} + +/* + * to_regoperator - converts "oprname(args)" to operator OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regoperator(PG_FUNCTION_ARGS) +{ + char *opr_name_or_oid = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Oid result; + List *names; + int nargs; + Oid argtypes[FUNC_MAX_ARGS]; + + /* + * Parse the name and arguments, look up potential matches in the current + * namespace search list, and scan to see which one exactly matches the + * given argument types. (There will not be more than one match.) + */ + parseNameAndArgTypes(opr_name_or_oid, true, &names, &nargs, argtypes); + if (nargs == 1) + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_PARAMETER), + errmsg("missing argument"), + errhint("Use NONE to denote the missing argument of a unary operator."))); + if (nargs != 2) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ARGUMENTS), + errmsg("too many arguments"), + errhint("Provide two argument types for operator."))); + + result = OpernameGetOprid(names, argtypes[0], argtypes[1]); + + if (!OidIsValid(result)) + PG_RETURN_NULL(); + + PG_RETURN_OID(result); +} + +/* + * format_operator_extended - converts operator OID to "opr_name(args)" + * + * This exports the useful functionality of regoperatorout for use + * in other backend modules. The result is a palloc'd string, or NULL. + * + * The following bits in 'flags' modify the behavior: + * - FORMAT_OPERATOR_INVALID_AS_NULL + * if the operator OID is invalid or unknown, return NULL instead + * of the numeric OID. + * - FORMAT_OPERATOR_FORCE_QUALIFY + * always schema-qualify operator names, regardless of search_path + */ +char * +format_operator_extended(Oid operator_oid, bits16 flags) +{ + char *result; + HeapTuple opertup; + + opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid)); + + if (HeapTupleIsValid(opertup)) + { + Form_pg_operator operform = (Form_pg_operator) GETSTRUCT(opertup); + char *oprname = NameStr(operform->oprname); + char *nspname; + StringInfoData buf; + + /* XXX no support here for bootstrap mode */ + Assert(!IsBootstrapProcessingMode()); + + initStringInfo(&buf); + + /* + * Would this oper be found (given the right args) by regoperatorin? + * If not, or if caller explicitly requests it, we need to qualify it. + */ + if ((flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 || + !OperatorIsVisible(operator_oid)) + { + nspname = get_namespace_name(operform->oprnamespace); + appendStringInfo(&buf, "%s.", + quote_identifier(nspname)); + } + + appendStringInfo(&buf, "%s(", oprname); + + if (operform->oprleft) + appendStringInfo(&buf, "%s,", + (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ? + format_type_be_qualified(operform->oprleft) : + format_type_be(operform->oprleft)); + else + appendStringInfoString(&buf, "NONE,"); + + if (operform->oprright) + appendStringInfo(&buf, "%s)", + (flags & FORMAT_OPERATOR_FORCE_QUALIFY) != 0 ? + format_type_be_qualified(operform->oprright) : + format_type_be(operform->oprright)); + else + appendStringInfoString(&buf, "NONE)"); + + result = buf.data; + + ReleaseSysCache(opertup); + } + else if ((flags & FORMAT_OPERATOR_INVALID_AS_NULL) != 0) + { + /* If object is undefined, return NULL as wanted by caller */ + result = NULL; + } + else + { + /* + * If OID doesn't match any pg_operator entry, return it numerically + */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", operator_oid); + } + + return result; +} + +char * +format_operator(Oid operator_oid) +{ + return format_operator_extended(operator_oid, 0); +} + +char * +format_operator_qualified(Oid operator_oid) +{ + return format_operator_extended(operator_oid, + FORMAT_OPERATOR_FORCE_QUALIFY); +} + +void +format_operator_parts(Oid operator_oid, List **objnames, List **objargs, + bool missing_ok) +{ + HeapTuple opertup; + Form_pg_operator oprForm; + + opertup = SearchSysCache1(OPEROID, ObjectIdGetDatum(operator_oid)); + if (!HeapTupleIsValid(opertup)) + { + if (!missing_ok) + elog(ERROR, "cache lookup failed for operator with OID %u", + operator_oid); + return; + } + + oprForm = (Form_pg_operator) GETSTRUCT(opertup); + *objnames = list_make2(get_namespace_name_or_temp(oprForm->oprnamespace), + pstrdup(NameStr(oprForm->oprname))); + *objargs = NIL; + if (oprForm->oprleft) + *objargs = lappend(*objargs, + format_type_be_qualified(oprForm->oprleft)); + if (oprForm->oprright) + *objargs = lappend(*objargs, + format_type_be_qualified(oprForm->oprright)); + + ReleaseSysCache(opertup); +} + +/* + * regoperatorout - converts operator OID to "opr_name(args)" + */ +Datum +regoperatorout(PG_FUNCTION_ARGS) +{ + Oid oprid = PG_GETARG_OID(0); + char *result; + + if (oprid == InvalidOid) + result = pstrdup("0"); + else + result = format_operator(oprid); + + PG_RETURN_CSTRING(result); +} + +/* + * regoperatorrecv - converts external binary format to regoperator + */ +Datum +regoperatorrecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regoperatorsend - converts regoperator to binary format + */ +Datum +regoperatorsend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + + +/* + * regclassin - converts "classname" to class OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '-' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_class entry. + */ +Datum +regclassin(PG_FUNCTION_ARGS) +{ + char *class_name_or_oid = PG_GETARG_CSTRING(0); + Oid result = InvalidOid; + List *names; + + /* '-' ? */ + if (strcmp(class_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (class_name_or_oid[0] >= '0' && + class_name_or_oid[0] <= '9' && + strspn(class_name_or_oid, "0123456789") == strlen(class_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(class_name_or_oid))); + PG_RETURN_OID(result); + } + + /* Else it's a name, possibly schema-qualified */ + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regclass values must be OIDs in bootstrap mode"); + + /* + * Normal case: parse the name into components and see if it matches any + * pg_class entries in the current search path. + */ + names = stringToQualifiedNameList(class_name_or_oid); + + /* We might not even have permissions on this relation; don't lock it. */ + result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false); + + PG_RETURN_OID(result); +} + +/* + * to_regclass - converts "classname" to class OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regclass(PG_FUNCTION_ARGS) +{ + char *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Oid result; + List *names; + + /* + * Parse the name into components and see if it matches any pg_class + * entries in the current search path. + */ + names = stringToQualifiedNameList(class_name); + + /* We might not even have permissions on this relation; don't lock it. */ + result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true); + + if (OidIsValid(result)) + PG_RETURN_OID(result); + else + PG_RETURN_NULL(); +} + +/* + * regclassout - converts class OID to "class_name" + */ +Datum +regclassout(PG_FUNCTION_ARGS) +{ + Oid classid = PG_GETARG_OID(0); + char *result; + HeapTuple classtup; + + if (classid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + classtup = SearchSysCache1(RELOID, ObjectIdGetDatum(classid)); + + if (HeapTupleIsValid(classtup)) + { + Form_pg_class classform = (Form_pg_class) GETSTRUCT(classtup); + char *classname = NameStr(classform->relname); + + /* + * In bootstrap mode, skip the fancy namespace stuff and just return + * the class name. (This path is only needed for debugging output + * anyway.) + */ + if (IsBootstrapProcessingMode()) + result = pstrdup(classname); + else + { + char *nspname; + + /* + * Would this class be found by regclassin? If not, qualify it. + */ + if (RelationIsVisible(classid)) + nspname = NULL; + else + nspname = get_namespace_name(classform->relnamespace); + + result = quote_qualified_identifier(nspname, classname); + } + + ReleaseSysCache(classtup); + } + else + { + /* If OID doesn't match any pg_class entry, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", classid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regclassrecv - converts external binary format to regclass + */ +Datum +regclassrecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regclasssend - converts regclass to binary format + */ +Datum +regclasssend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + + +/* + * regcollationin - converts "collationname" to collation OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '-' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_collation entry. + */ +Datum +regcollationin(PG_FUNCTION_ARGS) +{ + char *collation_name_or_oid = PG_GETARG_CSTRING(0); + Oid result = InvalidOid; + List *names; + + /* '-' ? */ + if (strcmp(collation_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (collation_name_or_oid[0] >= '0' && + collation_name_or_oid[0] <= '9' && + strspn(collation_name_or_oid, "0123456789") == strlen(collation_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(collation_name_or_oid))); + PG_RETURN_OID(result); + } + + /* Else it's a name, possibly schema-qualified */ + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regcollation values must be OIDs in bootstrap mode"); + + /* + * Normal case: parse the name into components and see if it matches any + * pg_collation entries in the current search path. + */ + names = stringToQualifiedNameList(collation_name_or_oid); + + result = get_collation_oid(names, false); + + PG_RETURN_OID(result); +} + +/* + * to_regcollation - converts "collationname" to collation OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regcollation(PG_FUNCTION_ARGS) +{ + char *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Oid result; + List *names; + + /* + * Parse the name into components and see if it matches any pg_collation + * entries in the current search path. + */ + names = stringToQualifiedNameList(collation_name); + + /* We might not even have permissions on this relation; don't lock it. */ + result = get_collation_oid(names, true); + + if (OidIsValid(result)) + PG_RETURN_OID(result); + else + PG_RETURN_NULL(); +} + +/* + * regcollationout - converts collation OID to "collation_name" + */ +Datum +regcollationout(PG_FUNCTION_ARGS) +{ + Oid collationid = PG_GETARG_OID(0); + char *result; + HeapTuple collationtup; + + if (collationid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + collationtup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationid)); + + if (HeapTupleIsValid(collationtup)) + { + Form_pg_collation collationform = (Form_pg_collation) GETSTRUCT(collationtup); + char *collationname = NameStr(collationform->collname); + + /* + * In bootstrap mode, skip the fancy namespace stuff and just return + * the collation name. (This path is only needed for debugging output + * anyway.) + */ + if (IsBootstrapProcessingMode()) + result = pstrdup(collationname); + else + { + char *nspname; + + /* + * Would this collation be found by regcollationin? If not, + * qualify it. + */ + if (CollationIsVisible(collationid)) + nspname = NULL; + else + nspname = get_namespace_name(collationform->collnamespace); + + result = quote_qualified_identifier(nspname, collationname); + } + + ReleaseSysCache(collationtup); + } + else + { + /* If OID doesn't match any pg_collation entry, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", collationid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regcollationrecv - converts external binary format to regcollation + */ +Datum +regcollationrecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regcollationsend - converts regcollation to binary format + */ +Datum +regcollationsend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + + +/* + * regtypein - converts "typename" to type OID + * + * The type name can be specified using the full type syntax recognized by + * the parser; for example, DOUBLE PRECISION and INTEGER[] will work and be + * translated to the correct type names. (We ignore any typmod info + * generated by the parser, however.) + * + * We also accept a numeric OID, for symmetry with the output routine, + * and for possible use in bootstrap mode. + * + * '-' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_type entry. + */ +Datum +regtypein(PG_FUNCTION_ARGS) +{ + char *typ_name_or_oid = PG_GETARG_CSTRING(0); + Oid result = InvalidOid; + int32 typmod; + + /* '-' ? */ + if (strcmp(typ_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (typ_name_or_oid[0] >= '0' && + typ_name_or_oid[0] <= '9' && + strspn(typ_name_or_oid, "0123456789") == strlen(typ_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(typ_name_or_oid))); + PG_RETURN_OID(result); + } + + /* Else it's a type name, possibly schema-qualified or decorated */ + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regtype values must be OIDs in bootstrap mode"); + + /* + * Normal case: invoke the full parser to deal with special cases such as + * array syntax. + */ + parseTypeString(typ_name_or_oid, &result, &typmod, false); + + PG_RETURN_OID(result); +} + +/* + * to_regtype - converts "typename" to type OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regtype(PG_FUNCTION_ARGS) +{ + char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Oid result; + int32 typmod; + + /* + * Invoke the full parser to deal with special cases such as array syntax. + */ + parseTypeString(typ_name, &result, &typmod, true); + + if (OidIsValid(result)) + PG_RETURN_OID(result); + else + PG_RETURN_NULL(); +} + +/* + * regtypeout - converts type OID to "typ_name" + */ +Datum +regtypeout(PG_FUNCTION_ARGS) +{ + Oid typid = PG_GETARG_OID(0); + char *result; + HeapTuple typetup; + + if (typid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + typetup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid)); + + if (HeapTupleIsValid(typetup)) + { + Form_pg_type typeform = (Form_pg_type) GETSTRUCT(typetup); + + /* + * In bootstrap mode, skip the fancy namespace stuff and just return + * the type name. (This path is only needed for debugging output + * anyway.) + */ + if (IsBootstrapProcessingMode()) + { + char *typname = NameStr(typeform->typname); + + result = pstrdup(typname); + } + else + result = format_type_be(typid); + + ReleaseSysCache(typetup); + } + else + { + /* If OID doesn't match any pg_type entry, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", typid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regtyperecv - converts external binary format to regtype + */ +Datum +regtyperecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regtypesend - converts regtype to binary format + */ +Datum +regtypesend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + + +/* + * regconfigin - converts "tsconfigname" to tsconfig OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '-' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_ts_config entry. + */ +Datum +regconfigin(PG_FUNCTION_ARGS) +{ + char *cfg_name_or_oid = PG_GETARG_CSTRING(0); + Oid result; + List *names; + + /* '-' ? */ + if (strcmp(cfg_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (cfg_name_or_oid[0] >= '0' && + cfg_name_or_oid[0] <= '9' && + strspn(cfg_name_or_oid, "0123456789") == strlen(cfg_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(cfg_name_or_oid))); + PG_RETURN_OID(result); + } + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regconfig values must be OIDs in bootstrap mode"); + + /* + * Normal case: parse the name into components and see if it matches any + * pg_ts_config entries in the current search path. + */ + names = stringToQualifiedNameList(cfg_name_or_oid); + + result = get_ts_config_oid(names, false); + + PG_RETURN_OID(result); +} + +/* + * regconfigout - converts tsconfig OID to "tsconfigname" + */ +Datum +regconfigout(PG_FUNCTION_ARGS) +{ + Oid cfgid = PG_GETARG_OID(0); + char *result; + HeapTuple cfgtup; + + if (cfgid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + cfgtup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid)); + + if (HeapTupleIsValid(cfgtup)) + { + Form_pg_ts_config cfgform = (Form_pg_ts_config) GETSTRUCT(cfgtup); + char *cfgname = NameStr(cfgform->cfgname); + char *nspname; + + /* + * Would this config be found by regconfigin? If not, qualify it. + */ + if (TSConfigIsVisible(cfgid)) + nspname = NULL; + else + nspname = get_namespace_name(cfgform->cfgnamespace); + + result = quote_qualified_identifier(nspname, cfgname); + + ReleaseSysCache(cfgtup); + } + else + { + /* If OID doesn't match any pg_ts_config row, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", cfgid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regconfigrecv - converts external binary format to regconfig + */ +Datum +regconfigrecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regconfigsend - converts regconfig to binary format + */ +Datum +regconfigsend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + + +/* + * regdictionaryin - converts "tsdictionaryname" to tsdictionary OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '-' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_ts_dict entry. + */ +Datum +regdictionaryin(PG_FUNCTION_ARGS) +{ + char *dict_name_or_oid = PG_GETARG_CSTRING(0); + Oid result; + List *names; + + /* '-' ? */ + if (strcmp(dict_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (dict_name_or_oid[0] >= '0' && + dict_name_or_oid[0] <= '9' && + strspn(dict_name_or_oid, "0123456789") == strlen(dict_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(dict_name_or_oid))); + PG_RETURN_OID(result); + } + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regdictionary values must be OIDs in bootstrap mode"); + + /* + * Normal case: parse the name into components and see if it matches any + * pg_ts_dict entries in the current search path. + */ + names = stringToQualifiedNameList(dict_name_or_oid); + + result = get_ts_dict_oid(names, false); + + PG_RETURN_OID(result); +} + +/* + * regdictionaryout - converts tsdictionary OID to "tsdictionaryname" + */ +Datum +regdictionaryout(PG_FUNCTION_ARGS) +{ + Oid dictid = PG_GETARG_OID(0); + char *result; + HeapTuple dicttup; + + if (dictid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + dicttup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictid)); + + if (HeapTupleIsValid(dicttup)) + { + Form_pg_ts_dict dictform = (Form_pg_ts_dict) GETSTRUCT(dicttup); + char *dictname = NameStr(dictform->dictname); + char *nspname; + + /* + * Would this dictionary be found by regdictionaryin? If not, qualify + * it. + */ + if (TSDictionaryIsVisible(dictid)) + nspname = NULL; + else + nspname = get_namespace_name(dictform->dictnamespace); + + result = quote_qualified_identifier(nspname, dictname); + + ReleaseSysCache(dicttup); + } + else + { + /* If OID doesn't match any pg_ts_dict row, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", dictid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regdictionaryrecv - converts external binary format to regdictionary + */ +Datum +regdictionaryrecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regdictionarysend - converts regdictionary to binary format + */ +Datum +regdictionarysend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + +/* + * regrolein - converts "rolename" to role OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '-' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_authid entry. + */ +Datum +regrolein(PG_FUNCTION_ARGS) +{ + char *role_name_or_oid = PG_GETARG_CSTRING(0); + Oid result; + List *names; + + /* '-' ? */ + if (strcmp(role_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (role_name_or_oid[0] >= '0' && + role_name_or_oid[0] <= '9' && + strspn(role_name_or_oid, "0123456789") == strlen(role_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(role_name_or_oid))); + PG_RETURN_OID(result); + } + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regrole values must be OIDs in bootstrap mode"); + + /* Normal case: see if the name matches any pg_authid entry. */ + names = stringToQualifiedNameList(role_name_or_oid); + + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_role_oid(strVal(linitial(names)), false); + + PG_RETURN_OID(result); +} + +/* + * to_regrole - converts "rolename" to role OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regrole(PG_FUNCTION_ARGS) +{ + char *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Oid result; + List *names; + + names = stringToQualifiedNameList(role_name); + + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_role_oid(strVal(linitial(names)), true); + + if (OidIsValid(result)) + PG_RETURN_OID(result); + else + PG_RETURN_NULL(); +} + +/* + * regroleout - converts role OID to "role_name" + */ +Datum +regroleout(PG_FUNCTION_ARGS) +{ + Oid roleoid = PG_GETARG_OID(0); + char *result; + + if (roleoid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + result = GetUserNameFromId(roleoid, true); + + if (result) + { + /* pstrdup is not really necessary, but it avoids a compiler warning */ + result = pstrdup(quote_identifier(result)); + } + else + { + /* If OID doesn't match any role, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", roleoid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regrolerecv - converts external binary format to regrole + */ +Datum +regrolerecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regrolesend - converts regrole to binary format + */ +Datum +regrolesend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + +/* + * regnamespacein - converts "nspname" to namespace OID + * + * We also accept a numeric OID, for symmetry with the output routine. + * + * '-' signifies unknown (OID 0). In all other cases, the input must + * match an existing pg_namespace entry. + */ +Datum +regnamespacein(PG_FUNCTION_ARGS) +{ + char *nsp_name_or_oid = PG_GETARG_CSTRING(0); + Oid result; + List *names; + + /* '-' ? */ + if (strcmp(nsp_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (nsp_name_or_oid[0] >= '0' && + nsp_name_or_oid[0] <= '9' && + strspn(nsp_name_or_oid, "0123456789") == strlen(nsp_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(nsp_name_or_oid))); + PG_RETURN_OID(result); + } + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regnamespace values must be OIDs in bootstrap mode"); + + /* Normal case: see if the name matches any pg_namespace entry. */ + names = stringToQualifiedNameList(nsp_name_or_oid); + + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_namespace_oid(strVal(linitial(names)), false); + + PG_RETURN_OID(result); +} + +/* + * to_regnamespace - converts "nspname" to namespace OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regnamespace(PG_FUNCTION_ARGS) +{ + char *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Oid result; + List *names; + + names = stringToQualifiedNameList(nsp_name); + + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_namespace_oid(strVal(linitial(names)), true); + + if (OidIsValid(result)) + PG_RETURN_OID(result); + else + PG_RETURN_NULL(); +} + +/* + * regnamespaceout - converts namespace OID to "nsp_name" + */ +Datum +regnamespaceout(PG_FUNCTION_ARGS) +{ + Oid nspid = PG_GETARG_OID(0); + char *result; + + if (nspid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + result = get_namespace_name(nspid); + + if (result) + { + /* pstrdup is not really necessary, but it avoids a compiler warning */ + result = pstrdup(quote_identifier(result)); + } + else + { + /* If OID doesn't match any namespace, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", nspid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regnamespacerecv - converts external binary format to regnamespace + */ +Datum +regnamespacerecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regnamespacesend - converts regnamespace to binary format + */ +Datum +regnamespacesend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + +/* + * text_regclass: convert text to regclass + * + * This could be replaced by CoerceViaIO, except that we need to treat + * text-to-regclass as an implicit cast to support legacy forms of nextval() + * and related functions. + */ +Datum +text_regclass(PG_FUNCTION_ARGS) +{ + text *relname = PG_GETARG_TEXT_PP(0); + Oid result; + RangeVar *rv; + + rv = makeRangeVarFromNameList(textToQualifiedNameList(relname)); + + /* We might not even have permissions on this relation; don't lock it. */ + result = RangeVarGetRelid(rv, NoLock, false); + + PG_RETURN_OID(result); +} + + +/* + * Given a C string, parse it into a qualified-name list. + */ +List * +stringToQualifiedNameList(const char *string) +{ + char *rawname; + List *result = NIL; + List *namelist; + ListCell *l; + + /* We need a modifiable copy of the input string. */ + rawname = pstrdup(string); + + if (!SplitIdentifierString(rawname, '.', &namelist)) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + if (namelist == NIL) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + foreach(l, namelist) + { + char *curname = (char *) lfirst(l); + + result = lappend(result, makeString(pstrdup(curname))); + } + + pfree(rawname); + list_free(namelist); + + return result; +} + +/***************************************************************************** + * SUPPORT ROUTINES * + *****************************************************************************/ + +/* + * Given a C string, parse it into a qualified function or operator name + * followed by a parenthesized list of type names. Reduce the + * type names to an array of OIDs (returned into *nargs and *argtypes; + * the argtypes array should be of size FUNC_MAX_ARGS). The function or + * operator name is returned to *names as a List of Strings. + * + * If allowNone is true, accept "NONE" and return it as InvalidOid (this is + * for unary operators). + */ +static void +parseNameAndArgTypes(const char *string, bool allowNone, List **names, + int *nargs, Oid *argtypes) +{ + char *rawname; + char *ptr; + char *ptr2; + char *typename; + bool in_quote; + bool had_comma; + int paren_count; + Oid typeid; + int32 typmod; + + /* We need a modifiable copy of the input string. */ + rawname = pstrdup(string); + + /* Scan to find the expected left paren; mustn't be quoted */ + in_quote = false; + for (ptr = rawname; *ptr; ptr++) + { + if (*ptr == '"') + in_quote = !in_quote; + else if (*ptr == '(' && !in_quote) + break; + } + if (*ptr == '\0') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("expected a left parenthesis"))); + + /* Separate the name and parse it into a list */ + *ptr++ = '\0'; + *names = stringToQualifiedNameList(rawname); + + /* Check for the trailing right parenthesis and remove it */ + ptr2 = ptr + strlen(ptr); + while (--ptr2 > ptr) + { + if (!scanner_isspace(*ptr2)) + break; + } + if (*ptr2 != ')') + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("expected a right parenthesis"))); + + *ptr2 = '\0'; + + /* Separate the remaining string into comma-separated type names */ + *nargs = 0; + had_comma = false; + + for (;;) + { + /* allow leading whitespace */ + while (scanner_isspace(*ptr)) + ptr++; + if (*ptr == '\0') + { + /* End of string. Okay unless we had a comma before. */ + if (had_comma) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("expected a type name"))); + break; + } + typename = ptr; + /* Find end of type name --- end of string or comma */ + /* ... but not a quoted or parenthesized comma */ + in_quote = false; + paren_count = 0; + for (; *ptr; ptr++) + { + if (*ptr == '"') + in_quote = !in_quote; + else if (*ptr == ',' && !in_quote && paren_count == 0) + break; + else if (!in_quote) + { + switch (*ptr) + { + case '(': + case '[': + paren_count++; + break; + case ')': + case ']': + paren_count--; + break; + } + } + } + if (in_quote || paren_count != 0) + ereport(ERROR, + (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), + errmsg("improper type name"))); + + ptr2 = ptr; + if (*ptr == ',') + { + had_comma = true; + *ptr++ = '\0'; + } + else + { + had_comma = false; + Assert(*ptr == '\0'); + } + /* Lop off trailing whitespace */ + while (--ptr2 >= typename) + { + if (!scanner_isspace(*ptr2)) + break; + *ptr2 = '\0'; + } + + if (allowNone && pg_strcasecmp(typename, "none") == 0) + { + /* Special case for NONE */ + typeid = InvalidOid; + typmod = -1; + } + else + { + /* Use full parser to resolve the type name */ + parseTypeString(typename, &typeid, &typmod, false); + } + if (*nargs >= FUNC_MAX_ARGS) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ARGUMENTS), + errmsg("too many arguments"))); + + argtypes[*nargs] = typeid; + (*nargs)++; + } + + pfree(rawname); +} |