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 ccb9b75..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 7th September 1999
- version 1.71
+ 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.
 
         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 ))
-
-#    define PL_sv_undef                sv_undef
-#    define PL_na              na
-
-#endif
-
-/* DEFSV appears first in 5.004_56 */
-#ifndef DEFSV
-#    define DEFSV              GvSV(defgv)
-#endif
+/* Mention DB_VERSION_MAJOR_CFG, DB_VERSION_MINOR_CFG, and
+   DB_VERSION_PATCH_CFG here so that Configure pulls them all in. */
 
 /* 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. */
 
-#undef __attribute__
-
-/* 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
+/* #if DB_VERSION_MAJOR_CFG < 2  */
+#ifndef DB_VERSION_MAJOR
+#    undef __attribute__
 #endif
 
 #ifdef COMPAT185
 #    include <db.h>
 #endif
 
-#ifndef pTHX
-#    define pTHX
-#    define pTHX_
-#    define aTHX
-#    define aTHX_
-#endif
+/* Wall starts with 5.7.x */
 
-#ifndef newSVpvn
-#    define newSVpvn(a,b)      newSVpv(a,b)
-#endif
+#if PERL_REVISION > 5 || (PERL_REVISION == 5 && PERL_VERSION >= 7)
+
+/* 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
+
+#    undef  dNOOP
+#    define dNOOP extern int Perl___notused
+
+    /* 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
 #    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
@@ -242,6 +281,7 @@ typedef db_recno_t  recno_t;
 
 #else /* db version 1.x */
 
+#define BERKELEY_DB_1
 #define BERKELEY_DB_1_OR_2
 
 typedef union INFO {
@@ -300,16 +340,16 @@ 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->cursor->c_close(db->cursor),\
-                                         (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)          \
@@ -317,7 +357,7 @@ typedef union INFO {
 
 #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)
@@ -331,8 +371,12 @@ 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 ;
@@ -340,72 +384,71 @@ typedef struct {
 #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
 
@@ -469,8 +512,27 @@ u_int              flags ;
 
 #endif /* DB_VERSION_MAJOR */
 
+static void
+tidyUp(DB_File db)
+{
+    db->aborted = TRUE ;
+}
+
 
 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 */
+
 #ifdef CAN_PROTOTYPE
 btree_compare(const DBT *key1, const DBT *key2)
 #else
@@ -478,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 
@@ -503,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) ;
@@ -514,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
@@ -534,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 
@@ -559,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) ;
@@ -570,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 ;
  
@@ -582,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(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, size_t size)
+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 = "" ;
@@ -606,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 ;
 
@@ -616,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 ;
 
@@ -628,6 +769,28 @@ 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
 
 #if defined(TRACE) && defined(BERKELEY_DB_1_OR_2)
 
@@ -663,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) ;
 }
@@ -737,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 ;
     }
@@ -770,16 +935,18 @@ SV *   sv ;
     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 ;
 
@@ -1043,16 +1210,15 @@ SV *   sv ;
     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 */
-#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 ;
 
@@ -1099,23 +1265,23 @@ SV *   sv ;
 
            svp = hv_fetch(action, "ffactor", 7, FALSE);
           if (svp)
-              (void)dbp->set_h_ffactor(dbp, SvIV(*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, SvIV(*svp)) ;
+               (void)dbp->set_h_nelem(dbp, my_SvUV32(*svp)) ;
          
            svp = hv_fetch(action, "bsize", 5, FALSE);
           if (svp)
-               (void)dbp->set_pagesize(dbp, SvIV(*svp));
+               (void)dbp->set_pagesize(dbp, my_SvUV32(*svp));
            
            svp = hv_fetch(action, "cachesize", 9, FALSE);
           if (svp)
-               (void)dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ;
+               (void)dbp->set_cachesize(dbp, 0, my_SvUV32(*svp), 0) ;
          
            svp = hv_fetch(action, "lorder", 6, FALSE);
           if (svp)
-               (void)dbp->set_lorder(dbp, SvIV(*svp)) ;
+               (void)dbp->set_lorder(dbp, (int)SvIV(*svp)) ;
 
            PrintHash(info) ; 
         }
@@ -1142,19 +1308,19 @@ SV *   sv ;
 
            svp = hv_fetch(action, "flags", 5, FALSE);
           if (svp)
