1 /* Berkeley DB interface.
3 Hacked: Guido van Rossum
4 Btree and Recno additions plus sequence methods: David Ely
5 Hacked by Gustavo Niemeyer <niemeyer@conectiva.com> fixing recno
9 - provide a way to access the various hash functions
10 - support more open flags
12 The windows port of the Berkeley DB code is hard to find on the web:
13 www.nightmare.com/software.html
21 #include <sys/types.h>
29 /* Please don't include internal header files of the Berkeley db package
30 (it messes up the info required in the Setup file) */
35 int di_size
; /* -1 means recompute */
38 PyThread_type_lock di_lock
;
42 static PyTypeObject Bsddbtype
;
44 #define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
45 #define check_bsddbobject_open(v, r) if ((v)->di_bsddb == NULL) \
46 { PyErr_SetString(BsddbError, \
47 "BSDDB object has already been closed"); \
50 static PyObject
*BsddbError
;
53 newdbhashobject(char *file
, int flags
, int mode
,
54 int bsize
, int ffactor
, int nelem
, int cachesize
,
60 if ((dp
= PyObject_New(bsddbobject
, &Bsddbtype
)) == NULL
)
64 info
.ffactor
= ffactor
;
66 info
.cachesize
= cachesize
;
67 info
.hash
= NULL
; /* XXX should derive from hash argument */
73 Py_BEGIN_ALLOW_THREADS
74 dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_HASH
, &info
);
76 if (dp
->di_bsddb
== NULL
) {
77 PyErr_SetFromErrno(BsddbError
);
86 dp
->di_type
= DB_HASH
;
89 dp
->di_lock
= PyThread_allocate_lock();
90 if (dp
->di_lock
== NULL
) {
91 PyErr_SetString(BsddbError
, "can't allocate lock");
97 return (PyObject
*)dp
;
101 newdbbtobject(char *file
, int flags
, int mode
,
102 int btflags
, int cachesize
, int maxkeypage
,
103 int minkeypage
, int psize
, int lorder
)
108 if ((dp
= PyObject_New(bsddbobject
, &Bsddbtype
)) == NULL
)
111 info
.flags
= btflags
;
112 info
.cachesize
= cachesize
;
113 info
.maxkeypage
= maxkeypage
;
114 info
.minkeypage
= minkeypage
;
116 info
.lorder
= lorder
;
117 info
.compare
= 0; /* Use default comparison functions, for now..*/
123 Py_BEGIN_ALLOW_THREADS
124 dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_BTREE
, &info
);
126 if (dp
->di_bsddb
== NULL
) {
127 PyErr_SetFromErrno(BsddbError
);
136 dp
->di_type
= DB_BTREE
;
139 dp
->di_lock
= PyThread_allocate_lock();
140 if (dp
->di_lock
== NULL
) {
141 PyErr_SetString(BsddbError
, "can't allocate lock");
147 return (PyObject
*)dp
;
151 newdbrnobject(char *file
, int flags
, int mode
,
152 int rnflags
, int cachesize
, int psize
, int lorder
,
153 size_t reclen
, u_char bval
, char *bfname
)
159 if ((dp
= PyObject_New(bsddbobject
, &Bsddbtype
)) == NULL
)
162 info
.flags
= rnflags
;
163 info
.cachesize
= cachesize
;
165 info
.lorder
= lorder
;
166 info
.reclen
= reclen
;
168 info
.bfname
= bfname
;
173 /* This is a hack to avoid a dbopen() bug that happens when
175 fd
= open(file
, flags
);
181 Py_BEGIN_ALLOW_THREADS
182 dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_RECNO
, &info
);
185 if (dp
->di_bsddb
== NULL
) {
186 PyErr_SetFromErrno(BsddbError
);
195 dp
->di_type
= DB_RECNO
;
198 dp
->di_lock
= PyThread_allocate_lock();
199 if (dp
->di_lock
== NULL
) {
200 PyErr_SetString(BsddbError
, "can't allocate lock");
206 return (PyObject
*)dp
;
210 bsddb_dealloc(bsddbobject
*dp
)
214 PyThread_acquire_lock(dp
->di_lock
, 0);
215 PyThread_release_lock(dp
->di_lock
);
216 PyThread_free_lock(dp
->di_lock
);
220 if (dp
->di_bsddb
!= NULL
) {
222 Py_BEGIN_ALLOW_THREADS
223 status
= (dp
->di_bsddb
->close
)(dp
->di_bsddb
);
227 "Python bsddb: close errno %d in dealloc\n",
234 #define BSDDB_BGN_SAVE(_dp) \
235 Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1);
236 #define BSDDB_END_SAVE(_dp) \
237 PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS
239 #define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS
240 #define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS
244 bsddb_length(bsddbobject
*dp
)
246 check_bsddbobject_open(dp
, -1);
247 if (dp
->di_size
< 0) {
252 for (status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
,
253 &krec
, &drec
,R_FIRST
);
255 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
,
256 &krec
, &drec
, R_NEXT
))
260 PyErr_SetFromErrno(BsddbError
);
269 bsddb_subscript(bsddbobject
*dp
, PyObject
*key
)
273 char *data
,buf
[4096];
278 if (dp
->di_type
== DB_RECNO
) {
279 if (!PyArg_Parse(key
, "i", &recno
)) {
280 PyErr_SetString(PyExc_TypeError
,
281 "key type must be integer");
285 krec
.size
= sizeof(recno
);
288 if (!PyArg_Parse(key
, "s#", &data
, &size
)) {
289 PyErr_SetString(PyExc_TypeError
,
290 "key type must be string");
296 check_bsddbobject_open(dp
, NULL
);
299 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
301 if (drec
.size
> sizeof(buf
)) data
= malloc(drec
.size
);
303 if (data
!=NULL
) memcpy(data
,drec
.data
,drec
.size
);
306 if (data
==NULL
) return PyErr_NoMemory();
309 PyErr_SetFromErrno(BsddbError
);
311 PyErr_SetObject(PyExc_KeyError
, key
);
315 result
= PyString_FromStringAndSize(data
, (int)drec
.size
);
316 if (data
!= buf
) free(data
);
321 bsddb_ass_sub(bsddbobject
*dp
, PyObject
*key
, PyObject
*value
)
329 if (dp
->di_type
== DB_RECNO
) {
330 if (!PyArg_Parse(key
, "i", &recno
)) {
331 PyErr_SetString(PyExc_TypeError
,
332 "bsddb key type must be integer");
336 krec
.size
= sizeof(recno
);
339 if (!PyArg_Parse(key
, "s#", &data
, &size
)) {
340 PyErr_SetString(PyExc_TypeError
,
341 "bsddb key type must be string");
347 check_bsddbobject_open(dp
, -1);
351 status
= (dp
->di_bsddb
->del
)(dp
->di_bsddb
, &krec
, 0);
355 if (!PyArg_Parse(value
, "s#", &data
, &size
)) {
356 PyErr_SetString(PyExc_TypeError
,
357 "bsddb value type must be string");
363 status
= (dp
->di_bsddb
->put
)(dp
->di_bsddb
, &krec
, &drec
, 0);
368 PyErr_SetFromErrno(BsddbError
);
370 PyErr_SetObject(PyExc_KeyError
, key
);
376 static PyMappingMethods bsddb_as_mapping
= {
377 (lenfunc
)bsddb_length
, /*mp_length*/
378 (binaryfunc
)bsddb_subscript
, /*mp_subscript*/
379 (objobjargproc
)bsddb_ass_sub
, /*mp_ass_subscript*/
383 bsddb_close(bsddbobject
*dp
)
385 if (dp
->di_bsddb
!= NULL
) {
388 status
= (dp
->di_bsddb
->close
)(dp
->di_bsddb
);
392 PyErr_SetFromErrno(BsddbError
);
402 bsddb_keys(bsddbobject
*dp
)
404 PyObject
*list
, *item
=NULL
;
406 char *data
=NULL
,buf
[4096];
410 check_bsddbobject_open(dp
, NULL
);
411 list
= PyList_New(0);
415 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_FIRST
);
417 if (krec
.size
> sizeof(buf
)) data
= malloc(krec
.size
);
419 if (data
!= NULL
) memcpy(data
,krec
.data
,krec
.size
);
422 if (status
== 0 && data
==NULL
) return PyErr_NoMemory();
423 while (status
== 0) {
424 if (dp
->di_type
== DB_RECNO
)
425 item
= PyInt_FromLong(*((int*)data
));
427 item
= PyString_FromStringAndSize(data
,
429 if (data
!= buf
) free(data
);
434 err
= PyList_Append(list
, item
);
441 status
= (dp
->di_bsddb
->seq
)
442 (dp
->di_bsddb
, &krec
, &drec
, R_NEXT
);
444 if (krec
.size
> sizeof(buf
))
445 data
= malloc(krec
.size
);
448 memcpy(data
,krec
.data
,krec
.size
);
451 if (data
== NULL
) return PyErr_NoMemory();
454 PyErr_SetFromErrno(BsddbError
);
459 dp
->di_size
= PyList_Size(list
); /* We just did the work */
464 bsddb_has_key(bsddbobject
*dp
, PyObject
*args
)
472 if (dp
->di_type
== DB_RECNO
) {
473 if (!PyArg_ParseTuple(args
, "i;key type must be integer",
478 krec
.size
= sizeof(recno
);
481 if (!PyArg_ParseTuple(args
, "s#;key type must be string",
488 check_bsddbobject_open(dp
, NULL
);
491 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
494 PyErr_SetFromErrno(BsddbError
);
498 return PyInt_FromLong(status
== 0);
502 bsddb_set_location(bsddbobject
*dp
, PyObject
*key
)
506 char *data
,buf
[4096];
511 if (dp
->di_type
== DB_RECNO
) {
512 if (!PyArg_ParseTuple(key
, "i;key type must be integer",
517 krec
.size
= sizeof(recno
);
520 if (!PyArg_ParseTuple(key
, "s#;key type must be string",
527 check_bsddbobject_open(dp
, NULL
);
530 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_CURSOR
);
532 if (drec
.size
> sizeof(buf
)) data
= malloc(drec
.size
);
534 if (data
!=NULL
) memcpy(data
,drec
.data
,drec
.size
);
537 if (data
==NULL
) return PyErr_NoMemory();
540 PyErr_SetFromErrno(BsddbError
);
542 PyErr_SetObject(PyExc_KeyError
, key
);
546 if (dp
->di_type
== DB_RECNO
)
547 result
= Py_BuildValue("is#", *((int*)krec
.data
),
550 result
= Py_BuildValue("s#s#", krec
.data
, krec
.size
,
552 if (data
!= buf
) free(data
);
557 bsddb_seq(bsddbobject
*dp
, int sequence_request
)
561 char *kdata
=NULL
,kbuf
[4096];
562 char *ddata
=NULL
,dbuf
[4096];
565 check_bsddbobject_open(dp
, NULL
);
570 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
,
571 &drec
, sequence_request
);
573 if (krec
.size
> sizeof(kbuf
)) kdata
= malloc(krec
.size
);
575 if (kdata
!= NULL
) memcpy(kdata
,krec
.data
,krec
.size
);
576 if (drec
.size
> sizeof(dbuf
)) ddata
= malloc(drec
.size
);
578 if (ddata
!= NULL
) memcpy(ddata
,drec
.data
,drec
.size
);
582 if ((kdata
== NULL
) || (ddata
== NULL
))
583 return PyErr_NoMemory();
588 PyErr_SetFromErrno(BsddbError
);
590 PyErr_SetString(PyExc_KeyError
, "no key/data pairs");
594 if (dp
->di_type
== DB_RECNO
)
595 result
= Py_BuildValue("is#", *((int*)kdata
),
598 result
= Py_BuildValue("s#s#", kdata
, krec
.size
,
600 if (kdata
!= kbuf
) free(kdata
);
601 if (ddata
!= dbuf
) free(ddata
);
606 bsddb_next(bsddbobject
*dp
)
608 return bsddb_seq(dp
, R_NEXT
);
611 bsddb_previous(bsddbobject
*dp
)
613 return bsddb_seq(dp
, R_PREV
);
616 bsddb_first(bsddbobject
*dp
)
618 return bsddb_seq(dp
, R_FIRST
);
621 bsddb_last(bsddbobject
*dp
)
623 return bsddb_seq(dp
, R_LAST
);
626 bsddb_sync(bsddbobject
*dp
)
630 check_bsddbobject_open(dp
, NULL
);
632 status
= (dp
->di_bsddb
->sync
)(dp
->di_bsddb
, 0);
635 PyErr_SetFromErrno(BsddbError
);
638 return PyInt_FromLong(status
= 0);
640 static PyMethodDef bsddb_methods
[] = {
641 {"close", (PyCFunction
)bsddb_close
, METH_NOARGS
},
642 {"keys", (PyCFunction
)bsddb_keys
, METH_NOARGS
},
643 {"has_key", (PyCFunction
)bsddb_has_key
, METH_VARARGS
},
644 {"set_location", (PyCFunction
)bsddb_set_location
, METH_VARARGS
},
645 {"next", (PyCFunction
)bsddb_next
, METH_NOARGS
},
646 {"previous", (PyCFunction
)bsddb_previous
, METH_NOARGS
},
647 {"first", (PyCFunction
)bsddb_first
, METH_NOARGS
},
648 {"last", (PyCFunction
)bsddb_last
, METH_NOARGS
},
649 {"sync", (PyCFunction
)bsddb_sync
, METH_NOARGS
},
650 {NULL
, NULL
} /* sentinel */
654 bsddb_getattr(PyObject
*dp
, char *name
)
656 return Py_FindMethod(bsddb_methods
, dp
, name
);
659 static PyTypeObject Bsddbtype
= {
660 PyObject_HEAD_INIT(NULL
)
665 (destructor
)bsddb_dealloc
, /*tp_dealloc*/
667 (getattrfunc
)bsddb_getattr
, /*tp_getattr*/
672 0, /*tp_as_sequence*/
673 &bsddb_as_mapping
, /*tp_as_mapping*/
677 bsdhashopen(PyObject
*self
, PyObject
*args
)
681 int flags
= O_RDONLY
;
687 int hash
= 0; /* XXX currently ignored */
690 if (!PyArg_ParseTuple(args
, "z|siiiiiii:hashopen",
692 &bsize
, &ffactor
, &nelem
, &cachesize
,
696 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
699 else if (flag
[0] == 'w')
701 else if (flag
[0] == 'c')
702 flags
= O_RDWR
|O_CREAT
;
703 else if (flag
[0] == 'n')
704 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
706 PyErr_SetString(BsddbError
,
707 "Flag should begin with 'r', 'w', 'c' or 'n'");
710 if (flag
[1] == 'l') {
711 #if defined(O_EXLOCK) && defined(O_SHLOCK)
717 PyErr_SetString(BsddbError
,
718 "locking not supported on this platform");
723 return newdbhashobject(file
, flags
, mode
,
724 bsize
, ffactor
, nelem
, cachesize
, hash
, lorder
);
728 bsdbtopen(PyObject
*self
, PyObject
*args
)
732 int flags
= O_RDONLY
;
738 unsigned int psize
= 0;
741 if (!PyArg_ParseTuple(args
, "z|siiiiiii:btopen",
743 &btflags
, &cachesize
, &maxkeypage
, &minkeypage
,
747 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
750 else if (flag
[0] == 'w')
752 else if (flag
[0] == 'c')
753 flags
= O_RDWR
|O_CREAT
;
754 else if (flag
[0] == 'n')
755 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
757 PyErr_SetString(BsddbError
,
758 "Flag should begin with 'r', 'w', 'c' or 'n'");
761 if (flag
[1] == 'l') {
762 #if defined(O_EXLOCK) && defined(O_SHLOCK)
768 PyErr_SetString(BsddbError
,
769 "locking not supported on this platform");
774 return newdbbtobject(file
, flags
, mode
,
775 btflags
, cachesize
, maxkeypage
, minkeypage
,
780 bsdrnopen(PyObject
*self
, PyObject
*args
)
784 int flags
= O_RDONLY
;
788 unsigned int psize
= 0;
794 if (!PyArg_ParseTuple(args
, "z|siiiiiiss:rnopen",
796 &rnflags
, &cachesize
, &psize
, &lorder
,
797 &reclen
, &bval
, &bfname
))
801 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
804 else if (flag
[0] == 'w')
806 else if (flag
[0] == 'c')
807 flags
= O_RDWR
|O_CREAT
;
808 else if (flag
[0] == 'n')
809 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
811 PyErr_SetString(BsddbError
,
812 "Flag should begin with 'r', 'w', 'c' or 'n'");
815 if (flag
[1] == 'l') {
816 #if defined(O_EXLOCK) && defined(O_SHLOCK)
822 PyErr_SetString(BsddbError
,
823 "locking not supported on this platform");
827 else if (flag
[1] != '\0') {
828 PyErr_SetString(BsddbError
,
829 "Flag char 2 should be 'l' or absent");
833 return newdbrnobject(file
, flags
, mode
, rnflags
, cachesize
,
834 psize
, lorder
, reclen
, bval
[0], bfname
);
837 static PyMethodDef bsddbmodule_methods
[] = {
838 {"hashopen", (PyCFunction
)bsdhashopen
, METH_VARARGS
},
839 {"btopen", (PyCFunction
)bsdbtopen
, METH_VARARGS
},
840 {"rnopen", (PyCFunction
)bsdrnopen
, METH_VARARGS
},
841 /* strictly for use by dbhhash!!! */
842 {"open", (PyCFunction
)bsdhashopen
, METH_VARARGS
},
850 Bsddbtype
.ob_type
= &PyType_Type
;
851 m
= Py_InitModule("bsddb185", bsddbmodule_methods
);
854 d
= PyModule_GetDict(m
);
855 BsddbError
= PyErr_NewException("bsddb.error", NULL
, NULL
);
856 if (BsddbError
!= NULL
)
857 PyDict_SetItemString(d
, "error", BsddbError
);