bpo-32788: Better error handling in sqlite3. (GH-3723)

Propagate unexpected errors (like MemoryError and KeyboardInterrupt) to user.
This commit is contained in:
Serhiy Storchaka 2018-12-10 16:06:08 +02:00 committed by GitHub
parent dffccc6b59
commit fc662ac332
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 154 additions and 122 deletions

View file

@ -94,40 +94,47 @@ static void pysqlite_cursor_dealloc(pysqlite_Cursor* self)
Py_TYPE(self)->tp_free((PyObject*)self);
}
PyObject* _pysqlite_get_converter(PyObject* key)
static PyObject *
_pysqlite_get_converter(const char *keystr, Py_ssize_t keylen)
{
PyObject* upcase_key;
PyObject* retval;
PyObject *key;
PyObject *upcase_key;
PyObject *retval;
_Py_IDENTIFIER(upper);
key = PyUnicode_FromStringAndSize(keystr, keylen);
if (!key) {
return NULL;
}
upcase_key = _PyObject_CallMethodId(key, &PyId_upper, NULL);
Py_DECREF(key);
if (!upcase_key) {
return NULL;
}
retval = PyDict_GetItem(_pysqlite_converters, upcase_key);
retval = PyDict_GetItemWithError(_pysqlite_converters, upcase_key);
Py_DECREF(upcase_key);
return retval;
}
int pysqlite_build_row_cast_map(pysqlite_Cursor* self)
static int
pysqlite_build_row_cast_map(pysqlite_Cursor* self)
{
int i;
const char* type_start = (const char*)-1;
const char* pos;
const char* colname;
const char* decltype;
PyObject* py_decltype;
PyObject* converter;
PyObject* key;
if (!self->connection->detect_types) {
return 0;
}
Py_XSETREF(self->row_cast_map, PyList_New(0));
if (!self->row_cast_map) {
return -1;
}
for (i = 0; i < sqlite3_column_count(self->statement->st); i++) {
converter = NULL;
@ -135,20 +142,17 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self)
if (self->connection->detect_types & PARSE_COLNAMES) {
colname = sqlite3_column_name(self->statement->st, i);
if (colname) {
const char *type_start = NULL;
for (pos = colname; *pos != 0; pos++) {
if (*pos == '[') {
type_start = pos + 1;
} else if (*pos == ']' && type_start != (const char*)-1) {
key = PyUnicode_FromStringAndSize(type_start, pos - type_start);
if (!key) {
/* creating a string failed, but it is too complicated
* to propagate the error here, we just assume there is
* no converter and proceed */
break;
}
else if (*pos == ']' && type_start != NULL) {
converter = _pysqlite_get_converter(type_start, pos - type_start);
if (!converter && PyErr_Occurred()) {
Py_CLEAR(self->row_cast_map);
return -1;
}
converter = _pysqlite_get_converter(key);
Py_DECREF(key);
break;
}
}
@ -164,16 +168,14 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self)
* 'NUMBER(10)' to be treated as 'NUMBER', for example.
* In other words, it will work as people expect it to work.*/
if (*pos == ' ' || *pos == '(' || *pos == 0) {
py_decltype = PyUnicode_FromStringAndSize(decltype, pos - decltype);
if (!py_decltype) {
converter = _pysqlite_get_converter(decltype, pos - decltype);
if (!converter && PyErr_Occurred()) {
Py_CLEAR(self->row_cast_map);
return -1;
}
break;
}
}
converter = _pysqlite_get_converter(py_decltype);
Py_DECREF(py_decltype);
}
}
@ -182,11 +184,7 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self)
}
if (PyList_Append(self->row_cast_map, converter) != 0) {
if (converter != Py_None) {
Py_DECREF(converter);
}
Py_CLEAR(self->row_cast_map);
return -1;
}
}
@ -194,7 +192,8 @@ int pysqlite_build_row_cast_map(pysqlite_Cursor* self)
return 0;
}
PyObject* _pysqlite_build_column_name(const char* colname)
static PyObject *
_pysqlite_build_column_name(const char* colname)
{
const char* pos;
@ -218,7 +217,8 @@ PyObject* _pysqlite_build_column_name(const char* colname)
* Precondidition:
* - sqlite3_step() has been called before and it returned SQLITE_ROW.
*/
PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
static PyObject *
_pysqlite_fetch_one_row(pysqlite_Cursor* self)
{
int i, numcols;
PyObject* row;
@ -227,12 +227,10 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
PyObject* converter;
PyObject* converted;
Py_ssize_t nbytes;
PyObject* buffer;
const char* val_str;
char buf[200];
const char* colname;
PyObject* buf_bytes;
PyObject* error_obj;
PyObject* error_msg;
if (self->reset) {
PyErr_SetString(pysqlite_InterfaceError, errmsg_fetch_across_rollback);
@ -248,13 +246,13 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
return NULL;
for (i = 0; i < numcols; i++) {
if (self->connection->detect_types) {
assert(self->row_cast_map != NULL);
converter = PyList_GetItem(self->row_cast_map, i);
if (!converter) {
converter = Py_None;
}
} else {
if (self->connection->detect_types
&& self->row_cast_map != NULL
&& i < PyList_GET_SIZE(self->row_cast_map))
{
converter = PyList_GET_ITEM(self->row_cast_map, i);
}
else {
converter = Py_None;
}
@ -270,8 +268,6 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
goto error;
converted = PyObject_CallFunction(converter, "O", item);
Py_DECREF(item);
if (!converted)
break;
}
} else {
Py_BEGIN_ALLOW_THREADS
@ -289,7 +285,7 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
nbytes = sqlite3_column_bytes(self->statement->st, i);
if (self->connection->text_factory == (PyObject*)&PyUnicode_Type) {
converted = PyUnicode_FromStringAndSize(val_str, nbytes);
if (!converted) {
if (!converted && PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)) {
PyErr_Clear();
colname = sqlite3_column_name(self->statement->st, i);
if (!colname) {
@ -297,18 +293,12 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
}
PyOS_snprintf(buf, sizeof(buf) - 1, "Could not decode to UTF-8 column '%s' with text '%s'",
colname , val_str);
buf_bytes = PyByteArray_FromStringAndSize(buf, strlen(buf));
if (!buf_bytes) {
error_msg = PyUnicode_Decode(buf, strlen(buf), "ascii", "replace");
if (!error_msg) {
PyErr_SetString(pysqlite_OperationalError, "Could not decode to UTF-8");
} else {
error_obj = PyUnicode_FromEncodedObject(buf_bytes, "ascii", "replace");
if (!error_obj) {
PyErr_SetString(pysqlite_OperationalError, "Could not decode to UTF-8");
} else {
PyErr_SetObject(pysqlite_OperationalError, error_obj);
Py_DECREF(error_obj);
}
Py_DECREF(buf_bytes);
PyErr_SetObject(pysqlite_OperationalError, error_msg);
Py_DECREF(error_msg);
}
}
} else if (self->connection->text_factory == (PyObject*)&PyBytes_Type) {
@ -321,20 +311,15 @@ PyObject* _pysqlite_fetch_one_row(pysqlite_Cursor* self)
} else {
/* coltype == SQLITE_BLOB */
nbytes = sqlite3_column_bytes(self->statement->st, i);
buffer = PyBytes_FromStringAndSize(
converted = PyBytes_FromStringAndSize(
sqlite3_column_blob(self->statement->st, i), nbytes);
if (!buffer)
break;
converted = buffer;
}
}
if (converted) {
PyTuple_SetItem(row, i, converted);
} else {
Py_INCREF(Py_None);
PyTuple_SetItem(row, i, Py_None);
if (!converted) {
goto error;
}
PyTuple_SetItem(row, i, converted);
}
if (PyErr_Occurred())
@ -372,7 +357,8 @@ static int check_cursor(pysqlite_Cursor* cur)
return pysqlite_check_thread(cur->connection) && pysqlite_check_connection(cur->connection);
}
PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
static PyObject *
_pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject* args)
{
PyObject* operation;
PyObject* parameters_list = NULL;
@ -542,7 +528,7 @@ PyObject* _pysqlite_query_execute(pysqlite_Cursor* self, int multiple, PyObject*
}
if (pysqlite_build_row_cast_map(self) != 0) {
PyErr_SetString(pysqlite_OperationalError, "Error while building row_cast_map");
_PyErr_FormatFromCause(pysqlite_OperationalError, "Error while building row_cast_map");
goto error;
}
@ -631,7 +617,8 @@ PyObject* pysqlite_cursor_executemany(pysqlite_Cursor* self, PyObject* args)
return _pysqlite_query_execute(self, 1, args);
}
PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
static PyObject *
pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
{
PyObject* script_obj;
PyObject* script_str = NULL;
@ -718,12 +705,6 @@ PyObject* pysqlite_cursor_executescript(pysqlite_Cursor* self, PyObject* args)
}
}
PyObject* pysqlite_cursor_getiter(pysqlite_Cursor *self)
{
Py_INCREF(self);
return (PyObject*)self;
}
PyObject* pysqlite_cursor_iternext(pysqlite_Cursor *self)
{
PyObject* next_row_tuple;
@ -961,7 +942,7 @@ PyTypeObject pysqlite_CursorType = {
0, /* tp_clear */
0, /* tp_richcompare */
offsetof(pysqlite_Cursor, in_weakreflist), /* tp_weaklistoffset */
(getiterfunc)pysqlite_cursor_getiter, /* tp_iter */
PyObject_SelfIter, /* tp_iter */
(iternextfunc)pysqlite_cursor_iternext, /* tp_iternext */
cursor_methods, /* tp_methods */
cursor_members, /* tp_members */