-              (void)dbp->set_flags(dbp, SvIV(*svp)) ;
+              (void)dbp->set_flags(dbp, my_SvUV32(*svp)) ;
    
            svp = hv_fetch(action, "cachesize", 9, FALSE);
           if (svp)
-               (void)dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ;
+               (void)dbp->set_cachesize(dbp, 0, my_SvUV32(*svp), 0) ;
          
            svp = hv_fetch(action, "psize", 5, FALSE);
           if (svp)
-               (void)dbp->set_pagesize(dbp, SvIV(*svp)) ;
+               (void)dbp->set_pagesize(dbp, my_SvUV32(*svp)) ;
          
            svp = hv_fetch(action, "lorder", 6, FALSE);
           if (svp)
-               (void)dbp->set_lorder(dbp, SvIV(*svp)) ;
+               (void)dbp->set_lorder(dbp, (int)SvIV(*svp)) ;
 
             PrintBtree(info) ;
          
@@ -1180,17 +1346,17 @@ SV *   sv ;
 
            svp = hv_fetch(action, "cachesize", 9, FALSE);
           if (svp) {
-               status = dbp->set_cachesize(dbp, 0, SvIV(*svp), 0) ;
+               status = dbp->set_cachesize(dbp, 0, my_SvUV32(*svp), 0) ;
           }
          
            svp = hv_fetch(action, "psize", 5, FALSE);
           if (svp) {
-               status = dbp->set_pagesize(dbp, SvIV(*svp)) ;
+               status = dbp->set_pagesize(dbp, my_SvUV32(*svp)) ;
            }
          
            svp = hv_fetch(action, "lorder", 6, FALSE);
           if (svp) {
-               status = dbp->set_lorder(dbp, SvIV(*svp)) ;
+               status = dbp->set_lorder(dbp, (int)SvIV(*svp)) ;
           }
 
            svp = hv_fetch(action, "bval", 4, FALSE);
@@ -1200,7 +1366,7 @@ SV *   sv ;
                 if (SvPOK(*svp))
                    value = (int)*SvPV(*svp, n_a) ;
                else
-                   value = SvIV(*svp) ;
+                   value = (int)SvIV(*svp) ;
 
                if (fixed) {
                    status = dbp->set_re_pad(dbp, value) ;
@@ -1214,7 +1380,7 @@ SV *   sv ;
           if (fixed) {
                svp = hv_fetch(action, "reclen", 6, FALSE);
               if (svp) {
-                  u_int32_t len =  (u_int32_t)SvIV(*svp) ;
+                  u_int32_t len =  my_SvUV32(*svp) ;
                    status = dbp->set_re_len(dbp, len) ;
               }    
           }
@@ -1233,10 +1399,10 @@ SV *   sv ;
                name = NULL ;
          
 
-           status = dbp->set_flags(dbp, DB_RENUMBER) ;
+           status = dbp->set_flags(dbp, (u_int32_t)DB_RENUMBER) ;
          
                if (flags){
-                   (void)dbp->set_flags(dbp, flags) ;
+                   (void)dbp->set_flags(dbp, (u_int32_t)flags) ;
                }
             PrintRecno(info) ;
         }
@@ -1245,7 +1411,7 @@ SV *   sv ;
     }
 
     {
-        int            Flags = 0 ;
+        u_int32_t      Flags = 0 ;
         int            status ;
 
         /* Map 1.x flags to 3.x flags */
@@ -1264,14 +1430,22 @@ SV *   sv ;
             Flags |= DB_TRUNCATE ;
 #endif
 
-        status = RETVAL->dbp->open(RETVAL->dbp, name, NULL, RETVAL->type, 
+#ifdef AT_LEAST_DB_4_1
+        status = (RETVAL->dbp->open)(RETVAL->dbp, NULL, name, NULL, RETVAL->type, 
                                Flags, mode) ; 
+#else
+        status = (RETVAL->dbp->open)(RETVAL->dbp, name, NULL, RETVAL->type, 
+                               Flags, mode) ; 
+#endif
        /* printf("open returned %d %s\n", status, db_strerror(status)) ; */
 
-        if (status == 0)
+        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)) ; */
+           /* printf("cursor returned %d %s\n", status, db_strerror(status)) ; */
+       }
 
         if (status)
            RETVAL->dbp = NULL ;
@@ -1285,246 +1459,19 @@ SV *   sv ;
 } /* ParseOpenInfo */
 
 
-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;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_SETCURSOR"))
-#ifdef R_SETCURSOR
-           return R_SETCURSOR;
-#else
-           goto not_there;
-#endif
-       if (strEQ(name, "R_SNAPSHOT"))
-#ifdef R_SNAPSHOT
-           return R_SNAPSHOT;
-#else
-           goto not_there;
-#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;
-    }
-    errno = EINVAL;
-    return 0;
-
-not_there:
-    errno = ENOENT;
-    return 0;
-}
+#include "constants.h"   
 
 MODULE = DB_File       PACKAGE = DB_File       PREFIX = db_
 
+INCLUDE: constants.xs
+
 BOOT:
   {
+#ifdef dTHX
+    dTHX;
+#endif    
+    /* SV * sv_err = perl_get_sv(ERR_BUFF, GV_ADD|GV_ADDMULTI) ;  */
+    MY_CXT_INIT;
     __getBerkeleyDBInfo() ;
  
     DBT_clear(empty) ; 
@@ -1532,10 +1479,6 @@ BOOT:
     empty.size =  sizeof(recno_t) ;
   }
 
-double
-constant(name,arg)
-       char *          name
-       int             arg
 
 
 DB_File
@@ -1557,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
@@ -1566,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)
@@ -1584,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 ;
@@ -1597,6 +1544,8 @@ db_DELETE(db, key, flags=0)
        DB_File         db
        DBTKEY          key
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        INIT:
          CurrentDB = db ;
 
@@ -1605,6 +1554,8 @@ int
 db_EXISTS(db, key)
        DB_File         db
        DBTKEY          key
+       PREINIT:
+         dMY_CXT;
        CODE:
        {
           DBT          value ;
@@ -1616,18 +1567,20 @@ db_EXISTS(db, key)
        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_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)
@@ -1639,13 +1592,18 @@ 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 ;
@@ -1659,14 +1617,18 @@ db_FIRSTKEY(db)
            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_clear(key) ; 
            DBT_clear(value) ; 
            CurrentDB = db ;
            RETVAL = do_SEQ(db, key, value, R_NEXT) ;
@@ -1682,13 +1644,14 @@ 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_clear(key) ; 
@@ -1703,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 ;
@@ -1711,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;
@@ -1720,10 +1684,14 @@ unshift(db, ...)
        OUTPUT:
            RETVAL
 
-I32
+void
 pop(db)
        DB_File         db
+       PREINIT:
+         dMY_CXT;
        ALIAS:          POP = 1
+       PREINIT:
+         I32 RETVAL;
        CODE:
        {
            DBTKEY      key ;
@@ -1747,10 +1715,14 @@ pop(db)
            }
        }
 
-I32
+void
 shift(db)
        DB_File         db
+       PREINIT:
+         dMY_CXT;
        ALIAS:          SHIFT = 1
+       PREINIT:
+         I32 RETVAL;
        CODE:
        {
            DBT         value ;
@@ -1777,6 +1749,8 @@ shift(db)
 I32
 push(db, ...)
        DB_File         db
+       PREINIT:
+         dMY_CXT;
        ALIAS:          PUSH = 1
        CODE:
        {
@@ -1802,7 +1776,8 @@ push(db, ...)
                    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 ;
                    ++ keyval ;
                    key.data = &keyval ;
@@ -1819,6 +1794,8 @@ push(db, ...)
 I32
 length(db)
        DB_File         db
+       PREINIT:
+         dMY_CXT;
        ALIAS:          FETCHSIZE = 1
        CODE:
            CurrentDB = db ;
@@ -1836,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) ;
@@ -1855,6 +1834,8 @@ db_get(db, key, value, flags=0)
        DBTKEY          key
        DBT             value = NO_INIT
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        CODE:
          CurrentDB = db ;
          DBT_clear(value) ; 
@@ -1875,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) ;
@@ -1891,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 
@@ -1913,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) ;
@@ -1930,6 +1919,8 @@ db_seq(db, key, value, flags)
        DBTKEY          key 
        DBT             value = NO_INIT
        u_int           flags
+       PREINIT:
+         dMY_CXT;
        CODE:
          CurrentDB = db ;
          DBT_clear(value) ; 
@@ -1945,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)
@@ -1979,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)
@@ -1987,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)
@@ -1995,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 */