This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #36297] builtin attrs on subrutine declarations
[perl5.git] / ext / DB_File / DB_File.xs
index b8c820a..76f9eb8 100644 (file)
@@ -2,13 +2,13 @@
 
  DB_File.xs -- Perl 5 interface to Berkeley DB 
 
- written by Paul Marquess <Paul.Marquess@btinternet.com>
- last modified 22nd July 1999
- version 1.68
+ written by Paul Marquess <pmqs@cpan.org>
+ last modified 12th March 2005
+ version 1.811
 
  All comments/suggestions/problems are welcome
 
-     Copyright (c) 1995-9 Paul Marquess. All rights reserved.
+     Copyright (c) 1995-2005 Paul Marquess. All rights reserved.
      This program is free software; you can redistribute it and/or
      modify it under the same terms as Perl itself.
 
                Fixed a small memory leak in the filter code.
         1.68 -  fixed backward compatability bug with R_IAFTER & R_IBEFORE
                merged in the 5.005_58 changes
-
-
+        1.69 -  fixed a bug in push -- DB_APPEND wasn't working properly.
+               Fixed the R_SETCURSOR bug introduced in 1.68
+               Added a new Perl variable $DB_File::db_ver 
+        1.70 -  Initialise $DB_File::db_ver and $DB_File::db_version with 
+               GV_ADD|GV_ADDMULT -- bug spotted by Nick Ing-Simmons.
+               Added a BOOT check to test for equivalent versions of db.h &
+               libdb.a/so.
+        1.71 -  Support for Berkeley DB version 3.
+               Support for Berkeley DB 2/3's backward compatability mode.
+               Rewrote push
+        1.72 -  No change to DB_File.xs
+        1.73 -  No change to DB_File.xs
+        1.74 -  A call to open needed parenthesised to stop it clashing
+                with a win32 macro.
+               Added Perl core patches 7703 & 7801.
+        1.75 -  Fixed Perl core patch 7703.
+               Added suppport to allow DB_File to be built with 
+               Berkeley DB 3.2 -- btree_compare, btree_prefix and hash_cb
+               needed to be changed.
+        1.76 -  No change to DB_File.xs
+        1.77 -  Tidied up a few types used in calling newSVpvn.
+        1.78 -  Core patch 10335, 10372, 10534, 10549, 11051 included.
+        1.79 -  NEXTKEY ignores the input key.
+                Added lots of casts
+        1.800 - Moved backward compatability code into ppport.h.
+                Use the new constants code.
+        1.801 - No change to DB_File.xs
+        1.802 - No change to DB_File.xs
+        1.803 - FETCH, STORE & DELETE don't map the flags parameter
+                into the equivalent Berkeley DB function anymore.
+        1.804 - no change.
+        1.805 - recursion detection added to the callbacks
+                Support for 4.1.X added.
+                Filter code can now cope with read-only $_
+        1.806 - recursion detection beefed up.
+        1.807 - no change
+        1.808 - leak fixed in ParseOpenInfo
+        1.809 - no change
+        1.810 - no change
+        1.811 - no change
 
 */
 
+#define PERL_NO_GET_CONTEXT
 #include "EXTERN.h"  
 #include "perl.h"
 #include "XSUB.h"
 
-#ifndef PERL_VERSION
-#    include "patchlevel.h"
-#    define PERL_REVISION      5
-#    define PERL_VERSION       PATCHLEVEL
-#    define PERL_SUBVERSION    SUBVERSION
+#ifdef _NOT_CORE
+#  include "ppport.h"
 #endif
 
-#if PERL_REVISION == 5 && (PERL_VERSION < 4 || (PERL_VERSION == 4 && PERL_SUBVERSION <= 75 ))
+/* Mention DB_VERSION_MAJOR_CFG, DB_VERSION_MINOR_CFG, and
+   DB_VERSION_PATCH_CFG here so that Configure pulls them all in. */
 
-#    define PL_sv_undef                sv_undef
-#    define PL_na              na
+/* Being the Berkeley DB we prefer the <sys/cdefs.h> (which will be
+ * shortly #included by the <db.h>) __attribute__ to the possibly
+ * already defined __attribute__, for example by GNUC or by Perl. */
 
+/* #if DB_VERSION_MAJOR_CFG < 2  */
+#ifndef DB_VERSION_MAJOR
+#    undef __attribute__
 #endif
 
-/* DEFSV appears first in 5.004_56 */
-#ifndef DEFSV
-#    define DEFSV              GvSV(defgv)
+#ifdef COMPAT185
+#    include <db_185.h>
+#else
+#    include <db.h>
 #endif
 
-/* Being the Berkeley DB we prefer the <sys/cdefs.h> (which will be
- * shortly #included by the <db.h>) __attribute__ to the possibly
- * already defined __attribute__, for example by GNUC or by Perl. */
+/* Wall starts with 5.7.x */
 
-#undef __attribute__
+#if PERL_REVISION > 5 || (PERL_REVISION == 5 && PERL_VERSION >= 7)
 
-/* If Perl has been compiled with Threads support,the symbol op will
-   be defined here. This clashes with a field name in db.h, so get rid of it.
- */
-#ifdef op
-#    undef op
-#endif
-#include <db.h>
+/* Since we dropped the gccish definition of __attribute__ we will want
+ * to redefine dNOOP, however (so that dTHX continues to work).  Yes,
+ * all this means that we can't do attribute checking on the DB_File,
+ * boo, hiss. */
+#  ifndef DB_VERSION_MAJOR
 
-#ifndef pTHX
-#    define pTHX
-#    define pTHX_
-#    define aTHX
-#    define aTHX_
-#endif
+#    undef  dNOOP
+#    define dNOOP extern int Perl___notused
 
-#ifndef newSVpvn
-#    define newSVpvn(a,b)      newSVpv(a,b)
-#endif
+    /* Ditto for dXSARGS. */
+#    undef  dXSARGS
+#    define dXSARGS                            \
+       dSP; dMARK;                     \
+       I32 ax = mark - PL_stack_base + 1;      \
+       I32 items = sp - mark
+
+#  endif
+
+/* avoid -Wall; DB_File xsubs never make use of `ix' setup for ALIASes */
+#  undef dXSI32
+#  define dXSI32 dNOOP
+
+#endif /* Perl >= 5.7 */
 
 #include <fcntl.h> 
 
 /* #define TRACE */
-#define DBM_FILTERING
+
+#ifdef TRACE
+#    define Trace(x)        printf x
+#else
+#    define Trace(x)
+#endif
 
 
+#define DBT_clear(x)   Zero(&x, 1, DBT) ;
 
 #ifdef DB_VERSION_MAJOR
 
+#if DB_VERSION_MAJOR == 2
+#    define BERKELEY_DB_1_OR_2
+#endif
+
+#if DB_VERSION_MAJOR > 3 || (DB_VERSION_MAJOR == 3 && DB_VERSION_MINOR >= 2)
+#    define AT_LEAST_DB_3_2
+#endif
+
+#if DB_VERSION_MAJOR > 4 || (DB_VERSION_MAJOR == 4 && DB_VERSION_MINOR >= 1)
+#    define AT_LEAST_DB_4_1
+#endif
+
 /* map version 2 features & constants onto their version 1 equivalent */
 
 #ifdef DB_Prefix_t
 
 /* DBTYPE stays the same */
 /* HASHINFO, RECNOINFO and BTREEINFO  map to DB_INFO */
