diff options
Diffstat (limited to 'Modules/_sqlite/connection.c')
-rw-r--r-- | Modules/_sqlite/connection.c | 197 |
1 files changed, 130 insertions, 67 deletions
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index 78aad3799b3..64e43ebcbce 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -56,6 +56,7 @@ int connection_init(Connection* self, PyObject* args, PyObject* kwargs) self->begin_statement = NULL; self->statement_cache = NULL; + self->statements = NULL; Py_INCREF(Py_None); self->row_factory = Py_None; @@ -74,6 +75,9 @@ int connection_init(Connection* self, PyObject* args, PyObject* kwargs) if (!isolation_level) { isolation_level = PyString_FromString(""); + if (!isolation_level) { + return -1; + } } else { Py_INCREF(isolation_level); } @@ -86,6 +90,12 @@ int connection_init(Connection* self, PyObject* args, PyObject* kwargs) return -1; } + self->statements = PyList_New(0); + if (!self->statements) { + return -1; + } + self->created_statements = 0; + /* By default, the Cache class INCREFs the factory in its initializer, and * decrefs it in its deallocator method. Since this would create a circular * reference here, we're breaking it by decrementing self, and telling the @@ -126,6 +136,7 @@ int connection_init(Connection* self, PyObject* args, PyObject* kwargs) return 0; } +/* Empty the entire statement cache of this connection */ void flush_statement_cache(Connection* self) { Node* node; @@ -147,15 +158,16 @@ void flush_statement_cache(Connection* self) void reset_all_statements(Connection* self) { - Node* node; - Statement* statement; - - node = self->statement_cache->first; - - while (node) { - statement = (Statement*)(node->data); - (void)statement_reset(statement); - node = node->next; + int i; + PyObject* weakref; + PyObject* statement; + + for (i = 0; i < PyList_Size(self->statements); i++) { + weakref = PyList_GetItem(self->statements, i); + statement = PyWeakref_GetObject(weakref); + if (statement != Py_None) { + (void)statement_reset((Statement*)statement); + } } } @@ -178,6 +190,7 @@ void connection_dealloc(Connection* self) Py_XDECREF(self->row_factory); Py_XDECREF(self->text_factory); Py_XDECREF(self->collations); + Py_XDECREF(self->statements); self->ob_type->tp_free((PyObject*)self); } @@ -391,7 +404,7 @@ void _set_result(sqlite3_context* context, PyObject* py_val) Py_ssize_t buflen; PyObject* stringval; - if (PyErr_Occurred()) { + if ((!py_val) || PyErr_Occurred()) { /* Errors in callbacks are ignored, and we return NULL */ PyErr_Clear(); sqlite3_result_null(context); @@ -399,21 +412,23 @@ void _set_result(sqlite3_context* context, PyObject* py_val) sqlite3_result_null(context); } else if (PyInt_Check(py_val)) { longval = PyInt_AsLong(py_val); - /* TODO: investigate what to do with range overflows - long vs. long long */ sqlite3_result_int64(context, (PY_LONG_LONG)longval); } else if (PyFloat_Check(py_val)) { sqlite3_result_double(context, PyFloat_AsDouble(py_val)); } else if (PyBuffer_Check(py_val)) { if (PyObject_AsCharBuffer(py_val, &buffer, &buflen) != 0) { PyErr_SetString(PyExc_ValueError, "could not convert BLOB to buffer"); + } else { + sqlite3_result_blob(context, buffer, buflen, SQLITE_TRANSIENT); } - sqlite3_result_blob(context, buffer, buflen, SQLITE_TRANSIENT); } else if (PyString_Check(py_val)) { sqlite3_result_text(context, PyString_AsString(py_val), -1, SQLITE_TRANSIENT); } else if (PyUnicode_Check(py_val)) { stringval = PyUnicode_AsUTF8String(py_val); - sqlite3_result_text(context, PyString_AsString(stringval), -1, SQLITE_TRANSIENT); - Py_DECREF(stringval); + if (stringval) { + sqlite3_result_text(context, PyString_AsString(stringval), -1, SQLITE_TRANSIENT); + Py_DECREF(stringval); + } } else { /* TODO: raise error */ } @@ -450,6 +465,7 @@ PyObject* _build_py_params(sqlite3_context *context, int argc, sqlite3_value** a cur_py_value = PyUnicode_DecodeUTF8(val_str, strlen(val_str), NULL); /* TODO: have a way to show errors here */ if (!cur_py_value) { + PyErr_Clear(); Py_INCREF(Py_None); cur_py_value = Py_None; } @@ -458,10 +474,12 @@ PyObject* _build_py_params(sqlite3_context *context, int argc, sqlite3_value** a buflen = sqlite3_value_bytes(cur_value); cur_py_value = PyBuffer_New(buflen); if (!cur_py_value) { - /* TODO: error */ + break; } if (PyObject_AsWriteBuffer(cur_py_value, &raw_buffer, &buflen)) { - /* TODO: error */ + Py_DECREF(cur_py_value); + cur_py_value = NULL; + break; } memcpy(raw_buffer, sqlite3_value_blob(cur_value), buflen); break; @@ -470,6 +488,12 @@ PyObject* _build_py_params(sqlite3_context *context, int argc, sqlite3_value** a Py_INCREF(Py_None); cur_py_value = Py_None; } + + if (!cur_py_value) { + Py_DECREF(args); + return NULL; + } + PyTuple_SetItem(args, i, cur_py_value); } @@ -481,8 +505,7 @@ void _func_callback(sqlite3_context* context, int argc, sqlite3_value** argv) { PyObject* args; PyObject* py_func; - PyObject* py_retval; - + PyObject* py_retval = NULL; PyGILState_STATE threadstate; @@ -491,9 +514,10 @@ void _func_callback(sqlite3_context* context, int argc, sqlite3_value** argv) py_func = (PyObject*)sqlite3_user_data(context); args = _build_py_params(context, argc, argv); - - py_retval = PyObject_CallObject(py_func, args); - Py_DECREF(args); + if (args) { + py_retval = PyObject_CallObject(py_func, args); + Py_DECREF(args); + } _set_result(context, py_retval); Py_XDECREF(py_retval); @@ -504,10 +528,10 @@ void _func_callback(sqlite3_context* context, int argc, sqlite3_value** argv) static void _step_callback(sqlite3_context *context, int argc, sqlite3_value** params) { PyObject* args; - PyObject* function_result; + PyObject* function_result = NULL; PyObject* aggregate_class; PyObject** aggregate_instance; - PyObject* stepmethod; + PyObject* stepmethod = NULL; PyGILState_STATE threadstate; @@ -520,44 +544,42 @@ static void _step_callback(sqlite3_context *context, int argc, sqlite3_value** p if (*aggregate_instance == 0) { *aggregate_instance = PyObject_CallFunction(aggregate_class, ""); - if (PyErr_Occurred()) - { + if (PyErr_Occurred()) { PyErr_Clear(); *aggregate_instance = 0; - PyGILState_Release(threadstate); - return; + goto error; } } stepmethod = PyObject_GetAttrString(*aggregate_instance, "step"); - if (!stepmethod) - { - PyGILState_Release(threadstate); - return; + if (!stepmethod) { + goto error; } args = _build_py_params(context, argc, params); + if (!args) { + goto error; + } function_result = PyObject_CallObject(stepmethod, args); Py_DECREF(args); - Py_DECREF(stepmethod); - if (function_result == NULL) { + if (!function_result) { PyErr_Clear(); - } else { - Py_DECREF(function_result); } +error: + Py_XDECREF(stepmethod); + Py_XDECREF(function_result); + PyGILState_Release(threadstate); } void _final_callback(sqlite3_context* context) { - PyObject* args; - PyObject* function_result; + PyObject* function_result = NULL; PyObject** aggregate_instance; PyObject* aggregate_class; - PyObject* finalizemethod; PyGILState_STATE threadstate; @@ -570,35 +592,56 @@ void _final_callback(sqlite3_context* context) /* this branch is executed if there was an exception in the aggregate's * __init__ */ - PyGILState_Release(threadstate); - return; + goto error; } - finalizemethod = PyObject_GetAttrString(*aggregate_instance, "finalize"); - - if (!finalizemethod) { - /* - PyErr_SetString(ProgrammingError, "finalize method missing"); - goto error; - */ + function_result = PyObject_CallMethod(*aggregate_instance, "finalize", ""); + if (!function_result) { + PyErr_Clear(); Py_INCREF(Py_None); function_result = Py_None; - } else { - args = PyTuple_New(0); - if (!args) - return; - function_result = PyObject_CallObject(finalizemethod, args); - Py_DECREF(args); - Py_DECREF(finalizemethod); } _set_result(context, function_result); + +error: Py_XDECREF(*aggregate_instance); Py_XDECREF(function_result); PyGILState_Release(threadstate); } +void _drop_unused_statement_references(Connection* self) +{ + PyObject* new_list; + PyObject* weakref; + int i; + + /* we only need to do this once in a while */ + if (self->created_statements++ < 200) { + return; + } + + self->created_statements = 0; + + new_list = PyList_New(0); + if (!new_list) { + return; + } + + for (i = 0; i < PyList_Size(self->statements); i++) { + weakref = PyList_GetItem(self->statements, i); + if (weakref != Py_None) { + if (PyList_Append(new_list, weakref) != 0) { + Py_DECREF(new_list); + return; + } + } + } + + Py_DECREF(self->statements); + self->statements = new_list; +} PyObject* connection_create_function(Connection* self, PyObject* args, PyObject* kwargs) { @@ -617,10 +660,16 @@ PyObject* connection_create_function(Connection* self, PyObject* args, PyObject* rc = sqlite3_create_function(self->db, name, narg, SQLITE_UTF8, (void*)func, _func_callback, NULL, NULL); - PyDict_SetItem(self->function_pinboard, func, Py_None); + if (rc != SQLITE_OK) { + /* Workaround for SQLite bug: no error code or string is available here */ + PyErr_SetString(OperationalError, "Error creating function"); + return NULL; + } else { + PyDict_SetItem(self->function_pinboard, func, Py_None); - Py_INCREF(Py_None); - return Py_None; + Py_INCREF(Py_None); + return Py_None; + } } PyObject* connection_create_aggregate(Connection* self, PyObject* args, PyObject* kwargs) @@ -639,7 +688,8 @@ PyObject* connection_create_aggregate(Connection* self, PyObject* args, PyObject rc = sqlite3_create_function(self->db, name, n_arg, SQLITE_UTF8, (void*)aggregate_class, 0, &_step_callback, &_final_callback); if (rc != SQLITE_OK) { - _seterror(self->db); + /* Workaround for SQLite bug: no error code or string is available here */ + PyErr_SetString(OperationalError, "Error creating aggregate"); return NULL; } else { PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None); @@ -682,7 +732,6 @@ static PyObject* connection_get_total_changes(Connection* self, void* unused) static int connection_set_isolation_level(Connection* self, PyObject* isolation_level) { - PyObject* empty; PyObject* res; PyObject* begin_statement; @@ -697,15 +746,10 @@ static int connection_set_isolation_level(Connection* self, PyObject* isolation_ Py_INCREF(Py_None); self->isolation_level = Py_None; - empty = PyTuple_New(0); - if (!empty) { - return -1; - } - res = connection_commit(self, empty); + res = connection_commit(self, NULL); if (!res) { return -1; } - Py_DECREF(empty); Py_DECREF(res); self->inTransaction = 0; @@ -738,12 +782,15 @@ PyObject* connection_call(Connection* self, PyObject* args, PyObject* kwargs) { PyObject* sql; Statement* statement; + PyObject* weakref; int rc; if (!PyArg_ParseTuple(args, "O", &sql)) { return NULL; } + _drop_unused_statement_references(self); + statement = PyObject_New(Statement, &StatementType); if (!statement) { return NULL; @@ -762,8 +809,24 @@ PyObject* connection_call(Connection* self, PyObject* args, PyObject* kwargs) Py_DECREF(statement); statement = 0; + } else { + weakref = PyWeakref_NewRef((PyObject*)statement, NULL); + if (!weakref) { + Py_DECREF(statement); + statement = 0; + goto error; + } + + if (PyList_Append(self->statements, weakref) != 0) { + Py_DECREF(weakref); + statement = 0; + goto error; + } + + Py_DECREF(weakref); } +error: return (PyObject*)statement; } @@ -983,7 +1046,7 @@ finally: } static char connection_doc[] = -PyDoc_STR("<missing docstring>"); +PyDoc_STR("SQLite database connection object."); static PyGetSetDef connection_getset[] = { {"isolation_level", (getter)connection_get_isolation_level, (setter)connection_set_isolation_level}, @@ -1011,7 +1074,7 @@ static PyMethodDef connection_methods[] = { {"executescript", (PyCFunction)connection_executescript, METH_VARARGS, PyDoc_STR("Executes a multiple SQL statements at once. Non-standard.")}, {"create_collation", (PyCFunction)connection_create_collation, METH_VARARGS, - PyDoc_STR("Creates a collation function.")}, + PyDoc_STR("Creates a collation function. Non-standard.")}, {NULL, NULL} }; |