3 DB_File.xs -- Perl 5 interface to Berkeley DB
5 written by Paul Marquess (pmarquess@bfsec.bt.co.uk)
6 last modified 4th Sept 1996
9 All comments/suggestions/problems are welcome
13 0.2 - No longer bombs out if dbopen returns an error.
14 0.3 - Added some support for multiple btree compares
15 1.0 - Complete support for multiple callbacks added.
16 Fixed a problem with pushing a value onto an empty list.
17 1.01 - Fixed a SunOS core dump problem.
18 The return value from TIEHASH wasn't set to NULL when
19 dbopen returned an error.
20 1.02 - Use ALIAS to define TIEARRAY.
21 Removed some redundant commented code.
22 Merged OS2 code into the main distribution.
23 Allow negative subscripts with RECNO interface.
24 Changed the default flags to O_CREAT|O_RDWR
45 typedef DB_File_type * DB_File ;
57 #define db_DESTROY(db) ((db->dbp)->close)(db->dbp)
58 #define db_DELETE(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
59 #define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
60 #define db_FETCH(db, key, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
62 #define db_close(db) ((db->dbp)->close)(db->dbp)
63 #define db_del(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
64 #define db_fd(db) ((db->dbp)->fd)(db->dbp)
65 #define db_put(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
66 #define db_get(db, key, value, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
67 #define db_seq(db, key, value, flags) ((db->dbp)->seq)(db->dbp, &key, &value, flags)
68 #define db_sync(db, flags) ((db->dbp)->sync)(db->dbp, flags)
71 #define OutputValue(arg, name) \
72 { if (RETVAL == 0) { \
73 sv_setpvn(arg, name.data, name.size) ; \
77 #define OutputKey(arg, name) \
80 if (db->type != DB_RECNO) { \
81 sv_setpvn(arg, name.data, name.size); \
84 sv_setiv(arg, (I32)*(I32*)name.data - 1); \
88 /* Internal Global Data */
89 static recno_t Value ;
90 static DB_File CurrentDB ;
91 static recno_t zero = 0 ;
92 static DBTKEY empty = { &zero, sizeof(recno_t) } ;
96 btree_compare(key1, key2)
101 void * data1, * data2 ;
108 /* As newSVpv will assume that the data pointer is a null terminated C
109 string if the size parameter is 0, make sure that data points to an
110 empty string if the length is 0
122 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
123 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
126 count = perl_call_sv(CurrentDB->compare, G_SCALAR);
131 croak ("DB_File btree_compare: expected 1 return value from %s, got %d\n", count) ;
143 btree_prefix(key1, key2)
148 void * data1, * data2 ;
155 /* As newSVpv will assume that the data pointer is a null terminated C
156 string if the size parameter is 0, make sure that data points to an
157 empty string if the length is 0
169 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
170 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
173 count = perl_call_sv(CurrentDB->prefix, G_SCALAR);
178 croak ("DB_File btree_prefix: expected 1 return value from %s, got %d\n", count) ;
202 XPUSHs(sv_2mortal(newSVpv((char*)data,size)));
205 count = perl_call_sv(CurrentDB->hash, G_SCALAR);
210 croak ("DB_File hash_cb: expected 1 return value from %s, got %d\n", count) ;
228 printf ("HASH Info\n") ;
229 printf (" hash = %s\n", (hash.hash != NULL ? "redefined" : "default")) ;
230 printf (" bsize = %d\n", hash.bsize) ;
231 printf (" ffactor = %d\n", hash.ffactor) ;
232 printf (" nelem = %d\n", hash.nelem) ;
233 printf (" cachesize = %d\n", hash.cachesize) ;
234 printf (" lorder = %d\n", hash.lorder) ;
242 printf ("RECNO Info\n") ;
243 printf (" flags = %d\n", recno.flags) ;
244 printf (" cachesize = %d\n", recno.cachesize) ;
245 printf (" psize = %d\n", recno.psize) ;
246 printf (" lorder = %d\n", recno.lorder) ;
247 printf (" reclen = %d\n", recno.reclen) ;
248 printf (" bval = %d\n", recno.bval) ;
249 printf (" bfname = %d [%s]\n", recno.bfname, recno.bfname) ;
255 printf ("BTREE Info\n") ;
256 printf (" compare = %s\n", (btree.compare ? "redefined" : "default")) ;
257 printf (" prefix = %s\n", (btree.prefix ? "redefined" : "default")) ;
258 printf (" flags = %d\n", btree.flags) ;
259 printf (" cachesize = %d\n", btree.cachesize) ;
260 printf (" psize = %d\n", btree.psize) ;
261 printf (" maxkeypage = %d\n", btree.maxkeypage) ;
262 printf (" minkeypage = %d\n", btree.minkeypage) ;
263 printf (" lorder = %d\n", btree.lorder) ;
268 #define PrintRecno(recno)
269 #define PrintHash(hash)
270 #define PrintBtree(btree)
283 RETVAL = (db->seq)(db, &key, &value, R_LAST) ;
285 RETVAL = *(I32 *)key.data ;
286 else if (RETVAL == 1) /* No key means empty file */
293 GetRecnoKey(db, value)
298 /* Get the length of the array */
299 I32 length = GetArrayLength(db->dbp) ;
301 /* check for attempt to write before start of array */
302 if (length + value + 1 <= 0)
303 croak("Modification of non-creatable array value attempted, subscript %d", value) ;
305 value = length + value + 1 ;
314 ParseOpenInfo(name, flags, mode, sv, string)
324 DB_File RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
325 void * openinfo = NULL ;
327 /* Default to HASH */
328 RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
329 RETVAL->type = DB_HASH ;
334 croak ("type parameter is not a reference") ;
336 action = (HV*)SvRV(sv);
337 if (sv_isa(sv, "DB_File::HASHINFO"))
339 RETVAL->type = DB_HASH ;
340 openinfo = (void*)&info ;
342 svp = hv_fetch(action, "hash", 4, FALSE);
344 if (svp && SvOK(*svp))
346 info.hash.hash = hash_cb ;
347 RETVAL->hash = newSVsv(*svp) ;
350 info.hash.hash = NULL ;
352 svp = hv_fetch(action, "bsize", 5, FALSE);
353 info.hash.bsize = svp ? SvIV(*svp) : 0;
355 svp = hv_fetch(action, "ffactor", 7, FALSE);
356 info.hash.ffactor = svp ? SvIV(*svp) : 0;
358 svp = hv_fetch(action, "nelem", 5, FALSE);
359 info.hash.nelem = svp ? SvIV(*svp) : 0;
361 svp = hv_fetch(action, "cachesize", 9, FALSE);
362 info.hash.cachesize = svp ? SvIV(*svp) : 0;
364 svp = hv_fetch(action, "lorder", 6, FALSE);
365 info.hash.lorder = svp ? SvIV(*svp) : 0;
369 else if (sv_isa(sv, "DB_File::BTREEINFO"))
371 RETVAL->type = DB_BTREE ;
372 openinfo = (void*)&info ;
374 svp = hv_fetch(action, "compare", 7, FALSE);
375 if (svp && SvOK(*svp))
377 info.btree.compare = btree_compare ;
378 RETVAL->compare = newSVsv(*svp) ;
381 info.btree.compare = NULL ;
383 svp = hv_fetch(action, "prefix", 6, FALSE);
384 if (svp && SvOK(*svp))
386 info.btree.prefix = btree_prefix ;
387 RETVAL->prefix = newSVsv(*svp) ;
390 info.btree.prefix = NULL ;
392 svp = hv_fetch(action, "flags", 5, FALSE);
393 info.btree.flags = svp ? SvIV(*svp) : 0;
395 svp = hv_fetch(action, "cachesize", 9, FALSE);
396 info.btree.cachesize = svp ? SvIV(*svp) : 0;
398 svp = hv_fetch(action, "minkeypage", 10, FALSE);
399 info.btree.minkeypage = svp ? SvIV(*svp) : 0;
401 svp = hv_fetch(action, "maxkeypage", 10, FALSE);
402 info.btree.maxkeypage = svp ? SvIV(*svp) : 0;
404 svp = hv_fetch(action, "psize", 5, FALSE);
405 info.btree.psize = svp ? SvIV(*svp) : 0;
407 svp = hv_fetch(action, "lorder", 6, FALSE);
408 info.btree.lorder = svp ? SvIV(*svp) : 0;
413 else if (sv_isa(sv, "DB_File::RECNOINFO"))
415 RETVAL->type = DB_RECNO ;
416 openinfo = (void *)&info ;
418 svp = hv_fetch(action, "flags", 5, FALSE);
419 info.recno.flags = (u_long) svp ? SvIV(*svp) : 0;
421 svp = hv_fetch(action, "cachesize", 9, FALSE);
422 info.recno.cachesize = (u_int) svp ? SvIV(*svp) : 0;
424 svp = hv_fetch(action, "psize", 5, FALSE);
425 info.recno.psize = (int) svp ? SvIV(*svp) : 0;
427 svp = hv_fetch(action, "lorder", 6, FALSE);
428 info.recno.lorder = (int) svp ? SvIV(*svp) : 0;
430 svp = hv_fetch(action, "reclen", 6, FALSE);
431 info.recno.reclen = (size_t) svp ? SvIV(*svp) : 0;
433 svp = hv_fetch(action, "bval", 4, FALSE);
434 if (svp && SvOK(*svp))
437 info.recno.bval = (u_char)*SvPV(*svp, na) ;
439 info.recno.bval = (u_char)(unsigned long) SvIV(*svp) ;
443 if (info.recno.flags & R_FIXEDLEN)
444 info.recno.bval = (u_char) ' ' ;
446 info.recno.bval = (u_char) '\n' ;
449 svp = hv_fetch(action, "bfname", 6, FALSE);
451 char * ptr = SvPV(*svp,na) ;
452 info.recno.bfname = (char*) na ? ptr : 0 ;
458 croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
462 /* OS2 Specific Code */
469 RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ;
479 croak("DB_File::%s not implemented on this architecture", s);
493 if (strEQ(name, "BTREEMAGIC"))
499 if (strEQ(name, "BTREEVERSION"))
509 if (strEQ(name, "DB_LOCK"))
515 if (strEQ(name, "DB_SHMEM"))
521 if (strEQ(name, "DB_TXN"))
535 if (strEQ(name, "HASHMAGIC"))
541 if (strEQ(name, "HASHVERSION"))
557 if (strEQ(name, "MAX_PAGE_NUMBER"))
558 #ifdef MAX_PAGE_NUMBER
559 return (U32)MAX_PAGE_NUMBER;
563 if (strEQ(name, "MAX_PAGE_OFFSET"))
564 #ifdef MAX_PAGE_OFFSET
565 return MAX_PAGE_OFFSET;
569 if (strEQ(name, "MAX_REC_NUMBER"))
570 #ifdef MAX_REC_NUMBER
571 return (U32)MAX_REC_NUMBER;
585 if (strEQ(name, "RET_ERROR"))
591 if (strEQ(name, "RET_SPECIAL"))
597 if (strEQ(name, "RET_SUCCESS"))
603 if (strEQ(name, "R_CURSOR"))
609 if (strEQ(name, "R_DUP"))
615 if (strEQ(name, "R_FIRST"))
621 if (strEQ(name, "R_FIXEDLEN"))
627 if (strEQ(name, "R_IAFTER"))
633 if (strEQ(name, "R_IBEFORE"))
639 if (strEQ(name, "R_LAST"))
645 if (strEQ(name, "R_NEXT"))
651 if (strEQ(name, "R_NOKEY"))
657 if (strEQ(name, "R_NOOVERWRITE"))
659 return R_NOOVERWRITE;
663 if (strEQ(name, "R_PREV"))
669 if (strEQ(name, "R_RECNOSYNC"))
675 if (strEQ(name, "R_SETCURSOR"))
681 if (strEQ(name, "R_SNAPSHOT"))
705 if (strEQ(name, "__R_UNUSED"))
721 MODULE = DB_File PACKAGE = DB_File PREFIX = db_
730 db_TIEHASH(dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0640, type=DB_HASH)
737 char * name = (char *) NULL ;
738 SV * sv = (SV *) NULL ;
740 if (items >= 2 && SvOK(ST(1)))
741 name = (char*) SvPV(ST(1), na) ;
746 RETVAL = ParseOpenInfo(name, flags, mode, sv, "new") ;
747 if (RETVAL->dbp == NULL)
760 SvREFCNT_dec(db->hash) ;
762 SvREFCNT_dec(db->compare) ;
764 SvREFCNT_dec(db->prefix) ;
769 db_DELETE(db, key, flags=0)
786 RETVAL = (((db->dbp)->get)(db->dbp, &key, &value, 0) == 0) ;
792 db_FETCH(db, key, flags=0)
801 RETVAL = ((db->dbp)->get)(db->dbp, &key, &value, flags) ;
802 ST(0) = sv_newmortal();
804 sv_setpvn(ST(0), value.data, value.size);
808 db_STORE(db, key, value, flags=0)
827 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
828 ST(0) = sv_newmortal();
831 if (Db->type != DB_RECNO)
832 sv_setpvn(ST(0), key.data, key.size);
834 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
848 RETVAL = (Db->seq)(Db, &key, &value, R_NEXT) ;
849 ST(0) = sv_newmortal();
852 if (Db->type != DB_RECNO)
853 sv_setpvn(ST(0), key.data, key.size);
855 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
860 # These would be nice for RECNO
876 for (i = items-1 ; i > 0 ; --i)
878 value.data = SvPV(ST(i), na) ;
882 key.size = sizeof(int) ;
883 RETVAL = (Db->put)(Db, &key, &value, R_IBEFORE) ;
901 /* First get the final value */
902 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
903 ST(0) = sv_newmortal();
907 /* the call to del will trash value, so take a copy now */
908 sv_setpvn(ST(0), value.data, value.size);
909 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
911 sv_setsv(ST(0), &sv_undef);
925 /* get the first value */
926 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
927 ST(0) = sv_newmortal();
931 /* the call to del will trash value, so take a copy now */
932 sv_setpvn(ST(0), value.data, value.size);
933 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
935 sv_setsv (ST(0), &sv_undef) ;
946 DBTKEY * keyptr = &key ;
952 /* Set the Cursor to the Last element */
953 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
958 for (i = items - 1 ; i > 0 ; --i)
960 value.data = SvPV(ST(i), na) ;
962 RETVAL = (Db->put)(Db, keyptr, &value, R_IAFTER) ;
977 RETVAL = GetArrayLength(db->dbp) ;
983 # Now provide an interface to the rest of the DB functionality
987 db_del(db, key, flags=0)
996 db_get(db, key, value, flags=0)
1007 db_put(db, key, value, flags=0)
1015 key if (flags & (R_IAFTER|R_IBEFORE)) OutputKey(ST(1), key);
1024 db_sync(db, flags=0)
1032 db_seq(db, key, value, flags)