-typedef DB_INFO        INFO ;
+#if DB_VERSION_MAJOR == 2
+    typedef DB_INFO    INFO ;
+#else /* DB_VERSION_MAJOR > 2 */
+#    define DB_FIXEDLEN        (0x8000)
+#endif /* DB_VERSION_MAJOR == 2 */
 
 /* version 2 has db_recno_t in place of recno_t        */
 typedef db_recno_t     recno_t;
@@ -161,11 +228,18 @@ typedef db_recno_t        recno_t;
 #define R_NEXT          DB_NEXT
 #define R_NOOVERWRITE   DB_NOOVERWRITE
 #define R_PREV          DB_PREV
-#define R_SETCURSOR     (-1 )
+
+#if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
+#  define R_SETCURSOR  0x800000
+#else
+#  define R_SETCURSOR  (-100)
+#endif
+
 #define R_RECNOSYNC     0
 #define R_FIXEDLEN     DB_FIXEDLEN
 #define R_DUP          DB_DUP
 
+
 #define db_HA_hash     h_hash
 #define db_HA_ffactor  h_ffactor
 #define db_HA_nelem    h_nelem
@@ -200,13 +274,16 @@ typedef db_recno_t        recno_t;
 #define DB_flags(x, v) x |= v 
 
 #if DB_VERSION_MAJOR == 2 && DB_VERSION_MINOR < 5
-#define flagSet(flags, bitmask)        ((flags) & (bitmask))
+#    define flagSet(flags, bitmask)    ((flags) & (bitmask))
 #else
-#define flagSet(flags, bitmask)        (((flags) & DB_OPFLAGS_MASK) == (bitmask))
+#    define flagSet(flags, bitmask)    (((flags) & DB_OPFLAGS_MASK) == (bitmask))
 #endif
 
 #else /* db version 1.x */
 
+#define BERKELEY_DB_1
+#define BERKELEY_DB_1_OR_2
+
 typedef union INFO {
         HASHINFO       hash ;
         RECNOINFO      recno ;
@@ -215,17 +292,17 @@ typedef union INFO {
 
 
 #ifdef mDB_Prefix_t 
-#ifdef DB_Prefix_t
-#undef DB_Prefix_t
-#endif
-#define DB_Prefix_t    mDB_Prefix_t 
+#  ifdef DB_Prefix_t
+#    undef DB_Prefix_t
+#  endif
+#  define DB_Prefix_t  mDB_Prefix_t 
 #endif
 
 #ifdef mDB_Hash_t
-#ifdef DB_Hash_t
-#undef DB_Hash_t
-#endif
-#define DB_Hash_t      mDB_Hash_t
+#  ifdef DB_Hash_t
+#    undef DB_Hash_t
+#  endif
+#  define DB_Hash_t    mDB_Hash_t
 #endif
 
 #define db_HA_hash     hash.hash
@@ -263,28 +340,29 @@ typedef union INFO {
 
 
 
-#define db_DELETE(db, key, flags)       ((db->dbp)->del)(db->dbp, TXN &key, flags)
-#define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, TXN &key, &value, flags)
-#define db_FETCH(db, key, flags)        ((db->dbp)->get)(db->dbp, TXN &key, &value, flags)
+#define db_DELETE(db, key, flags)       ((db->dbp)->del)(db->dbp, TXN &key, 0)
+#define db_STORE(db, key, value, flags) ((db->dbp)->put)(db->dbp, TXN &key, &value, 0)
+#define db_FETCH(db, key, flags)        ((db->dbp)->get)(db->dbp, TXN &key, &value, 0)
 
 #define db_sync(db, flags)              ((db->dbp)->sync)(db->dbp, flags)
 #define db_get(db, key, value, flags)   ((db->dbp)->get)(db->dbp, TXN &key, &value, flags)
 
 #ifdef DB_VERSION_MAJOR
-#define db_DESTROY(db)                  ((db->dbp)->close)(db->dbp, 0)
+#define db_DESTROY(db)                  (!db->aborted && ( db->cursor->c_close(db->cursor),\
+                                         (db->dbp->close)(db->dbp, 0) ))
 #define db_close(db)                   ((db->dbp)->close)(db->dbp, 0)
 #define db_del(db, key, flags)          (flagSet(flags, R_CURSOR)                                      \
                                                ? ((db->cursor)->c_del)(db->cursor, 0)          \
                                                : ((db->dbp)->del)(db->dbp, NULL, &key, flags) )
 
-#else
+#else /* ! DB_VERSION_MAJOR */
 
-#define db_DESTROY(db)                  ((db->dbp)->close)(db->dbp)
+#define db_DESTROY(db)                  (!db->aborted && ((db->dbp)->close)(db->dbp))
 #define db_close(db)                   ((db->dbp)->close)(db->dbp)
 #define db_del(db, key, flags)          ((db->dbp)->del)(db->dbp, &key, flags)
 #define db_put(db, key, value, flags)   ((db->dbp)->put)(db->dbp, &key, &value, flags)
 
-#endif
+#endif /* ! DB_VERSION_MAJOR */
 
 
 #define db_seq(db, key, value, flags)   do_SEQ(db, key, value, flags)
@@ -293,79 +371,84 @@ typedef struct {
        DBTYPE  type ;
        DB *    dbp ;
        SV *    compare ;
+       bool    in_compare ;
        SV *    prefix ;
+       bool    in_prefix ;
        SV *    hash ;
+       bool    in_hash ;
+       bool    aborted ;
        int     in_memory ;
+#ifdef BERKELEY_DB_1_OR_2
        INFO    info ;
+#endif 
 #ifdef DB_VERSION_MAJOR
        DBC *   cursor ;
 #endif
-#ifdef DBM_FILTERING
        SV *    filter_fetch_key ;
        SV *    filter_store_key ;
        SV *    filter_fetch_value ;
        SV *    filter_store_value ;
        int     filtering ;
-#endif /* DBM_FILTERING */
 
        } DB_File_type;
 
 typedef DB_File_type * DB_File ;
 typedef DBT DBTKEY ;
 
