diff options
author | Erlend Egeberg Aasland <erlend.aasland@innova.no> | 2022-04-15 00:02:56 (GMT) |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-04-15 00:02:56 (GMT) |
commit | ee475430d431814cbb6eb5e8a6c0ae51943349d4 (patch) | |
tree | e9464bb51a6304a77da9461d28564b00689edfc1 /Modules/_sqlite/connection.c | |
parent | c9d41bcd68dbe339396523e931904930a87819b9 (diff) | |
download | cpython-ee475430d431814cbb6eb5e8a6c0ae51943349d4.zip cpython-ee475430d431814cbb6eb5e8a6c0ae51943349d4.tar.gz cpython-ee475430d431814cbb6eb5e8a6c0ae51943349d4.tar.bz2 |
gh-69093: Support basic incremental I/O to blobs in `sqlite3` (GH-30680)
Authored-by: Aviv Palivoda <palaviv@gmail.com>
Co-authored-by: Erlend E. Aasland <erlend.aasland@innova.no>
Co-authored-by: palaviv <palaviv@gmail.com>
Co-authored-by: Kumar Aditya <59607654+kumaraditya303@users.noreply.github.com>
Co-authored-by: Jelle Zijlstra <jelle.zijlstra@gmail.com>
Diffstat (limited to 'Modules/_sqlite/connection.c')
-rw-r--r-- | Modules/_sqlite/connection.c | 87 |
1 files changed, 85 insertions, 2 deletions
diff --git a/Modules/_sqlite/connection.c b/Modules/_sqlite/connection.c index d7c0a9e..85fb128 100644 --- a/Modules/_sqlite/connection.c +++ b/Modules/_sqlite/connection.c @@ -26,6 +26,7 @@ #include "connection.h" #include "statement.h" #include "cursor.h" +#include "blob.h" #include "prepare_protocol.h" #include "util.h" @@ -234,10 +235,17 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, return -1; } - // Create list of weak references to cursors. + /* Create lists of weak references to cursors and blobs */ PyObject *cursors = PyList_New(0); if (cursors == NULL) { - Py_DECREF(statement_cache); + Py_XDECREF(statement_cache); + return -1; + } + + PyObject *blobs = PyList_New(0); + if (blobs == NULL) { + Py_XDECREF(statement_cache); + Py_XDECREF(cursors); return -1; } @@ -250,6 +258,7 @@ pysqlite_connection_init_impl(pysqlite_Connection *self, self->thread_ident = PyThread_get_thread_ident(); self->statement_cache = statement_cache; self->cursors = cursors; + self->blobs = blobs; self->created_cursors = 0; self->row_factory = Py_NewRef(Py_None); self->text_factory = Py_NewRef(&PyUnicode_Type); @@ -291,6 +300,7 @@ connection_traverse(pysqlite_Connection *self, visitproc visit, void *arg) Py_VISIT(Py_TYPE(self)); Py_VISIT(self->statement_cache); Py_VISIT(self->cursors); + Py_VISIT(self->blobs); Py_VISIT(self->row_factory); Py_VISIT(self->text_factory); VISIT_CALLBACK_CONTEXT(self->trace_ctx); @@ -314,6 +324,7 @@ connection_clear(pysqlite_Connection *self) { Py_CLEAR(self->statement_cache); Py_CLEAR(self->cursors); + Py_CLEAR(self->blobs); Py_CLEAR(self->row_factory); Py_CLEAR(self->text_factory); clear_callback_context(self->trace_ctx); @@ -430,6 +441,76 @@ pysqlite_connection_cursor_impl(pysqlite_Connection *self, PyObject *factory) } /*[clinic input] +_sqlite3.Connection.blobopen as blobopen + + table: str + Table name. + column as col: str + Column name. + row: int + Row index. + / + * + readonly: bool(accept={int}) = False + Open the BLOB without write permissions. + name: str = "main" + Database name. + +Open and return a BLOB object. +[clinic start generated code]*/ + +static PyObject * +blobopen_impl(pysqlite_Connection *self, const char *table, const char *col, + int row, int readonly, const char *name) +/*[clinic end generated code: output=0c8e2e58516d0b5c input=1e7052516acfc94d]*/ +{ + if (!pysqlite_check_thread(self) || !pysqlite_check_connection(self)) { + return NULL; + } + + int rc; + sqlite3_blob *blob; + + Py_BEGIN_ALLOW_THREADS + rc = sqlite3_blob_open(self->db, name, table, col, row, !readonly, &blob); + Py_END_ALLOW_THREADS + + if (rc != SQLITE_OK) { + _pysqlite_seterror(self->state, self->db); + return NULL; + } + + pysqlite_Blob *obj = PyObject_GC_New(pysqlite_Blob, self->state->BlobType); + if (obj == NULL) { + goto error; + } + + obj->connection = (pysqlite_Connection *)Py_NewRef(self); + obj->blob = blob; + obj->offset = 0; + obj->in_weakreflist = NULL; + + PyObject_GC_Track(obj); + + // Add our blob to connection blobs list + PyObject *weakref = PyWeakref_NewRef((PyObject *)obj, NULL); + if (weakref == NULL) { + goto error; + } + rc = PyList_Append(self->blobs, weakref); + Py_DECREF(weakref); + if (rc < 0) { + goto error; + } + + return (PyObject *)obj; + +error: + Py_XDECREF(obj); + return NULL; +} + +/*[clinic input] _sqlite3.Connection.close as pysqlite_connection_close Closes the connection. @@ -451,6 +532,7 @@ pysqlite_connection_close_impl(pysqlite_Connection *self) return NULL; } + pysqlite_close_all_blobs(self); Py_CLEAR(self->statement_cache); connection_close(self); @@ -2257,6 +2339,7 @@ static PyMethodDef connection_methods[] = { SERIALIZE_METHODDEF DESERIALIZE_METHODDEF CREATE_WINDOW_FUNCTION_METHODDEF + BLOBOPEN_METHODDEF {NULL, NULL} }; |