1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
7 Permission to use, copy, modify, and distribute this software and its
8 documentation for any purpose and without fee is hereby granted,
9 provided that the above copyright notice appear in all copies and that
10 both that copyright notice and this permission notice appear in
11 supporting documentation, and that the names of Stichting Mathematisch
12 Centrum or CWI or Corporation for National Research Initiatives or
13 CNRI not be used in advertising or publicity pertaining to
14 distribution of the software without specific, written prior
17 While CWI is the initial source for this software, a modified version
18 is made available by the Corporation for National Research Initiatives
19 (CNRI) at the Internet address ftp://ftp.python.org.
21 STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
22 REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
23 MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
24 CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
25 DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
26 PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
27 TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
28 PERFORMANCE OF THIS SOFTWARE.
30 ******************************************************************/
32 /* Berkeley DB interface.
34 Hacked: Guido van Rossum
35 Btree and Recno additions plus sequence methods: David Ely
38 - provide interface to the B-tree and record libraries too
39 - provide a way to access the various hash functions
40 - support more open flags
42 The windows port of the Berkeley DB code is hard to find on the web:
43 www.nightmare.com/software.html
51 #include <sys/types.h>
55 /* Please don't include internal header files of the Berkeley db package
56 (it messes up the info required in the Setup file) */
61 int di_size
; /* -1 means recompute */
63 PyThread_type_lock di_lock
;
67 staticforward PyTypeObject Bsddbtype
;
69 #define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
70 #define check_bsddbobject_open(v) if ((v)->di_bsddb == NULL) \
71 { PyErr_SetString(BsddbError, "BSDDB object has already been closed"); \
74 static PyObject
*BsddbError
;
77 newdbhashobject(file
, flags
, mode
,
78 bsize
, ffactor
, nelem
, cachesize
, hash
, lorder
)
86 int hash
; /* XXX ignored */
92 if ((dp
= PyObject_NEW(bsddbobject
, &Bsddbtype
)) == NULL
)
96 info
.ffactor
= ffactor
;
98 info
.cachesize
= cachesize
;
99 info
.hash
= NULL
; /* XXX should derive from hash argument */
100 info
.lorder
= lorder
;
105 Py_BEGIN_ALLOW_THREADS
106 dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_HASH
, &info
);
108 if (dp
->di_bsddb
== NULL
) {
109 PyErr_SetFromErrno(BsddbError
);
119 dp
->di_lock
= PyThread_allocate_lock();
120 if (dp
->di_lock
== NULL
) {
121 PyErr_SetString(BsddbError
, "can't allocate lock");
127 return (PyObject
*)dp
;
131 newdbbtobject(file
, flags
, mode
,
132 btflags
, cachesize
, maxkeypage
, minkeypage
, psize
, lorder
)
146 if ((dp
= PyObject_NEW(bsddbobject
, &Bsddbtype
)) == NULL
)
149 info
.flags
= btflags
;
150 info
.cachesize
= cachesize
;
151 info
.maxkeypage
= maxkeypage
;
152 info
.minkeypage
= minkeypage
;
154 info
.lorder
= lorder
;
155 info
.compare
= 0; /* Use default comparison functions, for now..*/
161 Py_BEGIN_ALLOW_THREADS
162 dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_BTREE
, &info
);
164 if (dp
->di_bsddb
== NULL
) {
165 PyErr_SetFromErrno(BsddbError
);
175 dp
->di_lock
= PyThread_allocate_lock();
176 if (dp
->di_lock
== NULL
) {
177 PyErr_SetString(BsddbError
, "can't allocate lock");
183 return (PyObject
*)dp
;
187 newdbrnobject(file
, flags
, mode
,
188 rnflags
, cachesize
, psize
, lorder
, reclen
, bval
, bfname
)
203 if ((dp
= PyObject_NEW(bsddbobject
, &Bsddbtype
)) == NULL
)
206 info
.flags
= rnflags
;
207 info
.cachesize
= cachesize
;
209 info
.lorder
= lorder
;
210 info
.reclen
= reclen
;
212 info
.bfname
= bfname
;
217 Py_BEGIN_ALLOW_THREADS
218 dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_RECNO
, &info
);
220 if (dp
->di_bsddb
== NULL
) {
221 PyErr_SetFromErrno(BsddbError
);
231 dp
->di_lock
= PyThread_allocate_lock();
232 if (dp
->di_lock
== NULL
) {
233 PyErr_SetString(BsddbError
, "can't allocate lock");
239 return (PyObject
*)dp
;
248 PyThread_acquire_lock(dp
->di_lock
, 0);
249 PyThread_release_lock(dp
->di_lock
);
250 PyThread_free_lock(dp
->di_lock
);
254 if (dp
->di_bsddb
!= NULL
) {
256 Py_BEGIN_ALLOW_THREADS
257 status
= (dp
->di_bsddb
->close
)(dp
->di_bsddb
);
261 "Python bsddb: close errno %d in dealloc\n",
268 #define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1);
269 #define BSDDB_END_SAVE(_dp) PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS
271 #define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS
272 #define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS
279 if (dp
->di_bsddb
== NULL
) {
280 PyErr_SetString(BsddbError
, "BSDDB object has already been closed");
283 if (dp
->di_size
< 0) {
288 for (status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
,
289 &krec
, &drec
,R_FIRST
);
291 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
,
292 &krec
, &drec
, R_NEXT
))
296 PyErr_SetFromErrno(BsddbError
);
305 bsddb_subscript(dp
, key
)
311 char *data
,buf
[4096];
315 if (!PyArg_Parse(key
, "s#", &data
, &size
))
317 check_bsddbobject_open(dp
);
323 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
325 if (drec
.size
> sizeof(buf
)) data
= malloc(drec
.size
);
327 memcpy(data
,drec
.data
,drec
.size
);
332 PyErr_SetFromErrno(BsddbError
);
334 PyErr_SetObject(PyExc_KeyError
, key
);
338 result
= PyString_FromStringAndSize(data
, (int)drec
.size
);
339 if (data
!= buf
) free(data
);
344 bsddb_ass_sub(dp
, key
, value
)
346 PyObject
*key
, *value
;
353 if (!PyArg_Parse(key
, "s#", &data
, &size
)) {
354 PyErr_SetString(PyExc_TypeError
,
355 "bsddb key type must be string");
358 if (dp
->di_bsddb
== NULL
) {
359 PyErr_SetString(BsddbError
, "BSDDB object has already been closed");
367 status
= (dp
->di_bsddb
->del
)(dp
->di_bsddb
, &krec
, 0);
371 if (!PyArg_Parse(value
, "s#", &data
, &size
)) {
372 PyErr_SetString(PyExc_TypeError
,
373 "bsddb value type must be string");
379 /* For RECNO, put fails with 'No space left on device'
380 after a few short records are added?? Looks fine
381 to this point... linked with 1.85 on Solaris Intel
382 Roger E. Masse 1/16/97
384 printf("before put data: '%s', size: %d\n",
385 drec
.data
, drec
.size
);
386 printf("before put key= '%s', size= %d\n",
387 krec
.data
, krec
.size
);
390 status
= (dp
->di_bsddb
->put
)(dp
->di_bsddb
, &krec
, &drec
, 0);
395 PyErr_SetFromErrno(BsddbError
);
397 PyErr_SetObject(PyExc_KeyError
, key
);
403 static PyMappingMethods bsddb_as_mapping
= {
404 (inquiry
)bsddb_length
, /*mp_length*/
405 (binaryfunc
)bsddb_subscript
, /*mp_subscript*/
406 (objobjargproc
)bsddb_ass_sub
, /*mp_ass_subscript*/
410 bsddb_close(dp
, args
)
414 if (!PyArg_NoArgs(args
))
416 if (dp
->di_bsddb
!= NULL
) {
419 status
= (dp
->di_bsddb
->close
)(dp
->di_bsddb
);
423 PyErr_SetFromErrno(BsddbError
);
437 PyObject
*list
, *item
;
439 char *data
=NULL
,buf
[4096];
443 if (!PyArg_NoArgs(args
))
445 check_bsddbobject_open(dp
);
446 list
= PyList_New(0);
450 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_FIRST
);
452 if (krec
.size
> sizeof(buf
)) data
= malloc(krec
.size
);
454 memcpy(data
,krec
.data
,krec
.size
);
457 while (status
== 0) {
458 item
= PyString_FromStringAndSize(data
, (int)krec
.size
);
459 if (data
!= buf
) free(data
);
464 err
= PyList_Append(list
, item
);
471 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_NEXT
);
473 if (krec
.size
> sizeof(buf
)) data
= malloc(krec
.size
);
475 memcpy(data
,krec
.data
,krec
.size
);
480 PyErr_SetFromErrno(BsddbError
);
485 dp
->di_size
= PyList_Size(list
); /* We just did the work */
490 bsddb_has_key(dp
, args
)
499 if (!PyArg_Parse(args
, "s#", &data
, &size
))
501 check_bsddbobject_open(dp
);
506 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
509 PyErr_SetFromErrno(BsddbError
);
513 return PyInt_FromLong(status
== 0);
517 bsddb_set_location(dp
, key
)
523 char *data
,buf
[4096];
527 if (!PyArg_Parse(key
, "s#", &data
, &size
))
529 check_bsddbobject_open(dp
);
534 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_CURSOR
);
536 if (drec
.size
> sizeof(buf
)) data
= malloc(drec
.size
);
538 memcpy(data
,drec
.data
,drec
.size
);
543 PyErr_SetFromErrno(BsddbError
);
545 PyErr_SetObject(PyExc_KeyError
, key
);
549 result
= Py_BuildValue("s#s#", krec
.data
, krec
.size
, data
, drec
.size
);
550 if (data
!= buf
) free(data
);
555 bsddb_seq(dp
, args
, sequence_request
)
558 int sequence_request
;
562 char *kdata
=NULL
,kbuf
[4096];
563 char *ddata
=NULL
,dbuf
[4096];
566 if (!PyArg_NoArgs(args
))
569 check_bsddbobject_open(dp
);
574 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
,
575 &drec
, sequence_request
);
577 if (krec
.size
> sizeof(kbuf
)) kdata
= malloc(krec
.size
);
579 memcpy(kdata
,krec
.data
,krec
.size
);
580 if (drec
.size
> sizeof(dbuf
)) ddata
= malloc(drec
.size
);
582 memcpy(ddata
,drec
.data
,drec
.size
);
587 PyErr_SetFromErrno(BsddbError
);
589 PyErr_SetObject(PyExc_KeyError
, args
);
593 result
= Py_BuildValue("s#s#", kdata
, krec
.size
, ddata
, drec
.size
);
594 if (kdata
!= kbuf
) free(kdata
);
595 if (ddata
!= dbuf
) free(ddata
);
604 return bsddb_seq(dp
, key
, R_NEXT
);
607 bsddb_previous(dp
, key
)
611 return bsddb_seq(dp
, key
, R_PREV
);
618 return bsddb_seq(dp
, key
, R_FIRST
);
625 return bsddb_seq(dp
, key
, R_LAST
);
634 if (!PyArg_NoArgs(args
))
636 check_bsddbobject_open(dp
);
638 status
= (dp
->di_bsddb
->sync
)(dp
->di_bsddb
, 0);
641 PyErr_SetFromErrno(BsddbError
);
644 return PyInt_FromLong(status
= 0);
646 static PyMethodDef bsddb_methods
[] = {
647 {"close", (PyCFunction
)bsddb_close
},
648 {"keys", (PyCFunction
)bsddb_keys
},
649 {"has_key", (PyCFunction
)bsddb_has_key
},
650 {"set_location", (PyCFunction
)bsddb_set_location
},
651 {"next", (PyCFunction
)bsddb_next
},
652 {"previous", (PyCFunction
)bsddb_previous
},
653 {"first", (PyCFunction
)bsddb_first
},
654 {"last", (PyCFunction
)bsddb_last
},
655 {"sync", (PyCFunction
)bsddb_sync
},
656 {NULL
, NULL
} /* sentinel */
660 bsddb_getattr(dp
, name
)
664 return Py_FindMethod(bsddb_methods
, dp
, name
);
667 static PyTypeObject Bsddbtype
= {
668 PyObject_HEAD_INIT(NULL
)
673 (destructor
)bsddb_dealloc
, /*tp_dealloc*/
675 (getattrfunc
)bsddb_getattr
, /*tp_getattr*/
680 0, /*tp_as_sequence*/
681 &bsddb_as_mapping
, /*tp_as_mapping*/
685 bsdhashopen(self
, args
)
691 int flags
= O_RDONLY
;
697 int hash
= 0; /* XXX currently ignored */
700 if (!PyArg_ParseTuple(args
, "s|siiiiiii",
702 &bsize
, &ffactor
, &nelem
, &cachesize
,
706 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
709 else if (flag
[0] == 'w')
711 else if (flag
[0] == 'c')
712 flags
= O_RDWR
|O_CREAT
;
713 else if (flag
[0] == 'n')
714 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
716 PyErr_SetString(BsddbError
,
717 "Flag should begin with 'r', 'w', 'c' or 'n'");
720 if (flag
[1] == 'l') {
721 #if defined(O_EXLOCK) && defined(O_SHLOCK)
727 PyErr_SetString(BsddbError
,
728 "locking not supported on this platform");
733 return newdbhashobject(file
, flags
, mode
,
734 bsize
, ffactor
, nelem
, cachesize
, hash
, lorder
);
738 bsdbtopen(self
, args
)
744 int flags
= O_RDONLY
;
750 unsigned int psize
= 0;
753 if (!PyArg_ParseTuple(args
, "s|siiiiiii",
755 &btflags
, &cachesize
, &maxkeypage
, &minkeypage
,
759 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
762 else if (flag
[0] == 'w')
764 else if (flag
[0] == 'c')
765 flags
= O_RDWR
|O_CREAT
;
766 else if (flag
[0] == 'n')
767 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
769 PyErr_SetString(BsddbError
,
770 "Flag should begin with 'r', 'w', 'c' or 'n'");
773 if (flag
[1] == 'l') {
774 #if defined(O_EXLOCK) && defined(O_SHLOCK)
780 PyErr_SetString(BsddbError
,
781 "locking not supported on this platform");
786 return newdbbtobject(file
, flags
, mode
,
787 btflags
, cachesize
, maxkeypage
, minkeypage
,
792 bsdrnopen(self
, args
)
798 int flags
= O_RDONLY
;
802 unsigned int psize
= 0;
808 if (!PyArg_ParseTuple(args
, "s|siiiiiiss",
810 &rnflags
, &cachesize
, &psize
, &lorder
,
811 &reclen
, &bval
, &bfname
))
815 printf("file: %s\n", file
);
816 printf("flag: %s\n", flag
);
817 printf("mode: %d\n", mode
);
818 printf("rnflags: 0x%x\n", rnflags
);
819 printf("cachesize: %d\n", cachesize
);
820 printf("psize: %d\n", psize
);
821 printf("lorder: %d\n", 0);
822 printf("reclen: %d\n", reclen
);
823 printf("bval: %c\n", bval
[0]);
824 printf("bfname %s\n", bfname
);
828 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
831 else if (flag
[0] == 'w')
833 else if (flag
[0] == 'c')
834 flags
= O_RDWR
|O_CREAT
;
835 else if (flag
[0] == 'n')
836 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
838 PyErr_SetString(BsddbError
,
839 "Flag should begin with 'r', 'w', 'c' or 'n'");
842 if (flag
[1] == 'l') {
843 #if defined(O_EXLOCK) && defined(O_SHLOCK)
849 PyErr_SetString(BsddbError
,
850 "locking not supported on this platform");
854 else if (flag
[1] != '\0') {
855 PyErr_SetString(BsddbError
,
856 "Flag char 2 should be 'l' or absent");
860 return newdbrnobject(file
, flags
, mode
, rnflags
, cachesize
,
861 psize
, lorder
, reclen
, bval
[0], bfname
);
864 static PyMethodDef bsddbmodule_methods
[] = {
865 {"hashopen", (PyCFunction
)bsdhashopen
, 1},
866 {"btopen", (PyCFunction
)bsdbtopen
, 1},
867 {"rnopen", (PyCFunction
)bsdrnopen
, 1},
875 Bsddbtype
.ob_type
= &PyType_Type
;
876 m
= Py_InitModule("bsddb", bsddbmodule_methods
);
877 d
= PyModule_GetDict(m
);
878 BsddbError
= PyErr_NewException("bsddb.error", NULL
, NULL
);
879 if (BsddbError
!= NULL
)
880 PyDict_SetItemString(d
, "error", BsddbError
);