diff -r 1c38457da5a1 Lib/sqlite3/test/regression.py --- a/Lib/sqlite3/test/regression.py Thu Aug 25 21:12:16 2016 -0700 +++ b/Lib/sqlite3/test/regression.py Fri Aug 26 22:33:40 2016 +0800 @@ -147,10 +147,23 @@ def CheckSetIsolationLevel(self): """ - See issue 3312. + See issue 27861. """ + class CustomStr(str): + def __del__(self): + con.isolation_level = "" + levels = ["", "DEFERRED", "IMMEDIATE", "EXCLUSIVE"] + con = sqlite.connect(":memory:") - setattr(con, "isolation_level", "\xe9") + setattr(con, "isolation_level", None) + for level in levels: + setattr(con, "isolation_level", level) + setattr(con, "isolation_level", level.lower()) + setattr(con, "isolation_level", level.capitalize()) + setattr(con, "isolation_level", CustomStr(level)) + self.assertRaises(TypeError, setattr, con, "isolation_level", 1) + self.assertRaises(TypeError, setattr, con, "isolation_level", b'abc') + self.assertRaises(ValueError, setattr, con, "isolation_level", "abc") def CheckCursorConstructorCallCheck(self): """ diff -r 1c38457da5a1 Modules/_sqlite/connection.c --- a/Modules/_sqlite/connection.c Thu Aug 25 21:12:16 2016 -0700 +++ b/Modules/_sqlite/connection.c Fri Aug 26 22:33:40 2016 +0800 @@ -43,6 +43,8 @@ _Py_IDENTIFIER(cursor); +static const char *isolation_levels[] = {"", "DEFERRED", "IMMEDIATE", "EXCLUSIVE", NULL}; + static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level); static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self); @@ -1171,7 +1173,7 @@ PyObject* begin_statement; static PyObject* begin_word; - Py_XDECREF(self->isolation_level); + Py_CLEAR(self->isolation_level); if (self->begin_statement) { PyMem_Free(self->begin_statement); @@ -1190,8 +1192,34 @@ self->inTransaction = 0; } else { - const char *statement; + const char *statement, **candidate; + PyObject *uppercase_level; Py_ssize_t size; + _Py_IDENTIFIER(upper); + + if (!PyUnicode_Check(isolation_level)) { + PyErr_Format(PyExc_TypeError, + "isolation_level must be a string or None, not %s", + Py_TYPE(isolation_level)->tp_name); + return -1; + } + + uppercase_level = _PyObject_CallMethodId(isolation_level, + &PyId_upper, ""); + if (!uppercase_level) { + return -1; + } + for (candidate = isolation_levels; *candidate; candidate++) { + if (PyUnicode_CompareWithASCIIString(uppercase_level, + *candidate) == 0) + break; + } + Py_DECREF(uppercase_level); + if (!*candidate) { + PyErr_SetString(PyExc_ValueError, + "invalid value for isolation_level"); + return -1; + } Py_INCREF(isolation_level); self->isolation_level = isolation_level;