3 DB_File.xs -- Perl 5 interface to Berkeley DB
5 written by Paul Marquess (pmarquess@bfsec.bt.co.uk)
6 last modified 14th Jan 1997
9 All comments/suggestions/problems are welcome
11 Copyright (c) 1995, 1996, 1997 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
38 1.10 - Fixed fd method so that it still returns -1 for
39 in-memory files when db 1.86 is used.
55 #define DB_Prefix_t mDB_Prefix_t
62 #define DB_Hash_t mDB_Hash_t
81 typedef DB_File_type * DB_File ;
87 #define db_DESTROY(db) ((db->dbp)->close)(db->dbp)
88 #define db_DELETE(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
89 #define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
90 #define db_FETCH(db, key, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
92 #define db_close(db) ((db->dbp)->close)(db->dbp)
93 #define db_del(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
94 #define db_fd(db) (db->in_memory \
96 : ((db->dbp)->fd)(db->dbp) )
97 #define db_put(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
98 #define db_get(db, key, value, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
99 #define db_seq(db, key, value, flags) ((db->dbp)->seq)(db->dbp, &key, &value, flags)
100 #define db_sync(db, flags) ((db->dbp)->sync)(db->dbp, flags)
103 #define OutputValue(arg, name) \
104 { if (RETVAL == 0) { \
105 sv_setpvn(arg, name.data, name.size) ; \
109 #define OutputKey(arg, name) \
112 if (db->type != DB_RECNO) { \
113 sv_setpvn(arg, name.data, name.size); \
116 sv_setiv(arg, (I32)*(I32*)name.data - 1); \
120 /* Internal Global Data */
121 static recno_t Value ;
122 static DB_File CurrentDB ;
123 static recno_t zero = 0 ;
124 static DBTKEY empty = { &zero, sizeof(recno_t) } ;
128 btree_compare(key1, key2)
133 void * data1, * data2 ;
140 /* As newSVpv will assume that the data pointer is a null terminated C
141 string if the size parameter is 0, make sure that data points to an
142 empty string if the length is 0
154 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
155 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
158 count = perl_call_sv(CurrentDB->compare, G_SCALAR);
163 croak ("DB_File btree_compare: expected 1 return value from %s, got %d\n", count) ;
175 btree_prefix(key1, key2)
180 void * data1, * data2 ;
187 /* As newSVpv will assume that the data pointer is a null terminated C
188 string if the size parameter is 0, make sure that data points to an
189 empty string if the length is 0
201 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
202 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
205 count = perl_call_sv(CurrentDB->prefix, G_SCALAR);
210 croak ("DB_File btree_prefix: expected 1 return value from %s, got %d\n", count) ;
233 /* DGH - Next two lines added to fix corrupted stack problem */
239 XPUSHs(sv_2mortal(newSVpv((char*)data,size)));
242 count = perl_call_sv(CurrentDB->hash, G_SCALAR);
247 croak ("DB_File hash_cb: expected 1 return value from %s, got %d\n", count) ;
265 printf ("HASH Info\n") ;
266 printf (" hash = %s\n", (hash->hash != NULL ? "redefined" : "default")) ;
267 printf (" bsize = %d\n", hash->bsize) ;
268 printf (" ffactor = %d\n", hash->ffactor) ;
269 printf (" nelem = %d\n", hash->nelem) ;
270 printf (" cachesize = %d\n", hash->cachesize) ;
271 printf (" lorder = %d\n", hash->lorder) ;
279 printf ("RECNO Info\n") ;
280 printf (" flags = %d\n", recno->flags) ;
281 printf (" cachesize = %d\n", recno->cachesize) ;
282 printf (" psize = %d\n", recno->psize) ;
283 printf (" lorder = %d\n", recno->lorder) ;
284 printf (" reclen = %d\n", recno->reclen) ;
285 printf (" bval = %d 0x%x\n", recno->bval, recno->bval) ;
286 printf (" bfname = %d [%s]\n", recno->bfname, recno->bfname) ;
293 printf ("BTREE Info\n") ;
294 printf (" compare = %s\n", (btree->compare ? "redefined" : "default")) ;
295 printf (" prefix = %s\n", (btree->prefix ? "redefined" : "default")) ;
296 printf (" flags = %d\n", btree->flags) ;
297 printf (" cachesize = %d\n", btree->cachesize) ;
298 printf (" psize = %d\n", btree->psize) ;
299 printf (" maxkeypage = %d\n", btree->maxkeypage) ;
300 printf (" minkeypage = %d\n", btree->minkeypage) ;
301 printf (" lorder = %d\n", btree->lorder) ;
306 #define PrintRecno(recno)
307 #define PrintHash(hash)
308 #define PrintBtree(btree)
321 RETVAL = (db->seq)(db, &key, &value, R_LAST) ;
323 RETVAL = *(I32 *)key.data ;
324 else if (RETVAL == 1) /* No key means empty file */
327 return ((I32)RETVAL) ;
331 GetRecnoKey(db, value)
336 /* Get the length of the array */
337 I32 length = GetArrayLength(db->dbp) ;
339 /* check for attempt to write before start of array */
340 if (length + value + 1 <= 0)
341 croak("Modification of non-creatable array value attempted, subscript %d", value) ;
343 value = length + value + 1 ;
352 ParseOpenInfo(name, flags, mode, sv)
360 DB_File RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
361 void * openinfo = NULL ;
362 union INFO * info = &RETVAL->info ;
364 /* Default to HASH */
365 RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
366 RETVAL->type = DB_HASH ;
368 /* DGH - Next line added to avoid SEGV on existing hash DB */
371 /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */
372 RETVAL->in_memory = (name == NULL) ;
377 croak ("type parameter is not a reference") ;
379 svp = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
380 if (svp && SvOK(*svp))
381 action = (HV*) SvRV(*svp) ;
383 croak("internal error") ;
385 if (sv_isa(sv, "DB_File::HASHINFO"))
387 RETVAL->type = DB_HASH ;
388 openinfo = (void*)info ;
390 svp = hv_fetch(action, "hash", 4, FALSE);
392 if (svp && SvOK(*svp))
394 info->hash.hash = hash_cb ;
395 RETVAL->hash = newSVsv(*svp) ;
398 info->hash.hash = NULL ;
400 svp = hv_fetch(action, "bsize", 5, FALSE);
401 info->hash.bsize = svp ? SvIV(*svp) : 0;
403 svp = hv_fetch(action, "ffactor", 7, FALSE);
404 info->hash.ffactor = svp ? SvIV(*svp) : 0;
406 svp = hv_fetch(action, "nelem", 5, FALSE);
407 info->hash.nelem = svp ? SvIV(*svp) : 0;
409 svp = hv_fetch(action, "cachesize", 9, FALSE);
410 info->hash.cachesize = svp ? SvIV(*svp) : 0;
412 svp = hv_fetch(action, "lorder", 6, FALSE);
413 info->hash.lorder = svp ? SvIV(*svp) : 0;
417 else if (sv_isa(sv, "DB_File::BTREEINFO"))
419 RETVAL->type = DB_BTREE ;
420 openinfo = (void*)info ;
422 svp = hv_fetch(action, "compare", 7, FALSE);
423 if (svp && SvOK(*svp))
425 info->btree.compare = btree_compare ;
426 RETVAL->compare = newSVsv(*svp) ;
429 info->btree.compare = NULL ;
431 svp = hv_fetch(action, "prefix", 6, FALSE);
432 if (svp && SvOK(*svp))
434 info->btree.prefix = btree_prefix ;
435 RETVAL->prefix = newSVsv(*svp) ;
438 info->btree.prefix = NULL ;
440 svp = hv_fetch(action, "flags", 5, FALSE);
441 info->btree.flags = svp ? SvIV(*svp) : 0;
443 svp = hv_fetch(action, "cachesize", 9, FALSE);
444 info->btree.cachesize = svp ? SvIV(*svp) : 0;
446 svp = hv_fetch(action, "minkeypage", 10, FALSE);
447 info->btree.minkeypage = svp ? SvIV(*svp) : 0;
449 svp = hv_fetch(action, "maxkeypage", 10, FALSE);
450 info->btree.maxkeypage = svp ? SvIV(*svp) : 0;
452 svp = hv_fetch(action, "psize", 5, FALSE);
453 info->btree.psize = svp ? SvIV(*svp) : 0;
455 svp = hv_fetch(action, "lorder", 6, FALSE);
456 info->btree.lorder = svp ? SvIV(*svp) : 0;
461 else if (sv_isa(sv, "DB_File::RECNOINFO"))
463 RETVAL->type = DB_RECNO ;
464 openinfo = (void *)info ;
466 svp = hv_fetch(action, "flags", 5, FALSE);
467 info->recno.flags = (u_long) svp ? SvIV(*svp) : 0;
469 svp = hv_fetch(action, "cachesize", 9, FALSE);
470 info->recno.cachesize = (u_int) svp ? SvIV(*svp) : 0;
472 svp = hv_fetch(action, "psize", 5, FALSE);
473 info->recno.psize = (int) svp ? SvIV(*svp) : 0;
475 svp = hv_fetch(action, "lorder", 6, FALSE);
476 info->recno.lorder = (int) svp ? SvIV(*svp) : 0;
478 svp = hv_fetch(action, "reclen", 6, FALSE);
479 info->recno.reclen = (size_t) svp ? SvIV(*svp) : 0;
481 svp = hv_fetch(action, "bval", 4, FALSE);
482 if (svp && SvOK(*svp))
485 info->recno.bval = (u_char)*SvPV(*svp, na) ;
487 info->recno.bval = (u_char)(unsigned long) SvIV(*svp) ;
491 if (info->recno.flags & R_FIXEDLEN)
492 info->recno.bval = (u_char) ' ' ;
494 info->recno.bval = (u_char) '\n' ;
497 svp = hv_fetch(action, "bfname", 6, FALSE);
498 if (svp && SvOK(*svp)) {
499 char * ptr = SvPV(*svp,na) ;
500 info->recno.bfname = (char*) na ? ptr : NULL ;
503 info->recno.bfname = NULL ;
508 croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
512 /* OS2 Specific Code */
519 RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ;
529 croak("DB_File::%s not implemented on this architecture", s);
543 if (strEQ(name, "BTREEMAGIC"))
549 if (strEQ(name, "BTREEVERSION"))
559 if (strEQ(name, "DB_LOCK"))
565 if (strEQ(name, "DB_SHMEM"))
571 if (strEQ(name, "DB_TXN"))
585 if (strEQ(name, "HASHMAGIC"))
591 if (strEQ(name, "HASHVERSION"))
607 if (strEQ(name, "MAX_PAGE_NUMBER"))
608 #ifdef MAX_PAGE_NUMBER
609 return (U32)MAX_PAGE_NUMBER;
613 if (strEQ(name, "MAX_PAGE_OFFSET"))
614 #ifdef MAX_PAGE_OFFSET
615 return MAX_PAGE_OFFSET;
619 if (strEQ(name, "MAX_REC_NUMBER"))
620 #ifdef MAX_REC_NUMBER
621 return (U32)MAX_REC_NUMBER;
635 if (strEQ(name, "RET_ERROR"))
641 if (strEQ(name, "RET_SPECIAL"))
647 if (strEQ(name, "RET_SUCCESS"))
653 if (strEQ(name, "R_CURSOR"))
659 if (strEQ(name, "R_DUP"))
665 if (strEQ(name, "R_FIRST"))
671 if (strEQ(name, "R_FIXEDLEN"))
677 if (strEQ(name, "R_IAFTER"))
683 if (strEQ(name, "R_IBEFORE"))
689 if (strEQ(name, "R_LAST"))
695 if (strEQ(name, "R_NEXT"))
701 if (strEQ(name, "R_NOKEY"))
707 if (strEQ(name, "R_NOOVERWRITE"))
709 return R_NOOVERWRITE;
713 if (strEQ(name, "R_PREV"))
719 if (strEQ(name, "R_RECNOSYNC"))
725 if (strEQ(name, "R_SETCURSOR"))
731 if (strEQ(name, "R_SNAPSHOT"))
755 if (strEQ(name, "__R_UNUSED"))
771 MODULE = DB_File PACKAGE = DB_File PREFIX = db_
780 db_DoTie_(dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0666, type=DB_HASH)
786 char * name = (char *) NULL ;
787 SV * sv = (SV *) NULL ;
789 if (items >= 2 && SvOK(ST(1)))
790 name = (char*) SvPV(ST(1), na) ;
795 RETVAL = ParseOpenInfo(name, flags, mode, sv) ;
796 if (RETVAL->dbp == NULL)
809 SvREFCNT_dec(db->hash) ;
811 SvREFCNT_dec(db->compare) ;
813 SvREFCNT_dec(db->prefix) ;
818 db_DELETE(db, key, flags=0)
835 RETVAL = (((db->dbp)->get)(db->dbp, &key, &value, 0) == 0) ;
841 db_FETCH(db, key, flags=0)
850 RETVAL = ((db->dbp)->get)(db->dbp, &key, &value, flags) ;
851 ST(0) = sv_newmortal();
853 sv_setpvn(ST(0), value.data, value.size);
857 db_STORE(db, key, value, flags=0)
876 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
877 ST(0) = sv_newmortal();
880 if (Db->type != DB_RECNO)
881 sv_setpvn(ST(0), key.data, key.size);
883 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
897 RETVAL = (Db->seq)(Db, &key, &value, R_NEXT) ;
898 ST(0) = sv_newmortal();
901 if (Db->type != DB_RECNO)
902 sv_setpvn(ST(0), key.data, key.size);
904 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
909 # These would be nice for RECNO
925 for (i = items-1 ; i > 0 ; --i)
927 value.data = SvPV(ST(i), na) ;
931 key.size = sizeof(int) ;
932 RETVAL = (Db->put)(Db, &key, &value, R_IBEFORE) ;
950 /* First get the final value */
951 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
952 ST(0) = sv_newmortal();
956 /* the call to del will trash value, so take a copy now */
957 sv_setpvn(ST(0), value.data, value.size);
958 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
960 sv_setsv(ST(0), &sv_undef);
974 /* get the first value */
975 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
976 ST(0) = sv_newmortal();
980 /* the call to del will trash value, so take a copy now */
981 sv_setpvn(ST(0), value.data, value.size);
982 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
984 sv_setsv (ST(0), &sv_undef) ;
995 DBTKEY * keyptr = &key ;
1001 /* Set the Cursor to the Last element */
1002 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
1007 for (i = items - 1 ; i > 0 ; --i)
1009 value.data = SvPV(ST(i), na) ;
1011 RETVAL = (Db->put)(Db, keyptr, &value, R_IAFTER) ;
1026 RETVAL = GetArrayLength(db->dbp) ;
1032 # Now provide an interface to the rest of the DB functionality
1036 db_del(db, key, flags=0)
1045 db_get(db, key, value, flags=0)
1056 db_put(db, key, value, flags=0)
1064 key if (flags & (R_IAFTER|R_IBEFORE)) OutputKey(ST(1), key);
1073 db_sync(db, flags=0)
1081 db_seq(db, key, value, flags)