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 not be used in advertising or publicity pertaining to
13 distribution of the software without specific, written prior permission.
15 STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO
16 THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
17 FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE
18 FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
20 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
21 OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 ******************************************************************/
25 /* Berkeley DB interface.
27 Hacked: Guido van Rossum
28 Btree and Recno additions plus sequence methods: David Ely
31 - provide interface to the B-tree and record libraries too
32 - provide a way to access the various hash functions
33 - support more open flags
36 #include "allobjects.h"
37 #include "modsupport.h"
39 #include <sys/types.h>
43 /* Please don't include internal header files of the Berkeley db package
44 (it messes up the info required in the Setup file) */
49 int di_size
; /* -1 means recompute */
52 staticforward typeobject Bsddbtype
;
54 #define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
56 static object
*BsddbError
;
59 newdbhashobject(file
, flags
, mode
,
60 bsize
, ffactor
, nelem
, cachesize
, hash
, lorder
)
68 int hash
; /* XXX ignored */
74 if ((dp
= NEWOBJ(bsddbobject
, &Bsddbtype
)) == NULL
)
78 info
.ffactor
= ffactor
;
80 info
.cachesize
= cachesize
;
81 info
.hash
= NULL
; /* XXX should derive from hash argument */
84 if ((dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_HASH
, &info
)) == NULL
) {
85 err_errno(BsddbError
);
96 newdbbtobject(file
, flags
, mode
,
97 btflags
, cachesize
, maxkeypage
, minkeypage
, psize
, lorder
)
111 if ((dp
= NEWOBJ(bsddbobject
, &Bsddbtype
)) == NULL
)
114 info
.flags
= btflags
;
115 info
.cachesize
= cachesize
;
116 info
.maxkeypage
= maxkeypage
;
117 info
.minkeypage
= minkeypage
;
119 info
.lorder
= lorder
;
120 info
.compare
= 0; /* Use default comparison functions, for now..*/
123 if ((dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_BTREE
, &info
)) == NULL
) {
124 err_errno(BsddbError
);
135 newdbrnobject(file
, flags
, mode
,
136 rnflags
, cachesize
, psize
, lorder
, reclen
, bval
, bfname
)
151 if ((dp
= NEWOBJ(bsddbobject
, &Bsddbtype
)) == NULL
)
154 info
.flags
= rnflags
;
155 info
.cachesize
= cachesize
;
157 info
.lorder
= lorder
;
158 info
.reclen
= reclen
;
160 info
.bfname
= bfname
;
162 if ((dp
->di_bsddb
= dbopen(file
, flags
, mode
, DB_RECNO
, &info
)) == NULL
) {
163 err_errno(BsddbError
);
178 if (dp
->di_bsddb
!= NULL
) {
179 if ((dp
->di_bsddb
->close
)(dp
->di_bsddb
) != 0)
181 "Python bsddb: close errno %s in dealloc\n", errno
);
190 if (dp
->di_size
< 0) {
194 for (status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
,R_FIRST
);
196 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_NEXT
))
199 err_errno(BsddbError
);
208 bsddb_subscript(dp
, key
)
218 if (!getargs(key
, "s#", &data
, &size
))
223 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
226 err_errno(BsddbError
);
228 err_setval(KeyError
, key
);
232 return newsizedstringobject((char *)drec
.data
, (int)drec
.size
);
236 bsddb_ass_sub(dp
, key
, value
)
245 if (!getargs(key
, "s#", &data
, &size
)) {
246 err_setstr(TypeError
, "bsddb key type must be string");
253 status
= (dp
->di_bsddb
->del
)(dp
->di_bsddb
, &krec
, 0);
256 if (!getargs(value
, "s#", &data
, &size
)) {
257 err_setstr(TypeError
, "bsddb value type must be string");
262 status
= (dp
->di_bsddb
->put
)(dp
->di_bsddb
, &krec
, &drec
, 0);
266 err_errno(BsddbError
);
268 err_setval(KeyError
, key
);
274 static mapping_methods bsddb_as_mapping
= {
275 (inquiry
)bsddb_length
, /*mp_length*/
276 (binaryfunc
)bsddb_subscript
, /*mp_subscript*/
277 (objobjargproc
)bsddb_ass_sub
, /*mp_ass_subscript*/
281 bsddb_close(dp
, args
)
287 if (dp
->di_bsddb
!= NULL
) {
288 if ((dp
->di_bsddb
->close
)(dp
->di_bsddb
) != 0) {
290 err_errno(BsddbError
);
311 list
= newlistobject(0);
314 for (status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_FIRST
);
316 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_NEXT
)) {
317 item
= newsizedstringobject((char *)krec
.data
, (int)krec
.size
);
322 err
= addlistitem(list
, item
);
330 err_errno(BsddbError
);
335 dp
->di_size
= getlistsize(list
); /* We just did the work for this... */
340 bsddb_has_key(dp
, args
)
349 if (!getargs(args
, "s#", &data
, &size
))
354 status
= (dp
->di_bsddb
->get
)(dp
->di_bsddb
, &krec
, &drec
, 0);
356 err_errno(BsddbError
);
360 return newintobject(status
== 0);
364 bsddb_set_location(dp
, key
)
374 if (!getargs(key
, "s#", &data
, &size
))
379 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, R_CURSOR
);
382 err_errno(BsddbError
);
384 err_setval(KeyError
, key
);
388 return mkvalue("s#s#", krec
.data
, krec
.size
, drec
.data
, drec
.size
);
392 bsddb_seq(dp
, args
, sequence_request
)
395 int sequence_request
;
406 status
= (dp
->di_bsddb
->seq
)(dp
->di_bsddb
, &krec
, &drec
, sequence_request
);
409 err_errno(BsddbError
);
411 err_setval(KeyError
, args
);
415 return mkvalue("s#s#", krec
.data
, krec
.size
, drec
.data
, drec
.size
);
423 return bsddb_seq(dp
, key
, R_NEXT
);
426 bsddb_previous(dp
, key
)
430 return bsddb_seq(dp
, key
, R_PREV
);
437 return bsddb_seq(dp
, key
, R_FIRST
);
444 return bsddb_seq(dp
, key
, R_LAST
);
453 status
= (dp
->di_bsddb
->sync
)(dp
->di_bsddb
, 0);
455 err_errno(BsddbError
);
458 return newintobject(status
= 0);
460 static struct methodlist bsddb_methods
[] = {
461 {"close", (method
)bsddb_close
},
462 {"keys", (method
)bsddb_keys
},
463 {"has_key", (method
)bsddb_has_key
},
464 {"set_location", (method
)bsddb_set_location
},
465 {"next", (method
)bsddb_next
},
466 {"previous", (method
)bsddb_previous
},
467 {"first", (method
)bsddb_first
},
468 {"last", (method
)bsddb_last
},
469 {"sync", (method
)bsddb_sync
},
470 {NULL
, NULL
} /* sentinel */
474 bsddb_getattr(dp
, name
)
478 return findmethod(bsddb_methods
, dp
, name
);
481 static typeobject Bsddbtype
= {
482 OB_HEAD_INIT(&Typetype
)
487 (destructor
)bsddb_dealloc
, /*tp_dealloc*/
489 (getattrfunc
)bsddb_getattr
, /*tp_getattr*/
494 0, /*tp_as_sequence*/
495 &bsddb_as_mapping
, /*tp_as_mapping*/
499 bsdhashopen(self
, args
)
505 int flags
= O_RDONLY
;
511 int hash
= 0; /* XXX currently ignored */
514 if (!newgetargs(args
, "s|siiiiiii",
516 &bsize
, &ffactor
, &nelem
, &cachesize
, &hash
, &lorder
))
519 /* XXX need a way to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
522 else if (flag
[0] == 'w')
524 else if (flag
[0] == 'c')
525 flags
= O_RDWR
|O_CREAT
;
526 else if (flag
[0] == 'n')
527 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
529 err_setstr(BsddbError
,
530 "Flag should begin with 'r', 'w', 'c' or 'n'");
533 if (flag
[1] == 'l') {
534 #if defined(O_EXLOCK) && defined(O_SHLOCK)
540 err_setstr(BsddbError
, "locking not supported on this platform");
545 return newdbhashobject(file
, flags
, mode
,
546 bsize
, ffactor
, nelem
, cachesize
, hash
, lorder
);
550 bsdbtopen(self
, args
)
556 int flags
= O_RDONLY
;
562 unsigned int psize
= 0;
565 if (!newgetargs(args
, "s|siiiiiii",
567 &btflags
, &cachesize
, &maxkeypage
, &minkeypage
,
571 /* XXX need a way to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
574 else if (flag
[0] == 'w')
576 else if (flag
[0] == 'c')
577 flags
= O_RDWR
|O_CREAT
;
578 else if (flag
[0] == 'n')
579 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
581 err_setstr(BsddbError
,
582 "Flag should begin with 'r', 'w', 'c' or 'n'");
585 if (flag
[1] == 'l') {
586 #if defined(O_EXLOCK) && defined(O_SHLOCK)
592 err_setstr(BsddbError
, "locking not supported on this platform");
597 return newdbbtobject(file
, flags
, mode
,
598 btflags
, cachesize
, maxkeypage
, minkeypage
,
603 bsdrnopen(self
, args
)
609 int flags
= O_RDONLY
;
613 unsigned int psize
= 0;
619 if (!newgetargs(args
, "s|siiiiiiss",
621 &rnflags
, &cachesize
, &psize
, &lorder
,
622 &reclen
, &bval
, &bfname
))
625 /* XXX need a way to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
628 else if (flag
[0] == 'w')
630 else if (flag
[0] == 'c')
631 flags
= O_RDWR
|O_CREAT
;
632 else if (flag
[0] == 'n')
633 flags
= O_RDWR
|O_CREAT
|O_TRUNC
;
635 err_setstr(BsddbError
,
636 "Flag should begin with 'r', 'w', 'c' or 'n'");
639 if (flag
[1] == 'l') {
640 #if defined(O_EXLOCK) && defined(O_SHLOCK)
646 err_setstr(BsddbError
, "locking not supported on this platform");
650 else if (flag
[1] != '\0') {
651 err_setstr(BsddbError
,
652 "Flag char 2 should be 'l' or absent");
656 return newdbrnobject(file
, flags
, mode
,
657 rnflags
, cachesize
, psize
, lorder
, bval
[0], bfname
);
660 static struct methodlist bsddbmodule_methods
[] = {
661 {"hashopen", (method
)bsdhashopen
, 1},
662 {"btopen", (method
)bsdbtopen
, 1},
663 {"rnopen", (method
)bsdrnopen
, 1},
671 m
= initmodule("bsddb", bsddbmodule_methods
);
672 d
= getmoduledict(m
);
673 BsddbError
= newstringobject("bsddb.error");
674 if (BsddbError
== NULL
|| dictinsert(d
, "error", BsddbError
))
675 fatal("can't define bsddb.error");