Commit 17a28b03 authored by Tom Lane's avatar Tom Lane

Improve the internal implementation of ereport().

Change all the auxiliary error-reporting routines to return void,
now that we no longer need to pretend they are passing something
useful to errfinish().  While this probably doesn't save anything
significant at the machine-code level, it allows detection of some
additional types of mistakes.

Pass the error location details (__FILE__, __LINE__, PG_FUNCNAME_MACRO)
to errfinish not errstart.  This shaves a few cycles off the case where
errstart decides we're not going to emit anything.

Re-implement elog() as a trivial wrapper around ereport(), removing
the separate support infrastructure it used to have.  Aside from
getting rid of some now-surplus code, this means that elog() now
really does have exactly the same semantics as ereport(), in particular
that it can skip evaluation work if the message is not to be emitted.

Andres Freund and Tom Lane

Discussion: https://postgr.es/m/CA+fd4k6N8EjNvZpM8nme+y+05mz-SM8Z_BgkixzkA34R+ej0Kw@mail.gmail.com
parent e3a87b49
......@@ -832,21 +832,21 @@ UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
* normal non-error case: computing character indexes would be much more
* expensive than storing token offsets.)
*/
int
void
executor_errposition(EState *estate, int location)
{
int pos;
/* No-op if location was not provided */
if (location < 0)
return 0;
return;
/* Can't do anything if source text is not available */
if (estate == NULL || estate->es_sourceText == NULL)
return 0;
return;
/* Convert offset to character number */
pos = pg_mbstrlen_with_len(estate->es_sourceText, location) + 1;
/* And pass it to the ereport mechanism */
return errposition(pos);
errposition(pos);
}
/*
......
......@@ -1246,15 +1246,15 @@ coerce_to_specific_type(ParseState *pstate, Node *node,
* XXX possibly this is more generally useful than coercion errors;
* if so, should rename and place with parser_errposition.
*/
int
void
parser_coercion_errposition(ParseState *pstate,
int coerce_location,
Node *input_expr)
{
if (coerce_location >= 0)
return parser_errposition(pstate, coerce_location);
parser_errposition(pstate, coerce_location);
else
return parser_errposition(pstate, exprLocation(input_expr));
parser_errposition(pstate, exprLocation(input_expr));
}
......
......@@ -106,21 +106,21 @@ free_parsestate(ParseState *pstate)
* normal non-error case: computing character indexes would be much more
* expensive than storing token offsets.)
*/
int
void
parser_errposition(ParseState *pstate, int location)
{
int pos;
/* No-op if location was not provided */
if (location < 0)
return 0;
return;
/* Can't do anything if source text is not available */
if (pstate == NULL || pstate->p_sourcetext == NULL)
return 0;
return;
/* Convert offset to character number */
pos = pg_mbstrlen_with_len(pstate->p_sourcetext, location) + 1;
/* And pass it to the ereport mechanism */
return errposition(pos);
errposition(pos);
}
......
......@@ -1076,18 +1076,18 @@ other .
* (essentially, scan.l, parser.c, and gram.y), since it requires the
* yyscanner struct to still be available.
*/
int
void
scanner_errposition(int location, core_yyscan_t yyscanner)
{
int pos;
if (location < 0)
return 0; /* no-op if location is unknown */
return; /* no-op if location is unknown */
/* Convert byte offset to character number */
pos = pg_mbstrlen_with_len(yyextra->scanbuf, location) + 1;
/* And pass it to the ereport mechanism */
return errposition(pos);
errposition(pos);
}
/*
......
......@@ -92,7 +92,7 @@ static bool dsm_impl_mmap(dsm_op op, dsm_handle handle, Size request_size,
void **impl_private, void **mapped_address,
Size *mapped_size, int elevel);
#endif
static int errcode_for_dynamic_shared_memory(void);
static void errcode_for_dynamic_shared_memory(void);
const struct config_enum_entry dynamic_shared_memory_options[] = {
#ifdef USE_DSM_POSIX
......@@ -1030,11 +1030,11 @@ dsm_impl_unpin_segment(dsm_handle handle, void **impl_private)
}
}
static int
static void
errcode_for_dynamic_shared_memory(void)
{
if (errno == EFBIG || errno == ENOMEM)
return errcode(ERRCODE_OUT_OF_MEMORY);
errcode(ERRCODE_OUT_OF_MEMORY);
else
return errcode_for_file_access();
errcode_for_file_access();
}
......@@ -329,7 +329,7 @@ typedef struct JsObject
hash_destroy((jso)->val.json_hash); \
} while (0)
static int report_json_context(JsonLexContext *lex);
static void report_json_context(JsonLexContext *lex);
/* semantic action functions for json_object_keys */
static void okeys_object_field_start(void *state, char *fname, bool isnull);
......@@ -631,7 +631,7 @@ json_ereport_error(JsonParseErrorType error, JsonLexContext *lex)
* The return value isn't meaningful, but we make it non-void so that this
* can be invoked inside ereport().
*/
static int
static void
report_json_context(JsonLexContext *lex)
{
const char *context_start;
......@@ -689,7 +689,7 @@ report_json_context(JsonLexContext *lex)
prefix = (context_start > line_start) ? "..." : "";
suffix = (lex->token_type != JSON_TOKEN_END && context_end - lex->input < lex->input_length && *context_end != '\n' && *context_end != '\r') ? "..." : "";
return errcontext("JSON data, line %d: %s%s%s",
errcontext("JSON data, line %d: %s%s%s",
line_number, prefix, ctxt, suffix);
}
......
This diff is collapsed.
......@@ -546,7 +546,7 @@ exec_rt_fetch(Index rti, EState *estate)
extern Relation ExecGetRangeTableRelation(EState *estate, Index rti);
extern int executor_errposition(EState *estate, int location);
extern void executor_errposition(EState *estate, int location);
extern void RegisterExprContextCallback(ExprContext *econtext,
ExprContextCallbackFunction function,
......
......@@ -61,7 +61,7 @@ extern Node *coerce_to_specific_type_typmod(ParseState *pstate, Node *node,
Oid targetTypeId, int32 targetTypmod,
const char *constructName);
extern int parser_coercion_errposition(ParseState *pstate,
extern void parser_coercion_errposition(ParseState *pstate,
int coerce_location,
Node *input_expr);
......
......@@ -307,7 +307,7 @@ typedef struct ParseCallbackState
extern ParseState *make_parsestate(ParseState *parentParseState);
extern void free_parsestate(ParseState *pstate);
extern int parser_errposition(ParseState *pstate, int location);
extern void parser_errposition(ParseState *pstate, int location);
extern void setup_parser_errposition_callback(ParseCallbackState *pcbstate,
ParseState *pstate, int location);
......
......@@ -140,7 +140,7 @@ extern core_yyscan_t scanner_init(const char *str,
extern void scanner_finish(core_yyscan_t yyscanner);
extern int core_yylex(core_YYSTYPE *lvalp, YYLTYPE *llocp,
core_yyscan_t yyscanner);
extern int scanner_errposition(int location, core_yyscan_t yyscanner);
extern void scanner_errposition(int location, core_yyscan_t yyscanner);
extern void setup_scanner_errposition_callback(ScannerCallbackState *scbstate,
core_yyscan_t yyscanner,
int location);
......
......@@ -124,8 +124,8 @@
#define ereport_domain(elevel, domain, ...) \
do { \
pg_prevent_errno_in_scope(); \
if (errstart(elevel, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain)) \
__VA_ARGS__, errfinish(0); \
if (errstart(elevel, domain)) \
__VA_ARGS__, errfinish(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \
if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \
pg_unreachable(); \
} while(0)
......@@ -134,8 +134,8 @@
do { \
const int elevel_ = (elevel); \
pg_prevent_errno_in_scope(); \
if (errstart(elevel_, __FILE__, __LINE__, PG_FUNCNAME_MACRO, domain)) \
__VA_ARGS__, errfinish(0); \
if (errstart(elevel_, domain)) \
__VA_ARGS__, errfinish(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \
if (elevel_ >= ERROR) \
pg_unreachable(); \
} while(0)
......@@ -146,34 +146,33 @@
#define TEXTDOMAIN NULL
extern bool errstart(int elevel, const char *filename, int lineno,
const char *funcname, const char *domain);
extern void errfinish(int dummy,...);
extern bool errstart(int elevel, const char *domain);
extern void errfinish(const char *filename, int lineno, const char *funcname);
extern int errcode(int sqlerrcode);
extern void errcode(int sqlerrcode);
extern int errcode_for_file_access(void);
extern int errcode_for_socket_access(void);
extern void errcode_for_file_access(void);
extern void errcode_for_socket_access(void);
extern int errmsg(const char *fmt,...) pg_attribute_printf(1, 2);
extern int errmsg_internal(const char *fmt,...) pg_attribute_printf(1, 2);
extern void errmsg(const char *fmt,...) pg_attribute_printf(1, 2);
extern void errmsg_internal(const char *fmt,...) pg_attribute_printf(1, 2);
extern int errmsg_plural(const char *fmt_singular, const char *fmt_plural,
extern void errmsg_plural(const char *fmt_singular, const char *fmt_plural,
unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4);
extern int errdetail(const char *fmt,...) pg_attribute_printf(1, 2);
extern int errdetail_internal(const char *fmt,...) pg_attribute_printf(1, 2);
extern void errdetail(const char *fmt,...) pg_attribute_printf(1, 2);
extern void errdetail_internal(const char *fmt,...) pg_attribute_printf(1, 2);
extern int errdetail_log(const char *fmt,...) pg_attribute_printf(1, 2);
extern void errdetail_log(const char *fmt,...) pg_attribute_printf(1, 2);
extern int errdetail_log_plural(const char *fmt_singular,
extern void errdetail_log_plural(const char *fmt_singular,
const char *fmt_plural,
unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4);
extern int errdetail_plural(const char *fmt_singular, const char *fmt_plural,
extern void errdetail_plural(const char *fmt_singular, const char *fmt_plural,
unsigned long n,...) pg_attribute_printf(1, 4) pg_attribute_printf(2, 4);
extern int errhint(const char *fmt,...) pg_attribute_printf(1, 2);
extern void errhint(const char *fmt,...) pg_attribute_printf(1, 2);
/*
* errcontext() is typically called in error context callback functions, not
......@@ -185,22 +184,22 @@ extern int errhint(const char *fmt,...) pg_attribute_printf(1, 2);
*/
#define errcontext set_errcontext_domain(TEXTDOMAIN), errcontext_msg
extern int set_errcontext_domain(const char *domain);
extern void set_errcontext_domain(const char *domain);
extern int errcontext_msg(const char *fmt,...) pg_attribute_printf(1, 2);
extern void errcontext_msg(const char *fmt,...) pg_attribute_printf(1, 2);
extern int errhidestmt(bool hide_stmt);
extern int errhidecontext(bool hide_ctx);
extern void errhidestmt(bool hide_stmt);
extern void errhidecontext(bool hide_ctx);
extern int errbacktrace(void);
extern void errbacktrace(void);
extern int errfunction(const char *funcname);
extern int errposition(int cursorpos);
extern void errfunction(const char *funcname);
extern void errposition(int cursorpos);
extern int internalerrposition(int cursorpos);
extern int internalerrquery(const char *query);
extern void internalerrposition(int cursorpos);
extern void internalerrquery(const char *query);
extern int err_generic_string(int field, const char *str);
extern void err_generic_string(int field, const char *str);
extern int geterrcode(void);
extern int geterrposition(void);
......@@ -212,37 +211,8 @@ extern int getinternalerrposition(void);
* elog(ERROR, "portal \"%s\" not found", stmt->portalname);
*----------
*/
/*
* Using variadic macros, we can give the compiler a hint about the
* call not returning when elevel >= ERROR. See comments for ereport().
* Note that historically elog() has called elog_start (which saves errno)
* before evaluating "elevel", so we preserve that behavior here.
*/
#ifdef HAVE__BUILTIN_CONSTANT_P
#define elog(elevel, ...) \
do { \
pg_prevent_errno_in_scope(); \
elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \
elog_finish(elevel, __VA_ARGS__); \
if (__builtin_constant_p(elevel) && (elevel) >= ERROR) \
pg_unreachable(); \
} while(0)
#else /* !HAVE__BUILTIN_CONSTANT_P */
#define elog(elevel, ...) \
do { \
pg_prevent_errno_in_scope(); \
elog_start(__FILE__, __LINE__, PG_FUNCNAME_MACRO); \
{ \
const int elevel_ = (elevel); \
elog_finish(elevel_, __VA_ARGS__); \
if (elevel_ >= ERROR) \
pg_unreachable(); \
} \
} while(0)
#endif /* HAVE__BUILTIN_CONSTANT_P */
extern void elog_start(const char *filename, int lineno, const char *funcname);
extern void elog_finish(int elevel, const char *fmt,...) pg_attribute_printf(2, 3);
ereport(elevel, errmsg_internal(__VA_ARGS__))
/* Support for constructing error strings separately from ereport() calls */
......
......@@ -468,20 +468,20 @@ plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc, int *tok2_loc)
* parsing of a plpgsql function, since it requires the scanorig string
* to still be available.
*/
int
void
plpgsql_scanner_errposition(int location)
{
int pos;
if (location < 0 || scanorig == NULL)
return 0; /* no-op if location is unknown */
return; /* no-op if location is unknown */
/* Convert byte offset to character number */
pos = pg_mbstrlen_with_len(scanorig, location) + 1;
/* And pass it to the ereport mechanism */
(void) internalerrposition(pos);
/* Also pass the function body string */
return internalerrquery(scanorig);
internalerrquery(scanorig);
}
/*
......
......@@ -1319,7 +1319,7 @@ extern void plpgsql_append_source_text(StringInfo buf,
extern int plpgsql_peek(void);
extern void plpgsql_peek2(int *tok1_p, int *tok2_p, int *tok1_loc,
int *tok2_loc);
extern int plpgsql_scanner_errposition(int location);
extern void plpgsql_scanner_errposition(int location);
extern void plpgsql_yyerror(const char *message) pg_attribute_noreturn();
extern int plpgsql_location_to_lineno(int location);
extern int plpgsql_latest_lineno(void);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment