From bb9cc1216873604459724860d606283c398ea06b Mon Sep 17 00:00:00 2001 From: Ruben Pollan Date: Thu, 2 Feb 2017 20:25:20 +0100 Subject: [feat] add support for the blob interface Pysqlcipher support for the sqlite blob interface: https://sqlite.org/c3ref/blob_open.html Copying the code from the PR in pysqlite: https://github.com/ghaering/pysqlite/pull/93 --- src/connection.c | 90 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 88 insertions(+), 2 deletions(-) (limited to 'src/connection.c') diff --git a/src/connection.c b/src/connection.c index 7e4e96c..115d15a 100644 --- a/src/connection.c +++ b/src/connection.c @@ -30,6 +30,8 @@ #include "util.h" #include "sqlitecompat.h" +#include "blob.h" + #ifdef PYSQLITE_EXPERIMENTAL #include "backup.h" #endif @@ -91,6 +93,7 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject self->statement_cache = NULL; self->statements = NULL; self->cursors = NULL; + self->blobs = NULL; Py_INCREF(Py_None); self->row_factory = Py_None; @@ -167,10 +170,12 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject self->created_statements = 0; self->created_cursors = 0; - /* Create lists of weak references to statements/cursors */ + /* Create lists of weak references to statements/cursors/blobs */ self->statements = PyList_New(0); self->cursors = PyList_New(0); - if (!self->statements || !self->cursors) { + self->blobs = PyList_New(0); + + if (!self->statements || !self->cursors || !self->blobs) { return -1; } @@ -293,6 +298,7 @@ void pysqlite_connection_dealloc(pysqlite_Connection* self) Py_XDECREF(self->collations); Py_XDECREF(self->statements); Py_XDECREF(self->cursors); + Py_XDECREF(self->blobs); self->ob_type->tp_free((PyObject*)self); } @@ -390,6 +396,82 @@ PyObject* pysqlite_connection_backup(pysqlite_Connection* self, PyObject* args, } #endif +PyObject* pysqlite_connection_blob(pysqlite_Connection* self, PyObject* args, PyObject* kwargs) +{ + static char *kwlist[] = {"table", "column", "row", "flags", "dbname", NULL, NULL}; + int rc; + const char *dbname = "main", *table, *column; + sqlite3_int64 row; + int flags = 0; + sqlite3_blob* blob; + pysqlite_Blob *pyblob=0; + PyObject *weakref; + + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssL|is", kwlist, + &table, &column, &row, &flags, &dbname)) { + return NULL; + } + + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_blob_open(self->db, dbname, table, column, row, flags, &blob); + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { + _pysqlite_seterror(self->db, NULL); + return NULL; + } + + pyblob = PyObject_New(pysqlite_Blob, &pysqlite_BlobType); + if (!pyblob){ + goto error; + } + + rc = pysqlite_blob_init(pyblob, self, blob); + if (rc) { + Py_CLEAR(pyblob); + goto error; + } + + // Add our blob to connection blobs list + weakref=PyWeakref_NewRef((PyObject*)pyblob, NULL); + if (!weakref){ + Py_CLEAR(pyblob); + goto error; + } + if (PyList_Append(self->blobs, weakref) != 0) { + Py_CLEAR(pyblob); + Py_CLEAR(weakref); + goto error; + } + Py_DECREF(weakref); + + return (PyObject*)pyblob; + +error: + Py_BEGIN_ALLOW_THREADS + sqlite3_blob_close(blob); + Py_END_ALLOW_THREADS + return NULL; +} + + +void pysqlite_close_all_blobs(pysqlite_Connection* self) +{ + int i; + PyObject* weakref; + PyObject* blob; + + for (i = 0; i < PyList_Size(self->blobs); i++) { + weakref = PyList_GetItem(self->blobs, i); + blob = PyWeakref_GetObject(weakref); + if (blob != Py_None) { + pysqlite_blob_close((pysqlite_Blob*)blob); + } + } +} + + PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args) { PyObject* ret; @@ -401,6 +483,8 @@ PyObject* pysqlite_connection_close(pysqlite_Connection* self, PyObject* args) pysqlite_do_all_statements(self, ACTION_FINALIZE, 1); + pysqlite_close_all_blobs(self); + if (self->db) { if (self->apsw_connection) { ret = PyObject_CallMethod(self->apsw_connection, "close", ""); @@ -1597,6 +1681,8 @@ static PyMethodDef connection_methods[] = { {"backup", (PyCFunction)pysqlite_connection_backup, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Backup database.")}, #endif + {"blob", (PyCFunction)pysqlite_connection_blob, METH_VARARGS|METH_KEYWORDS, + PyDoc_STR("return a blob object")}, {"cursor", (PyCFunction)pysqlite_connection_cursor, METH_VARARGS|METH_KEYWORDS, PyDoc_STR("Return a cursor for the connection.")}, {"close", (PyCFunction)pysqlite_connection_close, METH_NOARGS, -- cgit v1.2.3