diff --git a/doc/src/sgml/sources.sgml b/doc/src/sgml/sources.sgml index 32ca2201b8..283c3e0357 100644 --- a/doc/src/sgml/sources.sgml +++ b/doc/src/sgml/sources.sgml @@ -103,9 +103,9 @@ less -x4 message text. In addition there are optional elements, the most common of which is an error identifier code that follows the SQL spec's SQLSTATE conventions. - ereport itself is just a shell function, that exists + ereport itself is just a shell macro, that exists mainly for the syntactic convenience of making message generation - look like a function call in the C source code. The only parameter + look like a single function call in the C source code. The only parameter accepted directly by ereport is the severity level. The primary message text and any optional message elements are generated by calling auxiliary functions, such as errmsg, @@ -116,36 +116,50 @@ less -x4 A typical call to ereport might look like this: ereport(ERROR, - (errcode(ERRCODE_DIVISION_BY_ZERO), - errmsg("division by zero"))); + errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero")); This specifies error severity level ERROR (a run-of-the-mill error). The errcode call specifies the SQLSTATE error code using a macro defined in src/include/utils/errcodes.h. The - errmsg call provides the primary message text. Notice the - extra set of parentheses surrounding the auxiliary function calls — - these are annoying but syntactically necessary. + errmsg call provides the primary message text. + + + + You will also frequently see this older style, with an extra set of + parentheses surrounding the auxiliary function calls: + +ereport(ERROR, + (errcode(ERRCODE_DIVISION_BY_ZERO), + errmsg("division by zero"))); + + The extra parentheses were required + before PostgreSQL version 12, but are now + optional. Here is a more complex example: ereport(ERROR, - (errcode(ERRCODE_AMBIGUOUS_FUNCTION), - errmsg("function %s is not unique", - func_signature_string(funcname, nargs, - NIL, actual_arg_types)), - errhint("Unable to choose a best candidate function. " - "You might need to add explicit typecasts."))); + errcode(ERRCODE_AMBIGUOUS_FUNCTION), + errmsg("function %s is not unique", + func_signature_string(funcname, nargs, + NIL, actual_arg_types)), + errhint("Unable to choose a best candidate function. " + "You might need to add explicit typecasts.")); This illustrates the use of format codes to embed run-time values into a message text. Also, an optional hint message is provided. + The auxiliary function calls can be written in any order, but + conventionally errcode + and errmsg appear first. If the severity level is ERROR or higher, - ereport aborts the execution of the user-defined - function and does not return to the caller. If the severity level is + ereport aborts execution of the current query + and does not return to the caller. If the severity level is lower than ERROR, ereport returns normally. @@ -390,7 +404,7 @@ elog(level, "format string", ...); is exactly equivalent to: -ereport(level, (errmsg_internal("format string", ...))); +ereport(level, errmsg_internal("format string", ...)); Notice that the SQLSTATE error code is always defaulted, and the message string is not subject to translation. diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 00c77b66c7..cb8c23e4b7 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -3720,15 +3720,15 @@ process_postgres_switches(int argc, char *argv[], GucContext ctx, /* spell the error message a bit differently depending on context */ if (IsUnderPostmaster) ereport(FATAL, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("invalid command-line argument for server process: %s", argv[optind]), - errhint("Try \"%s --help\" for more information.", progname))); + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("invalid command-line argument for server process: %s", argv[optind]), + errhint("Try \"%s --help\" for more information.", progname)); else ereport(FATAL, - (errcode(ERRCODE_SYNTAX_ERROR), - errmsg("%s: invalid command-line argument: %s", - progname, argv[optind]), - errhint("Try \"%s --help\" for more information.", progname))); + errcode(ERRCODE_SYNTAX_ERROR), + errmsg("%s: invalid command-line argument: %s", + progname, argv[optind]), + errhint("Try \"%s --help\" for more information.", progname)); } /* diff --git a/src/backend/utils/error/elog.c b/src/backend/utils/error/elog.c index 62eef7b71f..de705c86fa 100644 --- a/src/backend/utils/error/elog.c +++ b/src/backend/utils/error/elog.c @@ -1116,16 +1116,6 @@ errcontext_msg(const char *fmt,...) * translate it. Instead, each errcontext_msg() call should be preceded by * a set_errcontext_domain() call to specify the domain. This is usually * done transparently by the errcontext() macro. - * - * Although errcontext is primarily meant for use at call sites distant from - * the original ereport call, there are a few places that invoke errcontext - * within ereport. The expansion of errcontext as a comma expression calling - * set_errcontext_domain then errcontext_msg is problematic in this case, - * because the intended comma expression becomes two arguments to errfinish, - * which the compiler is at liberty to evaluate in either order. But in - * such a case, the set_errcontext_domain calls must be selecting the same - * TEXTDOMAIN value that the errstart call did, so order does not matter - * so long as errstart initializes context_domain along with domain. */ int set_errcontext_domain(const char *domain) diff --git a/src/include/utils/elog.h b/src/include/utils/elog.h index 0a4ef029ce..4ff69daf3b 100644 --- a/src/include/utils/elog.h +++ b/src/include/utils/elog.h @@ -91,9 +91,9 @@ /*---------- * New-style error reporting API: to be used in this way: * ereport(ERROR, - * (errcode(ERRCODE_UNDEFINED_CURSOR), - * errmsg("portal \"%s\" not found", stmt->portalname), - * ... other errxxx() fields as needed ...)); + * errcode(ERRCODE_UNDEFINED_CURSOR), + * errmsg("portal \"%s\" not found", stmt->portalname), + * ... other errxxx() fields as needed ...); * * The error level is required, and so is a primary error message (errmsg * or errmsg_internal). All else is optional. errcode() defaults to @@ -101,6 +101,9 @@ * if elevel is WARNING, or ERRCODE_SUCCESSFUL_COMPLETION if elevel is * NOTICE or below. * + * Before Postgres v12, extra parentheses were required around the + * list of auxiliary function calls; that's now optional. + * * ereport_domain() allows a message domain to be specified, for modules that * wish to use a different message catalog from the backend's. To avoid having * one copy of the default text domain per .o file, we define it as NULL here @@ -118,28 +121,28 @@ *---------- */ #ifdef HAVE__BUILTIN_CONSTANT_P -#define ereport_domain(elevel, domain, rest) \ +#define ereport_domain(elevel, domain, ...) \ do { \ pg_prevent_errno_in_scope(); \ if (errstart(elevel, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain)) \ - errfinish rest; \ + __VA_ARGS__, errfinish(0); \ if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \ pg_unreachable(); \ } while(0) #else /* !HAVE__BUILTIN_CONSTANT_P */ -#define ereport_domain(elevel, domain, rest) \ +#define ereport_domain(elevel, domain, ...) \ do { \ const int elevel_ = (elevel); \ pg_prevent_errno_in_scope(); \ if (errstart(elevel_, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain)) \ - errfinish rest; \ + __VA_ARGS__, errfinish(0); \ if (elevel_ >= ERROR) \ pg_unreachable(); \ } while(0) #endif /* HAVE__BUILTIN_CONSTANT_P */ -#define ereport(elevel, rest) \ - ereport_domain(elevel, TEXTDOMAIN, rest) +#define ereport(elevel, ...) \ + ereport_domain(elevel, TEXTDOMAIN, __VA_ARGS__) #define TEXTDOMAIN NULL