-#ifdef DBM_FILTERING
-
-#define ckFilter(arg,type,name)                                        \
-       if (db->type) {                                         \
-           SV * save_defsv ;                                   \
-            /* printf("filtering %s\n", name) ;*/              \
-           if (db->filtering)                                  \
-               croak("recursion detected in %s", name) ;       \
-           db->filtering = TRUE ;                              \
-           save_defsv = newSVsv(DEFSV) ;                       \
-           sv_setsv(DEFSV, arg) ;                              \
-           PUSHMARK(sp) ;                                      \
-           (void) perl_call_sv(db->type, G_DISCARD|G_NOARGS);  \
-           sv_setsv(arg, DEFSV) ;                              \
-           sv_setsv(DEFSV, save_defsv) ;                       \
-           SvREFCNT_dec(save_defsv) ;                          \
-           db->filtering = FALSE ;                             \
-           /*printf("end of filtering %s\n", name) ;*/         \
-       }
-
-#else
-
-#define ckFilter(arg,type, name)
-
-#endif /* DBM_FILTERING */
-
 #define my_sv_setpvn(sv, d, s) sv_setpvn(sv, (s ? d : (void*)""), s)
 
 #define OutputValue(arg, name)                                         \
        { if (RETVAL == 0) {                                            \
+             SvGETMAGIC(arg) ;                                         \
              my_sv_setpvn(arg, name.data, name.size) ;                 \
-             ckFilter(arg, filter_fetch_value,"filter_fetch_value") ;  \
+             TAINT;                                                    \
+             SvTAINTED_on(arg);                                        \
+             SvUTF8_off(arg);                                          \
+             DBM_ckFilter(arg, filter_fetch_value,"filter_fetch_value") ;      \
          }                                                             \
        }
 
 #define OutputKey(arg, name)                                           \
        { if (RETVAL == 0)                                              \
          {                                                             \
+               SvGETMAGIC(arg) ;                                       \
                if (db->type != DB_RECNO) {                             \
                    my_sv_setpvn(arg, name.data, name.size);            \
                }                                                       \
                else                                                    \
                    sv_setiv(arg, (I32)*(I32*)name.data - 1);           \
-             ckFilter(arg, filter_fetch_key,"filter_fetch_key") ;      \
+             TAINT;                                                    \
+             SvTAINTED_on(arg);                                        \
+             SvUTF8_off(arg);                                          \
+             DBM_ckFilter(arg, filter_fetch_key,"filter_fetch_key") ;  \
          }                                                             \
        }
 
+#define my_SvUV32(sv) ((u_int32_t)SvUV(sv))
+
+#ifdef CAN_PROTOTYPE
+extern void __getBerkeleyDBInfo(void);
+#endif
 
 /* Internal Global Data */
-static recno_t Value ; 
-static recno_t zero = 0 ;
-static DB_File CurrentDB ;
-static DBTKEY empty ;
+
+#define MY_CXT_KEY "DB_File::_guts" XS_VERSION
+
+typedef struct {
+    recno_t    x_Value; 
+    recno_t    x_zero;
+    DB_File    x_CurrentDB;
+    DBTKEY     x_empty;
+} my_cxt_t;
+
+START_MY_CXT
+
+#define Value          (MY_CXT.x_Value)
+#define zero           (MY_CXT.x_zero)
+#define CurrentDB      (MY_CXT.x_CurrentDB)
+#define empty          (MY_CXT.x_empty)
+
+#define ERR_BUFF "DB_File::Error"
 
 #ifdef DB_VERSION_MAJOR
 
@@ -430,37 +513,26 @@ u_int             flags ;
 #endif /* DB_VERSION_MAJOR */
 
 static void
-GetVersionInfo(pTHX)
+tidyUp(DB_File db)
 {
-    SV * ver_sv = perl_get_sv("DB_File::db_version", TRUE) ;
-#ifdef DB_VERSION_MAJOR
-    int Major, Minor, Patch ;
+    db->aborted = TRUE ;
+}
 
-    (void)db_version(&Major, &Minor, &Patch) ;
 
-    /* check that libdb is recent enough  -- we need 2.3.4 or greater */
-    if (Major == 2 && (Minor < 3 || (Minor ==  3 && Patch < 4)))
-       croak("DB_File needs Berkeley DB 2.3.4 or greater, you have %d.%d.%d\n",
-                Major, Minor, Patch) ;
-#if PERL_VERSION > 3
-    sv_setpvf(ver_sv, "%d.%d", Major, Minor) ;
-#else
-    {
-        char buffer[40] ;
-        sprintf(buffer, "%d.%d", Major, Minor) ;
-        sv_setpv(ver_sv, buffer) ; 
-    }
-#endif
-#else
-    sv_setiv(ver_sv, 1) ;
-#endif
+static int
+#ifdef AT_LEAST_DB_3_2
 
-}
+#ifdef CAN_PROTOTYPE
+btree_compare(DB * db, const DBT *key1, const DBT *key2)
+#else
+btree_compare(db, key1, key2)
+DB * db ;
+const DBT * key1 ;
+const DBT * key2 ;
+#endif /* CAN_PROTOTYPE */
 
+#else /* Berkeley DB < 3.2 */
 
-static int
 #ifdef CAN_PROTOTYPE
 btree_compare(const DBT *key1, const DBT *key2)
 #else
@@ -468,17 +540,27 @@ btree_compare(key1, key2)
 const DBT * key1 ;
 const DBT * key2 ;
 #endif
+
+#endif
+
 {
 #ifdef dTHX
     dTHX;
 #endif    
     dSP ;
+    dMY_CXT ;
     void * data1, * data2 ;
     int retval ;
     int count ;
     
-    data1 = key1->data ;
-    data2 = key2->data ;
+
+    if (CurrentDB->in_compare) {
+        tidyUp(CurrentDB);
+        croak ("DB_File btree_compare: recursion detected\n") ;
+    }
+
+    data1 = (char *) key1->data ;
+    data2 = (char *) key2->data ;
 
 #ifndef newSVpvn
     /* As newSVpv will assume that the data pointer is a null terminated C 
@@ -493,6 +575,10 @@ const DBT * key2 ;
 
     ENTER ;
     SAVETMPS;
+    SAVESPTR(CurrentDB);
+    CurrentDB->in_compare = FALSE;
+    SAVEINT(CurrentDB->in_compare);
+    CurrentDB->in_compare = TRUE;
 
     PUSHMARK(SP) ;
     EXTEND(SP,2) ;
@@ -504,19 +590,35 @@ const DBT * key2 ;
 
     SPAGAIN ;
 
-    if (count != 1)
+    if (count != 1){
+        tidyUp(CurrentDB);
         croak ("DB_File btree_compare: expected 1 return value from compare sub, got %d\n", count) ;
+    }
 
     retval = POPi ;
 
     PUTBACK ;
     FREETMPS ;
     LEAVE ;
+
     return (retval) ;
 
 }
 
 static DB_Prefix_t
+#ifdef AT_LEAST_DB_3_2
+
+#ifdef CAN_PROTOTYPE
+btree_prefix(DB * db, const DBT *key1, const DBT *key2)
+#else
+btree_prefix(db, key1, key2)
+Db * db ;
+const DBT * key1 ;
+const DBT * key2 ;
+#endif
+
+#else /* Berkeley DB < 3.2 */
+
 #ifdef CAN_PROTOTYPE
 btree_prefix(const DBT *key1, const DBT *key2)
 #else
@@ -524,17 +626,25 @@ btree_prefix(key1, key2)
 const DBT * key1 ;
 const DBT * key2 ;
 #endif
+
+#endif
 {
 #ifdef dTHX
     dTHX;
 #endif    
     dSP ;
-    void * data1, * data2 ;
+    dMY_CXT ;
+    char * data1, * data2 ;
     int retval ;
     int count ;
     
-    data1 = key1->data ;
-    data2 = key2->data ;
+    if (CurrentDB->in_prefix){
+        tidyUp(CurrentDB);
+        croak ("DB_File btree_prefix: recursion detected\n") ;
+    }
+
+    data1 = (char *) key1->data ;
+    data2 = (char *) key2->data ;
 
 #ifndef newSVpvn
     /* As newSVpv will assume that the data pointer is a null terminated C 
@@ -549,6 +659,10 @@ const DBT * key2 ;
 
     ENTER ;
     SAVETMPS;
+    SAVESPTR(CurrentDB);
+    CurrentDB->in_prefix = FALSE;
+    SAVEINT(CurrentDB->in_prefix);
+    CurrentDB->in_prefix = TRUE;
 
     PUSHMARK(SP) ;
     EXTEND(SP,2) ;
@@ -560,8 +674,10 @@ const DBT * key2 ;
 
     SPAGAIN ;
 
-    if (count != 1)
+    if (count != 1){
+        tidyUp(CurrentDB);
         croak ("DB_File btree_prefix: expected 1 return value from prefix sub, got %d\n", count) ;
+    }
  
     retval = POPi ;
  
@@ -572,22 +688,50 @@ const DBT * key2 ;
     return (retval) ;
 }
 
+
+#ifdef BERKELEY_DB_1
+#    define HASH_CB_SIZE_TYPE size_t
+#else
+#    define HASH_CB_SIZE_TYPE u_int32_t
+#endif
+
 static DB_Hash_t
+#ifdef AT_LEAST_DB_3_2
+
 #ifdef CAN_PROTOTYPE
-hash_cb(const void *data, size_t size)
+hash_cb(DB * db, const void *data, u_int32_t size)
+#else
+hash_cb(db, data, size)
+DB * db ;
+const void * data ;
+HASH_CB_SIZE_TYPE size ;
+#endif
+
+#else /* Berkeley DB < 3.2 */
+
+#ifdef CAN_PROTOTYPE
+hash_cb(const void *data, HASH_CB_SIZE_TYPE size)
 #else
 hash_cb(data, size)
 const void * data ;
-size_t size ;
+HASH_CB_SIZE_TYPE size ;
+#endif
+
 #endif
 {
 #ifdef dTHX
     dTHX;
 #endif    
     dSP ;
-    int retval ;
+    dMY_CXT;
+    int retval = 0;
     int count ;
 
+    if (CurrentDB->in_hash){
+        tidyUp(CurrentDB);
+        croak ("DB_File hash callback: recursion detected\n") ;
+    }
+
 #ifndef newSVpvn
     if (size == 0)
         data = "" ;
@@ -596,9 +740,14 @@ size_t size ;
      /* DGH - Next two lines added to fix corrupted stack problem */
     ENTER ;
     SAVETMPS;
+    SAVESPTR(CurrentDB);
+    CurrentDB->in_hash = FALSE;
+    SAVEINT(CurrentDB->in_hash);
+    CurrentDB->in_hash = TRUE;
 
     PUSHMARK(SP) ;
 
+
     XPUSHs(sv_2mortal(newSVpvn((char*)data,size)));
     PUTBACK ;
 
@@ -606,8 +755,10 @@ size_t size ;
 
     SPAGAIN ;
 
-    if (count != 1)
+    if (count != 1){
+        tidyUp(CurrentDB);
         croak ("DB_File hash_cb: expected 1 return value from hash sub, got %d\n", count) ;
+    }
 
     retval = POPi ;
 
@@ -618,8 +769,30 @@ size_t size ;
     return (retval) ;
 }
 
+#if 0
+static void
+#ifdef CAN_PROTOTYPE
+db_errcall_cb(const char * db_errpfx, char * buffer)
+#else
+db_errcall_cb(db_errpfx, buffer)
+const char * db_errpfx;
+char * buffer;
+#endif
+{
+#ifdef dTHX
+    dTHX;
+#endif    
+    SV * sv = perl_get_sv(ERR_BUFF, FALSE) ;
+    if (sv) {
+        if (db_errpfx)
+            sv_setpvf(sv, "%s: %s", db_errpfx, buffer) ;
+        else
+            sv_setpv(sv, buffer) ;
+    }
+} 
+#endif
 
-#ifdef TRACE
+#if defined(TRACE) && defined(BERKELEY_DB_1_OR_2)
 
 static void
 #ifdef CAN_PROTOTYPE
@@ -653,7 +826,7 @@ INFO * recno ;
     printf ("  cachesize = %d\n", recno->db_RE_cachesize) ;
     printf ("  psize     = %d\n", recno->db_RE_psize) ;
     printf ("  lorder    = %d\n", recno->db_RE_lorder) ;
-    printf ("  reclen    = %ul\n", (unsigned long)recno->db_RE_reclen) ;
+    printf ("  reclen    = %lu\n", (unsigned long)recno->db_RE_reclen) ;
     printf ("  bval      = %d 0x%x\n", recno->db_RE_bval, recno->db_RE_bval) ;
     printf ("  bfname    = %d [%s]\n", recno->db_RE_bfname, recno->db_RE_bfname) ;
 }
@@ -702,8 +875,8 @@ DB_File db ;
     DBT                value ;
     int                RETVAL ;
 
-    DBT_flags(key) ;
-    DBT_flags(value) ;
+    DBT_clear(key) ;
+    DBT_clear(value) ;
     RETVAL = do_SEQ(db, key, value, R_LAST) ;
     if (RETVAL == 0)
         RETVAL = *(I32 *)key.data ;
@@ -727,8 +900,10 @@ I32      value ;
        I32 length = GetArrayLength(aTHX_ db) ;
 
        /* check for attempt to write before start of array */
-       if (length + value + 1 <= 0)
+       if (length + value + 1 <= 0) {
+            tidyUp(db);
            croak("Modification of non-creatable array value attempted, subscript %ld", (long)value) ;
+       }
 
        value = length + value + 1 ;
     }
@@ -738,6 +913,7 @@ I32      value ;
     return value ;
 }
 
+
 static DB_File
 #ifdef CAN_PROTOTYPE
 ParseOpenInfo(pTHX_ int isHASH, char *name, int flags, int mode, SV *sv)
@@ -750,22 +926,27 @@ int    mode ;
 SV *   sv ;
 #endif
 {
+
+#ifdef BERKELEY_DB_1_OR_2 /* Berkeley DB Version 1  or 2 */
+
     SV **      svp;
     HV *       action ;
     DB_File    RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
     void *     openinfo = NULL ;
     INFO       * info  = &RETVAL->info ;
     STRLEN     n_a;
+    dMY_CXT;
 
-/* printf("In ParseOpenInfo name=[%s] flags=[%d] mode = [%d]\n", name, flags, mode) ;  */
+#ifdef TRACE    
+    printf("In ParseOpenInfo name=[%s] flags=[%d] mode=[%d] SV NULL=[%d]\n", 
+                   name, flags, mode, sv == NULL) ;  
+#endif
     Zero(RETVAL, 1, DB_File_type) ;
 
     /* Default to HASH */
-#ifdef DBM_FILTERING
     RETVAL->filtering = 0 ;
     RETVAL->filter_fetch_key = RETVAL->filter_store_key = 
     RETVAL->filter_fetch_value = RETVAL->filter_store_value =
-#endif /* DBM_FILTERING */
     RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
     RETVAL->type = DB_HASH ;
 
@@ -1010,264 +1191,294 @@ SV *   sv ;
 
     }
 #else
