mirror of
https://github.com/python/cpython.git
synced 2025-11-01 18:51:43 +00:00
bpo-44859: Improve error handling in sqlite3 and and raise more accurate exceptions. (GH-27654)
* MemoryError is now raised instead of sqlite3.Warning when memory is not enough for encoding a statement to UTF-8 in Connection.__call__() and Cursor.execute(). * UnicodEncodeError is now raised instead of sqlite3.Warning when the statement contains surrogate characters in Connection.__call__() and Cursor.execute(). * TypeError is now raised instead of ValueError for non-string script argument in Cursor.executescript(). * ValueError is now raised for script containing the null character instead of truncating it in Cursor.executescript(). * Correctly handle exceptions raised when getting boolean value of the result of the progress handler. * Add many tests covering different corner cases. Co-authored-by: Erlend Egeberg Aasland <erlend.aasland@innova.no>
This commit is contained in:
parent
ebecffdb6d
commit
0eec6276fd
10 changed files with 226 additions and 52 deletions
|
|
@ -119,6 +119,35 @@ PyDoc_STRVAR(pysqlite_cursor_executescript__doc__,
|
|||
#define PYSQLITE_CURSOR_EXECUTESCRIPT_METHODDEF \
|
||||
{"executescript", (PyCFunction)pysqlite_cursor_executescript, METH_O, pysqlite_cursor_executescript__doc__},
|
||||
|
||||
static PyObject *
|
||||
pysqlite_cursor_executescript_impl(pysqlite_Cursor *self,
|
||||
const char *sql_script);
|
||||
|
||||
static PyObject *
|
||||
pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *arg)
|
||||
{
|
||||
PyObject *return_value = NULL;
|
||||
const char *sql_script;
|
||||
|
||||
if (!PyUnicode_Check(arg)) {
|
||||
_PyArg_BadArgument("executescript", "argument", "str", arg);
|
||||
goto exit;
|
||||
}
|
||||
Py_ssize_t sql_script_length;
|
||||
sql_script = PyUnicode_AsUTF8AndSize(arg, &sql_script_length);
|
||||
if (sql_script == NULL) {
|
||||
goto exit;
|
||||
}
|
||||
if (strlen(sql_script) != (size_t)sql_script_length) {
|
||||
PyErr_SetString(PyExc_ValueError, "embedded null character");
|
||||
goto exit;
|
||||
}
|
||||
return_value = pysqlite_cursor_executescript_impl(self, sql_script);
|
||||
|
||||
exit:
|
||||
return return_value;
|
||||
}
|
||||
|
||||
PyDoc_STRVAR(pysqlite_cursor_fetchone__doc__,
|
||||
"fetchone($self, /)\n"
|
||||
"--\n"
|
||||
|
|
@ -270,4 +299,4 @@ pysqlite_cursor_close(pysqlite_Cursor *self, PyTypeObject *cls, PyObject *const
|
|||
exit:
|
||||
return return_value;
|
||||
}
|
||||
/*[clinic end generated code: output=7b216aba2439f5cf input=a9049054013a1b77]*/
|
||||
/*[clinic end generated code: output=ace31a7481aa3f41 input=a9049054013a1b77]*/
|
||||
|
|
|
|||
|
|
@ -997,6 +997,14 @@ static int _progress_handler(void* user_arg)
|
|||
ret = _PyObject_CallNoArg((PyObject*)user_arg);
|
||||
|
||||
if (!ret) {
|
||||
/* abort query if error occurred */
|
||||
rc = -1;
|
||||
}
|
||||
else {
|
||||
rc = PyObject_IsTrue(ret);
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
if (rc < 0) {
|
||||
pysqlite_state *state = pysqlite_get_state(NULL);
|
||||
if (state->enable_callback_tracebacks) {
|
||||
PyErr_Print();
|
||||
|
|
@ -1004,12 +1012,6 @@ static int _progress_handler(void* user_arg)
|
|||
else {
|
||||
PyErr_Clear();
|
||||
}
|
||||
|
||||
/* abort query if error occurred */
|
||||
rc = 1;
|
||||
} else {
|
||||
rc = (int)PyObject_IsTrue(ret);
|
||||
Py_DECREF(ret);
|
||||
}
|
||||
|
||||
PyGILState_Release(gilstate);
|
||||
|
|
|
|||
|
|
@ -728,21 +728,21 @@ pysqlite_cursor_executemany_impl(pysqlite_Cursor *self, PyObject *sql,
|
|||
/*[clinic input]
|
||||
_sqlite3.Cursor.executescript as pysqlite_cursor_executescript
|
||||
|
||||
sql_script as script_obj: object
|
||||
sql_script: str
|
||||
/
|
||||
|
||||
Executes multiple SQL statements at once. Non-standard.
|
||||
[clinic start generated code]*/
|
||||
|
||||
static PyObject *
|
||||
pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
|
||||
/*[clinic end generated code: output=115a8132b0f200fe input=ba3ec59df205e362]*/
|
||||
pysqlite_cursor_executescript_impl(pysqlite_Cursor *self,
|
||||
const char *sql_script)
|
||||
/*[clinic end generated code: output=8fd726dde1c65164 input=1ac0693dc8db02a8]*/
|
||||
{
|
||||
_Py_IDENTIFIER(commit);
|
||||
const char* script_cstr;
|
||||
sqlite3_stmt* statement;
|
||||
int rc;
|
||||
Py_ssize_t sql_len;
|
||||
size_t sql_len;
|
||||
PyObject* result;
|
||||
|
||||
if (!check_cursor(self)) {
|
||||
|
|
@ -751,21 +751,12 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
|
|||
|
||||
self->reset = 0;
|
||||
|
||||
if (PyUnicode_Check(script_obj)) {
|
||||
script_cstr = PyUnicode_AsUTF8AndSize(script_obj, &sql_len);
|
||||
if (!script_cstr) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int max_length = sqlite3_limit(self->connection->db,
|
||||
SQLITE_LIMIT_LENGTH, -1);
|
||||
if (sql_len >= max_length) {
|
||||
PyErr_SetString(self->connection->DataError,
|
||||
"query string is too large");
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
PyErr_SetString(PyExc_ValueError, "script argument must be unicode.");
|
||||
sql_len = strlen(sql_script);
|
||||
int max_length = sqlite3_limit(self->connection->db,
|
||||
SQLITE_LIMIT_LENGTH, -1);
|
||||
if (sql_len >= (unsigned)max_length) {
|
||||
PyErr_SetString(self->connection->DataError,
|
||||
"query string is too large");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
@ -782,7 +773,7 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
|
|||
|
||||
Py_BEGIN_ALLOW_THREADS
|
||||
rc = sqlite3_prepare_v2(self->connection->db,
|
||||
script_cstr,
|
||||
sql_script,
|
||||
(int)sql_len + 1,
|
||||
&statement,
|
||||
&tail);
|
||||
|
|
@ -816,8 +807,8 @@ pysqlite_cursor_executescript(pysqlite_Cursor *self, PyObject *script_obj)
|
|||
if (*tail == (char)0) {
|
||||
break;
|
||||
}
|
||||
sql_len -= (tail - script_cstr);
|
||||
script_cstr = tail;
|
||||
sql_len -= (tail - sql_script);
|
||||
sql_script = tail;
|
||||
}
|
||||
|
||||
error:
|
||||
|
|
|
|||
|
|
@ -56,9 +56,6 @@ pysqlite_statement_create(pysqlite_Connection *connection, PyObject *sql)
|
|||
Py_ssize_t size;
|
||||
const char *sql_cstr = PyUnicode_AsUTF8AndSize(sql, &size);
|
||||
if (sql_cstr == NULL) {
|
||||
PyErr_Format(connection->Warning,
|
||||
"SQL is of wrong type ('%s'). Must be string.",
|
||||
Py_TYPE(sql)->tp_name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue