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