+
+#if defined(DB_LIBRARY_COMPATIBILITY_API) && DB_VERSION_MAJOR > 2
+    RETVAL->dbp = __db185_open(name, flags, mode, RETVAL->type, openinfo) ; 
+#else    
     RETVAL->dbp = dbopen(name, flags, mode, RETVAL->type, openinfo) ; 
+#endif /* DB_LIBRARY_COMPATIBILITY_API */
+
 #endif
 
     return (RETVAL) ;
-}
 
+#else /* Berkeley DB Version > 2 */
 
-static double 
-#ifdef CAN_PROTOTYPE
-constant(char *name, int arg)
-#else
-constant(name, arg)
-char *name;
-int arg;
-#endif
-{
-    errno = 0;
-    switch (*name) {
-    case 'A':
-       break;
-    case 'B':
-       if (strEQ(name, "BTREEMAGIC"))
-#ifdef BTREEMAGIC
-           return BTREEMAGIC;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "BTREEVERSION"))
-#ifdef BTREEVERSION
-           return BTREEVERSION;
-#else
-           goto not_there;
-#endif
-       break;
-    case 'C':
-       break;
-    case 'D':
-       if (strEQ(name, "DB_LOCK"))
-#ifdef DB_LOCK
-           return DB_LOCK;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "DB_SHMEM"))
-#ifdef DB_SHMEM
-           return DB_SHMEM;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "DB_TXN"))
-#ifdef DB_TXN
-           return (U32)DB_TXN;
-#else
-           goto not_there;
-#endif
-       break;
-    case 'E':
-       break;
-    case 'F':
-       break;
-    case 'G':
-       break;
-    case 'H':
-       if (strEQ(name, "HASHMAGIC"))
-#ifdef HASHMAGIC
-           return HASHMAGIC;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "HASHVERSION"))
-#ifdef HASHVERSION
-           return HASHVERSION;
-#else
-           goto not_there;
-#endif
-       break;
-    case 'I':
-       break;
-    case 'J':
-       break;
-    case 'K':
-       break;
-    case 'L':
-       break;
-    case 'M':
-       if (strEQ(name, "MAX_PAGE_NUMBER"))
-#ifdef MAX_PAGE_NUMBER
-           return (U32)MAX_PAGE_NUMBER;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "MAX_PAGE_OFFSET"))
-#ifdef MAX_PAGE_OFFSET
-           return MAX_PAGE_OFFSET;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "MAX_REC_NUMBER"))
-#ifdef MAX_REC_NUMBER
-           return (U32)MAX_REC_NUMBER;
-#else
-           goto not_there;
-#endif
-       break;
-    case 'N':
-       break;
-    case 'O':
-       break;
-    case 'P':
-       break;
-    case 'Q':
-       break;
-    case 'R':
-       if (strEQ(name, "RET_ERROR"))
-#ifdef RET_ERROR
-           return RET_ERROR;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "RET_SPECIAL"))
-#ifdef RET_SPECIAL
-           return RET_SPECIAL;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "RET_SUCCESS"))
-#ifdef RET_SUCCESS
-           return RET_SUCCESS;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_CURSOR"))
-#ifdef R_CURSOR
-           return R_CURSOR;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_DUP"))
-#ifdef R_DUP
-           return R_DUP;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_FIRST"))
-#ifdef R_FIRST
-           return R_FIRST;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_FIXEDLEN"))
-#ifdef R_FIXEDLEN
-           return R_FIXEDLEN;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_IAFTER"))
-#ifdef R_IAFTER
-           return R_IAFTER;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_IBEFORE"))
-#ifdef R_IBEFORE
-           return R_IBEFORE;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_LAST"))
-#ifdef R_LAST
-           return R_LAST;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_NEXT"))
-#ifdef R_NEXT
-           return R_NEXT;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_NOKEY"))
-#ifdef R_NOKEY
-           return R_NOKEY;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_NOOVERWRITE"))
-#ifdef R_NOOVERWRITE
-           return R_NOOVERWRITE;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_PREV"))
-#ifdef R_PREV
-           return R_PREV;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_RECNOSYNC"))
-#ifdef R_RECNOSYNC
-           return R_RECNOSYNC;
+    SV **      svp;
+    HV *       action ;
+    DB_File    RETVAL = (DB_File)safemalloc(sizeof(DB_File_type)) ;
+    DB *       dbp ;
+    STRLEN     n_a;
+    int                status ;
+    dMY_CXT;
+
+/* printf("In ParseOpenInfo name=[%s] flags=[%d] mode = [%d]\n", name, flags, mode) ;  */
+    Zero(RETVAL, 1, DB_File_type) ;
+
+    /* Default to HASH */
+    RETVAL->filtering = 0 ;
+    RETVAL->filter_fetch_key = RETVAL->filter_store_key = 
+    RETVAL->filter_fetch_value = RETVAL->filter_store_value =
+    RETVAL->hash = RETVAL->compare = RETVAL->prefix = NULL ;
+    RETVAL->type = DB_HASH ;
+
+     /* DGH - Next line added to avoid SEGV on existing hash DB */
+    CurrentDB = RETVAL; 
+
+    /* fd for 1.86 hash in memory files doesn't return -1 like 1.85 */
+    RETVAL->in_memory = (name == NULL) ;
+
+    status = db_create(&RETVAL->dbp, NULL,0) ;
+    /* printf("db_create returned %d %s\n", status, db_strerror(status)) ; */
+    if (status) {
+       RETVAL->dbp = NULL ;
+        return (RETVAL) ;
+    }  
+    dbp = RETVAL->dbp ;
+
+    if (sv)
+    {
+        if (! SvROK(sv) )
+            croak ("type parameter is not a reference") ;
+
+        svp  = hv_fetch( (HV*)SvRV(sv), "GOT", 3, FALSE) ;
+        if (svp && SvOK(*svp))
+            action  = (HV*) SvRV(*svp) ;
+       else
+           croak("internal error") ;
+
+        if (sv_isa(sv, "DB_File::HASHINFO"))
+        {
+
+           if (!isHASH)
+               croak("DB_File can only tie an associative array to a DB_HASH database") ;
+
+            RETVAL->type = DB_HASH ;
+  
+            svp = hv_fetch(action, "hash", 4, FALSE); 
+
+            if (svp && SvOK(*svp))
+            {
+               (void)dbp->set_h_hash(dbp, hash_cb) ;
+               RETVAL->hash = newSVsv(*svp) ;
+            }
+
+           svp = hv_fetch(action, "ffactor", 7, FALSE);
+          if (svp)
+              (void)dbp->set_h_ffactor(dbp, my_SvUV32(*svp)) ;
+         
+           svp = hv_fetch(action, "nelem", 5, FALSE);
+          if (svp)
+               (void)dbp->set_h_nelem(dbp, my_SvUV32(*svp)) ;
+         
+           svp = hv_fetch(action, "bsize", 5, FALSE);
+          if (svp)
+               (void)dbp->set_pagesize(dbp, my_SvUV32(*svp));
+           
+           svp = hv_fetch(action, "cachesize", 9, FALSE);
+          if (svp)
+               (void)dbp->set_cachesize(dbp, 0, my_SvUV32(*svp), 0) ;
+         
+           svp = hv_fetch(action, "lorder", 6, FALSE);
+          if (svp)
+               (void)dbp->set_lorder(dbp, (int)SvIV(*svp)) ;
+
+           PrintHash(info) ; 
+        }
+        else if (sv_isa(sv, "DB_File::BTREEINFO"))
+        {
+           if (!isHASH)
+               croak("DB_File can only tie an associative array to a DB_BTREE database");
+
+            RETVAL->type = DB_BTREE ;
+   
+            svp = hv_fetch(action, "compare", 7, FALSE);
+            if (svp && SvOK(*svp))
+            {
+                (void)dbp->set_bt_compare(dbp, btree_compare) ;
+               RETVAL->compare = newSVsv(*svp) ;
+            }
+
+            svp = hv_fetch(action, "prefix", 6, FALSE);
+            if (svp && SvOK(*svp))
+            {
+                (void)dbp->set_bt_prefix(dbp, btree_prefix) ;
+               RETVAL->prefix = newSVsv(*svp) ;
+            }
+
+           svp = hv_fetch(action, "flags", 5, FALSE);
+          if (svp)
+              (void)dbp->set_flags(dbp, my_SvUV32(*svp)) ;
+   
+           svp = hv_fetch(action, "cachesize", 9, FALSE);
+          if (svp)
+               (void)dbp->set_cachesize(dbp, 0, my_SvUV32(*svp), 0) ;
+         
+           svp = hv_fetch(action, "psize", 5, FALSE);
+          if (svp)
+               (void)dbp->set_pagesize(dbp, my_SvUV32(*svp)) ;
+         
+           svp = hv_fetch(action, "lorder", 6, FALSE);
+          if (svp)
+               (void)dbp->set_lorder(dbp, (int)SvIV(*svp)) ;
+
+            PrintBtree(info) ;
+         
+        }
+        else if (sv_isa(sv, "DB_File::RECNOINFO"))
+        {
+           int fixed = FALSE ;
+
+           if (isHASH)
+               croak("DB_File can only tie an array to a DB_RECNO database");
+
+            RETVAL->type = DB_RECNO ;
+
+           svp = hv_fetch(action, "flags", 5, FALSE);
+          if (svp) {
+               int flags = SvIV(*svp) ;
+               /* remove FIXDLEN, if present */
+               if (flags & DB_FIXEDLEN) {
+                   fixed = TRUE ;
+                   flags &= ~DB_FIXEDLEN ;
+               }
+          }
+
+           svp = hv_fetch(action, "cachesize", 9, FALSE);
+          if (svp) {
+               status = dbp->set_cachesize(dbp, 0, my_SvUV32(*svp), 0) ;
+          }
+         
+           svp = hv_fetch(action, "psize", 5, FALSE);
+          if (svp) {
+               status = dbp->set_pagesize(dbp, my_SvUV32(*svp)) ;
+           }
+         
+           svp = hv_fetch(action, "lorder", 6, FALSE);
+          if (svp) {
+               status = dbp->set_lorder(dbp, (int)SvIV(*svp)) ;
+          }
+
+           svp = hv_fetch(action, "bval", 4, FALSE);
+            if (svp && SvOK(*svp))
+            {
+               int value ;
+                if (SvPOK(*svp))
+                   value = (int)*SvPV(*svp, n_a) ;
+               else
+                   value = (int)SvIV(*svp) ;
+
+               if (fixed) {
+                   status = dbp->set_re_pad(dbp, value) ;
+               }
+               else {
+                   status = dbp->set_re_delim(dbp, value) ;
+               }
+
+            }
+
+          if (fixed) {
+               svp = hv_fetch(action, "reclen", 6, FALSE);
+              if (svp) {
+                  u_int32_t len =  my_SvUV32(*svp) ;
+                   status = dbp->set_re_len(dbp, len) ;
+              }    
+          }
+         
+           if (name != NULL) {
+               status = dbp->set_re_source(dbp, name) ;
+               name = NULL ;
+           }   
+
+            svp = hv_fetch(action, "bfname", 6, FALSE); 
+            if (svp && SvOK(*svp)) {
+               char * ptr = SvPV(*svp,n_a) ;
+               name = (char*) n_a ? ptr : NULL ;
+           }
+           else
+               name = NULL ;
+         
+
+           status = dbp->set_flags(dbp, (u_int32_t)DB_RENUMBER) ;
+         
+               if (flags){
+                   (void)dbp->set_flags(dbp, (u_int32_t)flags) ;
+               }
+            PrintRecno(info) ;
+        }
+        else
+            croak("type is not of type DB_File::HASHINFO, DB_File::BTREEINFO or DB_File::RECNOINFO");
+    }
+
+    {
+        u_int32_t      Flags = 0 ;
+        int            status ;
+
+        /* Map 1.x flags to 3.x flags */
+        if ((flags & O_CREAT) == O_CREAT)
+            Flags |= DB_CREATE ;
+
+#if O_RDONLY == 0
+        if (flags == O_RDONLY)
 #else
-           goto not_there;
+        if ((flags & O_RDONLY) == O_RDONLY && (flags & O_RDWR) != O_RDWR)
 #endif
-       if (strEQ(name, "R_SETCURSOR"))
-#ifdef R_SETCURSOR
-           return R_SETCURSOR;
-#else
-           goto not_there;
+            Flags |= DB_RDONLY ;
+
+#ifdef O_TRUNC
+        if ((flags & O_TRUNC) == O_TRUNC)
+            Flags |= DB_TRUNCATE ;
 #endif
-       if (strEQ(name, "R_SNAPSHOT"))
-#ifdef R_SNAPSHOT
-           return R_SNAPSHOT;
+
+#ifdef AT_LEAST_DB_4_1
+        status = (RETVAL->dbp->open)(RETVAL->dbp, NULL, name, NULL, RETVAL->type, 
+                               Flags, mode) ; 
 #else
-           goto not_there;
+        status = (RETVAL->dbp->open)(RETVAL->dbp, name, NULL, RETVAL->type, 
+                               Flags, mode) ; 
 #endif
-       break;
-    case 'S':
-       break;
-    case 'T':
-       break;
-    case 'U':
-       break;
-    case 'V':
-       break;
-    case 'W':
-       break;
-    case 'X':
-       break;
-    case 'Y':
-       break;
-    case 'Z':
-       break;
-    case '_':
-       break;
+       /* printf("open returned %d %s\n", status, db_strerror(status)) ; */
+
+        if (status == 0) {
+           /* RETVAL->dbp->set_errcall(RETVAL->dbp, db_errcall_cb) ;*/
+
+            status = (RETVAL->dbp->cursor)(RETVAL->dbp, NULL, &RETVAL->cursor,
+                       0) ;
+           /* printf("cursor returned %d %s\n", status, db_strerror(status)) ; */
+       }
+
+        if (status)
+           RETVAL->dbp = NULL ;
+
     }
