diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2022-12-27 12:26:01 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2022-12-27 12:26:01 -0500 |
commit | 858e776c84f48841e7e16fba7b690b76e54f3675 (patch) | |
tree | d66a1512ca446af90173d5ff8fd57863f98be6f7 /src/backend/utils/adt/regproc.c | |
parent | 78212f21011449f0374831323655baa7c00f3680 (diff) | |
download | postgresql-858e776c84f48841e7e16fba7b690b76e54f3675.tar.gz postgresql-858e776c84f48841e7e16fba7b690b76e54f3675.zip |
Convert the reg* input functions to report (most) errors softly.
This is not really complete, but it catches most cases of practical
interest. The main omissions are:
* regtype, regprocedure, and regoperator parse type names by
calling the main grammar, so any grammar-detected syntax error
will still be a hard error. Also, if one includes a type
modifier in such a type specification, errors detected by the
typmodin function will be hard errors.
* Lookup errors are handled just by passing missing_ok = true
to the relevant catalog lookup function. Because we've used
quite a restrictive definition of "missing_ok", this means that
edge cases such as "the named schema exists, but you lack
USAGE permission on it" are still hard errors.
It would make sense to me to replace most/all missing_ok
parameters with an escontext parameter and then allow these
additional lookup failure cases to be trapped too. But that's
a job for some other day.
Discussion: https://postgr.es/m/3342239.1671988406@sss.pgh.pa.us
Diffstat (limited to 'src/backend/utils/adt/regproc.c')
-rw-r--r-- | src/backend/utils/adt/regproc.c | 269 |
1 files changed, 187 insertions, 82 deletions
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index a6d695d6cbf..14d76c856d7 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -31,7 +31,9 @@ #include "catalog/pg_ts_dict.h" #include "catalog/pg_type.h" #include "lib/stringinfo.h" +#include "mb/pg_wchar.h" #include "miscadmin.h" +#include "nodes/miscnodes.h" #include "parser/parse_type.h" #include "parser/scansup.h" #include "utils/acl.h" @@ -43,8 +45,9 @@ static bool parseNumericOid(char *string, Oid *result, Node *escontext); static bool parseDashOrOid(char *string, Oid *result, Node *escontext); -static void parseNameAndArgTypes(const char *string, bool allowNone, - List **names, int *nargs, Oid *argtypes); +static bool parseNameAndArgTypes(const char *string, bool allowNone, + List **names, int *nargs, Oid *argtypes, + Node *escontext); /***************************************************************************** @@ -63,12 +66,13 @@ Datum regprocin(PG_FUNCTION_ARGS) { char *pro_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; RegProcedure result; List *names; FuncCandidateList clist; /* Handle "-" or numeric OID */ - if (parseDashOrOid(pro_name_or_oid, &result, fcinfo->context)) + if (parseDashOrOid(pro_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* Else it's a name, possibly schema-qualified */ @@ -84,15 +88,18 @@ regprocin(PG_FUNCTION_ARGS) * 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); + names = stringToQualifiedNameList(pro_name_or_oid, escontext); + if (names == NIL) + PG_RETURN_NULL(); + + clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true); if (clist == NULL) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function \"%s\" does not exist", pro_name_or_oid))); else if (clist->next != NULL) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("more than one function named \"%s\"", pro_name_or_oid))); @@ -113,12 +120,16 @@ to_regproc(PG_FUNCTION_ARGS) char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); List *names; FuncCandidateList clist; + ErrorSaveContext escontext = {T_ErrorSaveContext}; /* * Parse the name into components and see if it matches any pg_proc * entries in the current search path. */ - names = stringToQualifiedNameList(pro_name); + names = stringToQualifiedNameList(pro_name, (Node *) &escontext); + if (names == NIL) + PG_RETURN_NULL(); + clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true); if (clist == NULL || clist->next != NULL) @@ -222,6 +233,7 @@ Datum regprocedurein(PG_FUNCTION_ARGS) { char *pro_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; RegProcedure result; List *names; int nargs; @@ -229,7 +241,7 @@ regprocedurein(PG_FUNCTION_ARGS) FuncCandidateList clist; /* Handle "-" or numeric OID */ - if (parseDashOrOid(pro_name_or_oid, &result, fcinfo->context)) + if (parseDashOrOid(pro_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* The rest of this wouldn't work in bootstrap mode */ @@ -242,10 +254,13 @@ regprocedurein(PG_FUNCTION_ARGS) * 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); + if (!parseNameAndArgTypes(pro_name_or_oid, false, + &names, &nargs, argtypes, + escontext)) + PG_RETURN_NULL(); clist = FuncnameGetCandidates(names, nargs, NIL, false, false, - false, false); + false, true); for (; clist; clist = clist->next) { @@ -254,7 +269,7 @@ regprocedurein(PG_FUNCTION_ARGS) } if (clist == NULL) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("function \"%s\" does not exist", pro_name_or_oid))); @@ -276,13 +291,17 @@ to_regprocedure(PG_FUNCTION_ARGS) int nargs; Oid argtypes[FUNC_MAX_ARGS]; FuncCandidateList clist; + ErrorSaveContext escontext = {T_ErrorSaveContext}; /* * 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); + if (!parseNameAndArgTypes(pro_name, false, + &names, &nargs, argtypes, + (Node *) &escontext)) + PG_RETURN_NULL(); clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true); @@ -484,12 +503,13 @@ Datum regoperin(PG_FUNCTION_ARGS) { char *opr_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Oid result; List *names; FuncCandidateList clist; /* Handle "0" or numeric OID */ - if (parseNumericOid(opr_name_or_oid, &result, fcinfo->context)) + if (parseNumericOid(opr_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* Else it's a name, possibly schema-qualified */ @@ -502,15 +522,18 @@ regoperin(PG_FUNCTION_ARGS) * 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); + names = stringToQualifiedNameList(opr_name_or_oid, escontext); + if (names == NIL) + PG_RETURN_NULL(); + + clist = OpernameGetCandidates(names, '\0', true); if (clist == NULL) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator does not exist: %s", opr_name_or_oid))); else if (clist->next != NULL) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_AMBIGUOUS_FUNCTION), errmsg("more than one operator named %s", opr_name_or_oid))); @@ -531,12 +554,16 @@ to_regoper(PG_FUNCTION_ARGS) char *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); List *names; FuncCandidateList clist; + ErrorSaveContext escontext = {T_ErrorSaveContext}; /* * Parse the name into components and see if it matches any pg_operator * entries in the current search path. */ - names = stringToQualifiedNameList(opr_name); + names = stringToQualifiedNameList(opr_name, (Node *) &escontext); + if (names == NIL) + PG_RETURN_NULL(); + clist = OpernameGetCandidates(names, '\0', true); if (clist == NULL || clist->next != NULL) @@ -646,13 +673,14 @@ Datum regoperatorin(PG_FUNCTION_ARGS) { char *opr_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Oid result; List *names; int nargs; Oid argtypes[FUNC_MAX_ARGS]; /* Handle "0" or numeric OID */ - if (parseNumericOid(opr_name_or_oid, &result, fcinfo->context)) + if (parseNumericOid(opr_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* The rest of this wouldn't work in bootstrap mode */ @@ -665,14 +693,18 @@ regoperatorin(PG_FUNCTION_ARGS) * 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 (!parseNameAndArgTypes(opr_name_or_oid, true, + &names, &nargs, argtypes, + escontext)) + PG_RETURN_NULL(); + if (nargs == 1) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_UNDEFINED_PARAMETER), errmsg("missing argument"), errhint("Use NONE to denote the missing argument of a unary operator."))); if (nargs != 2) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("too many arguments"), errhint("Provide two argument types for operator."))); @@ -680,7 +712,7 @@ regoperatorin(PG_FUNCTION_ARGS) result = OpernameGetOprid(names, argtypes[0], argtypes[1]); if (!OidIsValid(result)) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_UNDEFINED_FUNCTION), errmsg("operator does not exist: %s", opr_name_or_oid))); @@ -700,23 +732,20 @@ to_regoperator(PG_FUNCTION_ARGS) List *names; int nargs; Oid argtypes[FUNC_MAX_ARGS]; + ErrorSaveContext escontext = {T_ErrorSaveContext}; /* * 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 (!parseNameAndArgTypes(opr_name_or_oid, true, + &names, &nargs, argtypes, + (Node *) &escontext)) + PG_RETURN_NULL(); + if (nargs != 2) - ereport(ERROR, - (errcode(ERRCODE_TOO_MANY_ARGUMENTS), - errmsg("too many arguments"), - errhint("Provide two argument types for operator."))); + PG_RETURN_NULL(); result = OpernameGetOprid(names, argtypes[0], argtypes[1]); @@ -903,11 +932,12 @@ Datum regclassin(PG_FUNCTION_ARGS) { char *class_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Oid result; List *names; /* Handle "-" or numeric OID */ - if (parseDashOrOid(class_name_or_oid, &result, fcinfo->context)) + if (parseDashOrOid(class_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* Else it's a name, possibly schema-qualified */ @@ -920,10 +950,18 @@ regclassin(PG_FUNCTION_ARGS) * 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); + names = stringToQualifiedNameList(class_name_or_oid, escontext); + if (names == NIL) + PG_RETURN_NULL(); /* We might not even have permissions on this relation; don't lock it. */ - result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, false); + result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true); + + if (!OidIsValid(result)) + ereturn(escontext, (Datum) 0, + (errcode(ERRCODE_UNDEFINED_TABLE), + errmsg("relation \"%s\" does not exist", + NameListToString(names)))); PG_RETURN_OID(result); } @@ -939,12 +977,15 @@ to_regclass(PG_FUNCTION_ARGS) char *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); Oid result; List *names; + ErrorSaveContext escontext = {T_ErrorSaveContext}; /* * Parse the name into components and see if it matches any pg_class * entries in the current search path. */ - names = stringToQualifiedNameList(class_name); + names = stringToQualifiedNameList(class_name, (Node *) &escontext); + if (names == NIL) + PG_RETURN_NULL(); /* We might not even have permissions on this relation; don't lock it. */ result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true); @@ -1045,11 +1086,12 @@ Datum regcollationin(PG_FUNCTION_ARGS) { char *collation_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Oid result; List *names; /* Handle "-" or numeric OID */ - if (parseDashOrOid(collation_name_or_oid, &result, fcinfo->context)) + if (parseDashOrOid(collation_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* Else it's a name, possibly schema-qualified */ @@ -1062,9 +1104,17 @@ regcollationin(PG_FUNCTION_ARGS) * 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); + names = stringToQualifiedNameList(collation_name_or_oid, escontext); + if (names == NIL) + PG_RETURN_NULL(); + + result = get_collation_oid(names, true); - result = get_collation_oid(names, false); + if (!OidIsValid(result)) + ereturn(escontext, (Datum) 0, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("collation \"%s\" for encoding \"%s\" does not exist", + NameListToString(names), GetDatabaseEncodingName()))); PG_RETURN_OID(result); } @@ -1080,12 +1130,15 @@ to_regcollation(PG_FUNCTION_ARGS) char *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); Oid result; List *names; + ErrorSaveContext escontext = {T_ErrorSaveContext}; /* * Parse the name into components and see if it matches any pg_collation * entries in the current search path. */ - names = stringToQualifiedNameList(collation_name); + names = stringToQualifiedNameList(collation_name, (Node *) &escontext); + if (names == NIL) + PG_RETURN_NULL(); result = get_collation_oid(names, true); @@ -1192,11 +1245,12 @@ Datum regtypein(PG_FUNCTION_ARGS) { char *typ_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Oid result; int32 typmod; /* Handle "-" or numeric OID */ - if (parseDashOrOid(typ_name_or_oid, &result, fcinfo->context)) + if (parseDashOrOid(typ_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* Else it's a type name, possibly schema-qualified or decorated */ @@ -1207,9 +1261,10 @@ regtypein(PG_FUNCTION_ARGS) /* * Normal case: invoke the full parser to deal with special cases such as - * array syntax. + * array syntax. We don't need to check for parseTypeString failure, + * since we'll just return anyway. */ - parseTypeString(typ_name_or_oid, &result, &typmod, false); + (void) parseTypeString(typ_name_or_oid, &result, &typmod, escontext); PG_RETURN_OID(result); } @@ -1225,13 +1280,12 @@ to_regtype(PG_FUNCTION_ARGS) char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); Oid result; int32 typmod; + ErrorSaveContext escontext = {T_ErrorSaveContext}; /* * Invoke the full parser to deal with special cases such as array syntax. */ - parseTypeString(typ_name, &result, &typmod, true); - - if (OidIsValid(result)) + if (parseTypeString(typ_name, &result, &typmod, (Node *) &escontext)) PG_RETURN_OID(result); else PG_RETURN_NULL(); @@ -1318,11 +1372,12 @@ Datum regconfigin(PG_FUNCTION_ARGS) { char *cfg_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Oid result; List *names; /* Handle "-" or numeric OID */ - if (parseDashOrOid(cfg_name_or_oid, &result, fcinfo->context)) + if (parseDashOrOid(cfg_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* The rest of this wouldn't work in bootstrap mode */ @@ -1333,9 +1388,17 @@ regconfigin(PG_FUNCTION_ARGS) * 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); + names = stringToQualifiedNameList(cfg_name_or_oid, escontext); + if (names == NIL) + PG_RETURN_NULL(); - result = get_ts_config_oid(names, false); + result = get_ts_config_oid(names, true); + + if (!OidIsValid(result)) + ereturn(escontext, (Datum) 0, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("text search configuration \"%s\" does not exist", + NameListToString(names)))); PG_RETURN_OID(result); } @@ -1419,11 +1482,12 @@ Datum regdictionaryin(PG_FUNCTION_ARGS) { char *dict_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Oid result; List *names; /* Handle "-" or numeric OID */ - if (parseDashOrOid(dict_name_or_oid, &result, fcinfo->context)) + if (parseDashOrOid(dict_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* The rest of this wouldn't work in bootstrap mode */ @@ -1434,9 +1498,17 @@ regdictionaryin(PG_FUNCTION_ARGS) * 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); + names = stringToQualifiedNameList(dict_name_or_oid, escontext); + if (names == NIL) + PG_RETURN_NULL(); + + result = get_ts_dict_oid(names, true); - result = get_ts_dict_oid(names, false); + if (!OidIsValid(result)) + ereturn(escontext, (Datum) 0, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("text search dictionary \"%s\" does not exist", + NameListToString(names)))); PG_RETURN_OID(result); } @@ -1520,11 +1592,12 @@ Datum regrolein(PG_FUNCTION_ARGS) { char *role_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Oid result; List *names; /* Handle "-" or numeric OID */ - if (parseDashOrOid(role_name_or_oid, &result, fcinfo->context)) + if (parseDashOrOid(role_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* The rest of this wouldn't work in bootstrap mode */ @@ -1532,14 +1605,22 @@ regrolein(PG_FUNCTION_ARGS) 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); + names = stringToQualifiedNameList(role_name_or_oid, escontext); + if (names == NIL) + PG_RETURN_NULL(); if (list_length(names) != 1) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); - result = get_role_oid(strVal(linitial(names)), false); + result = get_role_oid(strVal(linitial(names)), true); + + if (!OidIsValid(result)) + ereturn(escontext, (Datum) 0, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("role \"%s\" does not exist", + strVal(linitial(names))))); PG_RETURN_OID(result); } @@ -1555,13 +1636,14 @@ to_regrole(PG_FUNCTION_ARGS) char *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); Oid result; List *names; + ErrorSaveContext escontext = {T_ErrorSaveContext}; - names = stringToQualifiedNameList(role_name); + names = stringToQualifiedNameList(role_name, (Node *) &escontext); + if (names == NIL) + PG_RETURN_NULL(); if (list_length(names) != 1) - ereport(ERROR, - (errcode(ERRCODE_INVALID_NAME), - errmsg("invalid name syntax"))); + PG_RETURN_NULL(); result = get_role_oid(strVal(linitial(names)), true); @@ -1635,11 +1717,12 @@ Datum regnamespacein(PG_FUNCTION_ARGS) { char *nsp_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; Oid result; List *names; /* Handle "-" or numeric OID */ - if (parseDashOrOid(nsp_name_or_oid, &result, fcinfo->context)) + if (parseDashOrOid(nsp_name_or_oid, &result, escontext)) PG_RETURN_OID(result); /* The rest of this wouldn't work in bootstrap mode */ @@ -1647,14 +1730,22 @@ regnamespacein(PG_FUNCTION_ARGS) 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); + names = stringToQualifiedNameList(nsp_name_or_oid, escontext); + if (names == NIL) + PG_RETURN_NULL(); if (list_length(names) != 1) - ereport(ERROR, + ereturn(escontext, (Datum) 0, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); - result = get_namespace_oid(strVal(linitial(names)), false); + result = get_namespace_oid(strVal(linitial(names)), true); + + if (!OidIsValid(result)) + ereturn(escontext, (Datum) 0, + (errcode(ERRCODE_UNDEFINED_SCHEMA), + errmsg("schema \"%s\" does not exist", + strVal(linitial(names))))); PG_RETURN_OID(result); } @@ -1670,13 +1761,14 @@ to_regnamespace(PG_FUNCTION_ARGS) char *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); Oid result; List *names; + ErrorSaveContext escontext = {T_ErrorSaveContext}; - names = stringToQualifiedNameList(nsp_name); + names = stringToQualifiedNameList(nsp_name, (Node *) &escontext); + if (names == NIL) + PG_RETURN_NULL(); if (list_length(names) != 1) - ereport(ERROR, - (errcode(ERRCODE_INVALID_NAME), - errmsg("invalid name syntax"))); + PG_RETURN_NULL(); result = get_namespace_oid(strVal(linitial(names)), true); @@ -1763,9 +1855,13 @@ text_regclass(PG_FUNCTION_ARGS) /* * Given a C string, parse it into a qualified-name list. + * + * If escontext is an ErrorSaveContext node, invalid input will be + * reported there instead of being thrown, and we return NIL. + * (NIL is not possible as a success return, since empty-input is an error.) */ List * -stringToQualifiedNameList(const char *string) +stringToQualifiedNameList(const char *string, Node *escontext) { char *rawname; List *result = NIL; @@ -1776,12 +1872,12 @@ stringToQualifiedNameList(const char *string) rawname = pstrdup(string); if (!SplitIdentifierString(rawname, '.', &namelist)) - ereport(ERROR, + ereturn(escontext, NIL, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); if (namelist == NIL) - ereport(ERROR, + ereturn(escontext, NIL, (errcode(ERRCODE_INVALID_NAME), errmsg("invalid name syntax"))); @@ -1858,10 +1954,14 @@ parseDashOrOid(char *string, Oid *result, Node *escontext) * * If allowNone is true, accept "NONE" and return it as InvalidOid (this is * for unary operators). + * + * Returns true on success, false on failure (the latter only possible + * if escontext is an ErrorSaveContext node). */ -static void +static bool parseNameAndArgTypes(const char *string, bool allowNone, List **names, - int *nargs, Oid *argtypes) + int *nargs, Oid *argtypes, + Node *escontext) { char *rawname; char *ptr; @@ -1886,13 +1986,15 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, break; } if (*ptr == '\0') - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("expected a left parenthesis"))); /* Separate the name and parse it into a list */ *ptr++ = '\0'; - *names = stringToQualifiedNameList(rawname); + *names = stringToQualifiedNameList(rawname, escontext); + if (*names == NIL) + return false; /* Check for the trailing right parenthesis and remove it */ ptr2 = ptr + strlen(ptr); @@ -1902,7 +2004,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, break; } if (*ptr2 != ')') - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("expected a right parenthesis"))); @@ -1921,7 +2023,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, { /* End of string. Okay unless we had a comma before. */ if (had_comma) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("expected a type name"))); break; @@ -1953,7 +2055,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, } } if (in_quote || paren_count != 0) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), errmsg("improper type name"))); @@ -1985,10 +2087,11 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, else { /* Use full parser to resolve the type name */ - parseTypeString(typename, &typeid, &typmod, false); + if (!parseTypeString(typename, &typeid, &typmod, escontext)) + return false; } if (*nargs >= FUNC_MAX_ARGS) - ereport(ERROR, + ereturn(escontext, false, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("too many arguments"))); @@ -1997,4 +2100,6 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names, } pfree(rawname); + + return true; } |