Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit ed5e823

Browse files
committed
Gustavo Niemeyer <[email protected]>:
Fixed recno support (keys are integers rather than strings). Work around DB bug that cause stdin to be closed by rnopen() when the DB file needed to exist but did not (no longer segfaults). This closes SF tracker patch #403445. Also wrapped some long lines and added whitespace around operators -- FLD.
1 parent cf9926c commit ed5e823

1 file changed

Lines changed: 134 additions & 73 deletions

File tree

Modules/bsddbmodule.c

Lines changed: 134 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,10 @@
22
Author: Michael McLay
33
Hacked: Guido van Rossum
44
Btree and Recno additions plus sequence methods: David Ely
5+
Hacked by Gustavo Niemeyer <[email protected]> fixing recno
6+
support.
57
68
XXX To do:
7-
- provide interface to the B-tree and record libraries too
89
- provide a way to access the various hash functions
910
- support more open flags
1011
@@ -17,6 +18,10 @@
1718
#include "pythread.h"
1819
#endif
1920

21+
#ifdef HAVE_UNISTD_H
22+
#include <unistd.h>
23+
#endif
24+
2025
#include <sys/types.h>
2126
#include <sys/stat.h>
2227
#include <fcntl.h>
@@ -32,6 +37,7 @@ typedef struct {
3237
PyObject_HEAD
3338
DB *di_bsddb;
3439
int di_size; /* -1 means recompute */
40+
int di_type;
3541
#ifdef WITH_THREAD
3642
PyThread_type_lock di_lock;
3743
#endif
@@ -40,10 +46,10 @@ typedef struct {
4046
staticforward PyTypeObject Bsddbtype;
4147

4248
#define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
43-
#define check_bsddbobject_open(v) if ((v)->di_bsddb == NULL) \
49+
#define check_bsddbobject_open(v, r) if ((v)->di_bsddb == NULL) \
4450
{ PyErr_SetString(BsddbError, \
4551
"BSDDB object has already been closed"); \
46-
return NULL; }
52+
return r; }
4753

4854
static PyObject *BsddbError;
4955

@@ -81,6 +87,8 @@ newdbhashobject(char *file, int flags, int mode,
8187
}
8288

8389
dp->di_size = -1;
90+
dp->di_type = DB_HASH;
91+
8492
#ifdef WITH_THREAD
8593
dp->di_lock = PyThread_allocate_lock();
8694
if (dp->di_lock == NULL) {
@@ -129,6 +137,8 @@ newdbbtobject(char *file, int flags, int mode,
129137
}
130138

131139
dp->di_size = -1;
140+
dp->di_type = DB_BTREE;
141+
132142
#ifdef WITH_THREAD
133143
dp->di_lock = PyThread_allocate_lock();
134144
if (dp->di_lock == NULL) {
@@ -148,6 +158,7 @@ newdbrnobject(char *file, int flags, int mode,
148158
{
149159
bsddbobject *dp;
150160
RECNOINFO info;
161+
int fd;
151162

152163
if ((dp = PyObject_New(bsddbobject, &Bsddbtype)) == NULL)
153164
return NULL;
@@ -163,9 +174,18 @@ newdbrnobject(char *file, int flags, int mode,
163174
#ifdef O_BINARY
164175
flags |= O_BINARY;
165176
#endif
166-
Py_BEGIN_ALLOW_THREADS
167-
dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info);
168-
Py_END_ALLOW_THREADS
177+
/* This is a hack to avoid a dbopen() bug that happens when
178+
* it fails. */
179+
fd = open(file, flags);
180+
if (fd == -1) {
181+
dp->di_bsddb = NULL;
182+
}
183+
else {
184+
close(fd);
185+
Py_BEGIN_ALLOW_THREADS
186+
dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info);
187+
Py_END_ALLOW_THREADS
188+
}
169189
if (dp->di_bsddb == NULL) {
170190
PyErr_SetFromErrno(BsddbError);
171191
#ifdef WITH_THREAD
@@ -176,6 +196,8 @@ newdbrnobject(char *file, int flags, int mode,
176196
}
177197

178198
dp->di_size = -1;
199+
dp->di_type = DB_RECNO;
200+
179201
#ifdef WITH_THREAD
180202
dp->di_lock = PyThread_allocate_lock();
181203
if (dp->di_lock == NULL) {
@@ -225,11 +247,7 @@ bsddb_dealloc(bsddbobject *dp)
225247
static int
226248
bsddb_length(bsddbobject *dp)
227249
{
228-
if (dp->di_bsddb == NULL) {
229-
PyErr_SetString(BsddbError,
230-
"BSDDB object has already been closed");
231-
return -1;
232-
}
250+
check_bsddbobject_open(dp, -1);
233251
if (dp->di_size < 0) {
234252
DBT krec, drec;
235253
int status;
@@ -259,13 +277,27 @@ bsddb_subscript(bsddbobject *dp, PyObject *key)
259277
char *data,buf[4096];
260278
int size;
261279
PyObject *result;
262-
263-
if (!PyArg_Parse(key, "s#", &data, &size))
264-
return NULL;
265-
check_bsddbobject_open(dp);
280+
recno_t recno;
266281

267-
krec.data = data;
268-
krec.size = size;
282+
if (dp->di_type == DB_RECNO) {
283+
if (!PyArg_Parse(key, "i", &recno)) {
284+
PyErr_SetString(PyExc_TypeError,
285+
"key type must be integer");
286+
return NULL;
287+
}
288+
krec.data = &recno;
289+
krec.size = sizeof(recno);
290+
}
291+
else {
292+
if (!PyArg_Parse(key, "s#", &data, &size)) {
293+
PyErr_SetString(PyExc_TypeError,
294+
"key type must be string");
295+
return NULL;
296+
}
297+
krec.data = data;
298+
krec.size = size;
299+
}
300+
check_bsddbobject_open(dp, NULL);
269301

270302
BSDDB_BGN_SAVE(dp)
271303
status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
@@ -296,19 +328,27 @@ bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
296328
DBT krec, drec;
297329
char *data;
298330
int size;
331+
recno_t recno;
299332

300-
if (!PyArg_Parse(key, "s#", &data, &size)) {
301-
PyErr_SetString(PyExc_TypeError,
302-
"bsddb key type must be string");
303-
return -1;
333+
if (dp->di_type == DB_RECNO) {
334+
if (!PyArg_Parse(key, "i", &recno)) {
335+
PyErr_SetString(PyExc_TypeError,
336+
"bsddb key type must be integer");
337+
return -1;
338+
}
339+
krec.data = &recno;
340+
krec.size = sizeof(recno);
304341
}
305-
if (dp->di_bsddb == NULL) {
306-
PyErr_SetString(BsddbError,
307-
"BSDDB object has already been closed");
308-
return -1;
309-
}
310-
krec.data = data;
311-
krec.size = size;
342+
else {
343+
if (!PyArg_Parse(key, "s#", &data, &size)) {
344+
PyErr_SetString(PyExc_TypeError,
345+
"bsddb key type must be string");
346+
return -1;
347+
}
348+
krec.data = data;
349+
krec.size = size;
350+
}
351+
check_bsddbobject_open(dp, -1);
312352
dp->di_size = -1;
313353
if (value == NULL) {
314354
BSDDB_BGN_SAVE(dp)
@@ -323,17 +363,6 @@ bsddb_ass_sub(bsddbobject *dp, PyObject *key, PyObject *value)
323363
}
324364
drec.data = data;
325365
drec.size = size;
326-
#if 0
327-
/* For RECNO, put fails with 'No space left on device'
328-
after a few short records are added?? Looks fine
329-
to this point... linked with 1.85 on Solaris Intel
330-
Roger E. Masse 1/16/97
331-
*/
332-
printf("before put data: '%s', size: %d\n",
333-
drec.data, drec.size);
334-
printf("before put key= '%s', size= %d\n",
335-
krec.data, krec.size);
336-
#endif
337366
BSDDB_BGN_SAVE(dp)
338367
status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0);
339368
BSDDB_END_SAVE(dp)
@@ -378,15 +407,15 @@ bsddb_close(bsddbobject *dp, PyObject *args)
378407
static PyObject *
379408
bsddb_keys(bsddbobject *dp, PyObject *args)
380409
{
381-
PyObject *list, *item;
410+
PyObject *list, *item=NULL;
382411
DBT krec, drec;
383412
char *data=NULL,buf[4096];
384413
int status;
385414
int err;
386415

387416
if (!PyArg_NoArgs(args))
388417
return NULL;
389-
check_bsddbobject_open(dp);
418+
check_bsddbobject_open(dp, NULL);
390419
list = PyList_New(0);
391420
if (list == NULL)
392421
return NULL;
@@ -395,12 +424,16 @@ bsddb_keys(bsddbobject *dp, PyObject *args)
395424
if (status == 0) {
396425
if (krec.size > sizeof(buf)) data = malloc(krec.size);
397426
else data = buf;
398-
if (data!=NULL) memcpy(data,krec.data,krec.size);
427+
if (data != NULL) memcpy(data,krec.data,krec.size);
399428
}
400429
BSDDB_END_SAVE(dp)
401430
if (data==NULL) return PyErr_NoMemory();
402431
while (status == 0) {
403-
item = PyString_FromStringAndSize(data, (int)krec.size);
432+
if (dp->di_type == DB_RECNO)
433+
item = PyInt_FromLong(*((int*)data));
434+
else
435+
item = PyString_FromStringAndSize(data,
436+
(int)krec.size);
404437
if (data != buf) free(data);
405438
if (item == NULL) {
406439
Py_DECREF(list);
@@ -442,12 +475,27 @@ bsddb_has_key(bsddbobject *dp, PyObject *args)
442475
int status;
443476
char *data;
444477
int size;
478+
recno_t recno;
445479

446-
if (!PyArg_Parse(args, "s#", &data, &size))
447-
return NULL;
448-
check_bsddbobject_open(dp);
449-
krec.data = data;
450-
krec.size = size;
480+
if (dp->di_type == DB_RECNO) {
481+
if (!PyArg_Parse(args, "i", &recno)) {
482+
PyErr_SetString(PyExc_TypeError,
483+
"key type must be integer");
484+
return NULL;
485+
}
486+
krec.data = &recno;
487+
krec.size = sizeof(recno);
488+
}
489+
else {
490+
if (!PyArg_Parse(args, "s#", &data, &size)) {
491+
PyErr_SetString(PyExc_TypeError,
492+
"key type must be string");
493+
return NULL;
494+
}
495+
krec.data = data;
496+
krec.size = size;
497+
}
498+
check_bsddbobject_open(dp, NULL);
451499

452500
BSDDB_BGN_SAVE(dp)
453501
status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
@@ -468,12 +516,27 @@ bsddb_set_location(bsddbobject *dp, PyObject *key)
468516
char *data,buf[4096];
469517
int size;
470518
PyObject *result;
519+
recno_t recno;
471520

472-
if (!PyArg_Parse(key, "s#", &data, &size))
473-
return NULL;
474-
check_bsddbobject_open(dp);
475-
krec.data = data;
476-
krec.size = size;
521+
if (dp->di_type == DB_RECNO) {
522+
if (!PyArg_Parse(key, "i", &recno)) {
523+
PyErr_SetString(PyExc_TypeError,
524+
"key type must be integer");
525+
return NULL;
526+
}
527+
krec.data = &recno;
528+
krec.size = sizeof(recno);
529+
}
530+
else {
531+
if (!PyArg_Parse(key, "s#", &data, &size)) {
532+
PyErr_SetString(PyExc_TypeError,
533+
"key type must be string");
534+
return NULL;
535+
}
536+
krec.data = data;
537+
krec.size = size;
538+
}
539+
check_bsddbobject_open(dp, NULL);
477540

478541
BSDDB_BGN_SAVE(dp)
479542
status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR);
@@ -492,7 +555,12 @@ bsddb_set_location(bsddbobject *dp, PyObject *key)
492555
return NULL;
493556
}
494557

495-
result = Py_BuildValue("s#s#", krec.data, krec.size, data, drec.size);
558+
if (dp->di_type == DB_RECNO)
559+
result = Py_BuildValue("is#", *((int*)krec.data),
560+
data, drec.size);
561+
else
562+
result = Py_BuildValue("s#s#", krec.data, krec.size,
563+
data, drec.size);
496564
if (data != buf) free(data);
497565
return result;
498566
}
@@ -509,7 +577,7 @@ bsddb_seq(bsddbobject *dp, PyObject *args, int sequence_request)
509577
if (!PyArg_NoArgs(args))
510578
return NULL;
511579

512-
check_bsddbobject_open(dp);
580+
check_bsddbobject_open(dp, NULL);
513581
krec.data = 0;
514582
krec.size = 0;
515583

@@ -519,14 +587,14 @@ bsddb_seq(bsddbobject *dp, PyObject *args, int sequence_request)
519587
if (status == 0) {
520588
if (krec.size > sizeof(kbuf)) kdata = malloc(krec.size);
521589
else kdata = kbuf;
522-
if (kdata!=NULL) memcpy(kdata,krec.data,krec.size);
590+
if (kdata != NULL) memcpy(kdata,krec.data,krec.size);
523591
if (drec.size > sizeof(dbuf)) ddata = malloc(drec.size);
524592
else ddata = dbuf;
525-
if (ddata!=NULL) memcpy(ddata,drec.data,drec.size);
593+
if (ddata != NULL) memcpy(ddata,drec.data,drec.size);
526594
}
527595
BSDDB_END_SAVE(dp)
528596
if (status == 0) {
529-
if ((kdata==NULL) || (ddata==NULL))
597+
if ((kdata == NULL) || (ddata == NULL))
530598
return PyErr_NoMemory();
531599
}
532600
else {
@@ -538,7 +606,13 @@ bsddb_seq(bsddbobject *dp, PyObject *args, int sequence_request)
538606
return NULL;
539607
}
540608

541-
result = Py_BuildValue("s#s#", kdata, krec.size, ddata, drec.size);
609+
610+
if (dp->di_type == DB_RECNO)
611+
result = Py_BuildValue("is#", *((int*)kdata),
612+
ddata, drec.size);
613+
else
614+
result = Py_BuildValue("s#s#", kdata, krec.size,
615+
ddata, drec.size);
542616
if (kdata != kbuf) free(kdata);
543617
if (ddata != dbuf) free(ddata);
544618
return result;
@@ -571,7 +645,7 @@ bsddb_sync(bsddbobject *dp, PyObject *args)
571645

572646
if (!PyArg_NoArgs(args))
573647
return NULL;
574-
check_bsddbobject_open(dp);
648+
check_bsddbobject_open(dp, NULL);
575649
BSDDB_BGN_SAVE(dp)
576650
status = (dp->di_bsddb->sync)(dp->di_bsddb, 0);
577651
BSDDB_END_SAVE(dp)
@@ -741,19 +815,6 @@ bsdrnopen(PyObject *self, PyObject *args)
741815
&reclen, &bval, &bfname))
742816
return NULL;
743817

744-
# if 0
745-
printf("file: %s\n", file);
746-
printf("flag: %s\n", flag);
747-
printf("mode: %d\n", mode);
748-
printf("rnflags: 0x%x\n", rnflags);
749-
printf("cachesize: %d\n", cachesize);
750-
printf("psize: %d\n", psize);
751-
printf("lorder: %d\n", 0);
752-
printf("reclen: %d\n", reclen);
753-
printf("bval: %c\n", bval[0]);
754-
printf("bfname %s\n", bfname);
755-
#endif
756-
757818
if (flag != NULL) {
758819
/* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
759820
if (flag[0] == 'r')

0 commit comments

Comments
 (0)