-    errno = EINVAL;
-    return 0;
 
-not_there:
-    errno = ENOENT;
-    return 0;
-}
+    return (RETVAL) ;
+
+#endif /* Berkeley DB Version > 2 */
+
+} /* ParseOpenInfo */
+
+
+#include "constants.h"   
 
 MODULE = DB_File       PACKAGE = DB_File       PREFIX = db_
 
+INCLUDE: constants.xs
+
 BOOT:
   {
-    GetVersionInfo(aTHX) ;
+#ifdef dTHX
+    dTHX;
+#endif    
+    /* SV * sv_err = perl_get_sv(ERR_BUFF, GV_ADD|GV_ADDMULTI) ;  */
+    MY_CXT_INIT;
+    __getBerkeleyDBInfo() ;
  
+    DBT_clear(empty) ; 
     empty.data = &zero ;
     empty.size =  sizeof(recno_t) ;
-    DBT_flags(empty) ; 
   }
 
-double
-constant(name,arg)
-       char *          name
-       int             arg
 
 
 DB_File
@@ -1289,8 +1500,10 @@ db_DoTie_(isHASH, dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0666, type=DB_H
                sv = ST(5) ;
 
            RETVAL = ParseOpenInfo(aTHX_ isHASH, name, flags, mode, sv) ;
-           if (RETVAL->dbp == NULL)
+           if (RETVAL->dbp == NULL) {
+               Safefree(RETVAL);
                RETVAL = NULL ;
+           }
        }
        OUTPUT: 
            RETVAL
