Use py_resource module
[python/dscho.git] / Modules / bsddbmodule.c
blob8cf674e959e1c22f5c4fa616ba7c60a289bf331b
1 /***********************************************************
2 Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
3 The Netherlands.
5 All Rights Reserved
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.
26 Author: Michael McLay
27 Hacked: Guido van Rossum
28 Btree and Recno additions plus sequence methods: David Ely
30 XXX To do:
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>
40 #include <sys/stat.h>
41 #include <fcntl.h>
42 #include <db.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) */
46 typedef struct {
47 OB_HEAD
48 DB *di_bsddb;
49 int di_size; /* -1 means recompute */
50 } bsddbobject;
52 staticforward typeobject Bsddbtype;
54 #define is_bsddbobject(v) ((v)->ob_type == &Bsddbtype)
56 static object *BsddbError;
58 static object *
59 newdbhashobject(file, flags, mode,
60 bsize, ffactor, nelem, cachesize, hash, lorder)
61 char *file;
62 int flags;
63 int mode;
64 int bsize;
65 int ffactor;
66 int nelem;
67 int cachesize;
68 int hash; /* XXX ignored */
69 int lorder;
71 bsddbobject *dp;
72 HASHINFO info;
74 if ((dp = NEWOBJ(bsddbobject, &Bsddbtype)) == NULL)
75 return NULL;
77 info.bsize = bsize;
78 info.ffactor = ffactor;
79 info.nelem = nelem;
80 info.cachesize = cachesize;
81 info.hash = NULL; /* XXX should derive from hash argument */
82 info.lorder = lorder;
84 if ((dp->di_bsddb = dbopen(file, flags, mode, DB_HASH, &info)) == NULL) {
85 err_errno(BsddbError);
86 DECREF(dp);
87 return NULL;
90 dp->di_size = -1;
92 return (object *)dp;
95 static object *
96 newdbbtobject(file, flags, mode,
97 btflags, cachesize, maxkeypage, minkeypage, psize, lorder)
98 char *file;
99 int flags;
100 int mode;
101 int btflags;
102 int cachesize;
103 int maxkeypage;
104 int minkeypage;
105 int psize;
106 int lorder;
108 bsddbobject *dp;
109 BTREEINFO info;
111 if ((dp = NEWOBJ(bsddbobject, &Bsddbtype)) == NULL)
112 return NULL;
114 info.flags = btflags;
115 info.cachesize = cachesize;
116 info.maxkeypage = maxkeypage;
117 info.minkeypage = minkeypage;
118 info.psize = psize;
119 info.lorder = lorder;
120 info.compare = 0; /* Use default comparison functions, for now..*/
121 info.prefix = 0;
123 if ((dp->di_bsddb = dbopen(file, flags, mode, DB_BTREE, &info)) == NULL) {
124 err_errno(BsddbError);
125 DECREF(dp);
126 return NULL;
129 dp->di_size = -1;
131 return (object *)dp;
134 static object *
135 newdbrnobject(file, flags, mode,
136 rnflags, cachesize, psize, lorder, reclen, bval, bfname)
137 char *file;
138 int flags;
139 int mode;
140 int rnflags;
141 int cachesize;
142 int psize;
143 int lorder;
144 size_t reclen;
145 u_char bval;
146 char *bfname;
148 bsddbobject *dp;
149 RECNOINFO info;
151 if ((dp = NEWOBJ(bsddbobject, &Bsddbtype)) == NULL)
152 return NULL;
154 info.flags = rnflags;
155 info.cachesize = cachesize;
156 info.psize = psize;
157 info.lorder = lorder;
158 info.reclen = reclen;
159 info.bval = bval;
160 info.bfname = bfname;
162 if ((dp->di_bsddb = dbopen(file, flags, mode, DB_RECNO, &info)) == NULL) {
163 err_errno(BsddbError);
164 DECREF(dp);
165 return NULL;
168 dp->di_size = -1;
170 return (object *)dp;
174 static void
175 bsddb_dealloc(dp)
176 bsddbobject *dp;
178 if (dp->di_bsddb != NULL) {
179 if ((dp->di_bsddb->close)(dp->di_bsddb) != 0)
180 fprintf(stderr,
181 "Python bsddb: close errno %s in dealloc\n", errno);
183 DEL(dp);
186 static int
187 bsddb_length(dp)
188 bsddbobject *dp;
190 if (dp->di_size < 0) {
191 DBT krec, drec;
192 int status;
193 int size = 0;
194 for (status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec,R_FIRST);
195 status == 0;
196 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_NEXT))
197 size++;
198 if (status < 0) {
199 err_errno(BsddbError);
200 return -1;
202 dp->di_size = size;
204 return dp->di_size;
207 static object *
208 bsddb_subscript(dp, key)
209 bsddbobject *dp;
210 object *key;
212 int status;
213 object *v;
214 DBT krec, drec;
215 char *data;
216 int size;
218 if (!getargs(key, "s#", &data, &size))
219 return NULL;
220 krec.data = data;
221 krec.size = size;
223 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
224 if (status != 0) {
225 if (status < 0)
226 err_errno(BsddbError);
227 else
228 err_setval(KeyError, key);
229 return NULL;
232 return newsizedstringobject((char *)drec.data, (int)drec.size);
235 static int
236 bsddb_ass_sub(dp, key, value)
237 bsddbobject *dp;
238 object *key, *value;
240 int status;
241 DBT krec, drec;
242 char *data;
243 int size;
245 if (!getargs(key, "s#", &data, &size)) {
246 err_setstr(TypeError, "bsddb key type must be string");
247 return -1;
249 krec.data = data;
250 krec.size = size;
251 dp->di_size = -1;
252 if (value == NULL) {
253 status = (dp->di_bsddb->del)(dp->di_bsddb, &krec, 0);
255 else {
256 if (!getargs(value, "s#", &data, &size)) {
257 err_setstr(TypeError, "bsddb value type must be string");
258 return -1;
260 drec.data = data;
261 drec.size = size;
262 status = (dp->di_bsddb->put)(dp->di_bsddb, &krec, &drec, 0);
264 if (status != 0) {
265 if (status < 0)
266 err_errno(BsddbError);
267 else
268 err_setval(KeyError, key);
269 return -1;
271 return 0;
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*/
280 static object *
281 bsddb_close(dp, args)
282 bsddbobject *dp;
283 object *args;
285 if (!getnoarg(args))
286 return NULL;
287 if (dp->di_bsddb != NULL) {
288 if ((dp->di_bsddb->close)(dp->di_bsddb) != 0) {
289 dp->di_bsddb = NULL;
290 err_errno(BsddbError);
291 return NULL;
294 dp->di_bsddb = NULL;
295 INCREF(None);
296 return None;
299 static object *
300 bsddb_keys(dp, args)
301 bsddbobject *dp;
302 object *args;
304 object *list, *item;
305 DBT krec, drec;
306 int status;
307 int err;
309 if (!getnoarg(args))
310 return NULL;
311 list = newlistobject(0);
312 if (list == NULL)
313 return NULL;
314 for (status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_FIRST);
315 status == 0;
316 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_NEXT)) {
317 item = newsizedstringobject((char *)krec.data, (int)krec.size);
318 if (item == NULL) {
319 DECREF(list);
320 return NULL;
322 err = addlistitem(list, item);
323 DECREF(item);
324 if (err != 0) {
325 DECREF(list);
326 return NULL;
329 if (status < 0) {
330 err_errno(BsddbError);
331 DECREF(list);
332 return NULL;
334 if (dp->di_size < 0)
335 dp->di_size = getlistsize(list); /* We just did the work for this... */
336 return list;
339 static object *
340 bsddb_has_key(dp, args)
341 bsddbobject *dp;
342 object *args;
344 DBT krec, drec;
345 int status;
346 char *data;
347 int size;
349 if (!getargs(args, "s#", &data, &size))
350 return NULL;
351 krec.data = data;
352 krec.size = size;
354 status = (dp->di_bsddb->get)(dp->di_bsddb, &krec, &drec, 0);
355 if (status < 0) {
356 err_errno(BsddbError);
357 return NULL;
360 return newintobject(status == 0);
363 static object *
364 bsddb_set_location(dp, key)
365 bsddbobject *dp;
366 object *key;
368 int status;
369 object *v;
370 DBT krec, drec;
371 char *data;
372 int size;
374 if (!getargs(key, "s#", &data, &size))
375 return NULL;
376 krec.data = data;
377 krec.size = size;
379 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, R_CURSOR);
380 if (status != 0) {
381 if (status < 0)
382 err_errno(BsddbError);
383 else
384 err_setval(KeyError, key);
385 return NULL;
388 return mkvalue("s#s#", krec.data, krec.size, drec.data, drec.size);
391 static object *
392 bsddb_seq(dp, args, sequence_request)
393 bsddbobject *dp;
394 object *args;
395 int sequence_request;
397 int status;
398 DBT krec, drec;
400 if (!getnoarg(args))
401 return NULL;
403 krec.data = 0;
404 krec.size = 0;
406 status = (dp->di_bsddb->seq)(dp->di_bsddb, &krec, &drec, sequence_request);
407 if (status != 0) {
408 if (status < 0)
409 err_errno(BsddbError);
410 else
411 err_setval(KeyError, args);
412 return NULL;
415 return mkvalue("s#s#", krec.data, krec.size, drec.data, drec.size);
418 static object *
419 bsddb_next(dp, key)
420 bsddbobject *dp;
421 object *key;
423 return bsddb_seq(dp, key, R_NEXT);
425 static object *
426 bsddb_previous(dp, key)
427 bsddbobject *dp;
428 object *key;
430 return bsddb_seq(dp, key, R_PREV);
432 static object *
433 bsddb_first(dp, key)
434 bsddbobject *dp;
435 object *key;
437 return bsddb_seq(dp, key, R_FIRST);
439 static object *
440 bsddb_last(dp, key)
441 bsddbobject *dp;
442 object *key;
444 return bsddb_seq(dp, key, R_LAST);
446 static object *
447 bsddb_sync(dp, args)
448 bsddbobject *dp;
449 object *args;
451 int status;
453 status = (dp->di_bsddb->sync)(dp->di_bsddb, 0);
454 if (status != 0) {
455 err_errno(BsddbError);
456 return NULL;
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 */
473 static object *
474 bsddb_getattr(dp, name)
475 object *dp;
476 char *name;
478 return findmethod(bsddb_methods, dp, name);
481 static typeobject Bsddbtype = {
482 OB_HEAD_INIT(&Typetype)
484 "bsddb",
485 sizeof(bsddbobject),
487 (destructor)bsddb_dealloc, /*tp_dealloc*/
488 0, /*tp_print*/
489 (getattrfunc)bsddb_getattr, /*tp_getattr*/
490 0, /*tp_setattr*/
491 0, /*tp_compare*/
492 0, /*tp_repr*/
493 0, /*tp_as_number*/
494 0, /*tp_as_sequence*/
495 &bsddb_as_mapping, /*tp_as_mapping*/
498 static object *
499 bsdhashopen(self, args)
500 object *self;
501 object *args;
503 char *file;
504 char *flag = NULL;
505 int flags = O_RDONLY;
506 int mode = 0666;
507 int bsize = 0;
508 int ffactor = 0;
509 int nelem = 0;
510 int cachesize = 0;
511 int hash = 0; /* XXX currently ignored */
512 int lorder = 0;
514 if (!newgetargs(args, "s|siiiiiii",
515 &file, &flag, &mode,
516 &bsize, &ffactor, &nelem, &cachesize, &hash, &lorder))
517 return NULL;
518 if (flag != NULL) {
519 /* XXX need a way to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
520 if (flag[0] == 'r')
521 flags = O_RDONLY;
522 else if (flag[0] == 'w')
523 flags = O_RDWR;
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;
528 else {
529 err_setstr(BsddbError,
530 "Flag should begin with 'r', 'w', 'c' or 'n'");
531 return NULL;
533 if (flag[1] == 'l') {
534 #if defined(O_EXLOCK) && defined(O_SHLOCK)
535 if (flag[0] == 'r')
536 flags |= O_SHLOCK;
537 else
538 flags |= O_EXLOCK;
539 #else
540 err_setstr(BsddbError, "locking not supported on this platform");
541 return NULL;
542 #endif
545 return newdbhashobject(file, flags, mode,
546 bsize, ffactor, nelem, cachesize, hash, lorder);
549 static object *
550 bsdbtopen(self, args)
551 object *self;
552 object *args;
554 char *file;
555 char *flag = NULL;
556 int flags = O_RDONLY;
557 int mode = 0666;
558 int cachesize = 0;
559 int maxkeypage = 0;
560 int minkeypage = 0;
561 int btflags = 0;
562 unsigned int psize = 0;
563 int lorder = 0;
565 if (!newgetargs(args, "s|siiiiiii",
566 &file, &flag, &mode,
567 &btflags, &cachesize, &maxkeypage, &minkeypage,
568 &psize, &lorder))
569 return NULL;
570 if (flag != NULL) {
571 /* XXX need a way to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
572 if (flag[0] == 'r')
573 flags = O_RDONLY;
574 else if (flag[0] == 'w')
575 flags = O_RDWR;
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;
580 else {
581 err_setstr(BsddbError,
582 "Flag should begin with 'r', 'w', 'c' or 'n'");
583 return NULL;
585 if (flag[1] == 'l') {
586 #if defined(O_EXLOCK) && defined(O_SHLOCK)
587 if (flag[0] == 'r')
588 flags |= O_SHLOCK;
589 else
590 flags |= O_EXLOCK;
591 #else
592 err_setstr(BsddbError, "locking not supported on this platform");
593 return NULL;
594 #endif
597 return newdbbtobject(file, flags, mode,
598 btflags, cachesize, maxkeypage, minkeypage,
599 psize, lorder);
602 static object *
603 bsdrnopen(self, args)
604 object *self;
605 object *args;
607 char *file;
608 char *flag = NULL;
609 int flags = O_RDONLY;
610 int mode = 0666;
611 int cachesize = 0;
612 int rnflags = 0;
613 unsigned int psize = 0;
614 int lorder = 0;
615 size_t reclen = 0;
616 char *bval = "";
617 char *bfname = NULL;
619 if (!newgetargs(args, "s|siiiiiiss",
620 &file, &flag, &mode,
621 &rnflags, &cachesize, &psize, &lorder,
622 &reclen, &bval, &bfname))
623 return NULL;
624 if (flag != NULL) {
625 /* XXX need a way to pass O_EXCL, O_EXLOCK, O_NONBLOCK, O_SHLOCK */
626 if (flag[0] == 'r')
627 flags = O_RDONLY;
628 else if (flag[0] == 'w')
629 flags = O_RDWR;
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;
634 else {
635 err_setstr(BsddbError,
636 "Flag should begin with 'r', 'w', 'c' or 'n'");
637 return NULL;
639 if (flag[1] == 'l') {
640 #if defined(O_EXLOCK) && defined(O_SHLOCK)
641 if (flag[0] == 'r')
642 flags |= O_SHLOCK;
643 else
644 flags |= O_EXLOCK;
645 #else
646 err_setstr(BsddbError, "locking not supported on this platform");
647 return NULL;
648 #endif
650 else if (flag[1] != '\0') {
651 err_setstr(BsddbError,
652 "Flag char 2 should be 'l' or absent");
653 return NULL;
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},
664 {0, 0},
667 void
668 initbsddb() {
669 object *m, *d;
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");