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
48 #include <sys/types.h>
52 /* Please don't include internal header files of the Berkeley db package
53 (it messes up the info required in the Setup file) */
58 int di_size
; /* -1 means recompute */
60 PyThread_type_lock di_lock
;
64 staticforward PyTypeObject Bsddbtype
;
66 #define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
67 #define check_bsddbobject_open(v) if ((v)->di_bsddb == NULL) \
68 { PyErr_SetString(BsddbError, "BSDDB object has already been closed"); \
71 static PyObject
*BsddbError
;
74 newdbhashobject(file
, flags
, mode
,
75 bsize
, ffactor
, nelem
, cachesize
, hash
, lorder
)
83 int hash
; /* XXX ignored */
89 if ((dp
= PyObject_NEW(bsddbobject
, &Bsddbtype
)) == NULL
)
93 info
.ffactor
= ffactor
;
95 info
.cachesize
= cachesize
;
96 info
.hash
= NULL
; /* XXX should derive from hash argument */
102 Py_BEGIN_ALLOW_THREADS
103 dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_HASH
, &info
);
105 if (dp
->di_bsddb
== NULL
) {
106 PyErr_SetFromErrno(BsddbError
);
116 dp
->di_lock
= PyThread_allocate_lock();
117 if (dp
->di_lock
== NULL
) {
118 PyErr_SetString(BsddbError
, "can't allocate lock");
124 return (PyObject
*)dp
;
128 newdbbtobject(file
, flags
, mode
,
129 btflags
, cachesize
, maxkeypage
, minkeypage
, psize
, lorder
)
143 if ((dp
= PyObject_NEW(bsddbobject
, &Bsddbtype
)) == NULL
)
146 info
.flags
= btflags
;
147 info
.cachesize
= cachesize
;
148 info
.maxkeypage
= maxkeypage
;
149 info
.minkeypage
= minkeypage
;
151 info
.lorder
= lorder
;
152 info
.compare
= 0; /* Use default comparison functions, for now..*/
158 Py_BEGIN_ALLOW_THREADS
159 dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_BTREE
, &info
);
161 if (dp
->di_bsddb
== NULL
) {
162 PyErr_SetFromErrno(BsddbError
);
172 dp
->di_lock
= PyThread_allocate_lock();
173 if (dp
->di_lock
== NULL
) {
174 PyErr_SetString(BsddbError
, "can't allocate lock");
180 return (PyObject
*)dp
;
184 newdbrnobject(file
, flags
, mode
,
185 rnflags
, cachesize
, psize
, lorder
, reclen
, bval
, bfname
)
200 if ((dp
= PyObject_NEW(bsddbobject
, &Bsddbtype
)) == NULL
)
203 info
.flags
= rnflags
;
204 info
.cachesize
= cachesize
;
206 info
.lorder
= lorder
;
207 info
.reclen
= reclen
;
209 info
.bfname
= bfname
;
214 Py_BEGIN_ALLOW_THREADS
215 dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_RECNO
, &info
);
217 if (dp
->di_bsddb
== NULL
) {
218 PyErr_SetFromErrno(BsddbError
);
228 dp
->di_lock
= PyThread_allocate_lock();
229 if (dp
->di_lock
== NULL
) {
230 PyErr_SetString(BsddbError
, "can't allocate lock");
236 return (PyObject
*)dp
;
245 PyThread_acquire_lock(dp
->di_lock
, 0);
246 PyThread_release_lock(dp
->di_lock
);
247 PyThread_free_lock(dp
->di_lock
);
251 if (dp
->di_bsddb
!= NULL
) {
253 Py_BEGIN_ALLOW_THREADS
254 status
= (dp
->di_bsddb
->close
)(dp
->di_bsddb
);
258 "Python bsddb: close errno %d in dealloc\n",
265 #define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS PyThread_acquire_lock(_dp->di_lock,1);
266 #define BSDDB_END_SAVE(_dp) PyThread_release_lock(_dp->di_lock); Py_END_ALLOW_THREADS
268 #define BSDDB_BGN_SAVE(_dp) Py_BEGIN_ALLOW_THREADS
269 #define BSDDB_END_SAVE(_dp) Py_END_ALLOW_THREADS
276 if (dp
->di_bsddb
== NULL
) {
277 PyErr_SetString(BsddbError
, "BSDDB object has already been closed");
280 if (dp
->di_size
< 0) {
285 for (status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
,
286 &krec
, &drec
,R_FIRST
);
288 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
,
289 &krec
, &drec
, R_NEXT
))
293 PyErr_SetFromErrno(BsddbError
);
302 bsddb_subscript(dp
, key
)
308 char *data
,buf
[4096];
312 if (!PyArg_Parse(key
, "s#", &data
, &size
))
314 check_bsddbobject_open(dp
);
320 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
322 if (drec
.size
> sizeof(buf
)) data
= malloc(drec
.size
);
324 memcpy(data
,drec
.data
,drec
.size
);
329 PyErr_SetFromErrno(BsddbError
);
331 PyErr_SetObject(PyExc_KeyError
, key
);
335 result
= PyString_FromStringAndSize(data
, (int)drec
.size
);
336 if (data
!= buf
) free(data
);
341 bsddb_ass_sub(dp
, key
, value
)
343 PyObject
*key
, *value
;
350 if (!PyArg_Parse(key
, "s#", &data
, &size
)) {
351 PyErr_SetString(PyExc_TypeError
,
352 "bsddb key type must be string");
355 if (dp
->di_bsddb
== NULL
) {
356 PyErr_SetString(BsddbError
, "BSDDB object has already been closed");
364 status
= (dp
->di_bsddb
->del
)(dp
->di_bsddb
, &krec
, 0);
368 if (!PyArg_Parse(value
, "s#", &data
, &size
)) {
369 PyErr_SetString(PyExc_TypeError
,
370 "bsddb value type must be string");
376 /* For RECNO, put fails with 'No space left on device'
377 after a few short records are added?? Looks fine
378 to this point... linked with 1.85 on Solaris Intel
379 Roger E. Masse 1/16/97
381 printf("before put data: '%s', size: %d\n",
382 drec
.data
, drec
.size
);
383 printf("before put key= '%s', size= %d\n",
384 krec
.data
, krec
.size
);
387 status
= (dp
->di_bsddb
->put
)(dp
->di_bsddb
, &krec
, &drec
, 0);
392 PyErr_SetFromErrno(BsddbError
);
394 PyErr_SetObject(PyExc_KeyError
, key
);
400 static PyMappingMethods bsddb_as_mapping
= {
401 (inquiry
)bsddb_length
, /*mp_length*/
402 (binaryfunc
)bsddb_subscript
, /*mp_subscript*/
403 (objobjargproc
)bsddb_ass_sub
, /*mp_ass_subscript*/
407 bsddb_close(dp
, args
)
411 if (!PyArg_NoArgs(args
))
413 if (dp
->di_bsddb
!= NULL
) {
416 status
= (dp
->di_bsddb
->close
)(dp
->di_bsddb
);
420 PyErr_SetFromErrno(BsddbError
);
434 PyObject
*list
, *item
;
436 char *data
=NULL
,buf
[4096];
440 if (!PyArg_NoArgs(args
))
442 check_bsddbobject_open(dp
);
443 list
= PyList_New(0);
447 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_FIRST
);
449 if (krec
.size
> sizeof(buf
)) data
= malloc(krec
.size
);
451 memcpy(data
,krec
.data
,krec
.size
);
454 while (status
== 0) {
455 item
= PyString_FromStringAndSize(data
, (int)krec
.size
);
456 if (data
!= buf
) free(data
);
461 err
= PyList_Append(list
, item
);
468 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_NEXT
);
470 if (krec
.size
> sizeof(buf
)) data
= malloc(krec
.size
);
472 memcpy(data
,krec
.data
,krec
.size
);
477 PyErr_SetFromErrno(BsddbError
);
482 dp
->di_size
= PyList_Size(list
); /* We just did the work */
487 bsddb_has_key(dp
, args
)
496 if (!PyArg_Parse(args
, "s#", &data
, &size
))
498 check_bsddbobject_open(dp
);
503 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
506 PyErr_SetFromErrno(BsddbError
);
510 return PyInt_FromLong(status
== 0);
514 bsddb_set_location(dp
, key
)
520 char *data
,buf
[4096];
524 if (!PyArg_Parse(key
, "s#", &data
, &size
))
526 check_bsddbobject_open(dp
);
531 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_CURSOR
);
533 if (drec
.size
> sizeof(buf
)) data
= malloc(drec
.size
);
535 memcpy(data
,drec
.data
,drec
.size
);
540 PyErr_SetFromErrno(BsddbError
);
542 PyErr_SetObject(PyExc_KeyError
, key
);
546 result
= Py_BuildValue("s#s#", krec
.data
, krec
.size
, data
, drec
.size
);
547 if (data
!= buf
) free(data
);
552 bsddb_seq(dp
, args
, sequence_request
)
555 int sequence_request
;
559 char *kdata
=NULL
,kbuf
[4096];
560 char *ddata
=NULL
,dbuf
[4096];
563 if (!PyArg_NoArgs(args
))
566 check_bsddbobject_open(dp
);
571 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
,
572 &drec
, sequence_request
);
574 if (krec
.size
> sizeof(kbuf
)) kdata
= malloc(krec
.size
);
576 memcpy(kdata
,krec
.data
,krec
.size
);
577 if (drec
.size
> sizeof(dbuf
)) ddata
= malloc(drec
.size
);
579 memcpy(ddata
,drec
.data
,drec
.size
);
584 PyErr_SetFromErrno(BsddbError
);
586 PyErr_SetObject(PyExc_KeyError
, args
);
590 result
= Py_BuildValue("s#s#", kdata
, krec
.size
, ddata
, drec
.size
);
591 if (kdata
!= kbuf
) free(kdata
);
592 if (ddata
!= dbuf
) free(ddata
);
601 return bsddb_seq(dp
, key
, R_NEXT
);
604 bsddb_previous(dp
, key
)
608 return bsddb_seq(dp
, key
, R_PREV
);
615 return bsddb_seq(dp
, key
, R_FIRST
);
622 return bsddb_seq(dp
, key
, R_LAST
);
631 if (!PyArg_NoArgs(args
))
633 check_bsddbobject_open(dp
);
635 status
= (dp
->di_bsddb
->sync
)(dp
->di_bsddb
, 0);
638 PyErr_SetFromErrno(BsddbError
);
641 return PyInt_FromLong(status
= 0);
643 static PyMethodDef bsddb_methods
[] = {
644 {"close", (PyCFunction
)bsddb_close
},
645 {"keys", (PyCFunction
)bsddb_keys
},
646 {"has_key", (PyCFunction
)bsddb_has_key
},
647 {"set_location", (PyCFunction
)bsddb_set_location
},
648 {"next", (PyCFunction
)bsddb_next
},
649 {"previous", (PyCFunction
)bsddb_previous
},
650 {"first", (PyCFunction
)bsddb_first
},
651 {"last", (PyCFunction
)bsddb_last
},
652 {"sync", (PyCFunction
)bsddb_sync
},
653 {NULL
, NULL
} /* sentinel */
657 bsddb_getattr(dp
, name
)
661 return Py_FindMethod(bsddb_methods
, dp
, name
);
664 static PyTypeObject Bsddbtype
= {
665 PyObject_HEAD_INIT(NULL
)
670 (destructor
)bsddb_dealloc
, /*tp_dealloc*/
672 (getattrfunc
)bsddb_getattr
, /*tp_getattr*/
677 0, /*tp_as_sequence*/
678 &bsddb_as_mapping
, /*tp_as_mapping*/
682 bsdhashopen(self
, args
)
688 int flags
= O_RDONLY
;
694 int hash
= 0; /* XXX currently ignored */
697 if (!PyArg_ParseTuple(args
, "s|siiiiiii",
699 &bsize
, &ffactor
, &nelem
, &cachesize
,
703 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
706 else if (flag
[0] == 'w')
708 else if (flag
[0] == 'c')
709 flags
= O_RDWR
|O_CREAT
;
710 else if (flag
[0] == 'n')
711 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
713 PyErr_SetString(BsddbError
,
714 "Flag should begin with 'r', 'w', 'c' or 'n'");
717 if (flag
[1] == 'l') {
718 #if defined(O_EXLOCK) && defined(O_SHLOCK)
724 PyErr_SetString(BsddbError
,
725 "locking not supported on this platform");
730 return newdbhashobject(file
, flags
, mode
,
731 bsize
, ffactor
, nelem
, cachesize
, hash
, lorder
);
735 bsdbtopen(self
, args
)
741 int flags
= O_RDONLY
;
747 unsigned int psize
= 0;
750 if (!PyArg_ParseTuple(args
, "s|siiiiiii",
752 &btflags
, &cachesize
, &maxkeypage
, &minkeypage
,
756 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
759 else if (flag
[0] == 'w')
761 else if (flag
[0] == 'c')
762 flags
= O_RDWR
|O_CREAT
;
763 else if (flag
[0] == 'n')
764 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
766 PyErr_SetString(BsddbError
,
767 "Flag should begin with 'r', 'w', 'c' or 'n'");
770 if (flag
[1] == 'l') {
771 #if defined(O_EXLOCK) && defined(O_SHLOCK)
777 PyErr_SetString(BsddbError
,
778 "locking not supported on this platform");
783 return newdbbtobject(file
, flags
, mode
,
784 btflags
, cachesize
, maxkeypage
, minkeypage
,
789 bsdrnopen(self
, args
)
795 int flags
= O_RDONLY
;
799 unsigned int psize
= 0;
805 if (!PyArg_ParseTuple(args
, "s|siiiiiiss",
807 &rnflags
, &cachesize
, &psize
, &lorder
,
808 &reclen
, &bval
, &bfname
))
812 printf("file: %s\n", file
);
813 printf("flag: %s\n", flag
);
814 printf("mode: %d\n", mode
);
815 printf("rnflags: 0x%x\n", rnflags
);
816 printf("cachesize: %d\n", cachesize
);
817 printf("psize: %d\n", psize
);
818 printf("lorder: %d\n", 0);
819 printf("reclen: %d\n", reclen
);
820 printf("bval: %c\n", bval
[0]);
821 printf("bfname %s\n", bfname
);
825 /* XXX need to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
828 else if (flag
[0] == 'w')
830 else if (flag
[0] == 'c')
831 flags
= O_RDWR
|O_CREAT
;
832 else if (flag
[0] == 'n')
833 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
835 PyErr_SetString(BsddbError
,
836 "Flag should begin with 'r', 'w', 'c' or 'n'");
839 if (flag
[1] == 'l') {
840 #if defined(O_EXLOCK) && defined(O_SHLOCK)
846 PyErr_SetString(BsddbError
,
847 "locking not supported on this platform");
851 else if (flag
[1] != '\0') {
852 PyErr_SetString(BsddbError
,
853 "Flag char 2 should be 'l' or absent");
857 return newdbrnobject(file
, flags
, mode
, rnflags
, cachesize
,
858 psize
, lorder
, reclen
, bval
[0], bfname
);
861 static PyMethodDef bsddbmodule_methods
[] = {
862 {"hashopen", (PyCFunction
)bsdhashopen
, 1},
863 {"btopen", (PyCFunction
)bsdbtopen
, 1},
864 {"rnopen", (PyCFunction
)bsdrnopen
, 1},
872 Bsddbtype
.ob_type
= &PyType_Type
;
873 m
= Py_InitModule("bsddb", bsddbmodule_methods
);
874 d
= PyModule_GetDict(m
);
875 BsddbError
= PyErr_NewException("bsddb.error", NULL
, NULL
);
876 if (BsddbError
!= NULL
)
877 PyDict_SetItemString(d
, "error", BsddbError
);