On 20/07/12 08:59, Jan Urbański wrote:
On 18/07/12 17:17, Heikki Linnakangas wrote:
On 14.07.2012 17:50, Jan Urbański wrote:
If pg_do_encoding_conversion() throws an error, you don't get a chance
to call Py_DECREF() to release the string. Is that a problem?
If an error occurs in PLy_traceback(), after incrementing
recursion_depth, you don't get a chance to decrement it again. I'm not
sure if the Py* function calls can fail, but at least seemingly trivial
things like initStringInfo() can throw an out-of-memory error.
Of course you're right (on both accounts).
Here's a version with a bunch of PG_TRies thrown in.
Silly me, playing tricks with postincrements before fully waking up.
Here's v3, with a correct inequality test for exceeding the traceback
recursion test.
J
diff --git a/src/pl/plpython/plpy_elog.c b/src/pl/plpython/plpy_elog.c
new file mode 100644
index c375ac0..0ad8358
*** a/src/pl/plpython/plpy_elog.c
--- b/src/pl/plpython/plpy_elog.c
*************** static char *get_source_line(const char
*** 28,33 ****
--- 28,41 ----
/*
+ * Guard agains re-entrant calls to PLy_traceback, which can happen if
+ * traceback formatting functions raise Python errors.
+ */
+ #define TRACEBACK_RECURSION_LIMIT 2
+ static int recursion_depth = 0;
+
+
+ /*
* Emit a PG error or notice, together with any available info about
* the current Python error, previously set by PLy_exception_set().
* This should be used to propagate Python errors into PG. If fmt is
*************** static char *get_source_line(const char
*** 38,46 ****
void
PLy_elog(int elevel, const char *fmt,...)
{
! char *xmsg;
! char *tbmsg;
! int tb_depth;
StringInfoData emsg;
PyObject *exc,
*val,
--- 46,54 ----
void
PLy_elog(int elevel, const char *fmt,...)
{
! char *xmsg = NULL;
! char *tbmsg = NULL;
! int tb_depth = 0;
StringInfoData emsg;
PyObject *exc,
*val,
*************** PLy_elog(int elevel, const char *fmt,...
*** 62,68 ****
}
PyErr_Restore(exc, val, tb);
! PLy_traceback(&xmsg, &tbmsg, &tb_depth);
if (fmt)
{
--- 70,90 ----
}
PyErr_Restore(exc, val, tb);
! if (recursion_depth++ < TRACEBACK_RECURSION_LIMIT)
! {
! PG_TRY();
! {
! PLy_traceback(&xmsg, &tbmsg, &tb_depth);
! }
! PG_CATCH();
! {
! recursion_depth--;
! PG_RE_THROW();
! }
! PG_END_TRY();
! }
!
! recursion_depth--;
if (fmt)
{
diff --git a/src/pl/plpython/plpy_util.c b/src/pl/plpython/plpy_util.c
new file mode 100644
index 4aabafc..94c035e
*** a/src/pl/plpython/plpy_util.c
--- b/src/pl/plpython/plpy_util.c
*************** PLy_free(void *ptr)
*** 61,126 ****
PyObject *
PLyUnicode_Bytes(PyObject *unicode)
{
! PyObject *rv;
! const char *serverenc;
! /*
! * Map PostgreSQL encoding to a Python encoding name.
! */
! switch (GetDatabaseEncoding())
{
! case PG_SQL_ASCII:
! /*
! * Mapping SQL_ASCII to Python's 'ascii' is a bit bogus. Python's
! * 'ascii' means true 7-bit only ASCII, while PostgreSQL's
! * SQL_ASCII means that anything is allowed, and the system doesn't
! * try to interpret the bytes in any way. But not sure what else
! * to do, and we haven't heard any complaints...
! */
! serverenc = "ascii";
! break;
! case PG_WIN1250:
! serverenc = "cp1250";
! break;
! case PG_WIN1251:
! serverenc = "cp1251";
! break;
! case PG_WIN1252:
! serverenc = "cp1252";
! break;
! case PG_WIN1253:
! serverenc = "cp1253";
! break;
! case PG_WIN1254:
! serverenc = "cp1254";
! break;
! case PG_WIN1255:
! serverenc = "cp1255";
! break;
! case PG_WIN1256:
! serverenc = "cp1256";
! break;
! case PG_WIN1257:
! serverenc = "cp1257";
! break;
! case PG_WIN1258:
! serverenc = "cp1258";
! break;
! case PG_WIN866:
! serverenc = "cp866";
! break;
! case PG_WIN874:
! serverenc = "cp874";
! break;
! default:
! /* Other encodings have the same name in Python. */
! serverenc = GetDatabaseEncodingName();
! break;
}
! rv = PyUnicode_AsEncodedString(unicode, serverenc, "strict");
! if (rv == NULL)
! PLy_elog(ERROR, "could not convert Python Unicode object to PostgreSQL server encoding");
return rv;
}
--- 61,106 ----
PyObject *
PLyUnicode_Bytes(PyObject *unicode)
{
! PyObject *bytes, *rv;
! char *utf8string, *encoded;
! /* first encode the Python unicode object with UTF-8 */
! bytes = PyUnicode_AsUTF8String(unicode);
! if (bytes == NULL)
! PLy_elog(ERROR, "could not convert Python Unicode object to bytes");
!
! utf8string = PyBytes_AsString(bytes);
! if (utf8string == NULL) {
! Py_DECREF(bytes);
! PLy_elog(ERROR, "could not extract bytes from encoded string");
! }
!
! /* then convert to server encoding */
! PG_TRY();
{
! encoded = (char *) pg_do_encoding_conversion(
! (unsigned char *) utf8string,
! strlen(utf8string),
! PG_UTF8,
! GetDatabaseEncoding());
! }
! PG_CATCH();
! {
! Py_DECREF(bytes);
! PG_RE_THROW();
}
+ PG_END_TRY();
! /* finally, build a bytes object in the server encoding */
! rv = PyBytes_FromStringAndSize(encoded, strlen(encoded));
!
! /* if pg_do_encoding_conversion allocated memory, free it now */
! if (utf8string != encoded)
! {
! pfree(encoded);
! }
!
! Py_DECREF(bytes);
return rv;
}
--
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers