Propagate read error messages in COPY FROM

Fix ticket #270.
This commit is contained in:
Daniele Varrazzo 2015-02-08 01:42:21 +00:00
parent 7c5bc1b6cf
commit 66fdaeaf09
3 changed files with 50 additions and 3 deletions

1
NEWS
View File

@ -6,6 +6,7 @@ What's new in psycopg 2.5.5
- Named cursors used as context manager don't swallow the exception on exit - Named cursors used as context manager don't swallow the exception on exit
(:ticket:`#262`). (:ticket:`#262`).
- Propagate read error messages in COPY FROM (:ticket:`#270`).
- PostgreSQL time 24:00 is converted to Python 00:00 (:ticket:`#278`). - PostgreSQL time 24:00 is converted to Python 00:00 (:ticket:`#278`).

View File

@ -1376,9 +1376,27 @@ _pq_copy_in_v3(cursorObject *curs)
res = PQputCopyEnd(curs->conn->pgconn, NULL); res = PQputCopyEnd(curs->conn->pgconn, NULL);
else if (error == 2) else if (error == 2)
res = PQputCopyEnd(curs->conn->pgconn, "error in PQputCopyData() call"); res = PQputCopyEnd(curs->conn->pgconn, "error in PQputCopyData() call");
else else {
/* XXX would be nice to propagate the exception */ char buf[1024];
res = PQputCopyEnd(curs->conn->pgconn, "error in .read() call"); strcpy(buf, "error in .read() call");
if (PyErr_Occurred()) {
PyObject *t, *ex, *tb;
PyErr_Fetch(&t, &ex, &tb);
if (ex) {
PyObject *str;
str = PyObject_Str(ex);
str = psycopg_ensure_bytes(str);
if (str) {
PyOS_snprintf(buf, sizeof(buf),
"error in .read() call: %s %s",
((PyTypeObject *)t)->tp_name, Bytes_AsString(str));
Py_DECREF(str);
}
}
PyErr_Restore(t, ex, tb);
}
res = PQputCopyEnd(curs->conn->pgconn, buf);
}
CLEARPGRES(curs->pgres); CLEARPGRES(curs->pgres);

View File

@ -340,6 +340,34 @@ conn.close()
proc.communicate() proc.communicate()
self.assertEqual(0, proc.returncode) self.assertEqual(0, proc.returncode)
def test_copy_from_propagate_error(self):
class BrokenRead(_base):
def read(self, size):
return 1/0
def readline(self):
return 1/0
curs = self.conn.cursor()
# It seems we cannot do this, but now at least we propagate the error
# self.assertRaises(ZeroDivisionError,
# curs.copy_from, BrokenRead(), "tcopy")
try:
curs.copy_from(BrokenRead(), "tcopy")
except Exception, e:
self.assert_('ZeroDivisionError' in str(e))
def test_copy_to_propagate_error(self):
class BrokenWrite(_base):
def write(self, data):
return 1/0
curs = self.conn.cursor()
curs.execute("insert into tcopy values (10, 'hi')")
self.assertRaises(ZeroDivisionError,
curs.copy_to, BrokenWrite(), "tcopy")
decorate_all_tests(CopyTests, skip_copy_if_green) decorate_all_tests(CopyTests, skip_copy_if_green)