Commit 5681cde7 authored by Tom Lane's avatar Tom Lane

Make some small improvements in the accuracy of plpgsql's error location

reports; inspired by the misleading CONTEXT lines shown in recent bug report
from Stefan Kaltenbrunner.  Also, allow statement-type names shown in these
messages to be translated.
parent 17c8493c
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.184 2007/01/28 16:15:49 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.185 2007/01/28 17:58:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -267,6 +267,8 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo) ...@@ -267,6 +267,8 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
} }
} }
estate.err_text = gettext_noop("during function entry");
/* /*
* Set the magic variable FOUND to false * Set the magic variable FOUND to false
*/ */
...@@ -414,6 +416,8 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo) ...@@ -414,6 +416,8 @@ plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo)
} }
} }
estate.err_text = gettext_noop("during function exit");
/* /*
* Let the instrumentation plugin peek at this function * Let the instrumentation plugin peek at this function
*/ */
...@@ -608,6 +612,8 @@ plpgsql_exec_trigger(PLpgSQL_function *func, ...@@ -608,6 +612,8 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
CStringGetDatum(trigdata->tg_trigger->tgargs[i])); CStringGetDatum(trigdata->tg_trigger->tgargs[i]));
} }
estate.err_text = gettext_noop("during function entry");
/* /*
* Set the magic variable FOUND to false * Set the magic variable FOUND to false
*/ */
...@@ -644,6 +650,9 @@ plpgsql_exec_trigger(PLpgSQL_function *func, ...@@ -644,6 +650,9 @@ plpgsql_exec_trigger(PLpgSQL_function *func,
errmsg("control reached end of trigger procedure without RETURN"))); errmsg("control reached end of trigger procedure without RETURN")));
} }
estate.err_stmt = NULL;
estate.err_text = gettext_noop("during function exit");
if (estate.retisset) if (estate.retisset)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH), (errcode(ERRCODE_DATATYPE_MISMATCH),
...@@ -711,23 +720,32 @@ plpgsql_exec_error_callback(void *arg) ...@@ -711,23 +720,32 @@ plpgsql_exec_error_callback(void *arg)
if (estate->err_text == raise_skip_msg) if (estate->err_text == raise_skip_msg)
return; return;
if (estate->err_stmt != NULL) if (estate->err_text != NULL)
{
/* translator: last %s is a plpgsql statement type name */
errcontext("PL/pgSQL function \"%s\" line %d at %s",
estate->err_func->fn_name,
estate->err_stmt->lineno,
plpgsql_stmt_typename(estate->err_stmt));
}
else if (estate->err_text != NULL)
{ {
/* /*
* We don't expend the cycles to run gettext() on err_text unless we * We don't expend the cycles to run gettext() on err_text unless we
* actually need it. Therefore, places that set up err_text should * actually need it. Therefore, places that set up err_text should
* use gettext_noop() to ensure the strings get recorded in the * use gettext_noop() to ensure the strings get recorded in the
* message dictionary. * message dictionary.
*
* If both err_text and err_stmt are set, use the err_text as
* description, but report the err_stmt's line number. When
* err_stmt is not set, we're in function entry/exit, or some such
* place not attached to a specific line number.
*/ */
if (estate->err_stmt != NULL)
{
/*
* translator: last %s is a phrase such as "during statement
* block local variable initialization"
*/
errcontext("PL/pgSQL function \"%s\" line %d %s",
estate->err_func->fn_name,
estate->err_stmt->lineno,
gettext(estate->err_text));
}
else
{
/* /*
* translator: last %s is a phrase such as "while storing call * translator: last %s is a phrase such as "while storing call
* arguments into local variables" * arguments into local variables"
...@@ -736,6 +754,15 @@ plpgsql_exec_error_callback(void *arg) ...@@ -736,6 +754,15 @@ plpgsql_exec_error_callback(void *arg)
estate->err_func->fn_name, estate->err_func->fn_name,
gettext(estate->err_text)); gettext(estate->err_text));
} }
}
else if (estate->err_stmt != NULL)
{
/* translator: last %s is a plpgsql statement type name */
errcontext("PL/pgSQL function \"%s\" line %d at %s",
estate->err_func->fn_name,
estate->err_stmt->lineno,
plpgsql_stmt_typename(estate->err_stmt));
}
else else
errcontext("PL/pgSQL function \"%s\"", errcontext("PL/pgSQL function \"%s\"",
estate->err_func->fn_name); estate->err_func->fn_name);
...@@ -846,6 +873,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) ...@@ -846,6 +873,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
/* /*
* First initialize all variables declared in this block * First initialize all variables declared in this block
*/ */
estate->err_text = gettext_noop("during statement block local variable initialization");
for (i = 0; i < block->n_initvars; i++) for (i = 0; i < block->n_initvars; i++)
{ {
n = block->initvarnos[i]; n = block->initvarnos[i];
...@@ -915,6 +944,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) ...@@ -915,6 +944,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
EState *old_eval_estate = estate->eval_estate; EState *old_eval_estate = estate->eval_estate;
long int old_eval_estate_simple_id = estate->eval_estate_simple_id; long int old_eval_estate_simple_id = estate->eval_estate_simple_id;
estate->err_text = gettext_noop("during statement block entry");
BeginInternalSubTransaction(NULL); BeginInternalSubTransaction(NULL);
/* Want to run statements inside function's memory context */ /* Want to run statements inside function's memory context */
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
...@@ -929,9 +960,13 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) ...@@ -929,9 +960,13 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
*/ */
plpgsql_create_econtext(estate); plpgsql_create_econtext(estate);
estate->err_text = NULL;
/* Run the block's statements */ /* Run the block's statements */
rc = exec_stmts(estate, block->body); rc = exec_stmts(estate, block->body);
estate->err_text = gettext_noop("during statement block exit");
/* Commit the inner transaction, return to outer xact context */ /* Commit the inner transaction, return to outer xact context */
ReleaseCurrentSubTransaction(); ReleaseCurrentSubTransaction();
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
...@@ -953,6 +988,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) ...@@ -953,6 +988,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
ErrorData *edata; ErrorData *edata;
ListCell *e; ListCell *e;
estate->err_text = gettext_noop("during exception cleanup");
/* Save error info */ /* Save error info */
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
edata = CopyErrorData(); edata = CopyErrorData();
...@@ -1004,6 +1041,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) ...@@ -1004,6 +1041,8 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
errm_var->freeval = true; errm_var->freeval = true;
errm_var->isnull = false; errm_var->isnull = false;
estate->err_text = NULL;
rc = exec_stmts(estate, exception->action); rc = exec_stmts(estate, exception->action);
free_var(state_var); free_var(state_var);
...@@ -1025,9 +1064,13 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block) ...@@ -1025,9 +1064,13 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
/* /*
* Just execute the statements in the block's body * Just execute the statements in the block's body
*/ */
estate->err_text = NULL;
rc = exec_stmts(estate, block->body); rc = exec_stmts(estate, block->body);
} }
estate->err_text = NULL;
/* /*
* Handle the return code. * Handle the return code.
*/ */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.56 2007/01/05 22:20:02 momjian Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.57 2007/01/28 17:58:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -426,43 +426,43 @@ plpgsql_stmt_typename(PLpgSQL_stmt *stmt) ...@@ -426,43 +426,43 @@ plpgsql_stmt_typename(PLpgSQL_stmt *stmt)
switch (stmt->cmd_type) switch (stmt->cmd_type)
{ {
case PLPGSQL_STMT_BLOCK: case PLPGSQL_STMT_BLOCK:
return "block variables initialization"; return _("statement block");
case PLPGSQL_STMT_ASSIGN: case PLPGSQL_STMT_ASSIGN:
return "assignment"; return _("assignment");
case PLPGSQL_STMT_IF: case PLPGSQL_STMT_IF:
return "if"; return _("if");
case PLPGSQL_STMT_LOOP: case PLPGSQL_STMT_LOOP:
return "loop"; return _("loop");
case PLPGSQL_STMT_WHILE: case PLPGSQL_STMT_WHILE:
return "while"; return _("while");
case PLPGSQL_STMT_FORI: case PLPGSQL_STMT_FORI:
return "for with integer loopvar"; return _("for with integer loop variable");
case PLPGSQL_STMT_FORS: case PLPGSQL_STMT_FORS:
return "for over select rows"; return _("for over select rows");
case PLPGSQL_STMT_EXIT: case PLPGSQL_STMT_EXIT:
return "exit"; return _("exit");
case PLPGSQL_STMT_RETURN: case PLPGSQL_STMT_RETURN:
return "return"; return _("return");
case PLPGSQL_STMT_RETURN_NEXT: case PLPGSQL_STMT_RETURN_NEXT:
return "return next"; return _("return next");
case PLPGSQL_STMT_RAISE: case PLPGSQL_STMT_RAISE:
return "raise"; return _("raise");
case PLPGSQL_STMT_EXECSQL: case PLPGSQL_STMT_EXECSQL:
return "SQL statement"; return _("SQL statement");
case PLPGSQL_STMT_DYNEXECUTE: case PLPGSQL_STMT_DYNEXECUTE:
return "execute statement"; return _("execute statement");
case PLPGSQL_STMT_DYNFORS: case PLPGSQL_STMT_DYNFORS:
return "for over execute statement"; return _("for over execute statement");
case PLPGSQL_STMT_GETDIAG: case PLPGSQL_STMT_GETDIAG:
return "get diagnostics"; return _("get diagnostics");
case PLPGSQL_STMT_OPEN: case PLPGSQL_STMT_OPEN:
return "open"; return _("open");
case PLPGSQL_STMT_FETCH: case PLPGSQL_STMT_FETCH:
return "fetch"; return _("fetch");
case PLPGSQL_STMT_CLOSE: case PLPGSQL_STMT_CLOSE:
return "close"; return _("close");
case PLPGSQL_STMT_PERFORM: case PLPGSQL_STMT_PERFORM:
return "perform"; return _("perform");
} }
return "unknown"; return "unknown";
......
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