3 DB_File.xs -- Perl 5 interface to Berkeley DB
5 written by Paul Marquess (pmarquess@bfsec.bt.co.uk)
6 last modified 30th Apr 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.
40 1.11 - No change to DB_File.xs
41 1.12 - No change to DB_File.xs
42 1.13 - Tidied up a few casts.
43 1.14 - Made it illegal to tie an associative array to a RECNO
44 database and an ordinary array to a HASH or BTREE database.
60 #define DB_Prefix_t mDB_Prefix_t
67 #define DB_Hash_t mDB_Hash_t
86 typedef DB_File_type * DB_File ;
92 #define db_DESTROY(db) ((db->dbp)->close)(db->dbp)
93 #define db_DELETE(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
94 #define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
95 #define db_FETCH(db, key, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
97 #define db_close(db) ((db->dbp)->close)(db->dbp)
98 #define db_del(db, key, flags) ((db->dbp)->del)(db->dbp, &key, flags)
99 #define db_fd(db) (db->in_memory \
101 : ((db->dbp)->fd)(db->dbp) )
102 #define db_put(db, key, value, flags) ((db->dbp)->put)(db->dbp, &key, &value, flags)
103 #define db_get(db, key, value, flags) ((db->dbp)->get)(db->dbp, &key, &value, flags)
104 #define db_seq(db, key, value, flags) ((db->dbp)->seq)(db->dbp, &key, &value, flags)
105 #define db_sync(db, flags) ((db->dbp)->sync)(db->dbp, flags)
108 #define OutputValue(arg, name) \
109 { if (RETVAL == 0) { \
110 sv_setpvn(arg, name.data, name.size) ; \
114 #define OutputKey(arg, name) \
117 if (db->type != DB_RECNO) { \
118 sv_setpvn(arg, name.data, name.size); \
121 sv_setiv(arg, (I32)*(I32*)name.data - 1); \
125 /* Internal Global Data */
126 static recno_t Value ;
127 static DB_File CurrentDB ;
128 static recno_t zero = 0 ;
129 static DBTKEY empty = { &zero, sizeof(recno_t) } ;
133 btree_compare(key1, key2)
138 void * data1, * data2 ;
145 /* As newSVpv will assume that the data pointer is a null terminated C
146 string if the size parameter is 0, make sure that data points to an
147 empty string if the length is 0
159 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
160 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
163 count = perl_call_sv(CurrentDB->compare, G_SCALAR);
168 croak ("DB_File btree_compare: expected 1 return value from compare sub, got %d\n", count) ;
180 btree_prefix(key1, key2)
185 void * data1, * data2 ;
192 /* As newSVpv will assume that the data pointer is a null terminated C
193 string if the size parameter is 0, make sure that data points to an
194 empty string if the length is 0
206 PUSHs(sv_2mortal(newSVpv(data1,key1->size)));
207 PUSHs(sv_2mortal(newSVpv(data2,key2->size)));
210 count = perl_call_sv(CurrentDB->prefix, G_SCALAR);
215 croak ("DB_File btree_prefix: expected 1 return value from prefix sub, got %d\n", count) ;
238 /* DGH - Next two lines added to fix corrupted stack problem */
244 XPUSHs(sv_2mortal(newSVpv((char*)data,size)));
247 count = perl_call_sv(CurrentDB->hash, G_SCALAR);
252 croak ("DB_File hash_cb: expected 1 return value from hash sub, got %d\n", count) ;
270 printf ("HASH Info\n") ;
271 printf (" hash = %s\n", (hash->hash != NULL ? "redefined" : "default")) ;
272 printf (" bsize = %d\n", hash->bsize) ;
273 printf (" ffactor = %d\n", hash->ffactor) ;
274 printf (" nelem = %d\n", hash->nelem) ;
275 printf (" cachesize = %d\n", hash->cachesize) ;
276 printf (" lorder = %d\n", hash->lorder) ;
284 printf ("RECNO Info\n") ;
285 printf (" flags = %d\n", recno->flags) ;
286 printf (" cachesize = %d\n", recno->cachesize) ;
287 printf (" psize = %d\n", recno->psize) ;
288 printf (" lorder = %d\n", recno->lorder) ;
289 printf (" reclen = %lu\n", (unsigned long)recno->reclen) ;
290 printf (" bval = %d 0x%x\n", recno->bval, recno->bval) ;
291 printf (" bfname = %d [%s]\n", recno->bfname, recno->bfname) ;
298 printf ("BTREE Info\n") ;
299 printf (" compare = %s\n", (btree->compare ? "redefined" : "default")) ;
300 printf (" prefix = %s\n", (btree->prefix ? "redefined" : "default")) ;
301 printf (" flags = %d\n", btree->flags) ;
302 printf (" cachesize = %d\n", btree->cachesize) ;
303 printf (" psize = %d\n", btree->psize) ;
304 printf (" maxkeypage = %d\n", btree->maxkeypage) ;
305 printf (" minkeypage = %d\n", btree->minkeypage) ;
306 printf (" lorder = %d\n", btree->lorder) ;
311 #define PrintRecno(recno)
312 #define PrintHash(hash)
313 #define PrintBtree(btree)
326 RETVAL = (db->seq)(db, &key, &value, R_LAST) ;
328 RETVAL = *(I32 *)key.data ;
329 else if (RETVAL == 1) /* No key means empty file */
332 return ((I32)RETVAL) ;
336 GetRecnoKey(db, value)
341 /* Get the length of the array */
342 I32 length = GetArrayLength(db->dbp) ;
344 /* check for attempt to write before start of array */
345 if (length + value + 1 <= 0)
346 croak("Modification of non-creatable array value attempted, subscript %ld", (long)value) ;
348 value = length + value + 1 ;
357 ParseOpenInfo(isHASH, name, flags, mode, sv)
366 DB_File RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
367 void * openinfo = NULL ;
368 union INFO * info = &RETVAL->info ;
370 /* Default to HASH */
371 RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
372 RETVAL->type = DB_HASH ;
374 /* DGH - Next line added to avoid SEGV on existing hash DB */
377 /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */
378 RETVAL->in_memory = (name == NULL) ;
383 croak ("type parameter is not a reference") ;
385 svp = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
386 if (svp && SvOK(*svp))
387 action = (HV*) SvRV(*svp) ;
389 croak("internal error") ;
391 if (sv_isa(sv, "DB_File::HASHINFO"))
395 croak("DB_File can only tie an associative array to a DB_HASH database") ;
397 RETVAL->type = DB_HASH ;
398 openinfo = (void*)info ;
400 svp = hv_fetch(action, "hash", 4, FALSE);
402 if (svp && SvOK(*svp))
404 info->hash.hash = hash_cb ;
405 RETVAL->hash = newSVsv(*svp) ;
408 info->hash.hash = NULL ;
410 svp = hv_fetch(action, "bsize", 5, FALSE);
411 info->hash.bsize = svp ? SvIV(*svp) : 0;
413 svp = hv_fetch(action, "ffactor", 7, FALSE);
414 info->hash.ffactor = svp ? SvIV(*svp) : 0;
416 svp = hv_fetch(action, "nelem", 5, FALSE);
417 info->hash.nelem = svp ? SvIV(*svp) : 0;
419 svp = hv_fetch(action, "cachesize", 9, FALSE);
420 info->hash.cachesize = svp ? SvIV(*svp) : 0;
422 svp = hv_fetch(action, "lorder", 6, FALSE);
423 info->hash.lorder = svp ? SvIV(*svp) : 0;
427 else if (sv_isa(sv, "DB_File::BTREEINFO"))
430 croak("DB_File can only tie an associative array to a DB_BTREE database");
432 RETVAL->type = DB_BTREE ;
433 openinfo = (void*)info ;
435 svp = hv_fetch(action, "compare", 7, FALSE);
436 if (svp && SvOK(*svp))
438 info->btree.compare = btree_compare ;
439 RETVAL->compare = newSVsv(*svp) ;
442 info->btree.compare = NULL ;
444 svp = hv_fetch(action, "prefix", 6, FALSE);
445 if (svp && SvOK(*svp))
447 info->btree.prefix = btree_prefix ;
448 RETVAL->prefix = newSVsv(*svp) ;
451 info->btree.prefix = NULL ;
453 svp = hv_fetch(action, "flags", 5, FALSE);
454 info->btree.flags = svp ? SvIV(*svp) : 0;
456 svp = hv_fetch(action, "cachesize", 9, FALSE);
457 info->btree.cachesize = svp ? SvIV(*svp) : 0;
459 svp = hv_fetch(action, "minkeypage", 10, FALSE);
460 info->btree.minkeypage = svp ? SvIV(*svp) : 0;
462 svp = hv_fetch(action, "maxkeypage", 10, FALSE);
463 info->btree.maxkeypage = svp ? SvIV(*svp) : 0;
465 svp = hv_fetch(action, "psize", 5, FALSE);
466 info->btree.psize = svp ? SvIV(*svp) : 0;
468 svp = hv_fetch(action, "lorder", 6, FALSE);
469 info->btree.lorder = svp ? SvIV(*svp) : 0;
474 else if (sv_isa(sv, "DB_File::RECNOINFO"))
477 croak("DB_File can only tie an array to a DB_RECNO database");
479 RETVAL->type = DB_RECNO ;
480 openinfo = (void *)info ;
482 svp = hv_fetch(action, "flags", 5, FALSE);
483 info->recno.flags = (u_long) (svp ? SvIV(*svp) : 0);
485 svp = hv_fetch(action, "cachesize", 9, FALSE);
486 info->recno.cachesize = (u_int) (svp ? SvIV(*svp) : 0);
488 svp = hv_fetch(action, "psize", 5, FALSE);
489 info->recno.psize = (u_int) (svp ? SvIV(*svp) : 0);
491 svp = hv_fetch(action, "lorder", 6, FALSE);
492 info->recno.lorder = (int) (svp ? SvIV(*svp) : 0);
494 svp = hv_fetch(action, "reclen", 6, FALSE);
495 info->recno.reclen = (size_t) (svp ? SvIV(*svp) : 0);
497 svp = hv_fetch(action, "bval", 4, FALSE);
498 if (svp && SvOK(*svp))
501 info->recno.bval = (u_char)*SvPV(*svp, na) ;
503 info->recno.bval = (u_char)(unsigned long) SvIV(*svp) ;
507 if (info->recno.flags & R_FIXEDLEN)
508 info->recno.bval = (u_char) ' ' ;
510 info->recno.bval = (u_char) '\n' ;
513 svp = hv_fetch(action, "bfname", 6, FALSE);
514 if (svp && SvOK(*svp)) {
515 char * ptr = SvPV(*svp,na) ;
516 info->recno.bfname = (char*) (na ? ptr : NULL) ;
519 info->recno.bfname = NULL ;
524 croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
528 /* OS2 Specific Code */
535 RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ;
545 croak("DB_File::%s not implemented on this architecture", s);
559 if (strEQ(name, "BTREEMAGIC"))
565 if (strEQ(name, "BTREEVERSION"))
575 if (strEQ(name, "DB_LOCK"))
581 if (strEQ(name, "DB_SHMEM"))
587 if (strEQ(name, "DB_TXN"))
601 if (strEQ(name, "HASHMAGIC"))
607 if (strEQ(name, "HASHVERSION"))
623 if (strEQ(name, "MAX_PAGE_NUMBER"))
624 #ifdef MAX_PAGE_NUMBER
625 return (U32)MAX_PAGE_NUMBER;
629 if (strEQ(name, "MAX_PAGE_OFFSET"))
630 #ifdef MAX_PAGE_OFFSET
631 return MAX_PAGE_OFFSET;
635 if (strEQ(name, "MAX_REC_NUMBER"))
636 #ifdef MAX_REC_NUMBER
637 return (U32)MAX_REC_NUMBER;
651 if (strEQ(name, "RET_ERROR"))
657 if (strEQ(name, "RET_SPECIAL"))
663 if (strEQ(name, "RET_SUCCESS"))
669 if (strEQ(name, "R_CURSOR"))
675 if (strEQ(name, "R_DUP"))
681 if (strEQ(name, "R_FIRST"))
687 if (strEQ(name, "R_FIXEDLEN"))
693 if (strEQ(name, "R_IAFTER"))
699 if (strEQ(name, "R_IBEFORE"))
705 if (strEQ(name, "R_LAST"))
711 if (strEQ(name, "R_NEXT"))
717 if (strEQ(name, "R_NOKEY"))
723 if (strEQ(name, "R_NOOVERWRITE"))
725 return R_NOOVERWRITE;
729 if (strEQ(name, "R_PREV"))
735 if (strEQ(name, "R_RECNOSYNC"))
741 if (strEQ(name, "R_SETCURSOR"))
747 if (strEQ(name, "R_SNAPSHOT"))
771 if (strEQ(name, "__R_UNUSED"))
787 MODULE = DB_File PACKAGE = DB_File PREFIX = db_
796 db_DoTie_(isHASH, dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0666, type=DB_HASH)
803 char * name = (char *) NULL ;
804 SV * sv = (SV *) NULL ;
806 if (items >= 3 && SvOK(ST(2)))
807 name = (char*) SvPV(ST(2), na) ;
812 RETVAL = ParseOpenInfo(isHASH, name, flags, mode, sv) ;
813 if (RETVAL->dbp == NULL)
819 >>>> ORIGINAL VERSION
821 newXS("DB_File::TIEARRAY", XS_DB_File_db_TIEHASH, file);
826 newXS("DB_File::TIEARRAY", XS_DB_File_TIEHASH, file);
836 SvREFCNT_dec(db->hash) ;
838 SvREFCNT_dec(db->compare) ;
840 SvREFCNT_dec(db->prefix) ;
845 db_DELETE(db, key, flags=0)
862 RETVAL = (((db->dbp)->get)(db->dbp, &key, &value, 0) == 0) ;
868 db_FETCH(db, key, flags=0)
877 RETVAL = ((db->dbp)->get)(db->dbp, &key, &value, flags) ;
878 ST(0) = sv_newmortal();
880 sv_setpvn(ST(0), value.data, value.size);
884 db_STORE(db, key, value, flags=0)
903 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
904 ST(0) = sv_newmortal();
907 if (db->type != DB_RECNO)
908 sv_setpvn(ST(0), key.data, key.size);
910 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
924 RETVAL = (Db->seq)(Db, &key, &value, R_NEXT) ;
925 ST(0) = sv_newmortal();
928 if (db->type != DB_RECNO)
929 sv_setpvn(ST(0), key.data, key.size);
931 sv_setiv(ST(0), (I32)*(I32*)key.data - 1);
936 # These would be nice for RECNO
952 for (i = items-1 ; i > 0 ; --i)
954 value.data = SvPV(ST(i), na) ;
958 key.size = sizeof(int) ;
959 RETVAL = (Db->put)(Db, &key, &value, R_IBEFORE) ;
977 /* First get the final value */
978 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
979 ST(0) = sv_newmortal();
983 /* the call to del will trash value, so take a copy now */
984 sv_setpvn(ST(0), value.data, value.size);
985 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
987 sv_setsv(ST(0), &sv_undef);
1001 /* get the first value */
1002 RETVAL = (Db->seq)(Db, &key, &value, R_FIRST) ;
1003 ST(0) = sv_newmortal();
1007 /* the call to del will trash value, so take a copy now */
1008 sv_setpvn(ST(0), value.data, value.size);
1009 RETVAL = (Db->del)(Db, &key, R_CURSOR) ;
1011 sv_setsv (ST(0), &sv_undef) ;
1022 DBTKEY * keyptr = &key ;
1028 /* Set the Cursor to the Last element */
1029 RETVAL = (Db->seq)(Db, &key, &value, R_LAST) ;
1034 for (i = items - 1 ; i > 0 ; --i)
1036 value.data = SvPV(ST(i), na) ;
1038 RETVAL = (Db->put)(Db, keyptr, &value, R_IAFTER) ;
1053 RETVAL = GetArrayLength(db->dbp) ;
1059 # Now provide an interface to the rest of the DB functionality
1063 db_del(db, key, flags=0)
1072 db_get(db, key, value, flags=0)
1083 db_put(db, key, value, flags=0)
1091 key if (flags & (R_IAFTER|R_IBEFORE)) OutputKey(ST(1), key);
1100 db_sync(db, flags=0)
1108 db_seq(db, key, value, flags)