1
0
mirror of https://github.com/postgres/postgres.git synced 2025-05-02 11:44:50 +03:00

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
This commit is contained in:
Tom Lane 2022-12-27 12:26:01 -05:00
parent 78212f2101
commit 858e776c84
16 changed files with 403 additions and 128 deletions

View File

@ -2182,7 +2182,7 @@ pg_get_object_address(PG_FUNCTION_ARGS)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name or argument lists may not contain nulls"))); errmsg("name or argument lists may not contain nulls")));
typename = typeStringToTypeName(TextDatumGetCString(elems[0])); typename = typeStringToTypeName(TextDatumGetCString(elems[0]), NULL);
} }
else if (type == OBJECT_LARGEOBJECT) else if (type == OBJECT_LARGEOBJECT)
{ {
@ -2238,7 +2238,8 @@ pg_get_object_address(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("name or argument lists may not contain nulls"))); errmsg("name or argument lists may not contain nulls")));
args = lappend(args, args = lappend(args,
typeStringToTypeName(TextDatumGetCString(elems[i]))); typeStringToTypeName(TextDatumGetCString(elems[i]),
NULL));
} }
} }
else else

View File

@ -727,10 +727,15 @@ pts_error_callback(void *arg)
* Given a string that is supposed to be a SQL-compatible type declaration, * Given a string that is supposed to be a SQL-compatible type declaration,
* such as "int4" or "integer" or "character varying(32)", parse * such as "int4" or "integer" or "character varying(32)", parse
* the string and return the result as a TypeName. * the string and return the result as a TypeName.
* If the string cannot be parsed as a type, an error is raised. *
* If the string cannot be parsed as a type, an error is raised,
* unless escontext is an ErrorSaveContext node, in which case we may
* fill that and return NULL. But note that the ErrorSaveContext option
* is mostly aspirational at present: errors detected by the main
* grammar, rather than here, will still be thrown.
*/ */
TypeName * TypeName *
typeStringToTypeName(const char *str) typeStringToTypeName(const char *str, Node *escontext)
{ {
List *raw_parsetree_list; List *raw_parsetree_list;
TypeName *typeName; TypeName *typeName;
@ -763,49 +768,54 @@ typeStringToTypeName(const char *str)
return typeName; return typeName;
fail: fail:
ereport(ERROR, ereturn(escontext, NULL,
(errcode(ERRCODE_SYNTAX_ERROR), (errcode(ERRCODE_SYNTAX_ERROR),
errmsg("invalid type name \"%s\"", str))); errmsg("invalid type name \"%s\"", str)));
return NULL; /* keep compiler quiet */
} }
/* /*
* Given a string that is supposed to be a SQL-compatible type declaration, * Given a string that is supposed to be a SQL-compatible type declaration,
* such as "int4" or "integer" or "character varying(32)", parse * such as "int4" or "integer" or "character varying(32)", parse
* the string and convert it to a type OID and type modifier. * the string and convert it to a type OID and type modifier.
* If missing_ok is true, InvalidOid is returned rather than raising an error *
* when the type name is not found. * If escontext is an ErrorSaveContext node, then errors are reported by
* filling escontext and returning false, instead of throwing them.
*/ */
void bool
parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok) parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
Node *escontext)
{ {
TypeName *typeName; TypeName *typeName;
Type tup; Type tup;
typeName = typeStringToTypeName(str); typeName = typeStringToTypeName(str, escontext);
if (typeName == NULL)
return false;
tup = LookupTypeName(NULL, typeName, typmod_p, missing_ok); tup = LookupTypeName(NULL, typeName, typmod_p,
(escontext && IsA(escontext, ErrorSaveContext)));
if (tup == NULL) if (tup == NULL)
{ {
if (!missing_ok) ereturn(escontext, false,
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type \"%s\" does not exist", errmsg("type \"%s\" does not exist",
TypeNameToString(typeName)), TypeNameToString(typeName))));
parser_errposition(NULL, typeName->location)));
*typeid_p = InvalidOid;
} }
else else
{ {
Form_pg_type typ = (Form_pg_type) GETSTRUCT(tup); Form_pg_type typ = (Form_pg_type) GETSTRUCT(tup);
if (!typ->typisdefined) if (!typ->typisdefined)
ereport(ERROR, {
ReleaseSysCache(tup);
ereturn(escontext, false,
(errcode(ERRCODE_UNDEFINED_OBJECT), (errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type \"%s\" is only a shell", errmsg("type \"%s\" is only a shell",
TypeNameToString(typeName)), TypeNameToString(typeName))));
parser_errposition(NULL, typeName->location))); }
*typeid_p = typ->oid; *typeid_p = typ->oid;
ReleaseSysCache(tup); ReleaseSysCache(tup);
} }
return true;
} }

View File

@ -599,6 +599,7 @@ thesaurus_init(PG_FUNCTION_ARGS)
DictThesaurus *d; DictThesaurus *d;
char *subdictname = NULL; char *subdictname = NULL;
bool fileloaded = false; bool fileloaded = false;
List *namelist;
ListCell *l; ListCell *l;
d = (DictThesaurus *) palloc0(sizeof(DictThesaurus)); d = (DictThesaurus *) palloc0(sizeof(DictThesaurus));
@ -642,7 +643,8 @@ thesaurus_init(PG_FUNCTION_ARGS)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE), (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("missing Dictionary parameter"))); errmsg("missing Dictionary parameter")));
d->subdictOid = get_ts_dict_oid(stringToQualifiedNameList(subdictname), false); namelist = stringToQualifiedNameList(subdictname, NULL);
d->subdictOid = get_ts_dict_oid(namelist, false);
d->subdict = lookup_ts_dictionary_cache(d->subdictOid); d->subdict = lookup_ts_dictionary_cache(d->subdictOid);
compileTheLexeme(d); compileTheLexeme(d);

