123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617 |
- #include "blob.h"
- #include "util.h"
- #define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self)))
- #include "clinic/blob.c.h"
- #undef clinic_state
- /*[clinic input]
- module _sqlite3
- class _sqlite3.Blob "pysqlite_Blob *" "clinic_state()->BlobType"
- [clinic start generated code]*/
- /*[clinic end generated code: output=da39a3ee5e6b4b0d input=908d3e16a45f8da7]*/
- static void
- close_blob(pysqlite_Blob *self)
- {
- if (self->blob) {
- sqlite3_blob *blob = self->blob;
- self->blob = NULL;
- Py_BEGIN_ALLOW_THREADS
- sqlite3_blob_close(blob);
- Py_END_ALLOW_THREADS
- }
- }
- static int
- blob_traverse(pysqlite_Blob *self, visitproc visit, void *arg)
- {
- Py_VISIT(Py_TYPE(self));
- Py_VISIT(self->connection);
- return 0;
- }
- static int
- blob_clear(pysqlite_Blob *self)
- {
- Py_CLEAR(self->connection);
- return 0;
- }
- static void
- blob_dealloc(pysqlite_Blob *self)
- {
- PyTypeObject *tp = Py_TYPE(self);
- PyObject_GC_UnTrack(self);
- close_blob(self);
- if (self->in_weakreflist != NULL) {
- PyObject_ClearWeakRefs((PyObject*)self);
- }
- tp->tp_clear((PyObject *)self);
- tp->tp_free(self);
- Py_DECREF(tp);
- }
- // Return 1 if the blob object is usable, 0 if not.
- static int
- check_blob(pysqlite_Blob *self)
- {
- if (!pysqlite_check_connection(self->connection) ||
- !pysqlite_check_thread(self->connection)) {
- return 0;
- }
- if (self->blob == NULL) {
- pysqlite_state *state = self->connection->state;
- PyErr_SetString(state->ProgrammingError,
- "Cannot operate on a closed blob.");
- return 0;
- }
- return 1;
- }
- /*[clinic input]
- _sqlite3.Blob.close as blob_close
- Close the blob.
- [clinic start generated code]*/
- static PyObject *
- blob_close_impl(pysqlite_Blob *self)
- /*[clinic end generated code: output=848accc20a138d1b input=7bc178a402a40bd8]*/
- {
- if (!pysqlite_check_connection(self->connection) ||
- !pysqlite_check_thread(self->connection))
- {
- return NULL;
- }
- close_blob(self);
- Py_RETURN_NONE;
- };
- void
- pysqlite_close_all_blobs(pysqlite_Connection *self)
- {
- for (int i = 0; i < PyList_GET_SIZE(self->blobs); i++) {
- PyObject *weakref = PyList_GET_ITEM(self->blobs, i);
- PyObject *blob = PyWeakref_GetObject(weakref);
- if (!Py_IsNone(blob)) {
- close_blob((pysqlite_Blob *)blob);
- }
- }
- }
- static void
- blob_seterror(pysqlite_Blob *self, int rc)
- {
- assert(self->connection != NULL);
- #if SQLITE_VERSION_NUMBER < 3008008
- // SQLite pre 3.8.8 does not set this blob error on the connection
- if (rc == SQLITE_ABORT) {
- PyErr_SetString(self->connection->OperationalError,
- "Cannot operate on an expired blob handle");
- return;
- }
- #endif
- _pysqlite_seterror(self->connection->state, self->connection->db);
- }
- static PyObject *
- read_single(pysqlite_Blob *self, Py_ssize_t offset)
- {
- unsigned char buf = 0;
- int rc;
- Py_BEGIN_ALLOW_THREADS
- rc = sqlite3_blob_read(self->blob, (void *)&buf, 1, (int)offset);
- Py_END_ALLOW_THREADS
- if (rc != SQLITE_OK) {
- blob_seterror(self, rc);
- return NULL;
- }
- return PyLong_FromUnsignedLong((unsigned long)buf);
- }
- static PyObject *
- read_multiple(pysqlite_Blob *self, Py_ssize_t length, Py_ssize_t offset)
- {
- assert(length <= sqlite3_blob_bytes(self->blob));
- assert(offset < sqlite3_blob_bytes(self->blob));
- PyObject *buffer = PyBytes_FromStringAndSize(NULL, length);
- if (buffer == NULL) {
- return NULL;
- }
- char *raw_buffer = PyBytes_AS_STRING(buffer);
- int rc;
- Py_BEGIN_ALLOW_THREADS
- rc = sqlite3_blob_read(self->blob, raw_buffer, (int)length, (int)offset);
- Py_END_ALLOW_THREADS
- if (rc != SQLITE_OK) {
- Py_DECREF(buffer);
- blob_seterror(self, rc);
- return NULL;
- }
- return buffer;
- }
- /*[clinic input]
- _sqlite3.Blob.read as blob_read
- length: int = -1
- Read length in bytes.
- /
- Read data at the current offset position.
- If the end of the blob is reached, the data up to end of file will be returned.
- When length is not specified, or is negative, Blob.read() will read until the
- end of the blob.
- [clinic start generated code]*/
- static PyObject *
- blob_read_impl(pysqlite_Blob *self, int length)
- /*[clinic end generated code: output=1fc99b2541360dde input=f2e4aa4378837250]*/
- {
- if (!check_blob(self)) {
- return NULL;
- }
- /* Make sure we never read past "EOB". Also read the rest of the blob if a
- * negative length is specified. */
- int blob_len = sqlite3_blob_bytes(self->blob);
- int max_read_len = blob_len - self->offset;
- if (length < 0 || length > max_read_len) {
- length = max_read_len;
- }
- assert(length >= 0);
- if (length == 0) {
- return PyBytes_FromStringAndSize(NULL, 0);
- }
- PyObject *buffer = read_multiple(self, length, self->offset);
- if (buffer == NULL) {
- return NULL;
- }
- self->offset += length;
- return buffer;
- };
- static int
- inner_write(pysqlite_Blob *self, const void *buf, Py_ssize_t len,
- Py_ssize_t offset)
- {
- Py_ssize_t blob_len = sqlite3_blob_bytes(self->blob);
- Py_ssize_t remaining_len = blob_len - offset;
- if (len > remaining_len) {
- PyErr_SetString(PyExc_ValueError, "data longer than blob length");
- return -1;
- }
- assert(offset <= blob_len);
- int rc;
- Py_BEGIN_ALLOW_THREADS
- rc = sqlite3_blob_write(self->blob, buf, (int)len, (int)offset);
- Py_END_ALLOW_THREADS
- if (rc != SQLITE_OK) {
- blob_seterror(self, rc);
- return -1;
- }
- return 0;
- }
- /*[clinic input]
- _sqlite3.Blob.write as blob_write
- data: Py_buffer
- /
- Write data at the current offset.
- This function cannot change the blob length. Writing beyond the end of the
- blob will result in an exception being raised.
- [clinic start generated code]*/
- static PyObject *
- blob_write_impl(pysqlite_Blob *self, Py_buffer *data)
- /*[clinic end generated code: output=b34cf22601b570b2 input=a84712f24a028e6d]*/
- {
- if (!check_blob(self)) {
- return NULL;
- }
- int rc = inner_write(self, data->buf, data->len, self->offset);
- if (rc < 0) {
- return NULL;
- }
- self->offset += (int)data->len;
- Py_RETURN_NONE;
- }
- /*[clinic input]
- _sqlite3.Blob.seek as blob_seek
- offset: int
- origin: int = 0
- /
- Set the current access position to offset.
- The origin argument defaults to os.SEEK_SET (absolute blob positioning).
- Other values for origin are os.SEEK_CUR (seek relative to the current position)
- and os.SEEK_END (seek relative to the blob's end).
- [clinic start generated code]*/
- static PyObject *
- blob_seek_impl(pysqlite_Blob *self, int offset, int origin)
- /*[clinic end generated code: output=854c5a0e208547a5 input=5da9a07e55fe6bb6]*/
- {
- if (!check_blob(self)) {
- return NULL;
- }
- int blob_len = sqlite3_blob_bytes(self->blob);
- switch (origin) {
- case SEEK_SET:
- break;
- case SEEK_CUR:
- if (offset > INT_MAX - self->offset) {
- goto overflow;
- }
- offset += self->offset;
- break;
- case SEEK_END:
- if (offset > INT_MAX - blob_len) {
- goto overflow;
- }
- offset += blob_len;
- break;
- default:
- PyErr_SetString(PyExc_ValueError,
- "'origin' should be os.SEEK_SET, os.SEEK_CUR, or "
- "os.SEEK_END");
- return NULL;
- }
- if (offset < 0 || offset > blob_len) {
- PyErr_SetString(PyExc_ValueError, "offset out of blob range");
- return NULL;
- }
- self->offset = offset;
- Py_RETURN_NONE;
- overflow:
- PyErr_SetString(PyExc_OverflowError, "seek offset results in overflow");
- return NULL;
- }
- /*[clinic input]
- _sqlite3.Blob.tell as blob_tell
- Return the current access position for the blob.
- [clinic start generated code]*/
- static PyObject *
- blob_tell_impl(pysqlite_Blob *self)
- /*[clinic end generated code: output=3d3ba484a90b3a99 input=7e34057aa303612c]*/
- {
- if (!check_blob(self)) {
- return NULL;
- }
- return PyLong_FromLong(self->offset);
- }
- /*[clinic input]
- _sqlite3.Blob.__enter__ as blob_enter
- Blob context manager enter.
- [clinic start generated code]*/
- static PyObject *
- blob_enter_impl(pysqlite_Blob *self)
- /*[clinic end generated code: output=4fd32484b071a6cd input=fe4842c3c582d5a7]*/
- {
- if (!check_blob(self)) {
- return NULL;
- }
- return Py_NewRef(self);
- }
- /*[clinic input]
- _sqlite3.Blob.__exit__ as blob_exit
- type: object
- val: object
- tb: object
- /
- Blob context manager exit.
- [clinic start generated code]*/
- static PyObject *
- blob_exit_impl(pysqlite_Blob *self, PyObject *type, PyObject *val,
- PyObject *tb)
- /*[clinic end generated code: output=fc86ceeb2b68c7b2 input=575d9ecea205f35f]*/
- {
- if (!check_blob(self)) {
- return NULL;
- }
- close_blob(self);
- Py_RETURN_FALSE;
- }
- static Py_ssize_t
- blob_length(pysqlite_Blob *self)
- {
- if (!check_blob(self)) {
- return -1;
- }
- return sqlite3_blob_bytes(self->blob);
- };
- static Py_ssize_t
- get_subscript_index(pysqlite_Blob *self, PyObject *item)
- {
- Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
- if (i == -1 && PyErr_Occurred()) {
- return -1;
- }
- int blob_len = sqlite3_blob_bytes(self->blob);
- if (i < 0) {
- i += blob_len;
- }
- if (i < 0 || i >= blob_len) {
- PyErr_SetString(PyExc_IndexError, "Blob index out of range");
- return -1;
- }
- return i;
- }
- static PyObject *
- subscript_index(pysqlite_Blob *self, PyObject *item)
- {
- Py_ssize_t i = get_subscript_index(self, item);
- if (i < 0) {
- return NULL;
- }
- return read_single(self, i);
- }
- static int
- get_slice_info(pysqlite_Blob *self, PyObject *item, Py_ssize_t *start,
- Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelen)
- {
- if (PySlice_Unpack(item, start, stop, step) < 0) {
- return -1;
- }
- int len = sqlite3_blob_bytes(self->blob);
- *slicelen = PySlice_AdjustIndices(len, start, stop, *step);
- return 0;
- }
- static PyObject *
- subscript_slice(pysqlite_Blob *self, PyObject *item)
- {
- Py_ssize_t start, stop, step, len;
- if (get_slice_info(self, item, &start, &stop, &step, &len) < 0) {
- return NULL;
- }
- if (step == 1) {
- return read_multiple(self, len, start);
- }
- PyObject *blob = read_multiple(self, stop - start, start);
- if (blob == NULL) {
- return NULL;
- }
- PyObject *result = PyBytes_FromStringAndSize(NULL, len);
- if (result != NULL) {
- char *blob_buf = PyBytes_AS_STRING(blob);
- char *res_buf = PyBytes_AS_STRING(result);
- for (Py_ssize_t i = 0, j = 0; i < len; i++, j += step) {
- res_buf[i] = blob_buf[j];
- }
- Py_DECREF(blob);
- }
- return result;
- }
- static PyObject *
- blob_subscript(pysqlite_Blob *self, PyObject *item)
- {
- if (!check_blob(self)) {
- return NULL;
- }
- if (PyIndex_Check(item)) {
- return subscript_index(self, item);
- }
- if (PySlice_Check(item)) {
- return subscript_slice(self, item);
- }
- PyErr_SetString(PyExc_TypeError, "Blob indices must be integers");
- return NULL;
- }
- static int
- ass_subscript_index(pysqlite_Blob *self, PyObject *item, PyObject *value)
- {
- if (value == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Blob doesn't support item deletion");
- return -1;
- }
- if (!PyLong_Check(value)) {
- PyErr_Format(PyExc_TypeError,
- "'%s' object cannot be interpreted as an integer",
- Py_TYPE(value)->tp_name);
- return -1;
- }
- Py_ssize_t i = get_subscript_index(self, item);
- if (i < 0) {
- return -1;
- }
- long val = PyLong_AsLong(value);
- if (val == -1 && PyErr_Occurred()) {
- PyErr_Clear();
- val = -1;
- }
- if (val < 0 || val > 255) {
- PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
- return -1;
- }
- // Downcast to avoid endianness problems.
- unsigned char byte = (unsigned char)val;
- return inner_write(self, (const void *)&byte, 1, i);
- }
- static int
- ass_subscript_slice(pysqlite_Blob *self, PyObject *item, PyObject *value)
- {
- if (value == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "Blob doesn't support slice deletion");
- return -1;
- }
- Py_ssize_t start, stop, step, len;
- if (get_slice_info(self, item, &start, &stop, &step, &len) < 0) {
- return -1;
- }
- if (len == 0) {
- return 0;
- }
- Py_buffer vbuf;
- if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0) {
- return -1;
- }
- int rc = -1;
- if (vbuf.len != len) {
- PyErr_SetString(PyExc_IndexError,
- "Blob slice assignment is wrong size");
- }
- else if (step == 1) {
- rc = inner_write(self, vbuf.buf, len, start);
- }
- else {
- PyObject *blob_bytes = read_multiple(self, stop - start, start);
- if (blob_bytes != NULL) {
- char *blob_buf = PyBytes_AS_STRING(blob_bytes);
- for (Py_ssize_t i = 0, j = 0; i < len; i++, j += step) {
- blob_buf[j] = ((char *)vbuf.buf)[i];
- }
- rc = inner_write(self, blob_buf, stop - start, start);
- Py_DECREF(blob_bytes);
- }
- }
- PyBuffer_Release(&vbuf);
- return rc;
- }
- static int
- blob_ass_subscript(pysqlite_Blob *self, PyObject *item, PyObject *value)
- {
- if (!check_blob(self)) {
- return -1;
- }
- if (PyIndex_Check(item)) {
- return ass_subscript_index(self, item, value);
- }
- if (PySlice_Check(item)) {
- return ass_subscript_slice(self, item, value);
- }
- PyErr_SetString(PyExc_TypeError, "Blob indices must be integers");
- return -1;
- }
- static PyMethodDef blob_methods[] = {
- BLOB_CLOSE_METHODDEF
- BLOB_ENTER_METHODDEF
- BLOB_EXIT_METHODDEF
- BLOB_READ_METHODDEF
- BLOB_SEEK_METHODDEF
- BLOB_TELL_METHODDEF
- BLOB_WRITE_METHODDEF
- {NULL, NULL}
- };
- static struct PyMemberDef blob_members[] = {
- {"__weaklistoffset__", T_PYSSIZET, offsetof(pysqlite_Blob, in_weakreflist), READONLY},
- {NULL},
- };
- static PyType_Slot blob_slots[] = {
- {Py_tp_dealloc, blob_dealloc},
- {Py_tp_traverse, blob_traverse},
- {Py_tp_clear, blob_clear},
- {Py_tp_methods, blob_methods},
- {Py_tp_members, blob_members},
- // Mapping protocol
- {Py_mp_length, blob_length},
- {Py_mp_subscript, blob_subscript},
- {Py_mp_ass_subscript, blob_ass_subscript},
- {0, NULL},
- };
- static PyType_Spec blob_spec = {
- .name = MODULE_NAME ".Blob",
- .basicsize = sizeof(pysqlite_Blob),
- .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
- Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
- .slots = blob_slots,
- };
- int
- pysqlite_blob_setup_types(PyObject *mod)
- {
- PyObject *type = PyType_FromModuleAndSpec(mod, &blob_spec, NULL);
- if (type == NULL) {
- return -1;
- }
- pysqlite_state *state = pysqlite_get_state(mod);
- state->BlobType = (PyTypeObject *)type;
- return 0;
- }
|