summaryrefslogtreecommitdiffstats
path: root/Modules/_sqlite/connection.c
diff options
context:
space:
mode:
Diffstat (limited to 'Modules/_sqlite/connection.c')
-rw-r--r--Modules/_sqlite/connection.c87
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}
};