mirror of
https://git.postgresql.org/git/postgresql.git
synced 2025-01-06 15:24:56 +08:00
Fix PL/Python traceback for error in separate file
It assumed that the lineno from the traceback always refers to the PL/Python function. If you created a PL/Python function that imports some code, runs it, and that code raises an exception, PLy_traceback would get utterly confused. Now we look at the file name reported with the traceback and only print the source line if it came from the PL/Python function. Jan Urbański
This commit is contained in:
parent
0262251c33
commit
395fcac299
@ -4510,6 +4510,14 @@ get_source_line(const char *src, int lineno)
|
||||
if (next == NULL)
|
||||
return pstrdup(s);
|
||||
|
||||
/*
|
||||
* Sanity check, next < s if the line was all-whitespace, which should
|
||||
* never happen if Python reported a frame created on that line, but
|
||||
* check anyway.
|
||||
*/
|
||||
if (next < s)
|
||||
return NULL;
|
||||
|
||||
return pnstrdup(s, next - s);
|
||||
}
|
||||
|
||||
@ -4606,6 +4614,7 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
|
||||
PyObject *volatile code = NULL;
|
||||
PyObject *volatile name = NULL;
|
||||
PyObject *volatile lineno = NULL;
|
||||
PyObject *volatile filename = NULL;
|
||||
|
||||
PG_TRY();
|
||||
{
|
||||
@ -4624,6 +4633,10 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
|
||||
name = PyObject_GetAttrString(code, "co_name");
|
||||
if (name == NULL)
|
||||
elog(ERROR, "could not get function name from Python code object");
|
||||
|
||||
filename = PyObject_GetAttrString(code, "co_filename");
|
||||
if (filename == NULL)
|
||||
elog(ERROR, "could not get file name from Python code object");
|
||||
}
|
||||
PG_CATCH();
|
||||
{
|
||||
@ -4631,6 +4644,7 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
|
||||
Py_XDECREF(code);
|
||||
Py_XDECREF(name);
|
||||
Py_XDECREF(lineno);
|
||||
Py_XDECREF(filename);
|
||||
PG_RE_THROW();
|
||||
}
|
||||
PG_END_TRY();
|
||||
@ -4641,6 +4655,7 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
|
||||
char *proname;
|
||||
char *fname;
|
||||
char *line;
|
||||
char *plain_filename;
|
||||
long plain_lineno;
|
||||
|
||||
/*
|
||||
@ -4653,6 +4668,7 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
|
||||
fname = PyString_AsString(name);
|
||||
|
||||
proname = PLy_procedure_name(PLy_curr_procedure);
|
||||
plain_filename = PyString_AsString(filename);
|
||||
plain_lineno = PyInt_AsLong(lineno);
|
||||
|
||||
if (proname == NULL)
|
||||
@ -4664,7 +4680,9 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
|
||||
&tbstr, "\n PL/Python function \"%s\", line %ld, in %s",
|
||||
proname, plain_lineno - 1, fname);
|
||||
|
||||
if (PLy_curr_procedure)
|
||||
/* function code object was compiled with "<string>" as the filename */
|
||||
if (PLy_curr_procedure && plain_filename != NULL &&
|
||||
strcmp(plain_filename, "<string>") == 0)
|
||||
{
|
||||
/*
|
||||
* If we know the current procedure, append the exact line
|
||||
@ -4672,7 +4690,8 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
|
||||
* module behavior. We could store the already line-split
|
||||
* source to avoid splitting it every time, but producing a
|
||||
* traceback is not the most important scenario to optimize
|
||||
* for.
|
||||
* for. But we do not go as far as traceback.py in reading
|
||||
* the source of imported modules.
|
||||
*/
|
||||
line = get_source_line(PLy_curr_procedure->src, plain_lineno);
|
||||
if (line)
|
||||
@ -4687,6 +4706,7 @@ PLy_traceback(char **xmsg, char **tbmsg, int *tb_depth)
|
||||
Py_DECREF(code);
|
||||
Py_DECREF(name);
|
||||
Py_DECREF(lineno);
|
||||
Py_DECREF(filename);
|
||||
|
||||
/* Release the current frame and go to the next one. */
|
||||
tb_prev = tb;
|
||||
|
Loading…
Reference in New Issue
Block a user