diff options
author | Gerhard Häring <gh@ghaering.de> | 2010-03-05 15:20:03 (GMT) |
---|---|---|
committer | Gerhard Häring <gh@ghaering.de> | 2010-03-05 15:20:03 (GMT) |
commit | f9cee224461273307ca9f8a0e690a527496534ab (patch) | |
tree | c12745138703eba02cc59f892cf9f19db6cd7ff5 /Modules/_sqlite/connection.c | |
parent | 06dbff3b1f16dc232df0190cfed4b3af81aecda3 (diff) | |
download | cpython-f9cee224461273307ca9f8a0e690a527496534ab.zip cpython-f9cee224461273307ca9f8a0e690a527496534ab.tar.gz cpython-f9cee224461273307ca9f8a0e690a527496534ab.tar.bz2 |
Merged new pysqlite version 2.6.0 from trunk.
Diffstat (limited to 'Modules/_sqlite/connection.c')
-rw-r--r-- | Modules/_sqlite/connection.c | 206 |
1 files changed, 190 insertions, 16 deletions
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index a3170f3..5738e21 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -1,6 +1,6 @@ /* connection.c - the connection type * - * Copyright (C) 2004-2007 Gerhard Häring <gh@ghaering.de> + * Copyright (C) 2004-2010 Gerhard Häring <gh@ghaering.de> * * This file is part of pysqlite. * @@ -35,7 +35,14 @@ #define ACTION_FINALIZE 1 #define ACTION_RESET 2 +#if SQLITE_VERSION_NUMBER >= 3003008 +#ifndef SQLITE_OMIT_LOAD_EXTENSION +#define HAVE_LOAD_EXTENSION +#endif +#endif + static int pysqlite_connection_set_isolation_level(pysqlite_Connection* self, PyObject* isolation_level); +static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self); static void _sqlite3_result_error(sqlite3_context* ctx, const char* errmsg, int len) @@ -69,10 +76,13 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject return -1; } + self->initialized = 1; + self->begin_statement = NULL; self->statement_cache = NULL; self->statements = NULL; + self->cursors = NULL; Py_INCREF(Py_None); self->row_factory = Py_None; @@ -106,11 +116,15 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject return -1; } + self->created_statements = 0; + self->created_cursors = 0; + + /* Create lists of weak references to statements/cursors */ self->statements = PyList_New(0); - if (!self->statements) { + self->cursors = PyList_New(0); + if (!self->statements || !self->cursors) { 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 @@ -174,11 +188,12 @@ void pysqlite_flush_statement_cache(pysqlite_Connection* self) } /* action in (ACTION_RESET, ACTION_FINALIZE) */ -void pysqlite_do_all_statements(pysqlite_Connection* self, int action) +void pysqlite_do_all_statements(pysqlite_Connection* self, int action, int reset_cursors) { int i; PyObject* weakref; PyObject* statement; + pysqlite_Cursor* cursor; for (i = 0; i < PyList_Size(self->statements); i++) { weakref = PyList_GetItem(self->statements, i); @@ -191,6 +206,16 @@ void pysqlite_do_all_statements(pysqlite_Connection* self, int action) } } } + + if (reset_cursors) { + for (i = 0; i < PyList_Size(self->cursors); i++) { + weakref = PyList_GetItem(self->cursors, i); + cursor = (pysqlite_Cursor*)PyWeakref_GetObject(weakref); + if ((PyObject*)cursor != Py_None) { + cursor->reset = 1; + } + } + } } void pysqlite_connection_dealloc(pysqlite_Connection* self) @@ -213,17 +238,43 @@ void pysqlite_connection_dealloc(pysqlite_Connection* self) Py_XDECREF(self->text_factory); Py_XDECREF(self->collations); Py_XDECREF(self->statements); + Py_XDECREF(self->cursors); Py_TYPE(self)->tp_free((PyObject*)self); } +/* + * Registers a cursor with the connection. + * + * 0 => error; 1 => ok + */ +int pysqlite_connection_register_cursor(pysqlite_Connection* connection, PyObject* cursor) +{ + PyObject* weakref; + + weakref = PyWeakref_NewRef((PyObject*)cursor, NULL); + if (!weakref) { + goto error; + } + + if (PyList_Append(connection->cursors, weakref) != 0) { + Py_CLEAR(weakref); + goto error; + } + + Py_DECREF(weakref); + + return 1; +error: + return 0; +} + PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = {"factory", NULL, NULL}; PyObject* factory = NULL; PyObject* cursor; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O", kwlist, &factory)) { return NULL; @@ -239,6 +290,8 @@ PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args, cursor = PyObject_CallFunction(factory, "O", self); + _pysqlite_drop_unused_cursor_references(self); + if (cursor && self->row_factory != Py_None) { Py_XDECREF(((pysqlite_Cursor*)cursor)->row_factory); Py_INCREF(self->row_factory); @@ -256,7 +309,7 @@ PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args) return NULL; } - pysqlite_do_all_statements(self, ACTION_FINALIZE); + pysqlite_do_all_statements(self, ACTION_FINALIZE, 1); if (self->db) { Py_BEGIN_ALLOW_THREADS @@ -282,6 +335,11 @@ PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args) */ int pysqlite_check_connection(pysqlite_Connection* con) { + if (!con->initialized) { + PyErr_SetString(pysqlite_ProgrammingError, "Base Connection.__init__ not called."); + return 0; + } + if (!con->db) { PyErr_SetString(pysqlite_ProgrammingError, "Cannot operate on a closed database."); return 0; @@ -340,6 +398,8 @@ PyObject* pysqlite_connection_commit(pysqlite_Connection* self, PyObject* args) } if (self->inTransaction) { + pysqlite_do_all_statements(self, ACTION_RESET, 0); + Py_BEGIN_ALLOW_THREADS rc = sqlite3_prepare(self->db, "COMMIT", -1, &statement, &tail); Py_END_ALLOW_THREADS @@ -384,7 +444,7 @@ PyObject* pysqlite_connection_rollback(pysqlite_Connection* self, PyObject* args } if (self->inTransaction) { - pysqlite_do_all_statements(self, ACTION_RESET); + pysqlite_do_all_statements(self, ACTION_RESET, 1); Py_BEGIN_ALLOW_THREADS rc = sqlite3_prepare(self->db, "ROLLBACK", -1, &statement, &tail); @@ -649,7 +709,7 @@ error: #endif } -void _pysqlite_drop_unused_statement_references(pysqlite_Connection* self) +static void _pysqlite_drop_unused_statement_references(pysqlite_Connection* self) { PyObject* new_list; PyObject* weakref; @@ -681,6 +741,38 @@ void _pysqlite_drop_unused_statement_references(pysqlite_Connection* self) self->statements = new_list; } +static void _pysqlite_drop_unused_cursor_references(pysqlite_Connection* self) +{ + PyObject* new_list; + PyObject* weakref; + int i; + + /* we only need to do this once in a while */ + if (self->created_cursors++ < 200) { + return; + } + + self->created_cursors = 0; + + new_list = PyList_New(0); + if (!new_list) { + return; + } + + for (i = 0; i < PyList_Size(self->cursors); i++) { + weakref = PyList_GetItem(self->cursors, i); + if (PyWeakref_GetObject(weakref) != Py_None) { + if (PyList_Append(new_list, weakref) != 0) { + Py_DECREF(new_list); + return; + } + } + } + + Py_DECREF(self->cursors); + self->cursors = new_list; +} + PyObject* pysqlite_connection_create_function(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = {"name", "narg", "func", NULL, NULL}; @@ -690,6 +782,10 @@ PyObject* pysqlite_connection_create_function(pysqlite_Connection* self, PyObjec int narg; int rc; + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO", kwlist, &name, &narg, &func)) { @@ -703,7 +799,8 @@ PyObject* pysqlite_connection_create_function(pysqlite_Connection* self, PyObjec PyErr_SetString(pysqlite_OperationalError, "Error creating function"); return NULL; } else { - PyDict_SetItem(self->function_pinboard, func, Py_None); + if (PyDict_SetItem(self->function_pinboard, func, Py_None) == -1) + return NULL; Py_INCREF(Py_None); return Py_None; @@ -719,6 +816,10 @@ PyObject* pysqlite_connection_create_aggregate(pysqlite_Connection* self, PyObje static char *kwlist[] = { "name", "n_arg", "aggregate_class", NULL }; int rc; + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "siO:create_aggregate", kwlist, &name, &n_arg, &aggregate_class)) { return NULL; @@ -730,7 +831,8 @@ PyObject* pysqlite_connection_create_aggregate(pysqlite_Connection* self, PyObje PyErr_SetString(pysqlite_OperationalError, "Error creating aggregate"); return NULL; } else { - PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None); + if (PyDict_SetItem(self->function_pinboard, aggregate_class, Py_None) == -1) + return NULL; Py_INCREF(Py_None); return Py_None; @@ -802,13 +904,17 @@ static int _progress_handler(void* user_arg) return rc; } -PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) +static PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) { PyObject* authorizer_cb; static char *kwlist[] = { "authorizer_callback", NULL }; int rc; + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_authorizer", kwlist, &authorizer_cb)) { return NULL; @@ -820,20 +926,25 @@ PyObject* pysqlite_connection_set_authorizer(pysqlite_Connection* self, PyObject PyErr_SetString(pysqlite_OperationalError, "Error setting authorizer callback"); return NULL; } else { - PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None); + if (PyDict_SetItem(self->function_pinboard, authorizer_cb, Py_None) == -1) + return NULL; Py_INCREF(Py_None); return Py_None; } } -PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) +static PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) { PyObject* progress_handler; int n; static char *kwlist[] = { "progress_handler", "n", NULL }; + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "Oi:set_progress_handler", kwlist, &progress_handler, &n)) { return NULL; @@ -844,13 +955,64 @@ PyObject* pysqlite_connection_set_progress_handler(pysqlite_Connection* self, Py sqlite3_progress_handler(self->db, 0, 0, (void*)0); } else { sqlite3_progress_handler(self->db, n, _progress_handler, progress_handler); - PyDict_SetItem(self->function_pinboard, progress_handler, Py_None); + if (PyDict_SetItem(self->function_pinboard, progress_handler, Py_None) == -1) + return NULL; } Py_INCREF(Py_None); return Py_None; } +#ifdef HAVE_LOAD_EXTENSION +static PyObject* pysqlite_enable_load_extension(pysqlite_Connection* self, PyObject* args) +{ + int rc; + int onoff; + + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + + if (!PyArg_ParseTuple(args, "i", &onoff)) { + return NULL; + } + + rc = sqlite3_enable_load_extension(self->db, onoff); + + if (rc != SQLITE_OK) { + PyErr_SetString(pysqlite_OperationalError, "Error enabling load extension"); + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +} + +static PyObject* pysqlite_load_extension(pysqlite_Connection* self, PyObject* args) +{ + int rc; + char* extension_name; + char* errmsg; + + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + + if (!PyArg_ParseTuple(args, "s", &extension_name)) { + return NULL; + } + + rc = sqlite3_load_extension(self->db, extension_name, 0, &errmsg); + if (rc != 0) { + PyErr_SetString(pysqlite_OperationalError, errmsg); + return NULL; + } else { + Py_INCREF(Py_None); + return Py_None; + } +} +#endif + int pysqlite_check_thread(pysqlite_Connection* self) { #ifdef WITH_THREAD @@ -948,6 +1110,10 @@ PyObject* pysqlite_connection_call(pysqlite_Connection* self, PyObject* args, Py PyObject* weakref; int rc; + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + if (!PyArg_ParseTuple(args, "O", &sql)) { return NULL; } @@ -1237,9 +1403,11 @@ pysqlite_connection_create_collation(pysqlite_Connection* self, PyObject* args) } if (callable != Py_None) { - PyDict_SetItem(self->collations, uppercase_name, callable); + if (PyDict_SetItem(self->collations, uppercase_name, callable) == -1) + goto finally; } else { - PyDict_DelItem(self->collations, uppercase_name); + if (PyDict_DelItem(self->collations, uppercase_name) == -1) + goto finally; } rc = sqlite3_create_collation(self->db, @@ -1327,6 +1495,12 @@ static PyMethodDef connection_methods[] = { PyDoc_STR("Creates a new aggregate. Non-standard.")}, {"set_authorizer", (PyCFunction)pysqlite_connection_set_authorizer, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Sets authorizer callback. Non-standard.")}, + #ifdef HAVE_LOAD_EXTENSION + {"enable_load_extension", (PyCFunction)pysqlite_enable_load_extension, METH_VARARGS, + PyDoc_STR("Enable dynamic loading of SQLite extension modules. Non-standard.")}, + {"load_extension", (PyCFunction)pysqlite_load_extension, METH_VARARGS, + PyDoc_STR("Load SQLite extension module. Non-standard.")}, + #endif {"set_progress_handler", (PyCFunction)pysqlite_connection_set_progress_handler, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Sets progress handler callback. Non-standard.")}, {"execute", (PyCFunction)pysqlite_connection_execute, METH_VARARGS, |