3 DB_File.xs -- Perl 5 interface to Berkeley DB
5 written by Paul Marquess (pmarquess@bfsec.bt.co.uk)
6 last modified 3rd Dec 1996
9 All comments/suggestions/problems are welcome
11 Copyright (c) 1995, 1996 Paul Marquess. All rights reserved.
12 This program is free software; you can redistribute it and/or
13 modify it under the same terms as Perl itself.
17 0.2 - No longer bombs out if dbopen returns an error.
18 0.3 - Added some support for multiple btree compares
19 1.0 - Complete support for multiple callbacks added.
20 Fixed a problem with pushing a value onto an empty list.
21 1.01 - Fixed a SunOS core dump problem.
22 The return value from TIEHASH wasn't set to NULL when
23 dbopen returned an error.
24 1.02 - Use ALIAS to define TIEARRAY.
25 Removed some redundant commented code.
26 Merged OS2 code into the main distribution.
27 Allow negative subscripts with RECNO interface.
28 Changed the default flags to O_CREAT|O_RDWR
30 1.04 - fixed a couple of bugs in hash_cb. Patches supplied by
31 Dave Hammen, hammen@gothamcity.jsc.nasa.gov
32 1.05 - Added logic to allow prefix & hash types to be specified via
34 1.06 - Minor namespace cleanup: Localized PrintBtree.
35 1.07 - Fixed bug with RECNO, where bval wasn't defaulting to "\n".
36 1.08 - No change to DB_File.xs
52 #define DB_Prefix_t mDB_Prefix_t
59 #define DB_Hash_t mDB_Hash_t
77 typedef DB_File_type * DB_File ;
83 #define db_DESTROY(db) ((db->dbp)->close)(db->dbp)
84 #define db_DELETE(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
85 #define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
86 #define db_FETCH(db, key, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
88 #define db_close(db) ((db->dbp)->close)(db->dbp)
89 #define db_del(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
90 #define db_fd(db) ((db->dbp)->fd)(db->dbp)
91 #define db_put(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
92 #define db_get(db, key, value, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
93 #define db_seq(db, key, value, flags) ((db->dbp)->seq)(db->dbp, &key, &value, flags)
94 #define db_sync(db, flags) ((db->dbp)->sync)(db->dbp, flags)
97 #define OutputValue(arg, name) \
98 { if (RETVAL == 0) { \
99 sv_setpvn(arg, name.data, name.size) ; \
103 #define OutputKey(arg, name) \
106 if (db->type != DB_RECNO) { \
107 sv_setpvn(arg, name.data, name.size); \
110 sv_setiv(arg, (I32)*(I32*)name.data - 1); \
114 /* Internal Global Data */
115 static recno_t Value ;
116 static DB_File CurrentDB ;
117 static recno_t zero = 0 ;
118 static DBTKEY empty = { &zero, sizeof(recno_t) } ;
122 btree_compare(key1, key2)
127 void * data1, * data2 ;
134 /* As newSVpv will assume that the data pointer is a null terminated C
135 string if the size parameter is 0, make sure that data points to an
136 empty string if the length is 0
148 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
149 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
152 count = perl_call_sv(CurrentDB->compare, G_SCALAR);
157 croak ("DB_File btree_compare: expected 1 return value from %s, got %d\n", count) ;
169 btree_prefix(key1, key2)
174 void * data1, * data2 ;
181 /* As newSVpv will assume that the data pointer is a null terminated C
182 string if the size parameter is 0, make sure that data points to an
183 empty string if the length is 0
195 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
196 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
199 count = perl_call_sv(CurrentDB->prefix, G_SCALAR);
204 croak ("DB_File btree_prefix: expected 1 return value from %s, got %d\n", count) ;
227 /* DGH - Next two lines added to fix corrupted stack problem */
233 XPUSHs(sv_2mortal(newSVpv((char*)data,size)));
236 count = perl_call_sv(CurrentDB->hash, G_SCALAR);
241 croak ("DB_File hash_cb: expected 1 return value from %s, got %d\n", count) ;
259 printf ("HASH Info\n") ;
260 printf (" hash = %s\n", (hash->hash != NULL ? "redefined" : "default")) ;
261 printf (" bsize = %d\n", hash->bsize) ;
262 printf (" ffactor = %d\n", hash->ffactor) ;
263 printf (" nelem = %d\n", hash->nelem) ;
264 printf (" cachesize = %d\n", hash->cachesize) ;
265 printf (" lorder = %d\n", hash->lorder) ;
273 printf ("RECNO Info\n") ;
274 printf (" flags = %d\n", recno->flags) ;
275 printf (" cachesize = %d\n", recno->cachesize) ;
276 printf (" psize = %d\n", recno->psize) ;
277 printf (" lorder = %d\n", recno->lorder) ;
278 printf (" reclen = %d\n", recno->reclen) ;
279 printf (" bval = %d 0x%x\n", recno->bval, recno->bval) ;
280 printf (" bfname = %d [%s]\n", recno->bfname, recno->bfname) ;
287 printf ("BTREE Info\n") ;
288 printf (" compare = %s\n", (btree->compare ? "redefined" : "default")) ;
289 printf (" prefix = %s\n", (btree->prefix ? "redefined" : "default")) ;
290 printf (" flags = %d\n", btree->flags) ;
291 printf (" cachesize = %d\n", btree->cachesize) ;
292 printf (" psize = %d\n", btree->psize) ;
293 printf (" maxkeypage = %d\n", btree->maxkeypage) ;
294 printf (" minkeypage = %d\n", btree->minkeypage) ;
295 printf (" lorder = %d\n", btree->lorder) ;
300 #define PrintRecno(recno)
301 #define PrintHash(hash)
302 #define PrintBtree(btree)
315 RETVAL = (db->seq)(db, &key, &value, R_LAST) ;
317 RETVAL = *(I32 *)key.data ;
318 else if (RETVAL == 1) /* No key means empty file */
325 GetRecnoKey(db, value)
330 /* Get the length of the array */
331 I32 length = GetArrayLength(db->dbp) ;
333 /* check for attempt to write before start of array */
334 if (length + value + 1 <= 0)
335 croak("Modification of non-creatable array value attempted, subscript %d", value) ;
337 value = length + value + 1 ;
346 ParseOpenInfo(name, flags, mode, sv)
354 DB_File RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
355 void * openinfo = NULL ;
356 union INFO * info = &RETVAL->info ;
358 /* Default to HASH */
359 RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
360 RETVAL->type = DB_HASH ;
362 /* DGH - Next line added to avoid SEGV on existing hash DB */
368 croak ("type parameter is not a reference") ;
370 svp = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
371 if (svp && SvOK(*svp))
372 action = (HV*) SvRV(*svp) ;
374 croak("internal error") ;
376 if (sv_isa(sv, "DB_File::HASHINFO"))
378 RETVAL->type = DB_HASH ;
379 openinfo = (void*)info ;
381 svp = hv_fetch(action, "hash", 4, FALSE);
383 if (svp && SvOK(*svp))
385 info->hash.hash = hash_cb ;
386 RETVAL->hash = newSVsv(*svp) ;
389 info->hash.hash = NULL ;
391 svp = hv_fetch(action, "bsize", 5, FALSE);
392 info->hash.bsize = svp ? SvIV(*svp) : 0;
394 svp = hv_fetch(action, "ffactor", 7, FALSE);
395 info->hash.ffactor = svp ? SvIV(*svp) : 0;
397 svp = hv_fetch(action, "nelem", 5, FALSE);
398 info->hash.nelem = svp ? SvIV(*svp) : 0;
400 svp = hv_fetch(action, "cachesize", 9, FALSE);
401 info->hash.cachesize = svp ? SvIV(*svp) : 0;
403 svp = hv_fetch(action, "lorder", 6, FALSE);
404 info->hash.lorder = svp ? SvIV(*svp) : 0;
408 else if (sv_isa(sv, "DB_File::BTREEINFO"))
410 RETVAL->type = DB_BTREE ;
411 openinfo = (void*)info ;
413 svp = hv_fetch(action, "compare", 7, FALSE);
414 if (svp && SvOK(*svp))
416 info->btree.compare = btree_compare ;
417 RETVAL->compare = newSVsv(*svp) ;
420 info->btree.compare = NULL ;
422 svp = hv_fetch(action, "prefix", 6, FALSE);
423 if (svp && SvOK(*svp))
425 info->btree.prefix = btree_prefix ;
426 RETVAL->prefix = newSVsv(*svp) ;
429 info->btree.prefix = NULL ;
431 svp = hv_fetch(action, "flags", 5, FALSE);
432 info->btree.flags = svp ? SvIV(*svp) : 0;
434 svp = hv_fetch(action, "cachesize", 9, FALSE);
435 info->btree.cachesize = svp ? SvIV(*svp) : 0;
437 svp = hv_fetch(action, "minkeypage", 10, FALSE);
438 info->btree.minkeypage = svp ? SvIV(*svp) : 0;
440 svp = hv_fetch(action, "maxkeypage", 10, FALSE);
441 info->btree.maxkeypage = svp ? SvIV(*svp) : 0;
443 svp = hv_fetch(action, "psize", 5, FALSE);
444 info->btree.psize = svp ? SvIV(*svp) : 0;
446 svp = hv_fetch(action, "lorder", 6, FALSE);
447 info->btree.lorder = svp ? SvIV(*svp) : 0;
452 else if (sv_isa(sv, "DB_File::RECNOINFO"))
454 RETVAL->type = DB_RECNO ;
455 openinfo = (void *)info ;
457 svp = hv_fetch(action, "flags", 5, FALSE);
458 info->recno.flags = (u_long) svp ? SvIV(*svp) : 0;
460 svp = hv_fetch(action, "cachesize", 9, FALSE);
461 info->recno.cachesize = (u_int) svp ? SvIV(*svp) : 0;
463 svp = hv_fetch(action, "psize", 5, FALSE);
464 info->recno.psize = (int) svp ? SvIV(*svp) : 0;
466 svp = hv_fetch(action, "lorder", 6, FALSE);
467 info->recno.lorder = (int) svp ? SvIV(*svp) : 0;
469 svp = hv_fetch(action, "reclen", 6, FALSE);
470 info->recno.reclen = (size_t) svp ? SvIV(*svp) : 0;
472 svp = hv_fetch(action, "bval", 4, FALSE);
473 if (svp && SvOK(*svp))
476 info->recno.bval = (u_char)*SvPV(*svp, na) ;
478 info->recno.bval = (u_char)(unsigned long) SvIV(*svp) ;
482 if (info->recno.flags & R_FIXEDLEN)
483 info->recno.bval = (u_char) ' ' ;
485 info->recno.bval = (u_char) '\n' ;
488 svp = hv_fetch(action, "bfname", 6, FALSE);
489 if (svp && SvOK(*svp)) {
490 char * ptr = SvPV(*svp,na) ;
491 info->recno.bfname = (char*) na ? ptr : NULL ;
494 info->recno.bfname = NULL ;
499 croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
503 /* OS2 Specific Code */
510 RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ;
520 croak("DB_File::%s not implemented on this architecture", s);
534 if (strEQ(name, "BTREEMAGIC"))
540 if (strEQ(name, "BTREEVERSION"))
550 if (strEQ(name, "DB_LOCK"))
556 if (strEQ(name, "DB_SHMEM"))
562 if (strEQ(name, "DB_TXN"))
576 if (strEQ(name, "HASHMAGIC"))
582 if (strEQ(name, "HASHVERSION"))
598 if (strEQ(name, "MAX_PAGE_NUMBER"))
599 #ifdef MAX_PAGE_NUMBER
600 return (U32)MAX_PAGE_NUMBER;
604 if (strEQ(name, "MAX_PAGE_OFFSET"))
605 #ifdef MAX_PAGE_OFFSET
606 return MAX_PAGE_OFFSET;
610 if (strEQ(name, "MAX_REC_NUMBER"))
611 #ifdef MAX_REC_NUMBER
612 return (U32)MAX_REC_NUMBER;
626 if (strEQ(name, "RET_ERROR"))
632 if (strEQ(name, "RET_SPECIAL"))
638 if (strEQ(name, "RET_SUCCESS"))
644 if (strEQ(name, "R_CURSOR"))
650 if (strEQ(name, "R_DUP"))
656 if (strEQ(name, "R_FIRST"))
662 if (strEQ(name, "R_FIXEDLEN"))
668 if (strEQ(name, "R_IAFTER"))
674 if (strEQ(name, "R_IBEFORE"))
680 if (strEQ(name, "R_LAST"))
686 if (strEQ(name, "R_NEXT"))
692 if (strEQ(name, "R_NOKEY"))
698 if (strEQ(name, "R_NOOVERWRITE"))
700 return R_NOOVERWRITE;
704 if (strEQ(name, "R_PREV"))
710 if (strEQ(name, "R_RECNOSYNC"))
716 if (strEQ(name, "R_SETCURSOR"))
722 if (strEQ(name, "R_SNAPSHOT"))
746 if (strEQ(name, "__R_UNUSED"))
762 MODULE = DB_File PACKAGE = DB_File PREFIX = db_
771 db_DoTie_(dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0640, type=DB_HASH)
777 char * name = (char *) NULL ;
778 SV * sv = (SV *) NULL ;
780 if (items >= 2 && SvOK(ST(1)))
781 name = (char*) SvPV(ST(1), na) ;
786 RETVAL = ParseOpenInfo(name, flags, mode, sv) ;
787 if (RETVAL->dbp == NULL)
800 SvREFCNT_dec(db->hash) ;
802 SvREFCNT_dec(db->compare) ;
804 SvREFCNT_dec(db->prefix) ;
809 db_DELETE(db, key, flags=0)
826 RETVAL = (((db->dbp)->get)(db->dbp, &key, &value, 0) == 0) ;
832 db_FETCH(db, key, flags=0)
841 RETVAL = ((db->dbp)->get)(db->dbp, &key, &value, flags) ;
842 ST(0) = sv_newmortal();
844 sv_setpvn(ST(0), value.data, value.size);
848 db_STORE(db, key, value, flags=0)
867 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
868 ST(0) = sv_newmortal();
871 if (Db->type != DB_RECNO)
872 sv_setpvn(ST(0), key.data, key.size);
874 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
888 RETVAL = (Db->seq)(Db, &key, &value, R_NEXT) ;
889 ST(0) = sv_newmortal();
892 if (Db->type != DB_RECNO)
893 sv_setpvn(ST(0), key.data, key.size);
895 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
900 # These would be nice for RECNO
916 for (i = items-1 ; i > 0 ; --i)
918 value.data = SvPV(ST(i), na) ;
922 key.size = sizeof(int) ;
923 RETVAL = (Db->put)(Db, &key, &value, R_IBEFORE) ;
941 /* First get the final value */
942 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
943 ST(0) = sv_newmortal();
947 /* the call to del will trash value, so take a copy now */
948 sv_setpvn(ST(0), value.data, value.size);
949 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
951 sv_setsv(ST(0), &sv_undef);
965 /* get the first value */
966 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
967 ST(0) = sv_newmortal();
971 /* the call to del will trash value, so take a copy now */
972 sv_setpvn(ST(0), value.data, value.size);
973 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
975 sv_setsv (ST(0), &sv_undef) ;
986 DBTKEY * keyptr = &key ;
992 /* Set the Cursor to the Last element */
993 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
998 for (i = items - 1 ; i > 0 ; --i)
1000 value.data = SvPV(ST(i), na) ;
1002 RETVAL = (Db->put)(Db, keyptr, &value, R_IAFTER) ;
1017 RETVAL = GetArrayLength(db->dbp) ;
1023 # Now provide an interface to the rest of the DB functionality
1027 db_del(db, key, flags=0)
1036 db_get(db, key, value, flags=0)
1047 db_put(db, key, value, flags=0)
1055 key if (flags & (R_IAFTER|R_IBEFORE)) OutputKey(ST(1), key);
1064 db_sync(db, flags=0)
1072 db_seq(db, key, value, flags)