3 DB_File.xs -- Perl 5 interface to Berkeley DB
5 written by Paul Marquess (pmarquess@bfsec.bt.co.uk)
6 last modified 18th 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
37 1.09 - Default mode for dbopen changed to 0666
53 #define DB_Prefix_t mDB_Prefix_t
60 #define DB_Hash_t mDB_Hash_t
78 typedef DB_File_type * DB_File ;
84 #define db_DESTROY(db) ((db->dbp)->close)(db->dbp)
85 #define db_DELETE(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
86 #define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
87 #define db_FETCH(db, key, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
89 #define db_close(db) ((db->dbp)->close)(db->dbp)
90 #define db_del(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
91 #define db_fd(db) ((db->dbp)->fd)(db->dbp)
92 #define db_put(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
93 #define db_get(db, key, value, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
94 #define db_seq(db, key, value, flags) ((db->dbp)->seq)(db->dbp, &key, &value, flags)
95 #define db_sync(db, flags) ((db->dbp)->sync)(db->dbp, flags)
98 #define OutputValue(arg, name) \
99 { if (RETVAL == 0) { \
100 sv_setpvn(arg, name.data, name.size) ; \
104 #define OutputKey(arg, name) \
107 if (db->type != DB_RECNO) { \
108 sv_setpvn(arg, name.data, name.size); \
111 sv_setiv(arg, (I32)*(I32*)name.data - 1); \
115 /* Internal Global Data */
116 static recno_t Value ;
117 static DB_File CurrentDB ;
118 static recno_t zero = 0 ;
119 static DBTKEY empty = { &zero, sizeof(recno_t) } ;
123 btree_compare(key1, key2)
128 void * data1, * data2 ;
135 /* As newSVpv will assume that the data pointer is a null terminated C
136 string if the size parameter is 0, make sure that data points to an
137 empty string if the length is 0
149 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
150 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
153 count = perl_call_sv(CurrentDB->compare, G_SCALAR);
158 croak ("DB_File btree_compare: expected 1 return value from %s, got %d\n", count) ;
170 btree_prefix(key1, key2)
175 void * data1, * data2 ;
182 /* As newSVpv will assume that the data pointer is a null terminated C
183 string if the size parameter is 0, make sure that data points to an
184 empty string if the length is 0
196 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
197 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
200 count = perl_call_sv(CurrentDB->prefix, G_SCALAR);
205 croak ("DB_File btree_prefix: expected 1 return value from %s, got %d\n", count) ;
228 /* DGH - Next two lines added to fix corrupted stack problem */
234 XPUSHs(sv_2mortal(newSVpv((char*)data,size)));
237 count = perl_call_sv(CurrentDB->hash, G_SCALAR);
242 croak ("DB_File hash_cb: expected 1 return value from %s, got %d\n", count) ;
260 printf ("HASH Info\n") ;
261 printf (" hash = %s\n", (hash->hash != NULL ? "redefined" : "default")) ;
262 printf (" bsize = %d\n", hash->bsize) ;
263 printf (" ffactor = %d\n", hash->ffactor) ;
264 printf (" nelem = %d\n", hash->nelem) ;
265 printf (" cachesize = %d\n", hash->cachesize) ;
266 printf (" lorder = %d\n", hash->lorder) ;
274 printf ("RECNO Info\n") ;
275 printf (" flags = %d\n", recno->flags) ;
276 printf (" cachesize = %d\n", recno->cachesize) ;
277 printf (" psize = %d\n", recno->psize) ;
278 printf (" lorder = %d\n", recno->lorder) ;
279 printf (" reclen = %d\n", recno->reclen) ;
280 printf (" bval = %d 0x%x\n", recno->bval, recno->bval) ;
281 printf (" bfname = %d [%s]\n", recno->bfname, recno->bfname) ;
288 printf ("BTREE Info\n") ;
289 printf (" compare = %s\n", (btree->compare ? "redefined" : "default")) ;
290 printf (" prefix = %s\n", (btree->prefix ? "redefined" : "default")) ;
291 printf (" flags = %d\n", btree->flags) ;
292 printf (" cachesize = %d\n", btree->cachesize) ;
293 printf (" psize = %d\n", btree->psize) ;
294 printf (" maxkeypage = %d\n", btree->maxkeypage) ;
295 printf (" minkeypage = %d\n", btree->minkeypage) ;
296 printf (" lorder = %d\n", btree->lorder) ;
301 #define PrintRecno(recno)
302 #define PrintHash(hash)
303 #define PrintBtree(btree)
316 RETVAL = (db->seq)(db, &key, &value, R_LAST) ;
318 RETVAL = *(I32 *)key.data ;
319 else if (RETVAL == 1) /* No key means empty file */
326 GetRecnoKey(db, value)
331 /* Get the length of the array */
332 I32 length = GetArrayLength(db->dbp) ;
334 /* check for attempt to write before start of array */
335 if (length + value + 1 <= 0)
336 croak("Modification of non-creatable array value attempted, subscript %d", value) ;
338 value = length + value + 1 ;
347 ParseOpenInfo(name, flags, mode, sv)
355 DB_File RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
356 void * openinfo = NULL ;
357 union INFO * info = &RETVAL->info ;
359 /* Default to HASH */
360 RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
361 RETVAL->type = DB_HASH ;
363 /* DGH - Next line added to avoid SEGV on existing hash DB */
369 croak ("type parameter is not a reference") ;
371 svp = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
372 if (svp && SvOK(*svp))
373 action = (HV*) SvRV(*svp) ;
375 croak("internal error") ;
377 if (sv_isa(sv, "DB_File::HASHINFO"))
379 RETVAL->type = DB_HASH ;
380 openinfo = (void*)info ;
382 svp = hv_fetch(action, "hash", 4, FALSE);
384 if (svp && SvOK(*svp))
386 info->hash.hash = hash_cb ;
387 RETVAL->hash = newSVsv(*svp) ;
390 info->hash.hash = NULL ;
392 svp = hv_fetch(action, "bsize", 5, FALSE);
393 info->hash.bsize = svp ? SvIV(*svp) : 0;
395 svp = hv_fetch(action, "ffactor", 7, FALSE);
396 info->hash.ffactor = svp ? SvIV(*svp) : 0;
398 svp = hv_fetch(action, "nelem", 5, FALSE);
399 info->hash.nelem = svp ? SvIV(*svp) : 0;
401 svp = hv_fetch(action, "cachesize", 9, FALSE);
402 info->hash.cachesize = svp ? SvIV(*svp) : 0;
404 svp = hv_fetch(action, "lorder", 6, FALSE);
405 info->hash.lorder = svp ? SvIV(*svp) : 0;
409 else if (sv_isa(sv, "DB_File::BTREEINFO"))
411 RETVAL->type = DB_BTREE ;
412 openinfo = (void*)info ;
414 svp = hv_fetch(action, "compare", 7, FALSE);
415 if (svp && SvOK(*svp))
417 info->btree.compare = btree_compare ;
418 RETVAL->compare = newSVsv(*svp) ;
421 info->btree.compare = NULL ;
423 svp = hv_fetch(action, "prefix", 6, FALSE);
424 if (svp && SvOK(*svp))
426 info->btree.prefix = btree_prefix ;
427 RETVAL->prefix = newSVsv(*svp) ;
430 info->btree.prefix = NULL ;
432 svp = hv_fetch(action, "flags", 5, FALSE);
433 info->btree.flags = svp ? SvIV(*svp) : 0;
435 svp = hv_fetch(action, "cachesize", 9, FALSE);
436 info->btree.cachesize = svp ? SvIV(*svp) : 0;
438 svp = hv_fetch(action, "minkeypage", 10, FALSE);
439 info->btree.minkeypage = svp ? SvIV(*svp) : 0;
441 svp = hv_fetch(action, "maxkeypage", 10, FALSE);
442 info->btree.maxkeypage = svp ? SvIV(*svp) : 0;
444 svp = hv_fetch(action, "psize", 5, FALSE);
445 info->btree.psize = svp ? SvIV(*svp) : 0;
447 svp = hv_fetch(action, "lorder", 6, FALSE);
448 info->btree.lorder = svp ? SvIV(*svp) : 0;
453 else if (sv_isa(sv, "DB_File::RECNOINFO"))
455 RETVAL->type = DB_RECNO ;
456 openinfo = (void *)info ;
458 svp = hv_fetch(action, "flags", 5, FALSE);
459 info->recno.flags = (u_long) svp ? SvIV(*svp) : 0;
461 svp = hv_fetch(action, "cachesize", 9, FALSE);
462 info->recno.cachesize = (u_int) svp ? SvIV(*svp) : 0;
464 svp = hv_fetch(action, "psize", 5, FALSE);
465 info->recno.psize = (int) svp ? SvIV(*svp) : 0;
467 svp = hv_fetch(action, "lorder", 6, FALSE);
468 info->recno.lorder = (int) svp ? SvIV(*svp) : 0;
470 svp = hv_fetch(action, "reclen", 6, FALSE);
471 info->recno.reclen = (size_t) svp ? SvIV(*svp) : 0;
473 svp = hv_fetch(action, "bval", 4, FALSE);
474 if (svp && SvOK(*svp))
477 info->recno.bval = (u_char)*SvPV(*svp, na) ;
479 info->recno.bval = (u_char)(unsigned long) SvIV(*svp) ;
483 if (info->recno.flags & R_FIXEDLEN)
484 info->recno.bval = (u_char) ' ' ;
486 info->recno.bval = (u_char) '\n' ;
489 svp = hv_fetch(action, "bfname", 6, FALSE);
490 if (svp && SvOK(*svp)) {
491 char * ptr = SvPV(*svp,na) ;
492 info->recno.bfname = (char*) na ? ptr : NULL ;
495 info->recno.bfname = NULL ;
500 croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
504 /* OS2 Specific Code */
511 RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ;
521 croak("DB_File::%s not implemented on this architecture", s);
535 if (strEQ(name, "BTREEMAGIC"))
541 if (strEQ(name, "BTREEVERSION"))
551 if (strEQ(name, "DB_LOCK"))
557 if (strEQ(name, "DB_SHMEM"))
563 if (strEQ(name, "DB_TXN"))
577 if (strEQ(name, "HASHMAGIC"))
583 if (strEQ(name, "HASHVERSION"))
599 if (strEQ(name, "MAX_PAGE_NUMBER"))
600 #ifdef MAX_PAGE_NUMBER
601 return (U32)MAX_PAGE_NUMBER;
605 if (strEQ(name, "MAX_PAGE_OFFSET"))
606 #ifdef MAX_PAGE_OFFSET
607 return MAX_PAGE_OFFSET;
611 if (strEQ(name, "MAX_REC_NUMBER"))
612 #ifdef MAX_REC_NUMBER
613 return (U32)MAX_REC_NUMBER;
627 if (strEQ(name, "RET_ERROR"))
633 if (strEQ(name, "RET_SPECIAL"))
639 if (strEQ(name, "RET_SUCCESS"))
645 if (strEQ(name, "R_CURSOR"))
651 if (strEQ(name, "R_DUP"))
657 if (strEQ(name, "R_FIRST"))
663 if (strEQ(name, "R_FIXEDLEN"))
669 if (strEQ(name, "R_IAFTER"))
675 if (strEQ(name, "R_IBEFORE"))
681 if (strEQ(name, "R_LAST"))
687 if (strEQ(name, "R_NEXT"))
693 if (strEQ(name, "R_NOKEY"))
699 if (strEQ(name, "R_NOOVERWRITE"))
701 return R_NOOVERWRITE;
705 if (strEQ(name, "R_PREV"))
711 if (strEQ(name, "R_RECNOSYNC"))
717 if (strEQ(name, "R_SETCURSOR"))
723 if (strEQ(name, "R_SNAPSHOT"))
747 if (strEQ(name, "__R_UNUSED"))
763 MODULE = DB_File PACKAGE = DB_File PREFIX = db_
772 db_DoTie_(dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0666, type=DB_HASH)
778 char * name = (char *) NULL ;
779 SV * sv = (SV *) NULL ;
781 if (items >= 2 && SvOK(ST(1)))
782 name = (char*) SvPV(ST(1), na) ;
787 RETVAL = ParseOpenInfo(name, flags, mode, sv) ;
788 if (RETVAL->dbp == NULL)
801 SvREFCNT_dec(db->hash) ;
803 SvREFCNT_dec(db->compare) ;
805 SvREFCNT_dec(db->prefix) ;
810 db_DELETE(db, key, flags=0)
827 RETVAL = (((db->dbp)->get)(db->dbp, &key, &value, 0) == 0) ;
833 db_FETCH(db, key, flags=0)
842 RETVAL = ((db->dbp)->get)(db->dbp, &key, &value, flags) ;
843 ST(0) = sv_newmortal();
845 sv_setpvn(ST(0), value.data, value.size);
849 db_STORE(db, key, value, flags=0)
868 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
869 ST(0) = sv_newmortal();
872 if (Db->type != DB_RECNO)
873 sv_setpvn(ST(0), key.data, key.size);
875 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
889 RETVAL = (Db->seq)(Db, &key, &value, R_NEXT) ;
890 ST(0) = sv_newmortal();
893 if (Db->type != DB_RECNO)
894 sv_setpvn(ST(0), key.data, key.size);
896 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
901 # These would be nice for RECNO
917 for (i = items-1 ; i > 0 ; --i)
919 value.data = SvPV(ST(i), na) ;
923 key.size = sizeof(int) ;
924 RETVAL = (Db->put)(Db, &key, &value, R_IBEFORE) ;
942 /* First get the final value */
943 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
944 ST(0) = sv_newmortal();
948 /* the call to del will trash value, so take a copy now */
949 sv_setpvn(ST(0), value.data, value.size);
950 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
952 sv_setsv(ST(0), &sv_undef);
966 /* get the first value */
967 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
968 ST(0) = sv_newmortal();
972 /* the call to del will trash value, so take a copy now */
973 sv_setpvn(ST(0), value.data, value.size);
974 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
976 sv_setsv (ST(0), &sv_undef) ;
987 DBTKEY * keyptr = &key ;
993 /* Set the Cursor to the Last element */
994 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
999 for (i = items - 1 ; i > 0 ; --i)
1001 value.data = SvPV(ST(i), na) ;
1003 RETVAL = (Db->put)(Db, keyptr, &value, R_IAFTER) ;
1018 RETVAL = GetArrayLength(db->dbp) ;
1024 # Now provide an interface to the rest of the DB functionality
1028 db_del(db, key, flags=0)
1037 db_get(db, key, value, flags=0)
1048 db_put(db, key, value, flags=0)
1056 key if (flags & (R_IAFTER|R_IBEFORE)) OutputKey(ST(1), key);
1065 db_sync(db, flags=0)
1073 db_seq(db, key, value, flags)