Merge enhancements from pysqlite3, errorcode/name and blob i/o.

This commit is contained in:
Charles Leifer 2019-08-09 11:00:40 -05:00
parent 9109f9faf1
commit a524fd33bc
10 changed files with 1168 additions and 24 deletions

View file

@ -27,6 +27,7 @@
#include "connection.h"
#include "statement.h"
#include "cursor.h"
#include "blob.h"
#include "prepare_protocol.h"
#include "util.h"
@ -114,6 +115,7 @@ int pysqlite_connection_init(pysqlite_Connection* self, PyObject* args, PyObject
Py_CLEAR(self->statement_cache);
Py_CLEAR(self->statements);
Py_CLEAR(self->cursors);
Py_CLEAR(self->blobs);
Py_INCREF(Py_None);
Py_XSETREF(self->row_factory, Py_None);
@ -162,10 +164,11 @@ 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;
}
@ -261,6 +264,7 @@ void pysqlite_connection_dealloc(pysqlite_Connection* self)
Py_XDECREF(self->collations);
Py_XDECREF(self->statements);
Py_XDECREF(self->cursors);
Py_XDECREF(self->blobs);
Py_TYPE(self)->tp_free((PyObject*)self);
}
@ -331,6 +335,84 @@ PyObject* pysqlite_connection_cursor(pysqlite_Connection* self, PyObject* args,
return cursor;
}
PyObject* pysqlite_connection_blob(pysqlite_Connection *self, PyObject *args,
PyObject *kwargs)
{
static char *kwlist[] = {"table", "column", "row", "readonly",
"dbname", NULL, NULL};
int rc;
const char *dbname = "main", *table, *column;
long long row;
int readonly = 0;
sqlite3_blob *blob;
pysqlite_Blob *pyblob = NULL;
PyObject *weakref;
if (!PyArg_ParseTupleAndKeywords(args, kwargs, "ssL|ps", kwlist,
&table, &column, &row, &readonly,
&dbname)) {
return NULL;
}
Py_BEGIN_ALLOW_THREADS
rc = sqlite3_blob_open(self->db, dbname, table, column, row,
!readonly, &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(weakref);
Py_CLEAR(pyblob);
goto error;
}
Py_DECREF(weakref);
return (PyObject*)pyblob;
error:
Py_BEGIN_ALLOW_THREADS
sqlite3_blob_close(blob);
Py_END_ALLOW_THREADS
return NULL;
}
static void pysqlite_close_all_blobs(pysqlite_Connection *self)
{
int i;
PyObject *weakref;
PyObject *blob;
for (i = 0; i < PyList_GET_SIZE(self->blobs); i++) {
weakref = PyList_GET_ITEM(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)
{
int rc;
@ -341,6 +423,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) {
rc = SQLITE3_CLOSE(self->db);
@ -1875,6 +1959,8 @@ static PyGetSetDef connection_getset[] = {
static PyMethodDef connection_methods[] = {
{"cursor", (PyCFunction)(void(*)(void))pysqlite_connection_cursor, METH_VARARGS|METH_KEYWORDS,
PyDoc_STR("Return a cursor for the connection.")},
{"open_blob", (PyCFunction)pysqlite_connection_blob, METH_VARARGS|METH_KEYWORDS,
PyDoc_STR("return a blob object")},
{"close", (PyCFunction)pysqlite_connection_close, METH_NOARGS,
PyDoc_STR("Closes the connection.")},
{"commit", (PyCFunction)pysqlite_connection_commit, METH_NOARGS,