View File

@ -724,7 +724,7 @@ pg_input_is_valid_common(FunctionCallInfo fcinfo,
Oid typoid; Oid typoid;
/* Parse type-name argument to obtain type OID and encoded typmod. */ /* Parse type-name argument to obtain type OID and encoded typmod. */
parseTypeString(typnamestr, &typoid, &my_extra->typmod, false); (void) parseTypeString(typnamestr, &typoid, &my_extra->typmod, NULL);
/* Update type-specific info if typoid changed. */ /* Update type-specific info if typoid changed. */
if (my_extra->typoid != typoid) if (my_extra->typoid != typoid)

View File

@ -31,7 +31,9 @@
#include "catalog/pg_ts_dict.h" #include "catalog/pg_ts_dict.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/miscnodes.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "parser/scansup.h" #include "parser/scansup.h"
#include "utils/acl.h" #include "utils/acl.h"
@ -43,8 +45,9 @@
static bool parseNumericOid(char *string, Oid *result, Node *escontext); static bool parseNumericOid(char *string, Oid *result, Node *escontext);
static bool parseDashOrOid(char *string, Oid *result, Node *escontext); static bool parseDashOrOid(char *string, Oid *result, Node *escontext);
static void parseNameAndArgTypes(const char *string, bool allowNone, static bool parseNameAndArgTypes(const char *string, bool allowNone,
List **names, int *nargs, Oid *argtypes); List **names, int *nargs, Oid *argtypes,
Node *escontext);
/***************************************************************************** /*****************************************************************************
@ -63,12 +66,13 @@ Datum
regprocin(PG_FUNCTION_ARGS) regprocin(PG_FUNCTION_ARGS)
{ {
char *pro_name_or_oid = PG_GETARG_CSTRING(0); char *pro_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
RegProcedure result; RegProcedure result;
List *names; List *names;
FuncCandidateList clist; FuncCandidateList clist;
/* Handle "-" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* Else it's a name, possibly schema-qualified */ /* 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 * Normal case: parse the name into components and see if it matches any
* pg_proc entries in the current search path. * pg_proc entries in the current search path.
*/ */
names = stringToQualifiedNameList(pro_name_or_oid); names = stringToQualifiedNameList(pro_name_or_oid, escontext);
clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, false); if (names == NIL)
PG_RETURN_NULL();
clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true);
if (clist == NULL) if (clist == NULL)
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function \"%s\" does not exist", pro_name_or_oid))); errmsg("function \"%s\" does not exist", pro_name_or_oid)));
else if (clist->next != NULL) else if (clist->next != NULL)
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION), (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("more than one function named \"%s\"", errmsg("more than one function named \"%s\"",
pro_name_or_oid))); pro_name_or_oid)));
@ -113,12 +120,16 @@ to_regproc(PG_FUNCTION_ARGS)
char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *pro_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
List *names; List *names;
FuncCandidateList clist; FuncCandidateList clist;
ErrorSaveContext escontext = {T_ErrorSaveContext};
/* /*
* Parse the name into components and see if it matches any pg_proc * Parse the name into components and see if it matches any pg_proc
* entries in the current search path. * 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); clist = FuncnameGetCandidates(names, -1, NIL, false, false, false, true);
if (clist == NULL || clist->next != NULL) if (clist == NULL || clist->next != NULL)
@ -222,6 +233,7 @@ Datum
regprocedurein(PG_FUNCTION_ARGS) regprocedurein(PG_FUNCTION_ARGS)
{ {
char *pro_name_or_oid = PG_GETARG_CSTRING(0); char *pro_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
RegProcedure result; RegProcedure result;
List *names; List *names;
int nargs; int nargs;
@ -229,7 +241,7 @@ regprocedurein(PG_FUNCTION_ARGS)
FuncCandidateList clist; FuncCandidateList clist;
/* Handle "-" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* The rest of this wouldn't work in bootstrap mode */ /* 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 * which one exactly matches the given argument types. (There will not be
* more than one match.) * 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, clist = FuncnameGetCandidates(names, nargs, NIL, false, false,
false, false); false, true);
for (; clist; clist = clist->next) for (; clist; clist = clist->next)
{ {
@ -254,7 +269,7 @@ regprocedurein(PG_FUNCTION_ARGS)
} }
if (clist == NULL) if (clist == NULL)
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("function \"%s\" does not exist", pro_name_or_oid))); errmsg("function \"%s\" does not exist", pro_name_or_oid)));
@ -276,13 +291,17 @@ to_regprocedure(PG_FUNCTION_ARGS)
int nargs; int nargs;
Oid argtypes[FUNC_MAX_ARGS]; Oid argtypes[FUNC_MAX_ARGS];
FuncCandidateList clist; FuncCandidateList clist;
ErrorSaveContext escontext = {T_ErrorSaveContext};
/* /*
* Parse the name and arguments, look up potential matches in the current * Parse the name and arguments, look up potential matches in the current
* namespace search list, and scan to see which one exactly matches the * namespace search list, and scan to see which one exactly matches the
* given argument types. (There will not be more than one match.) * 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); clist = FuncnameGetCandidates(names, nargs, NIL, false, false, false, true);
@ -484,12 +503,13 @@ Datum
regoperin(PG_FUNCTION_ARGS) regoperin(PG_FUNCTION_ARGS)
{ {
char *opr_name_or_oid = PG_GETARG_CSTRING(0); char *opr_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
Oid result; Oid result;
List *names; List *names;
FuncCandidateList clist; FuncCandidateList clist;
/* Handle "0" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* Else it's a name, possibly schema-qualified */ /* 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 * Normal case: parse the name into components and see if it matches any
* pg_operator entries in the current search path. * pg_operator entries in the current search path.
*/ */
names = stringToQualifiedNameList(opr_name_or_oid); names = stringToQualifiedNameList(opr_name_or_oid, escontext);
clist = OpernameGetCandidates(names, '\0', false); if (names == NIL)
PG_RETURN_NULL();
clist = OpernameGetCandidates(names, '\0', true);
if (clist == NULL) if (clist == NULL)
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator does not exist: %s", opr_name_or_oid))); errmsg("operator does not exist: %s", opr_name_or_oid)));
else if (clist->next != NULL) else if (clist->next != NULL)
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION), (errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("more than one operator named %s", errmsg("more than one operator named %s",
opr_name_or_oid))); opr_name_or_oid)));
@ -531,12 +554,16 @@ to_regoper(PG_FUNCTION_ARGS)
char *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *opr_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
List *names; List *names;
FuncCandidateList clist; FuncCandidateList clist;
ErrorSaveContext escontext = {T_ErrorSaveContext};
/* /*
* Parse the name into components and see if it matches any pg_operator * Parse the name into components and see if it matches any pg_operator
* entries in the current search path. * 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); clist = OpernameGetCandidates(names, '\0', true);
if (clist == NULL || clist->next != NULL) if (clist == NULL || clist->next != NULL)
@ -646,13 +673,14 @@ Datum
regoperatorin(PG_FUNCTION_ARGS) regoperatorin(PG_FUNCTION_ARGS)
{ {
char *opr_name_or_oid = PG_GETARG_CSTRING(0); char *opr_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
Oid result; Oid result;
List *names; List *names;
int nargs; int nargs;
Oid argtypes[FUNC_MAX_ARGS]; Oid argtypes[FUNC_MAX_ARGS];
/* Handle "0" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* The rest of this wouldn't work in bootstrap mode */ /* 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 * which one exactly matches the given argument types. (There will not be
* more than one match.) * 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) if (nargs == 1)
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_UNDEFINED_PARAMETER), (errcode(ERRCODE_UNDEFINED_PARAMETER),
errmsg("missing argument"), errmsg("missing argument"),
errhint("Use NONE to denote the missing argument of a unary operator."))); errhint("Use NONE to denote the missing argument of a unary operator.")));
if (nargs != 2) if (nargs != 2)
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS), (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
errmsg("too many arguments"), errmsg("too many arguments"),
errhint("Provide two argument types for operator."))); errhint("Provide two argument types for operator.")));
@ -680,7 +712,7 @@ regoperatorin(PG_FUNCTION_ARGS)
result = OpernameGetOprid(names, argtypes[0], argtypes[1]); result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
if (!OidIsValid(result)) if (!OidIsValid(result))
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_UNDEFINED_FUNCTION), (errcode(ERRCODE_UNDEFINED_FUNCTION),
errmsg("operator does not exist: %s", opr_name_or_oid))); errmsg("operator does not exist: %s", opr_name_or_oid)));
@ -700,23 +732,20 @@ to_regoperator(PG_FUNCTION_ARGS)
List *names; List *names;
int nargs; int nargs;
Oid argtypes[FUNC_MAX_ARGS]; Oid argtypes[FUNC_MAX_ARGS];
ErrorSaveContext escontext = {T_ErrorSaveContext};
/* /*
* Parse the name and arguments, look up potential matches in the current * Parse the name and arguments, look up potential matches in the current
* namespace search list, and scan to see which one exactly matches the * namespace search list, and scan to see which one exactly matches the
* given argument types. (There will not be more than one match.) * 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,
if (nargs == 1) &names, &nargs, argtypes,
ereport(ERROR, (Node *) &escontext))
(errcode(ERRCODE_UNDEFINED_PARAMETER), PG_RETURN_NULL();
errmsg("missing argument"),
errhint("Use NONE to denote the missing argument of a unary operator.")));
if (nargs != 2) if (nargs != 2)
ereport(ERROR, PG_RETURN_NULL();
(errcode(ERRCODE_TOO_MANY_ARGUMENTS),
errmsg("too many arguments"),
errhint("Provide two argument types for operator.")));
result = OpernameGetOprid(names, argtypes[0], argtypes[1]); result = OpernameGetOprid(names, argtypes[0], argtypes[1]);
@ -903,11 +932,12 @@ Datum
regclassin(PG_FUNCTION_ARGS) regclassin(PG_FUNCTION_ARGS)
{ {
char *class_name_or_oid = PG_GETARG_CSTRING(0); char *class_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
Oid result; Oid result;
List *names; List *names;
/* Handle "-" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* Else it's a name, possibly schema-qualified */ /* 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 * Normal case: parse the name into components and see if it matches any
* pg_class entries in the current search path. * 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. */ /* 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); PG_RETURN_OID(result);
} }
@ -939,12 +977,15 @@ to_regclass(PG_FUNCTION_ARGS)
char *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *class_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
Oid result; Oid result;
List *names; List *names;
ErrorSaveContext escontext = {T_ErrorSaveContext};
/* /*
* Parse the name into components and see if it matches any pg_class * Parse the name into components and see if it matches any pg_class
* entries in the current search path. * 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. */ /* We might not even have permissions on this relation; don't lock it. */
result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true); result = RangeVarGetRelid(makeRangeVarFromNameList(names), NoLock, true);
@ -1045,11 +1086,12 @@ Datum
regcollationin(PG_FUNCTION_ARGS) regcollationin(PG_FUNCTION_ARGS)
{ {
char *collation_name_or_oid = PG_GETARG_CSTRING(0); char *collation_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
Oid result; Oid result;
List *names; List *names;
/* Handle "-" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* Else it's a name, possibly schema-qualified */ /* 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 * Normal case: parse the name into components and see if it matches any
* pg_collation entries in the current search path. * 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, false); result = get_collation_oid(names, true);
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); PG_RETURN_OID(result);
} }
@ -1080,12 +1130,15 @@ to_regcollation(PG_FUNCTION_ARGS)
char *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
Oid result; Oid result;
List *names; List *names;
ErrorSaveContext escontext = {T_ErrorSaveContext};
/* /*
* Parse the name into components and see if it matches any pg_collation * Parse the name into components and see if it matches any pg_collation
* entries in the current search path. * 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); result = get_collation_oid(names, true);
@ -1192,11 +1245,12 @@ Datum
regtypein(PG_FUNCTION_ARGS) regtypein(PG_FUNCTION_ARGS)
{ {
char *typ_name_or_oid = PG_GETARG_CSTRING(0); char *typ_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
Oid result; Oid result;
int32 typmod; int32 typmod;
/* Handle "-" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* Else it's a type name, possibly schema-qualified or decorated */ /* 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 * 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); PG_RETURN_OID(result);
} }
@ -1225,13 +1280,12 @@ to_regtype(PG_FUNCTION_ARGS)
char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *typ_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
Oid result; Oid result;
int32 typmod; int32 typmod;
ErrorSaveContext escontext = {T_ErrorSaveContext};
/* /*
* Invoke the full parser to deal with special cases such as array syntax. * Invoke the full parser to deal with special cases such as array syntax.
*/ */
parseTypeString(typ_name, &result, &typmod, true); if (parseTypeString(typ_name, &result, &typmod, (Node *) &escontext))
if (OidIsValid(result))
PG_RETURN_OID(result); PG_RETURN_OID(result);
else else
PG_RETURN_NULL(); PG_RETURN_NULL();
@ -1318,11 +1372,12 @@ Datum
regconfigin(PG_FUNCTION_ARGS) regconfigin(PG_FUNCTION_ARGS)
{ {
char *cfg_name_or_oid = PG_GETARG_CSTRING(0); char *cfg_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
Oid result; Oid result;
List *names; List *names;
/* Handle "-" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* The rest of this wouldn't work in bootstrap mode */ /* 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 * Normal case: parse the name into components and see if it matches any
* pg_ts_config entries in the current search path. * 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); PG_RETURN_OID(result);
} }
@ -1419,11 +1482,12 @@ Datum
regdictionaryin(PG_FUNCTION_ARGS) regdictionaryin(PG_FUNCTION_ARGS)
{ {
char *dict_name_or_oid = PG_GETARG_CSTRING(0); char *dict_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
Oid result; Oid result;
List *names; List *names;
/* Handle "-" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* The rest of this wouldn't work in bootstrap mode */ /* 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 * Normal case: parse the name into components and see if it matches any
* pg_ts_dict entries in the current search path. * 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, false); result = get_ts_dict_oid(names, true);
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); PG_RETURN_OID(result);
} }
@ -1520,11 +1592,12 @@ Datum
regrolein(PG_FUNCTION_ARGS) regrolein(PG_FUNCTION_ARGS)
{ {
char *role_name_or_oid = PG_GETARG_CSTRING(0); char *role_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
Oid result; Oid result;
List *names; List *names;
/* Handle "-" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* The rest of this wouldn't work in bootstrap mode */ /* 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"); elog(ERROR, "regrole values must be OIDs in bootstrap mode");
/* Normal case: see if the name matches any pg_authid entry. */ /* 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) if (list_length(names) != 1)
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_NAME), (errcode(ERRCODE_INVALID_NAME),
errmsg("invalid name syntax"))); 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); PG_RETURN_OID(result);
} }
@ -1555,13 +1636,14 @@ to_regrole(PG_FUNCTION_ARGS)
char *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *role_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
Oid result; Oid result;
List *names; 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) if (list_length(names) != 1)
ereport(ERROR, PG_RETURN_NULL();
(errcode(ERRCODE_INVALID_NAME),
errmsg("invalid name syntax")));
result = get_role_oid(strVal(linitial(names)), true); result = get_role_oid(strVal(linitial(names)), true);
@ -1635,11 +1717,12 @@ Datum
regnamespacein(PG_FUNCTION_ARGS) regnamespacein(PG_FUNCTION_ARGS)
{ {
char *nsp_name_or_oid = PG_GETARG_CSTRING(0); char *nsp_name_or_oid = PG_GETARG_CSTRING(0);
Node *escontext = fcinfo->context;
Oid result; Oid result;
List *names; List *names;
/* Handle "-" or numeric OID */ /* 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); PG_RETURN_OID(result);
/* The rest of this wouldn't work in bootstrap mode */ /* 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"); elog(ERROR, "regnamespace values must be OIDs in bootstrap mode");
/* Normal case: see if the name matches any pg_namespace entry. */ /* 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) if (list_length(names) != 1)
ereport(ERROR, ereturn(escontext, (Datum) 0,
(errcode(ERRCODE_INVALID_NAME), (errcode(ERRCODE_INVALID_NAME),
errmsg("invalid name syntax"))); 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); PG_RETURN_OID(result);
} }
@ -1670,13 +1761,14 @@ to_regnamespace(PG_FUNCTION_ARGS)
char *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); char *nsp_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
Oid result; Oid result;
List *names; 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) if (list_length(names) != 1)
ereport(ERROR, PG_RETURN_NULL();
(errcode(ERRCODE_INVALID_NAME),
errmsg("invalid name syntax")));
result = get_namespace_oid(strVal(linitial(names)), true); 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. * 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 * List *
stringToQualifiedNameList(const char *string) stringToQualifiedNameList(const char *string, Node *escontext)
{ {
char *rawname; char *rawname;
List *result = NIL; List *result = NIL;
@ -1776,12 +1872,12 @@ stringToQualifiedNameList(const char *string)
rawname = pstrdup(string); rawname = pstrdup(string);
if (!SplitIdentifierString(rawname, '.', &namelist)) if (!SplitIdentifierString(rawname, '.', &namelist))
ereport(ERROR, ereturn(escontext, NIL,
(errcode(ERRCODE_INVALID_NAME), (errcode(ERRCODE_INVALID_NAME),
errmsg("invalid name syntax"))); errmsg("invalid name syntax")));
if (namelist == NIL) if (namelist == NIL)
ereport(ERROR, ereturn(escontext, NIL,
(errcode(ERRCODE_INVALID_NAME), (errcode(ERRCODE_INVALID_NAME),
errmsg("invalid name syntax"))); 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 * If allowNone is true, accept "NONE" and return it as InvalidOid (this is
* for unary operators). * 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, parseNameAndArgTypes(const char *string, bool allowNone, List **names,
int *nargs, Oid *argtypes) int *nargs, Oid *argtypes,
Node *escontext)
{ {
char *rawname; char *rawname;
char *ptr; char *ptr;
@ -1886,13 +1986,15 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names,
break; break;
} }
if (*ptr == '\0') if (*ptr == '\0')
ereport(ERROR, ereturn(escontext, false,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected a left parenthesis"))); errmsg("expected a left parenthesis")));
/* Separate the name and parse it into a list */ /* Separate the name and parse it into a list */
*ptr++ = '\0'; *ptr++ = '\0';
*names = stringToQualifiedNameList(rawname); *names = stringToQualifiedNameList(rawname, escontext);
if (*names == NIL)
return false;
/* Check for the trailing right parenthesis and remove it */ /* Check for the trailing right parenthesis and remove it */
ptr2 = ptr + strlen(ptr); ptr2 = ptr + strlen(ptr);
@ -1902,7 +2004,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names,
break; break;
} }
if (*ptr2 != ')') if (*ptr2 != ')')
ereport(ERROR, ereturn(escontext, false,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected a right parenthesis"))); 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. */ /* End of string. Okay unless we had a comma before. */
if (had_comma) if (had_comma)
ereport(ERROR, ereturn(escontext, false,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("expected a type name"))); errmsg("expected a type name")));
break; break;
@ -1953,7 +2055,7 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names,
} }
} }
if (in_quote || paren_count != 0) if (in_quote || paren_count != 0)
ereport(ERROR, ereturn(escontext, false,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION), (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("improper type name"))); errmsg("improper type name")));
@ -1985,10 +2087,11 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names,
else else
{ {
/* Use full parser to resolve the type name */ /* 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) if (*nargs >= FUNC_MAX_ARGS)
ereport(ERROR, ereturn(escontext, false,
(errcode(ERRCODE_TOO_MANY_ARGUMENTS), (errcode(ERRCODE_TOO_MANY_ARGUMENTS),
errmsg("too many arguments"))); errmsg("too many arguments")));
@ -1997,4 +2100,6 @@ parseNameAndArgTypes(const char *string, bool allowNone, List **names,
} }
pfree(rawname); pfree(rawname);
return true;
} }

View File

@ -2652,7 +2652,7 @@ tsvector_update_trigger(PG_FUNCTION_ARGS, bool config_column)
{ {
List *names; List *names;
names = stringToQualifiedNameList(trigger->tgargs[1]); names = stringToQualifiedNameList(trigger->tgargs[1], NULL);
/* require a schema so that results are not search path dependent */ /* require a schema so that results are not search path dependent */
if (list_length(names) < 2) if (list_length(names) < 2)
ereport(ERROR, ereport(ERROR,

View File

@ -38,6 +38,7 @@
#include "catalog/pg_ts_template.h" #include "catalog/pg_ts_template.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/miscnodes.h"
#include "tsearch/ts_cache.h" #include "tsearch/ts_cache.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/catcache.h" #include "utils/catcache.h"
@ -556,6 +557,8 @@ lookup_ts_config_cache(Oid cfgId)
Oid Oid
getTSCurrentConfig(bool emitError) getTSCurrentConfig(bool emitError)
{ {
List *namelist;
/* if we have a cached value, return it */ /* if we have a cached value, return it */
if (OidIsValid(TSCurrentConfigCache)) if (OidIsValid(TSCurrentConfigCache))
return TSCurrentConfigCache; return TSCurrentConfigCache;
@ -576,9 +579,22 @@ getTSCurrentConfig(bool emitError)
} }
/* Look up the config */ /* Look up the config */
TSCurrentConfigCache = if (emitError)
get_ts_config_oid(stringToQualifiedNameList(TSCurrentConfig), {
!emitError); namelist = stringToQualifiedNameList(TSCurrentConfig, NULL);
TSCurrentConfigCache = get_ts_config_oid(namelist, false);
}
else
{
ErrorSaveContext escontext = {T_ErrorSaveContext};
namelist = stringToQualifiedNameList(TSCurrentConfig,
(Node *) &escontext);
if (namelist != NIL)
TSCurrentConfigCache = get_ts_config_oid(namelist, true);
else
TSCurrentConfigCache = InvalidOid; /* bad name list syntax */
}
return TSCurrentConfigCache; return TSCurrentConfigCache;
} }
@ -594,12 +610,19 @@ check_default_text_search_config(char **newval, void **extra, GucSource source)
*/ */
if (IsTransactionState() && MyDatabaseId != InvalidOid) if (IsTransactionState() && MyDatabaseId != InvalidOid)
{ {
ErrorSaveContext escontext = {T_ErrorSaveContext};
List *namelist;
Oid cfgId; Oid cfgId;
HeapTuple tuple; HeapTuple tuple;
Form_pg_ts_config cfg; Form_pg_ts_config cfg;
char *buf; char *buf;
cfgId = get_ts_config_oid(stringToQualifiedNameList(*newval), true); namelist = stringToQualifiedNameList(*newval,
(Node *) &escontext);
if (namelist != NIL)
cfgId = get_ts_config_oid(namelist, true);
else
cfgId = InvalidOid; /* bad name list syntax */
/* /*
* When source == PGC_S_TEST, don't throw a hard error for a * When source == PGC_S_TEST, don't throw a hard error for a

View File

@ -1876,7 +1876,7 @@ RelationNameGetTupleDesc(const char *relname)
List *relname_list; List *relname_list;
/* Open relation and copy the tuple description */ /* Open relation and copy the tuple description */
relname_list = stringToQualifiedNameList(relname); relname_list = stringToQualifiedNameList(relname, NULL);
relvar = makeRangeVarFromNameList(relname_list); relvar = makeRangeVarFromNameList(relname_list);
rel = relation_openrv(relvar, AccessShareLock); rel = relation_openrv(relvar, AccessShareLock);
tupdesc = CreateTupleDescCopy(RelationGetDescr(rel)); tupdesc = CreateTupleDescCopy(RelationGetDescr(rel));

View File

@ -51,8 +51,9 @@ extern Datum stringTypeDatum(Type tp, char *string, int32 atttypmod);
extern Oid typeidTypeRelid(Oid type_id); extern Oid typeidTypeRelid(Oid type_id);
extern Oid typeOrDomainTypeRelid(Oid type_id); extern Oid typeOrDomainTypeRelid(Oid type_id);
extern TypeName *typeStringToTypeName(const char *str); extern TypeName *typeStringToTypeName(const char *str, Node *escontext);
extern void parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p, bool missing_ok); extern bool parseTypeString(const char *str, Oid *typeid_p, int32 *typmod_p,
Node *escontext);
/* true if typeid is composite, or domain over composite, but not RECORD */ /* true if typeid is composite, or domain over composite, but not RECORD */
#define ISCOMPLEX(typeid) (typeOrDomainTypeRelid(typeid) != InvalidOid) #define ISCOMPLEX(typeid) (typeOrDomainTypeRelid(typeid) != InvalidOid)

View File

@ -25,7 +25,7 @@ extern char *format_procedure_extended(Oid procedure_oid, bits16 flags);
#define FORMAT_OPERATOR_FORCE_QUALIFY 0x02 /* force qualification */ #define FORMAT_OPERATOR_FORCE_QUALIFY 0x02 /* force qualification */
extern char *format_operator_extended(Oid operator_oid, bits16 flags); extern char *format_operator_extended(Oid operator_oid, bits16 flags);
extern List *stringToQualifiedNameList(const char *string); extern List *stringToQualifiedNameList(const char *string, Node *escontext);
extern char *format_procedure(Oid procedure_oid); extern char *format_procedure(Oid procedure_oid);
extern char *format_procedure_qualified(Oid procedure_oid); extern char *format_procedure_qualified(Oid procedure_oid);
extern void format_procedure_parts(Oid procedure_oid, List **objnames, extern void format_procedure_parts(Oid procedure_oid, List **objnames,

View File

@ -3613,7 +3613,7 @@ plperl_spi_prepare(char *query, int argc, SV **argv)
char *typstr; char *typstr;
typstr = sv2cstr(argv[i]); typstr = sv2cstr(argv[i]);
parseTypeString(typstr, &typId, &typmod, false); (void) parseTypeString(typstr, &typId, &typmod, NULL);
pfree(typstr); pfree(typstr);
getTypeInputInfo(typId, &typInput, &typIOParam); getTypeInputInfo(typId, &typInput, &typIOParam);

View File

@ -3725,7 +3725,7 @@ parse_datatype(const char *string, int location)
error_context_stack = &syntax_errcontext; error_context_stack = &syntax_errcontext;
/* Let the main parser try to parse it under standard SQL rules */ /* Let the main parser try to parse it under standard SQL rules */
typeName = typeStringToTypeName(string); typeName = typeStringToTypeName(string, NULL);
typenameTypeIdAndMod(NULL, typeName, &type_id, &typmod); typenameTypeIdAndMod(NULL, typeName, &type_id, &typmod);
/* Restore former ereport callback */ /* Restore former ereport callback */

View File

@ -105,7 +105,7 @@ PLy_spi_prepare(PyObject *self, PyObject *args)
*information for input conversion. *information for input conversion.
********************************************************/ ********************************************************/
parseTypeString(sptr, &typeId, &typmod, false); (void) parseTypeString(sptr, &typeId, &typmod, NULL);
Py_DECREF(optr); Py_DECREF(optr);

View File

@ -615,7 +615,7 @@ call_pltcl_start_proc(Oid prolang, bool pltrusted)
error_context_stack = &errcallback; error_context_stack = &errcallback;
/* Parse possibly-qualified identifier and look up the function */ /* Parse possibly-qualified identifier and look up the function */
namelist = stringToQualifiedNameList(start_proc); namelist = stringToQualifiedNameList(start_proc, NULL);
procOid = LookupFuncName(namelist, 0, NULL, false); procOid = LookupFuncName(namelist, 0, NULL, false);
/* Current user must have permission to call function */ /* Current user must have permission to call function */
@ -2603,7 +2603,8 @@ pltcl_SPI_prepare(ClientData cdata, Tcl_Interp *interp,
typIOParam; typIOParam;
int32 typmod; int32 typmod;
parseTypeString(Tcl_GetString(argsObj[i]), &typId, &typmod, false); (void) parseTypeString(Tcl_GetString(argsObj[i]),
&typId, &typmod, NULL);
getTypeInputInfo(typId, &typInput, &typIOParam); getTypeInputInfo(typId, &typInput, &typIOParam);

View File

@ -245,7 +245,7 @@ LINE 1: SELECT regtype('int3');
^ ^
-- with schemaname -- with schemaname
SELECT regoper('ng_catalog.||/'); SELECT regoper('ng_catalog.||/');
ERROR: schema "ng_catalog" does not exist ERROR: operator does not exist: ng_catalog.||/
LINE 1: SELECT regoper('ng_catalog.||/'); LINE 1: SELECT regoper('ng_catalog.||/');
^ ^
SELECT regoperator('ng_catalog.+(int4,int4)'); SELECT regoperator('ng_catalog.+(int4,int4)');
@ -253,15 +253,15 @@ ERROR: operator does not exist: ng_catalog.+(int4,int4)
LINE 1: SELECT regoperator('ng_catalog.+(int4,int4)'); LINE 1: SELECT regoperator('ng_catalog.+(int4,int4)');
^ ^
SELECT regproc('ng_catalog.now'); SELECT regproc('ng_catalog.now');
ERROR: schema "ng_catalog" does not exist ERROR: function "ng_catalog.now" does not exist
LINE 1: SELECT regproc('ng_catalog.now'); LINE 1: SELECT regproc('ng_catalog.now');
^ ^
SELECT regprocedure('ng_catalog.abs(numeric)'); SELECT regprocedure('ng_catalog.abs(numeric)');
ERROR: schema "ng_catalog" does not exist ERROR: function "ng_catalog.abs(numeric)" does not exist
LINE 1: SELECT regprocedure('ng_catalog.abs(numeric)'); LINE 1: SELECT regprocedure('ng_catalog.abs(numeric)');
^ ^
SELECT regclass('ng_catalog.pg_class'); SELECT regclass('ng_catalog.pg_class');
ERROR: schema "ng_catalog" does not exist ERROR: relation "ng_catalog.pg_class" does not exist
LINE 1: SELECT regclass('ng_catalog.pg_class'); LINE 1: SELECT regclass('ng_catalog.pg_class');
^ ^
SELECT regtype('ng_catalog.int4'); SELECT regtype('ng_catalog.int4');
@ -269,7 +269,7 @@ ERROR: schema "ng_catalog" does not exist
LINE 1: SELECT regtype('ng_catalog.int4'); LINE 1: SELECT regtype('ng_catalog.int4');
^ ^
SELECT regcollation('ng_catalog."POSIX"'); SELECT regcollation('ng_catalog."POSIX"');
ERROR: schema "ng_catalog" does not exist ERROR: collation "ng_catalog.POSIX" for encoding "SQL_ASCII" does not exist
LINE 1: SELECT regcollation('ng_catalog."POSIX"'); LINE 1: SELECT regcollation('ng_catalog."POSIX"');
^ ^
-- schemaname not applicable -- schemaname not applicable
@ -406,7 +406,11 @@ SELECT to_regrole('"regress_regrole_test"');
(1 row) (1 row)
SELECT to_regrole('foo.bar'); SELECT to_regrole('foo.bar');
ERROR: invalid name syntax to_regrole
------------
(1 row)
SELECT to_regrole('Nonexistent'); SELECT to_regrole('Nonexistent');
to_regrole to_regrole
------------ ------------
@ -420,7 +424,11 @@ SELECT to_regrole('"Nonexistent"');
(1 row) (1 row)
SELECT to_regrole('foo.bar'); SELECT to_regrole('foo.bar');
ERROR: invalid name syntax to_regrole
------------
(1 row)
SELECT to_regnamespace('Nonexistent'); SELECT to_regnamespace('Nonexistent');
to_regnamespace to_regnamespace
----------------- -----------------
@ -434,4 +442,105 @@ SELECT to_regnamespace('"Nonexistent"');
(1 row) (1 row)
SELECT to_regnamespace('foo.bar'); SELECT to_regnamespace('foo.bar');
ERROR: invalid name syntax to_regnamespace
-----------------
(1 row)
-- Test soft-error API
SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
pg_input_error_message
-----------------------------------------------
relation "ng_catalog.pg_class" does not exist
(1 row)
SELECT pg_input_error_message('ng_catalog."POSIX"', 'regcollation');
pg_input_error_message
----------------------------------------------------------------------
collation "ng_catalog.POSIX" for encoding "SQL_ASCII" does not exist
(1 row)
SELECT pg_input_error_message('no_such_config', 'regconfig');
pg_input_error_message
-----------------------------------------------------------
text search configuration "no_such_config" does not exist
(1 row)
SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
pg_input_error_message
------------------------------------------------------------
text search dictionary "no_such_dictionary" does not exist
(1 row)
SELECT pg_input_error_message('Nonexistent', 'regnamespace');
pg_input_error_message
-------------------------------------
schema "nonexistent" does not exist
(1 row)
SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
pg_input_error_message
-----------------------------------------
operator does not exist: ng_catalog.||/
(1 row)
SELECT pg_input_error_message('-', 'regoper');
pg_input_error_message
--------------------------------
more than one operator named -
(1 row)
SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
pg_input_error_message
--------------------------------------------------
operator does not exist: ng_catalog.+(int4,int4)
(1 row)
SELECT pg_input_error_message('-', 'regoperator');
pg_input_error_message
-----------------------------
expected a left parenthesis
(1 row)
SELECT pg_input_error_message('ng_catalog.now', 'regproc');
pg_input_error_message
------------------------------------------
function "ng_catalog.now" does not exist
(1 row)
SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
pg_input_error_message
---------------------------------------------------
function "ng_catalog.abs(numeric)" does not exist
(1 row)
SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
pg_input_error_message
------------------------------
expected a right parenthesis
(1 row)
SELECT pg_input_error_message('regress_regrole_test', 'regrole');
pg_input_error_message
--------------------------------------------
role "regress_regrole_test" does not exist
(1 row)
SELECT pg_input_error_message('no_such_type', 'regtype');
pg_input_error_message
------------------------------------
type "no_such_type" does not exist
(1 row)
-- Some cases that should be soft errors, but are not yet
SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
ERROR: syntax error at or near "type"
LINE 1: SELECT pg_input_error_message('incorrect type name syntax', ...
^
CONTEXT: invalid type name "incorrect type name syntax"
SELECT pg_input_error_message('numeric(1,2,3)', 'regtype'); -- bogus typmod
ERROR: invalid NUMERIC type modifier
SELECT pg_input_error_message('way.too.many.names', 'regtype');
ERROR: improper qualified name (too many dotted names): way.too.many.names
SELECT pg_input_error_message('no_such_catalog.schema.name', 'regtype');
ERROR: cross-database references are not implemented: no_such_catalog.schema.name

View File

@ -120,3 +120,26 @@ SELECT to_regrole('foo.bar');
SELECT to_regnamespace('Nonexistent'); SELECT to_regnamespace('Nonexistent');
SELECT to_regnamespace('"Nonexistent"'); SELECT to_regnamespace('"Nonexistent"');
SELECT to_regnamespace('foo.bar'); SELECT to_regnamespace('foo.bar');
-- Test soft-error API
SELECT pg_input_error_message('ng_catalog.pg_class', 'regclass');
SELECT pg_input_error_message('ng_catalog."POSIX"', 'regcollation');
SELECT pg_input_error_message('no_such_config', 'regconfig');
SELECT pg_input_error_message('no_such_dictionary', 'regdictionary');
SELECT pg_input_error_message('Nonexistent', 'regnamespace');
SELECT pg_input_error_message('ng_catalog.||/', 'regoper');
SELECT pg_input_error_message('-', 'regoper');
SELECT pg_input_error_message('ng_catalog.+(int4,int4)', 'regoperator');
SELECT pg_input_error_message('-', 'regoperator');
SELECT pg_input_error_message('ng_catalog.now', 'regproc');
SELECT pg_input_error_message('ng_catalog.abs(numeric)', 'regprocedure');
SELECT pg_input_error_message('ng_catalog.abs(numeric', 'regprocedure');
SELECT pg_input_error_message('regress_regrole_test', 'regrole');
SELECT pg_input_error_message('no_such_type', 'regtype');
-- Some cases that should be soft errors, but are not yet
SELECT pg_input_error_message('incorrect type name syntax', 'regtype');
SELECT pg_input_error_message('numeric(1,2,3)', 'regtype'); -- bogus typmod
SELECT pg_input_error_message('way.too.many.names', 'regtype');
SELECT pg_input_error_message('no_such_catalog.schema.name', 'regtype');