@@ -1298,16 +1511,19 @@ db_DoTie_(isHASH, dbtype, name=undef, flags=O_CREAT|O_RDWR, mode=0666, type=DB_H
 int
 db_DESTROY(db)
        DB_File         db
+       PREINIT:
+         dMY_CXT;
        INIT:
          CurrentDB = db ;
+         Trace(("DESTROY %p\n", db));
        CLEANUP:
+         Trace(("DESTROY %p done\n", db));
          if (db->hash)
            SvREFCNT_dec(db->hash) ;
          if (db->compare)
            SvREFCNT_dec(db->compare) ;
          if (db->prefix)
            SvREFCNT_dec(db->prefix) ;
-#ifdef DBM_FILTERING
          if (db->filter_fetch_key)
            SvREFCNT_dec(db->filter_fetch_key) ;
          if (db->filter_store_key)
@@ -1316,8 +1532,7 @@ db_DESTROY(db)
            SvREFCNT_dec(db->filter_fetch_value) ;
          if (db->filter_store_value)
            SvREFCNT_dec(db->filter_store_value) ;
-#endif /* DBM_FILTERING */
-         Safefree(db) ;
+         safefree(db) ;
 #ifdef DB_VERSION_MAJOR
          if (RETVAL > 0)
            RETVAL = -1 ;
@@ -1329,6 +1544,8 @@ db_DELETE(db, key, flags=0)
        DB_File         db
        DBTKEY          key
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        INIT:
          CurrentDB = db ;
 
@@ -1337,29 +1554,33 @@ int
 db_EXISTS(db, key)
        DB_File         db
        DBTKEY          key
+       PREINIT:
+         dMY_CXT;
        CODE:
        {
           DBT          value ;
        
-         DBT_flags(value) ; 
+         DBT_clear(value) ; 
          CurrentDB = db ;
          RETVAL = (((db->dbp)->get)(db->dbp, TXN &key, &value, 0) == 0) ;
        }
        OUTPUT:
          RETVAL
 
-int
+void
 db_FETCH(db, key, flags=0)
        DB_File         db
        DBTKEY          key
        u_int           flags
+       PREINIT:
+         dMY_CXT ;
+         int RETVAL ;
        CODE:
        {
             DBT                value ;
 
-           DBT_flags(value) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
-           /* RETVAL = ((db->dbp)->get)(db->dbp, TXN &key, &value, flags) ; */
            RETVAL = db_get(db, key, value, flags) ;
            ST(0) = sv_newmortal();
            OutputValue(ST(0), value)
@@ -1371,35 +1592,44 @@ db_STORE(db, key, value, flags=0)
        DBTKEY          key
        DBT             value
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        INIT:
          CurrentDB = db ;
 
 
-int
+void
 db_FIRSTKEY(db)
        DB_File         db
+       PREINIT:
+         dMY_CXT ;
+         int RETVAL ;
        CODE:
        {
            DBTKEY      key ;
            DBT         value ;
 
-           DBT_flags(key) ; 
-           DBT_flags(value) ; 
+           DBT_clear(key) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
            RETVAL = do_SEQ(db, key, value, R_FIRST) ;
            ST(0) = sv_newmortal();
            OutputKey(ST(0), key) ;
        }
 
-int
+void
 db_NEXTKEY(db, key)
        DB_File         db
-       DBTKEY          key
+       DBTKEY          key = NO_INIT
+       PREINIT:
+         dMY_CXT ;
+         int RETVAL ;
        CODE:
        {
            DBT         value ;
 
-           DBT_flags(value) ; 
+           DBT_clear(key) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
            RETVAL = do_SEQ(db, key, value, R_NEXT) ;
            ST(0) = sv_newmortal();
@@ -1414,17 +1644,18 @@ int
 unshift(db, ...)
        DB_File         db
        ALIAS:          UNSHIFT = 1
+       PREINIT:
+         dMY_CXT;
        CODE:
        {
            DBTKEY      key ;
            DBT         value ;
            int         i ;
            int         One ;
-           DB *        Db = db->dbp ;
            STRLEN      n_a;
 
-           DBT_flags(key) ; 
-           DBT_flags(value) ; 
+           DBT_clear(key) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
 #ifdef DB_VERSION_MAJOR
            /* get the first value */
@@ -1435,7 +1666,8 @@ unshift(db, ...)
 #endif
            for (i = items-1 ; i > 0 ; --i)
            {
-               value.data = SvPV(ST(i), n_a) ;
+               DBM_ckFilter(ST(i), filter_store_value, "filter_store_value");
+               value.data = SvPVbyte(ST(i), n_a) ;
                value.size = n_a ;
                One = 1 ;
                key.data = &One ;
@@ -1443,7 +1675,7 @@ unshift(db, ...)
 #ifdef DB_VERSION_MAJOR
                RETVAL = (db->cursor->c_put)(db->cursor, &key, &value, DB_BEFORE) ;
 #else
-               RETVAL = (Db->put)(Db, &key, &value, R_IBEFORE) ;
+               RETVAL = (db->dbp->put)(db->dbp, &key, &value, R_IBEFORE) ;
 #endif
                if (RETVAL != 0)
                    break;
@@ -1452,17 +1684,21 @@ unshift(db, ...)
        OUTPUT:
            RETVAL
 
-I32
+void
 pop(db)
        DB_File         db
+       PREINIT:
+         dMY_CXT;
        ALIAS:          POP = 1
+       PREINIT:
+         I32 RETVAL;
        CODE:
        {
            DBTKEY      key ;
            DBT         value ;
 
-           DBT_flags(key) ; 
-           DBT_flags(value) ; 
+           DBT_clear(key) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
 
            /* First get the final value */
@@ -1479,17 +1715,21 @@ pop(db)
            }
        }
 
-I32
+void
 shift(db)
        DB_File         db
+       PREINIT:
+         dMY_CXT;
        ALIAS:          SHIFT = 1
+       PREINIT:
+         I32 RETVAL;
        CODE:
        {
            DBT         value ;
            DBTKEY      key ;
 
-           DBT_flags(key) ; 
-           DBT_flags(value) ; 
+           DBT_clear(key) ; 
+           DBT_clear(value) ; 
            CurrentDB = db ;
            /* get the first value */
            RETVAL = do_SEQ(db, key, value, R_FIRST) ;   
@@ -1509,6 +1749,8 @@ shift(db)
 I32
 push(db, ...)
        DB_File         db
+       PREINIT:
+         dMY_CXT;
        ALIAS:          PUSH = 1
        CODE:
        {
@@ -1517,47 +1759,43 @@ push(db, ...)
            DB *        Db = db->dbp ;
            int         i ;
            STRLEN      n_a;
+           int         keyval ;
 
            DBT_flags(key) ; 
            DBT_flags(value) ; 
            CurrentDB = db ;
-#ifdef DB_VERSION_MAJOR
-               RETVAL = 0 ;
-               key = empty ;
-               for (i = 1 ; i < items  ; ++i)
-               {
-                   value.data = SvPV(ST(i), n_a) ;
-                   value.size = n_a ;
-                   RETVAL = (Db->put)(Db, NULL, &key, &value, DB_APPEND) ;
-                   if (RETVAL != 0)
-                       break;
-               }
-#else          
-           
            /* Set the Cursor to the Last element */
            RETVAL = do_SEQ(db, key, value, R_LAST) ;
+#ifndef DB_VERSION_MAJOR                                   
            if (RETVAL >= 0)
+#endif     
            {
-               if (RETVAL == 1)
-                   key = empty ;
-               for (i = items - 1 ; i > 0 ; --i)
+               if (RETVAL == 0)
+                   keyval = *(int*)key.data ;
+               else
+                   keyval = 0 ;
+               for (i = 1 ; i < items ; ++i)
                {
-                   value.data = SvPV(ST(i), n_a) ;
+                   DBM_ckFilter(ST(i), filter_store_value, "filter_store_value");
+                   value.data = SvPVbyte(ST(i), n_a) ;
                    value.size = n_a ;
-                   RETVAL = (Db->put)(Db, &key, &value, R_IAFTER) ;
+                   ++ keyval ;
+                   key.data = &keyval ;
+                   key.size = sizeof(int) ;
+                   RETVAL = (Db->put)(Db, TXN &key, &value, 0) ;
                    if (RETVAL != 0)
                        break;
                }
            }
-#endif
        }
        OUTPUT:
            RETVAL
 
-
 I32
 length(db)
        DB_File         db
+       PREINIT:
+         dMY_CXT;
        ALIAS:          FETCHSIZE = 1
        CODE:
            CurrentDB = db ;
@@ -1575,6 +1813,8 @@ db_del(db, key, flags=0)
        DB_File         db
        DBTKEY          key
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        CODE:
          CurrentDB = db ;
          RETVAL = db_del(db, key, flags) ;
@@ -1594,9 +1834,11 @@ db_get(db, key, value, flags=0)
        DBTKEY          key
        DBT             value = NO_INIT
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        CODE:
          CurrentDB = db ;
-         DBT_flags(value) ; 
+         DBT_clear(value) ; 
          RETVAL = db_get(db, key, value, flags) ;
 #ifdef DB_VERSION_MAJOR
          if (RETVAL > 0)
@@ -1614,6 +1856,8 @@ db_put(db, key, value, flags=0)
        DBTKEY          key
        DBT             value
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        CODE:
          CurrentDB = db ;
          RETVAL = db_put(db, key, value, flags) ;
@@ -1630,16 +1874,20 @@ db_put(db, key, value, flags=0)
 int
 db_fd(db)
        DB_File         db
-       int             status = 0 ;
+       PREINIT:
+         dMY_CXT ;
        CODE:
          CurrentDB = db ;
 #ifdef DB_VERSION_MAJOR
          RETVAL = -1 ;
-         status = (db->in_memory
-               ? -1 
-               : ((db->dbp)->fd)(db->dbp, &RETVAL) ) ;
-         if (status != 0)
-           RETVAL = -1 ;
+         {
+           int status = 0 ;
+           status = (db->in_memory
+                     ? -1 
+                     : ((db->dbp)->fd)(db->dbp, &RETVAL) ) ;
+           if (status != 0)
+             RETVAL = -1 ;
+         }
 #else
          RETVAL = (db->in_memory
                ? -1 
@@ -1652,6 +1900,8 @@ int
 db_sync(db, flags=0)
        DB_File         db
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        CODE:
          CurrentDB = db ;
          RETVAL = db_sync(db, flags) ;
@@ -1669,9 +1919,11 @@ db_seq(db, key, value, flags)
        DBTKEY          key 
        DBT             value = NO_INIT
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        CODE:
          CurrentDB = db ;
-         DBT_flags(value) ; 
+         DBT_clear(value) ; 
          RETVAL = db_seq(db, key, value, flags);
 #ifdef DB_VERSION_MAJOR
          if (RETVAL > 0)
@@ -1684,33 +1936,13 @@ db_seq(db, key, value, flags)
          key
          value
 
-#ifdef DBM_FILTERING
-
-#define setFilter(type)                                        \
-       {                                               \
-           if (db->type)                               \
-               RETVAL = sv_mortalcopy(db->type) ;      \
-           ST(0) = RETVAL ;                            \
-           if (db->type && (code == &PL_sv_undef)) {   \
-                SvREFCNT_dec(db->type) ;               \
-               db->type = NULL ;                       \
-           }                                           \
-           else if (code) {                            \
-               if (db->type)                           \
-                   sv_setsv(db->type, code) ;          \
-               else                                    \
-                   db->type = newSVsv(code) ;          \
-           }                                           \
-       }
-
-
 SV *
 filter_fetch_key(db, code)
        DB_File         db
        SV *            code
        SV *            RETVAL = &PL_sv_undef ;
        CODE:
-           setFilter(filter_fetch_key) ;
+           DBM_setFilter(db->filter_fetch_key, code) ;
 
 SV *
 filter_store_key(db, code)
@@ -1718,7 +1950,7 @@ filter_store_key(db, code)
        SV *            code
        SV *            RETVAL = &PL_sv_undef ;
        CODE:
-           setFilter(filter_store_key) ;
+           DBM_setFilter(db->filter_store_key, code) ;
 
 SV *
 filter_fetch_value(db, code)
@@ -1726,7 +1958,7 @@ filter_fetch_value(db, code)
        SV *            code
        SV *            RETVAL = &PL_sv_undef ;
        CODE:
-           setFilter(filter_fetch_value) ;
+           DBM_setFilter(db->filter_fetch_value, code) ;
 
 SV *
 filter_store_value(db, code)
@@ -1734,6 +1966,5 @@ filter_store_value(db, code)
        SV *            code
        SV *            RETVAL = &PL_sv_undef ;
        CODE:
-           setFilter(filter_store_value) ;
+           DBM_setFilter(db->filter_store_value, code) ;
 
-#endif /* DBM_FILTERING */