Coverage Report

Created: 2022-07-08 00:21

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