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
)
279 if (dp
->di_type
== DB_RECNO
) {
280 if (!PyArg_Parse(key
, "i", &recno
)) {
281 PyErr_SetString(PyExc_TypeError
,
282 "key type must be integer");
286 krec
.size
= sizeof(recno
);
289 if (!PyArg_Parse(key
, "s#", &data
, &size
)) {
290 PyErr_SetString(PyExc_TypeError
,
291 "key type must be string");
297 check_bsddbobject_open(dp
, NULL
);
300 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
302 if (drec
.size
> sizeof(buf
)) data
= malloc(drec
.size
);
304 if (data
!=NULL
) memcpy(data
,drec
.data
,drec
.size
);
307 if (data
==NULL
) return PyErr_NoMemory();
310 PyErr_SetFromErrno(BsddbError
);
312 PyErr_SetObject(PyExc_KeyError
, key
);
316 result
= PyString_FromStringAndSize(data
, (int)drec
.size
);
317 if (data
!= buf
) free(data
);
322 bsddb_ass_sub(bsddbobject
*dp
, PyObject
*key
, PyObject
*value
)
330 if (dp
->di_type
== DB_RECNO
) {
331 if (!PyArg_Parse(key
, "i", &recno
)) {
332 PyErr_SetString(PyExc_TypeError
,
333 "bsddb key type must be integer");
337 krec
.size
= sizeof(recno
);
340 if (!PyArg_Parse(key
, "s#", &data
, &size
)) {
341 PyErr_SetString(PyExc_TypeError
,
342 "bsddb key type must be string");
348 check_bsddbobject_open(dp
, -1);
352 status
= (dp
->di_bsddb
->del
)(dp
->di_bsddb
, &krec
, 0);
356 if (!PyArg_Parse(value
, "s#", &data
, &size
)) {
357 PyErr_SetString(PyExc_TypeError
,
358 "bsddb value type must be string");
364 status
= (dp
->di_bsddb
->put
)(dp
->di_bsddb
, &krec
, &drec
, 0);
369 PyErr_SetFromErrno(BsddbError
);
371 PyErr_SetObject(PyExc_KeyError
, key
);
377 static PyMappingMethods bsddb_as_mapping
= {
378 (lenfunc
)bsddb_length
, /*mp_length*/
379 (binaryfunc
)bsddb_subscript
, /*mp_subscript*/
380 (objobjargproc
)bsddb_ass_sub
, /*mp_ass_subscript*/
384 bsddb_close(bsddbobject
*dp
)
386 if (dp
->di_bsddb
!= NULL
) {
389 status
= (dp
->di_bsddb
->close
)(dp
->di_bsddb
);
393 PyErr_SetFromErrno(BsddbError
);
403 bsddb_keys(bsddbobject
*dp
)
405 PyObject
*list
, *item
=NULL
;
407 char *data
=NULL
,buf
[4096];
411 check_bsddbobject_open(dp
, NULL
);
412 list
= PyList_New(0);
416 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_FIRST
);
418 if (krec
.size
> sizeof(buf
)) data
= malloc(krec
.size
);
420 if (data
!= NULL
) memcpy(data
,krec
.data
,krec
.size
);
423 if (status
== 0 && data
==NULL
) return PyErr_NoMemory();
424 while (status
== 0) {
425 if (dp
->di_type
== DB_RECNO
)
426 item
= PyInt_FromLong(*((int*)data
));
428 item
= PyString_FromStringAndSize(data
,
430 if (data
!= buf
) free(data
);
435 err
= PyList_Append(list
, item
);
442 status
= (dp
->di_bsddb
->seq
)
443 (dp
->di_bsddb
, &krec
, &drec
, R_NEXT
);
445 if (krec
.size
> sizeof(buf
))
446 data
= malloc(krec
.size
);
449 memcpy(data
,krec
.data
,krec
.size
);
452 if (data
== NULL
) return PyErr_NoMemory();
455 PyErr_SetFromErrno(BsddbError
);
460 dp
->di_size
= PyList_Size(list
); /* We just did the work */
465 bsddb_has_key(bsddbobject
*dp
, PyObject
*args
)
473 if (dp
->di_type
== DB_RECNO
) {
474 if (!PyArg_ParseTuple(args
, "i;key type must be integer",
479 krec
.size
= sizeof(recno
);
482 if (!PyArg_ParseTuple(args
, "s#;key type must be string",
489 check_bsddbobject_open(dp
, NULL
);
492 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
495 PyErr_SetFromErrno(BsddbError
);
499 return PyInt_FromLong(status
== 0);
503 bsddb_set_location(bsddbobject
*dp
, PyObject
*key
)
513 if (dp
->di_type
== DB_RECNO
) {
514 if (!PyArg_ParseTuple(key
, "i;key type must be integer",
519 krec
.size
= sizeof(recno
);
522 if (!PyArg_ParseTuple(key
, "s#;key type must be string",
529 check_bsddbobject_open(dp
, NULL
);
532 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_CURSOR
);
534 if (drec
.size
> sizeof(buf
)) data
= malloc(drec
.size
);
536 if (data
!=NULL
) memcpy(data
,drec
.data
,drec
.size
);
539 if (data
==NULL
) return PyErr_NoMemory();
542 PyErr_SetFromErrno(BsddbError
);
544 PyErr_SetObject(PyExc_KeyError
, key
);
548 if (dp
->di_type
== DB_RECNO
)
549 result
= Py_BuildValue("is#", *((int*)krec
.data
),
552 result
= Py_BuildValue("s#s#", krec
.data
, krec
.size
,
554 if (data
!= buf
) free(data
);
559 bsddb_seq(bsddbobject
*dp
, int sequence_request
)
563 char *kdata
=NULL
,kbuf
[4096];
564 char *ddata
=NULL
,dbuf
[4096];
567 check_bsddbobject_open(dp
, NULL
);
572 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
,
573 &drec
, sequence_request
);
575 if (krec
.size
> sizeof(kbuf
)) kdata
= malloc(krec
.size
);
577 if (kdata
!= NULL
) memcpy(kdata
,krec
.data
,krec
.size
);
578 if (drec
.size
> sizeof(dbuf
)) ddata
= malloc(drec
.size
);
580 if (ddata
!= NULL
) memcpy(ddata
,drec
.data
,drec
.size
);
584 if ((kdata
== NULL
) || (ddata
== NULL
))
585 return PyErr_NoMemory();
590 PyErr_SetFromErrno(BsddbError
);
592 PyErr_SetString(PyExc_KeyError
, "no key/data pairs");
596 if (dp
->di_type
== DB_RECNO
)
597 result
= Py_BuildValue("is#", *((int*)kdata
),
600 result
= Py_BuildValue("s#s#", kdata
, krec
.size
,
602 if (kdata
!= kbuf
) free(kdata
);
603 if (ddata
!= dbuf
) free(ddata
);
608 bsddb_next(bsddbobject
*dp
)
610 return bsddb_seq(dp
, R_NEXT
);
613 bsddb_previous(bsddbobject
*dp
)
615 return bsddb_seq(dp
, R_PREV
);
618 bsddb_first(bsddbobject
*dp
)
620 return bsddb_seq(dp
, R_FIRST
);
623 bsddb_last(bsddbobject
*dp
)
625 return bsddb_seq(dp
, R_LAST
);
628 bsddb_sync(bsddbobject
*dp
)
632 check_bsddbobject_open(dp
, NULL
);
634 status
= (dp
->di_bsddb
->sync
)(dp
->di_bsddb
, 0);
637 PyErr_SetFromErrno(BsddbError
);
640 return PyInt_FromLong(0);
642 static PyMethodDef bsddb_methods
[] = {
643 {"close", (PyCFunction
)bsddb_close
, METH_NOARGS
},
644 {"keys", (PyCFunction
)bsddb_keys
, METH_NOARGS
},
645 {"has_key", (PyCFunction
)bsddb_has_key
, METH_VARARGS
},
646 {"set_location", (PyCFunction
)bsddb_set_location
, METH_VARARGS
},
647 {"next", (PyCFunction
)bsddb_next
, METH_NOARGS
},
648 {"previous", (PyCFunction
)bsddb_previous
, METH_NOARGS
},
649 {"first", (PyCFunction
)bsddb_first
, METH_NOARGS
},
650 {"last", (PyCFunction
)bsddb_last
, METH_NOARGS
},
651 {"sync", (PyCFunction
)bsddb_sync
, METH_NOARGS
},
652 {NULL
, NULL
} /* sentinel */
656 bsddb_getattr(PyObject
*dp
, char *name
)
658 return Py_FindMethod(bsddb_methods
, dp
, name
);
661 static PyTypeObject Bsddbtype
= {
662 PyObject_HEAD_INIT(NULL
)
667 (destructor
)bsddb_dealloc
, /*tp_dealloc*/
669 (getattrfunc
)bsddb_getattr
, /*tp_getattr*/
674 0, /*tp_as_sequence*/
675 &bsddb_as_mapping
, /*tp_as_mapping*/
679 bsdhashopen(PyObject
*self
, PyObject
*args
)
683 int flags
= O_RDONLY
;
689 int hash
= 0; /* XXX currently ignored */
692 if (!PyArg_ParseTuple(args
, "z|siiiiiii:hashopen",
694 &bsize
, &ffactor
, &nelem
, &cachesize
,
698 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
701 else if (flag
[0] == 'w')
703 else if (flag
[0] == 'c')
704 flags
= O_RDWR
|O_CREAT
;
705 else if (flag
[0] == 'n')
706 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
708 PyErr_SetString(BsddbError
,
709 "Flag should begin with 'r', 'w', 'c' or 'n'");
712 if (flag
[1] == 'l') {
713 #if defined(O_EXLOCK) && defined(O_SHLOCK)
719 PyErr_SetString(BsddbError
,
720 "locking not supported on this platform");
725 return newdbhashobject(file
, flags
, mode
,
726 bsize
, ffactor
, nelem
, cachesize
, hash
, lorder
);
730 bsdbtopen(PyObject
*self
, PyObject
*args
)
734 int flags
= O_RDONLY
;
740 unsigned int psize
= 0;
743 if (!PyArg_ParseTuple(args
, "z|siiiiiii:btopen",
745 &btflags
, &cachesize
, &maxkeypage
, &minkeypage
,
749 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
752 else if (flag
[0] == 'w')
754 else if (flag
[0] == 'c')
755 flags
= O_RDWR
|O_CREAT
;
756 else if (flag
[0] == 'n')
757 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
759 PyErr_SetString(BsddbError
,
760 "Flag should begin with 'r', 'w', 'c' or 'n'");
763 if (flag
[1] == 'l') {
764 #if defined(O_EXLOCK) && defined(O_SHLOCK)
770 PyErr_SetString(BsddbError
,
771 "locking not supported on this platform");
776 return newdbbtobject(file
, flags
, mode
,
777 btflags
, cachesize
, maxkeypage
, minkeypage
,
782 bsdrnopen(PyObject
*self
, PyObject
*args
)
786 int flags
= O_RDONLY
;
790 unsigned int psize
= 0;
796 if (!PyArg_ParseTuple(args
, "z|siiiiiiss:rnopen",
798 &rnflags
, &cachesize
, &psize
, &lorder
,
799 &reclen
, &bval
, &bfname
))
803 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
806 else if (flag
[0] == 'w')
808 else if (flag
[0] == 'c')
809 flags
= O_RDWR
|O_CREAT
;
810 else if (flag
[0] == 'n')
811 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
813 PyErr_SetString(BsddbError
,
814 "Flag should begin with 'r', 'w', 'c' or 'n'");
817 if (flag
[1] == 'l') {
818 #if defined(O_EXLOCK) && defined(O_SHLOCK)
824 PyErr_SetString(BsddbError
,
825 "locking not supported on this platform");
829 else if (flag
[1] != '\0') {
830 PyErr_SetString(BsddbError
,
831 "Flag char 2 should be 'l' or absent");
835 return newdbrnobject(file
, flags
, mode
, rnflags
, cachesize
,
836 psize
, lorder
, reclen
, bval
[0], bfname
);
839 static PyMethodDef bsddbmodule_methods
[] = {
840 {"hashopen", (PyCFunction
)bsdhashopen
, METH_VARARGS
},
841 {"btopen", (PyCFunction
)bsdbtopen
, METH_VARARGS
},
842 {"rnopen", (PyCFunction
)bsdrnopen
, METH_VARARGS
},
843 /* strictly for use by dbhhash!!! */
844 {"open", (PyCFunction
)bsdhashopen
, METH_VARARGS
},
852 if (PyErr_WarnPy3k("the bsddb185 module has been removed in "
853 "Python 3.0", 2) < 0)
856 Bsddbtype
.ob_type
= &PyType_Type
;
857 m
= Py_InitModule("bsddb185", bsddbmodule_methods
);
860 d
= PyModule_GetDict(m
);
861 BsddbError
= PyErr_NewException("bsddb.error", NULL
, NULL
);
862 if (BsddbError
!= NULL
)
863 PyDict_SetItemString(d
, "error", BsddbError
);