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
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 {
4046staticforward 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
4854static 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)
225247static int
226248bsddb_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)
378407static PyObject *
379408bsddb_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