xref: /third_party/python/Modules/_sqlite/blob.c (revision 7db96d56)
1#include "blob.h"
2#include "util.h"
3
4#define clinic_state() (pysqlite_get_state_by_type(Py_TYPE(self)))
5#include "clinic/blob.c.h"
6#undef clinic_state
7
8/*[clinic input]
9module _sqlite3
10class _sqlite3.Blob "pysqlite_Blob *" "clinic_state()->BlobType"
11[clinic start generated code]*/
12/*[clinic end generated code: output=da39a3ee5e6b4b0d input=908d3e16a45f8da7]*/
13
14static void
15close_blob(pysqlite_Blob *self)
16{
17    if (self->blob) {
18        sqlite3_blob *blob = self->blob;
19        self->blob = NULL;
20
21        Py_BEGIN_ALLOW_THREADS
22        sqlite3_blob_close(blob);
23        Py_END_ALLOW_THREADS
24    }
25}
26
27static int
28blob_traverse(pysqlite_Blob *self, visitproc visit, void *arg)
29{
30    Py_VISIT(Py_TYPE(self));
31    Py_VISIT(self->connection);
32    return 0;
33}
34
35static int
36blob_clear(pysqlite_Blob *self)
37{
38    Py_CLEAR(self->connection);
39    return 0;
40}
41
42static void
43blob_dealloc(pysqlite_Blob *self)
44{
45    PyTypeObject *tp = Py_TYPE(self);
46    PyObject_GC_UnTrack(self);
47
48    close_blob(self);
49
50    if (self->in_weakreflist != NULL) {
51        PyObject_ClearWeakRefs((PyObject*)self);
52    }
53    tp->tp_clear((PyObject *)self);
54    tp->tp_free(self);
55    Py_DECREF(tp);
56}
57
58// Return 1 if the blob object is usable, 0 if not.
59static int
60check_blob(pysqlite_Blob *self)
61{
62    if (!pysqlite_check_connection(self->connection) ||
63        !pysqlite_check_thread(self->connection)) {
64        return 0;
65    }
66    if (self->blob == NULL) {
67        pysqlite_state *state = self->connection->state;
68        PyErr_SetString(state->ProgrammingError,
69                        "Cannot operate on a closed blob.");
70        return 0;
71    }
72    return 1;
73}
74
75
76/*[clinic input]
77_sqlite3.Blob.close as blob_close
78
79Close the blob.
80[clinic start generated code]*/
81
82static PyObject *
83blob_close_impl(pysqlite_Blob *self)
84/*[clinic end generated code: output=848accc20a138d1b input=7bc178a402a40bd8]*/
85{
86    if (!pysqlite_check_connection(self->connection) ||
87        !pysqlite_check_thread(self->connection))
88    {
89        return NULL;
90    }
91    close_blob(self);
92    Py_RETURN_NONE;
93};
94
95void
96pysqlite_close_all_blobs(pysqlite_Connection *self)
97{
98    for (int i = 0; i < PyList_GET_SIZE(self->blobs); i++) {
99        PyObject *weakref = PyList_GET_ITEM(self->blobs, i);
100        PyObject *blob = PyWeakref_GetObject(weakref);
101        if (!Py_IsNone(blob)) {
102            close_blob((pysqlite_Blob *)blob);
103        }
104    }
105}
106
107static void
108blob_seterror(pysqlite_Blob *self, int rc)
109{
110    assert(self->connection != NULL);
111#if SQLITE_VERSION_NUMBER < 3008008
112    // SQLite pre 3.8.8 does not set this blob error on the connection
113    if (rc == SQLITE_ABORT) {
114        PyErr_SetString(self->connection->OperationalError,
115                        "Cannot operate on an expired blob handle");
116        return;
117    }
118#endif
119    _pysqlite_seterror(self->connection->state, self->connection->db);
120}
121
122static PyObject *
123read_single(pysqlite_Blob *self, Py_ssize_t offset)
124{
125    unsigned char buf = 0;
126    int rc;
127    Py_BEGIN_ALLOW_THREADS
128    rc = sqlite3_blob_read(self->blob, (void *)&buf, 1, (int)offset);
129    Py_END_ALLOW_THREADS
130
131    if (rc != SQLITE_OK) {
132        blob_seterror(self, rc);
133        return NULL;
134    }
135    return PyLong_FromUnsignedLong((unsigned long)buf);
136}
137
138static PyObject *
139read_multiple(pysqlite_Blob *self, Py_ssize_t length, Py_ssize_t offset)
140{
141    assert(length <= sqlite3_blob_bytes(self->blob));
142    assert(offset < sqlite3_blob_bytes(self->blob));
143
144    PyObject *buffer = PyBytes_FromStringAndSize(NULL, length);
145    if (buffer == NULL) {
146        return NULL;
147    }
148
149    char *raw_buffer = PyBytes_AS_STRING(buffer);
150    int rc;
151    Py_BEGIN_ALLOW_THREADS
152    rc = sqlite3_blob_read(self->blob, raw_buffer, (int)length, (int)offset);
153    Py_END_ALLOW_THREADS
154
155    if (rc != SQLITE_OK) {
156        Py_DECREF(buffer);
157        blob_seterror(self, rc);
158        return NULL;
159    }
160    return buffer;
161}
162
163
164/*[clinic input]
165_sqlite3.Blob.read as blob_read
166
167    length: int = -1
168        Read length in bytes.
169    /
170
171Read data at the current offset position.
172
173If the end of the blob is reached, the data up to end of file will be returned.
174When length is not specified, or is negative, Blob.read() will read until the
175end of the blob.
176[clinic start generated code]*/
177
178static PyObject *
179blob_read_impl(pysqlite_Blob *self, int length)
180/*[clinic end generated code: output=1fc99b2541360dde input=f2e4aa4378837250]*/
181{
182    if (!check_blob(self)) {
183        return NULL;
184    }
185
186    /* Make sure we never read past "EOB". Also read the rest of the blob if a
187     * negative length is specified. */
188    int blob_len = sqlite3_blob_bytes(self->blob);
189    int max_read_len = blob_len - self->offset;
190    if (length < 0 || length > max_read_len) {
191        length = max_read_len;
192    }
193
194    assert(length >= 0);
195    if (length == 0) {
196        return PyBytes_FromStringAndSize(NULL, 0);
197    }
198
199    PyObject *buffer = read_multiple(self, length, self->offset);
200    if (buffer == NULL) {
201        return NULL;
202    }
203    self->offset += length;
204    return buffer;
205};
206
207static int
208inner_write(pysqlite_Blob *self, const void *buf, Py_ssize_t len,
209            Py_ssize_t offset)
210{
211    Py_ssize_t blob_len = sqlite3_blob_bytes(self->blob);
212    Py_ssize_t remaining_len = blob_len - offset;
213    if (len > remaining_len) {
214        PyErr_SetString(PyExc_ValueError, "data longer than blob length");
215        return -1;
216    }
217
218    assert(offset <= blob_len);
219    int rc;
220    Py_BEGIN_ALLOW_THREADS
221    rc = sqlite3_blob_write(self->blob, buf, (int)len, (int)offset);
222    Py_END_ALLOW_THREADS
223
224    if (rc != SQLITE_OK) {
225        blob_seterror(self, rc);
226        return -1;
227    }
228    return 0;
229}
230
231
232/*[clinic input]
233_sqlite3.Blob.write as blob_write
234
235    data: Py_buffer
236    /
237
238Write data at the current offset.
239
240This function cannot change the blob length.  Writing beyond the end of the
241blob will result in an exception being raised.
242[clinic start generated code]*/
243
244static PyObject *
245blob_write_impl(pysqlite_Blob *self, Py_buffer *data)
246/*[clinic end generated code: output=b34cf22601b570b2 input=a84712f24a028e6d]*/
247{
248    if (!check_blob(self)) {
249        return NULL;
250    }
251
252    int rc = inner_write(self, data->buf, data->len, self->offset);
253    if (rc < 0) {
254        return NULL;
255    }
256    self->offset += (int)data->len;
257    Py_RETURN_NONE;
258}
259
260
261/*[clinic input]
262_sqlite3.Blob.seek as blob_seek
263
264    offset: int
265    origin: int = 0
266    /
267
268Set the current access position to offset.
269
270The origin argument defaults to os.SEEK_SET (absolute blob positioning).
271Other values for origin are os.SEEK_CUR (seek relative to the current position)
272and os.SEEK_END (seek relative to the blob's end).
273[clinic start generated code]*/
274
275static PyObject *
276blob_seek_impl(pysqlite_Blob *self, int offset, int origin)
277/*[clinic end generated code: output=854c5a0e208547a5 input=5da9a07e55fe6bb6]*/
278{
279    if (!check_blob(self)) {
280        return NULL;
281    }
282
283    int blob_len = sqlite3_blob_bytes(self->blob);
284    switch (origin) {
285        case SEEK_SET:
286            break;
287        case SEEK_CUR:
288            if (offset > INT_MAX - self->offset) {
289                goto overflow;
290            }
291            offset += self->offset;
292            break;
293        case SEEK_END:
294            if (offset > INT_MAX - blob_len) {
295                goto overflow;
296            }
297            offset += blob_len;
298            break;
299        default:
300            PyErr_SetString(PyExc_ValueError,
301                            "'origin' should be os.SEEK_SET, os.SEEK_CUR, or "
302                            "os.SEEK_END");
303            return NULL;
304    }
305
306    if (offset < 0 || offset > blob_len) {
307        PyErr_SetString(PyExc_ValueError, "offset out of blob range");
308        return NULL;
309    }
310
311    self->offset = offset;
312    Py_RETURN_NONE;
313
314overflow:
315    PyErr_SetString(PyExc_OverflowError, "seek offset results in overflow");
316    return NULL;
317}
318
319
320/*[clinic input]
321_sqlite3.Blob.tell as blob_tell
322
323Return the current access position for the blob.
324[clinic start generated code]*/
325
326static PyObject *
327blob_tell_impl(pysqlite_Blob *self)
328/*[clinic end generated code: output=3d3ba484a90b3a99 input=7e34057aa303612c]*/
329{
330    if (!check_blob(self)) {
331        return NULL;
332    }
333    return PyLong_FromLong(self->offset);
334}
335
336
337/*[clinic input]
338_sqlite3.Blob.__enter__ as blob_enter
339
340Blob context manager enter.
341[clinic start generated code]*/
342
343static PyObject *
344blob_enter_impl(pysqlite_Blob *self)
345/*[clinic end generated code: output=4fd32484b071a6cd input=fe4842c3c582d5a7]*/
346{
347    if (!check_blob(self)) {
348        return NULL;
349    }
350    return Py_NewRef(self);
351}
352
353
354/*[clinic input]
355_sqlite3.Blob.__exit__ as blob_exit
356
357    type: object
358    val: object
359    tb: object
360    /
361
362Blob context manager exit.
363[clinic start generated code]*/
364
365static PyObject *
366blob_exit_impl(pysqlite_Blob *self, PyObject *type, PyObject *val,
367               PyObject *tb)
368/*[clinic end generated code: output=fc86ceeb2b68c7b2 input=575d9ecea205f35f]*/
369{
370    if (!check_blob(self)) {
371        return NULL;
372    }
373    close_blob(self);
374    Py_RETURN_FALSE;
375}
376
377static Py_ssize_t
378blob_length(pysqlite_Blob *self)
379{
380    if (!check_blob(self)) {
381        return -1;
382    }
383    return sqlite3_blob_bytes(self->blob);
384};
385
386static Py_ssize_t
387get_subscript_index(pysqlite_Blob *self, PyObject *item)
388{
389    Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError);
390    if (i == -1 && PyErr_Occurred()) {
391        return -1;
392    }
393    int blob_len = sqlite3_blob_bytes(self->blob);
394    if (i < 0) {
395        i += blob_len;
396    }
397    if (i < 0 || i >= blob_len) {
398        PyErr_SetString(PyExc_IndexError, "Blob index out of range");
399        return -1;
400    }
401    return i;
402}
403
404static PyObject *
405subscript_index(pysqlite_Blob *self, PyObject *item)
406{
407    Py_ssize_t i = get_subscript_index(self, item);
408    if (i < 0) {
409        return NULL;
410    }
411    return read_single(self, i);
412}
413
414static int
415get_slice_info(pysqlite_Blob *self, PyObject *item, Py_ssize_t *start,
416               Py_ssize_t *stop, Py_ssize_t *step, Py_ssize_t *slicelen)
417{
418    if (PySlice_Unpack(item, start, stop, step) < 0) {
419        return -1;
420    }
421    int len = sqlite3_blob_bytes(self->blob);
422    *slicelen = PySlice_AdjustIndices(len, start, stop, *step);
423    return 0;
424}
425
426static PyObject *
427subscript_slice(pysqlite_Blob *self, PyObject *item)
428{
429    Py_ssize_t start, stop, step, len;
430    if (get_slice_info(self, item, &start, &stop, &step, &len) < 0) {
431        return NULL;
432    }
433
434    if (step == 1) {
435        return read_multiple(self, len, start);
436    }
437    PyObject *blob = read_multiple(self, stop - start, start);
438    if (blob == NULL) {
439        return NULL;
440    }
441    PyObject *result = PyBytes_FromStringAndSize(NULL, len);
442    if (result != NULL) {
443        char *blob_buf = PyBytes_AS_STRING(blob);
444        char *res_buf = PyBytes_AS_STRING(result);
445        for (Py_ssize_t i = 0, j = 0; i < len; i++, j += step) {
446            res_buf[i] = blob_buf[j];
447        }
448        Py_DECREF(blob);
449    }
450    return result;
451}
452
453static PyObject *
454blob_subscript(pysqlite_Blob *self, PyObject *item)
455{
456    if (!check_blob(self)) {
457        return NULL;
458    }
459
460    if (PyIndex_Check(item)) {
461        return subscript_index(self, item);
462    }
463    if (PySlice_Check(item)) {
464        return subscript_slice(self, item);
465    }
466
467    PyErr_SetString(PyExc_TypeError, "Blob indices must be integers");
468    return NULL;
469}
470
471static int
472ass_subscript_index(pysqlite_Blob *self, PyObject *item, PyObject *value)
473{
474    if (value == NULL) {
475        PyErr_SetString(PyExc_TypeError,
476                        "Blob doesn't support item deletion");
477        return -1;
478    }
479    if (!PyLong_Check(value)) {
480        PyErr_Format(PyExc_TypeError,
481                     "'%s' object cannot be interpreted as an integer",
482                     Py_TYPE(value)->tp_name);
483        return -1;
484    }
485    Py_ssize_t i = get_subscript_index(self, item);
486    if (i < 0) {
487        return -1;
488    }
489
490    long val = PyLong_AsLong(value);
491    if (val == -1 && PyErr_Occurred()) {
492        PyErr_Clear();
493        val = -1;
494    }
495    if (val < 0 || val > 255) {
496        PyErr_SetString(PyExc_ValueError, "byte must be in range(0, 256)");
497        return -1;
498    }
499    // Downcast to avoid endianness problems.
500    unsigned char byte = (unsigned char)val;
501    return inner_write(self, (const void *)&byte, 1, i);
502}
503
504static int
505ass_subscript_slice(pysqlite_Blob *self, PyObject *item, PyObject *value)
506{
507    if (value == NULL) {
508        PyErr_SetString(PyExc_TypeError,
509                        "Blob doesn't support slice deletion");
510        return -1;
511    }
512
513    Py_ssize_t start, stop, step, len;
514    if (get_slice_info(self, item, &start, &stop, &step, &len) < 0) {
515        return -1;
516    }
517
518    if (len == 0) {
519        return 0;
520    }
521
522    Py_buffer vbuf;
523    if (PyObject_GetBuffer(value, &vbuf, PyBUF_SIMPLE) < 0) {
524        return -1;
525    }
526
527    int rc = -1;
528    if (vbuf.len != len) {
529        PyErr_SetString(PyExc_IndexError,
530                        "Blob slice assignment is wrong size");
531    }
532    else if (step == 1) {
533        rc = inner_write(self, vbuf.buf, len, start);
534    }
535    else {
536        PyObject *blob_bytes = read_multiple(self, stop - start, start);
537        if (blob_bytes != NULL) {
538            char *blob_buf = PyBytes_AS_STRING(blob_bytes);
539            for (Py_ssize_t i = 0, j = 0; i < len; i++, j += step) {
540                blob_buf[j] = ((char *)vbuf.buf)[i];
541            }
542            rc = inner_write(self, blob_buf, stop - start, start);
543            Py_DECREF(blob_bytes);
544        }
545    }
546    PyBuffer_Release(&vbuf);
547    return rc;
548}
549
550static int
551blob_ass_subscript(pysqlite_Blob *self, PyObject *item, PyObject *value)
552{
553    if (!check_blob(self)) {
554        return -1;
555    }
556
557    if (PyIndex_Check(item)) {
558        return ass_subscript_index(self, item, value);
559    }
560    if (PySlice_Check(item)) {
561        return ass_subscript_slice(self, item, value);
562    }
563
564    PyErr_SetString(PyExc_TypeError, "Blob indices must be integers");
565    return -1;
566}
567
568
569static PyMethodDef blob_methods[] = {
570    BLOB_CLOSE_METHODDEF
571    BLOB_ENTER_METHODDEF
572    BLOB_EXIT_METHODDEF
573    BLOB_READ_METHODDEF
574    BLOB_SEEK_METHODDEF
575    BLOB_TELL_METHODDEF
576    BLOB_WRITE_METHODDEF
577    {NULL, NULL}
578};
579
580static struct PyMemberDef blob_members[] = {
581    {"__weaklistoffset__", T_PYSSIZET, offsetof(pysqlite_Blob, in_weakreflist), READONLY},
582    {NULL},
583};
584
585static PyType_Slot blob_slots[] = {
586    {Py_tp_dealloc, blob_dealloc},
587    {Py_tp_traverse, blob_traverse},
588    {Py_tp_clear, blob_clear},
589    {Py_tp_methods, blob_methods},
590    {Py_tp_members, blob_members},
591
592    // Mapping protocol
593    {Py_mp_length, blob_length},
594    {Py_mp_subscript, blob_subscript},
595    {Py_mp_ass_subscript, blob_ass_subscript},
596    {0, NULL},
597};
598
599static PyType_Spec blob_spec = {
600    .name = MODULE_NAME ".Blob",
601    .basicsize = sizeof(pysqlite_Blob),
602    .flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC |
603              Py_TPFLAGS_IMMUTABLETYPE | Py_TPFLAGS_DISALLOW_INSTANTIATION),
604    .slots = blob_slots,
605};
606
607int
608pysqlite_blob_setup_types(PyObject *mod)
609{
610    PyObject *type = PyType_FromModuleAndSpec(mod, &blob_spec, NULL);
611    if (type == NULL) {
612        return -1;
613    }
614    pysqlite_state *state = pysqlite_get_state(mod);
615    state->BlobType = (PyTypeObject *)type;
616    return 0;
617}
618