DB_File(3)

DB_File(3)

dbz Home Page Subroutines Index DefaultColormap


NNAAMMEE
       DB_File - Perl5 access to Berkeley DB

SSYYNNOOPPSSIISS
        use DB_File ;

        [$X =] tie %hash,  'DB_File', [$filename, $flags, $mode, $DB_HASH] ;
        [$X =] tie %hash,  'DB_File', $filename, $flags, $mode, $DB_BTREE ;
        [$X =] tie @array, 'DB_File', $filename, $flags, $mode, $DB_RECNO ;

        $status = $X->del($key [, $flags]) ;
        $status = $X->put($key, $value [, $flags]) ;
        $status = $X->get($key, $value [, $flags]) ;
        $status = $X->seq($key, $value, $flags) ;
        $status = $X->sync([$flags]) ;
        $status = $X->fd ;

        # BTREE only
        $count = $X->get_dup($key) ;
        @list  = $X->get_dup($key) ;
        %list  = $X->get_dup($key, 1) ;

        # RECNO only
        $a = $X->length;
        $a = $X->pop ;
        $X->push(list);
        $a = $X->shift;
        $X->unshift(list);

        untie %hash ;
        untie @array ;

DDEESSCCRRIIPPTTIIOONN
       DDBB__FFiillee is a module which allows Perl programs to make use
       of the facilities provided by Berkeley DB.  If you intend
       to use this module you should really have a copy of the
       Berkeley DB manual pages at hand. The interface defined
       here mirrors the Berkeley DB interface closely.

       Please note that this module will only work with version
       1.x of Berkeley DB. Once Berkeley DB version 2 is
       released, DDBB__FFiillee will be upgraded to work with it.

       Berkeley DB is a C library which provides a consistent
       interface to a number of database formats.  DDBB__FFiillee
       provides an interface to all three of the database types
       currently supported by Berkeley DB.

       The file types are:

       DDBB__HHAASSHH
            This database type allows arbitrary key/value pairs
            to be stored in data files. This is equivalent to the

            functionality provided by other hashing packages like
            DBM, NDBM, ODBM, GDBM, and SDBM. Remember though, the
            files created using DB_HASH are not compatible with
            any of the other packages mentioned.

            A default hashing algorithm, which will be adequate
            for most applications, is built into Berkeley DB. If
            you do need to use your own hashing algorithm it is
            possible to write your own in Perl and have DDBB__FFiillee
            use it instead.

       DDBB__BBTTRREEEE
            The btree format allows arbitrary key/value pairs to
            be stored in a sorted, balanced binary tree.

            As with the DB_HASH format, it is possible to provide
            a user defined Perl routine to perform the comparison
            of keys. By default, though, the keys are stored in
            lexical order.

       DDBB__RREECCNNOO
            DB_RECNO allows both fixed-length and variable-length
            flat text files to be manipulated using the same
            key/value pair interface as in DB_HASH and DB_BTREE.
            In this case the key will consist of a record (line)
            number.

       IInntteerrffaaccee ttoo BBeerrkkeelleeyy DDBB

       DDBB__FFiillee allows access to Berkeley DB files using the tie()
       mechanism in Perl 5 (for full details, see the tie() entry
       in the perlfunc manpage). This facility allows DDBB__FFiillee to
       access Berkeley DB files using either an associative array
       (for DB_HASH & DB_BTREE file types) or an ordinary array
       (for the DB_RECNO file type).

       In addition to the tie() interface, it is also possible to
       access most of the functions provided in the Berkeley DB
       API directly.  See the section on THE API INTERFACE.

       OOppeenniinngg aa BBeerrkkeelleeyy DDBB DDaattaabbaassee FFiillee

       Berkeley DB uses the function dbopen() to open or create a
       database.  Here is the C prototype for dbopen():

             DB*
             dbopen (const char * file, int flags, int mode,
                     DBTYPE type, const void * openinfo)

       The parameter type is an enumeration which specifies which
       of the 3 interface methods (DB_HASH, DB_BTREE or DB_RECNO)
       is to be used.  Depending on which of these is actually
       chosen, the final parameter, openinfo points to a data
       structure which allows tailoring of the specific interface

       method.

       This interface is handled slightly differently in DDBB__FFiillee.
       Here is an equivalent call using DDBB__FFiillee:
               tie %array, 'DB_File', $filename, $flags, $mode, $DB_HASH ;

       The filename, flags and mode parameters are the direct
       equivalent of their dbopen() counterparts. The final
       parameter $DB_HASH performs the function of both the type
       and openinfo parameters in dbopen().

       In the example above $DB_HASH is actually a pre-defined
       reference to a hash object. DDBB__FFiillee has three of these
       pre-defined references.  Apart from $DB_HASH, there is
       also $DB_BTREE and $DB_RECNO.

       The keys allowed in each of these pre-defined references
       is limited to the names used in the equivalent C
       structure. So, for example, the $DB_HASH reference will
       only allow keys called bsize, cachesize, ffactor, hash,
       lorder and nelem.

       To change one of these elements, just assign to it like
       this:
               $DB_HASH->{'cachesize'} = 10000 ;

       The three predefined variables $DB_HASH, $DB_BTREE and
       $DB_RECNO are usually adequate for most applications.  If
       you do need to create extra instances of these objects,
       constructors are available for each file type.

       Here are examples of the constructors and the valid
       options available for DB_HASH, DB_BTREE and DB_RECNO
       respectively.

            $a = new DB_File::HASHINFO ;
            $a->{'bsize'} ;
            $a->{'cachesize'} ;
            $a->{'ffactor'};
            $a->{'hash'} ;
            $a->{'lorder'} ;
            $a->{'nelem'} ;

            $b = new DB_File::BTREEINFO ;
            $b->{'flags'} ;
            $b->{'cachesize'} ;
            $b->{'maxkeypage'} ;
            $b->{'minkeypage'} ;
            $b->{'psize'} ;
            $b->{'compare'} ;
            $b->{'prefix'} ;
            $b->{'lorder'} ;

            $c = new DB_File::RECNOINFO ;
            $c->{'bval'} ;
            $c->{'cachesize'} ;
            $c->{'psize'} ;
            $c->{'flags'} ;
            $c->{'lorder'} ;
            $c->{'reclen'} ;
            $c->{'bfname'} ;

       The values stored in the hashes above are mostly the
       direct equivalent of their C counterpart. Like their C
       counterparts, all are set to a default values - that means
       you don't have to set all of the values when you only want
       to change one. Here is an example:

            $a = new DB_File::HASHINFO ;
            $a->{'cachesize'} =  12345 ;
            tie %y, 'DB_File', "filename", $flags, 0777, $a ;

       A few of the options need extra discussion here. When
       used, the C equivalent of the keys hash, compare and
       prefix store pointers to C functions. In DDBB__FFiillee these
       keys are used to store references to Perl subs. Below are
       templates for each of the subs:

           sub hash
           {
               my ($data) = @_ ;
               ...
               # return the hash value for $data
               return $hash ;
           }

           sub compare
           {
               my ($key, $key2) = @_ ;
               ...
               # return  0 if $key1 eq $key2
               #        -1 if $key1 lt $key2
               #         1 if $key1 gt $key2
               return (-1 , 0 or 1) ;
           }

           sub prefix
           {
               my ($key, $key2) = @_ ;
               ...
               # return number of bytes of $key2 which are
               # necessary to determine that it is greater than $key1
               return $bytes ;
           }

       See the section on Changing the BTREE sort order for an
       example of using the compare template.

       If you are using the DB_RECNO interface and you intend
       making use of bval, you should check out the section on
       The 'bval' Option.

       DDeeffaauulltt PPaarraammeetteerrss

       It is possible to omit some or all of the final 4
       parameters in the call to tie and let them take default
       values. As DB_HASH is the most common file format used,
       the call:

           tie %A, "DB_File", "filename" ;

       is equivalent to:

           tie %A, "DB_File", "filename", O_CREAT|O_RDWR, 0666, $DB_HASH ;

       It is also possible to omit the filename parameter as
       well, so the call:

           tie %A, "DB_File" ;

       is equivalent to:

           tie %A, "DB_File", undef, O_CREAT|O_RDWR, 0666, $DB_HASH ;

       See the section on In Memory Databases for a discussion on
       the use of undef in place of a filename.

       IInn MMeemmoorryy DDaattaabbaasseess

       Berkeley DB allows the creation of in-memory databases by
       using NULL (that is, a (char *)0 in C) in place of the
       filename.  DDBB__FFiillee uses undef instead of NULL to provide
       this functionality.

DDBB__HHAASSHH
       The DB_HASH file format is probably the most commonly used
       of the three file formats that DDBB__FFiillee supports. It is
       also very straightforward to use.

       AA SSiimmppllee EExxaammppllee

       This example shows how to create a database, add key/value
       pairs to the database, delete keys/value pairs and finally
       how to enumerate the contents of the database.

           use strict ;
           use DB_File ;
           use vars qw( %h $k $v ) ;

           tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0640, $DB_HASH
               or die "Cannot open file 'fruit': $!\n";

           # Add a few key/value pairs to the file
           $h{"apple"} = "red" ;
           $h{"orange"} = "orange" ;
           $h{"banana"} = "yellow" ;
           $h{"tomato"} = "red" ;

           # Check for existence of a key
           print "Banana Exists\n\n" if $h{"banana"} ;

           # Delete a key/value pair.
           delete $h{"apple"} ;

           # print the contents of the file
           while (($k, $v) = each %h)
             { print "$k -> $v\n" }

           untie %h ;

       here is the output:

           Banana Exists

           orange -> orange
           tomato -> red
           banana -> yellow

       Note that the like ordinary associative arrays, the order
       of the keys retrieved is in an apparently random order.

DDBB__BBTTRREEEE
       The DB_BTREE format is useful when you want to store data
       in a given order. By default the keys will be stored in
       lexical order, but as you will see from the example shown
       in the next section, it is very easy to define your own
       sorting function.

       CChhaannggiinngg tthhee BBTTRREEEE ssoorrtt oorrddeerr

       This script shows how to override the default sorting
       algorithm that BTREE uses. Instead of using the normal
       lexical ordering, a case insensitive compare function will
       be used.

           use strict ;
           use DB_File ;

           my %h ;

           sub Compare
           {
               my ($key1, $key2) = @_ ;
               "\L$key1" cmp "\L$key2" ;
           }

           # specify the Perl sub that will do the comparison
           $DB_BTREE->{'compare'} = \&Compare ;

           tie %h, "DB_File", "tree", O_RDWR|O_CREAT, 0640, $DB_BTREE
               or die "Cannot open file 'tree': $!\n" ;

           # Add a key/value pair to the file
           $h{'Wall'} = 'Larry' ;
           $h{'Smith'} = 'John' ;
           $h{'mouse'} = 'mickey' ;
           $h{'duck'}  = 'donald' ;

           # Delete
           delete $h{"duck"} ;

           # Cycle through the keys printing them in order.
           # Note it is not necessary to sort the keys as
           # the btree will have kept them in order automatically.
           foreach (keys %h)
             { print "$_\n" }

           untie %h ;

       Here is the output from the code above.

           mouse
           Smith
           Wall

       There are a few point to bear in mind if you want to
       change the ordering in a BTREE database:

       1.   The new compare function must be specified when you
            create the database.

       2.   You cannot change the ordering once the database has
            been created. Thus you must use the same compare
            function every time you access the database.

       HHaannddlliinngg DDuupplliiccaattee KKeeyyss

       The BTREE file type optionally allows a single key to be
       associated with an arbitrary number of values. This option
       is enabled by setting the flags element of $DB_BTREE to
       R_DUP when creating the database.

       There are some difficulties in using the tied hash
       interface if you want to manipulate a BTREE database with
       duplicate keys. Consider this code:

           use strict ;
           use DB_File ;

           use vars qw($filename %h ) ;

           $filename = "tree" ;
           unlink $filename ;

           # Enable duplicate records
           $DB_BTREE->{'flags'} = R_DUP ;

           tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE
               or die "Cannot open $filename: $!\n";

           # Add some key/value pairs to the file
           $h{'Wall'} = 'Larry' ;
           $h{'Wall'} = 'Brick' ; # Note the duplicate key
           $h{'Wall'} = 'Brick' ; # Note the duplicate key and value
           $h{'Smith'} = 'John' ;
           $h{'mouse'} = 'mickey' ;

           # iterate through the associative array
           # and print each key/value pair.
           foreach (keys %h)
             { print "$_  -> $h{$_}\n" }

           untie %h ;

       Here is the output:

           Smith   -> John
           Wall    -> Larry
           Wall    -> Larry
           Wall    -> Larry
           mouse   -> mickey

       As you can see 3 records have been successfully created
       with key Wall - the only thing is, when they are retrieved
       from the database they seem to have the same value, namely
       Larry. The problem is caused by the way that the
       associative array interface works. Basically, when the
       associative array interface is used to fetch the value
       associated with a given key, it will only ever retrieve
       the first value.

       Although it may not be immediately obvious from the code
       above, the associative array interface can be used to
       write values with duplicate keys, but it cannot be used to
       read them back from the database.

       The way to get around this problem is to use the Berkeley
       DB API method called seq.  This method allows sequential
       access to key/value pairs. See the section on THE API
       INTERFACE for details of both the seq method and the API
       in general.

       Here is the script above rewritten using the seq API
       method.

           use strict ;
           use DB_File ;

           use vars qw($filename $x %h $status $key $value) ;

           $filename = "tree" ;
           unlink $filename ;

           # Enable duplicate records
           $DB_BTREE->{'flags'} = R_DUP ;

           $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE
               or die "Cannot open $filename: $!\n";

           # Add some key/value pairs to the file
           $h{'Wall'} = 'Larry' ;
           $h{'Wall'} = 'Brick' ; # Note the duplicate key
           $h{'Wall'} = 'Brick' ; # Note the duplicate key and value
           $h{'Smith'} = 'John' ;
           $h{'mouse'} = 'mickey' ;

           # iterate through the btree using seq
           # and print each key/value pair.
           $key = $value = 0 ;
           for ($status = $x->seq($key, $value, R_FIRST) ;
                $status == 0 ;
                $status = $x->seq($key, $value, R_NEXT) )
             {  print "$key -> $value\n" }

           undef $x ;
           untie %h ;

       that prints:

           Smith   -> John
           Wall    -> Brick
           Wall    -> Brick
           Wall    -> Larry
           mouse   -> mickey

       This time we have got all the key/value pairs, including
       the multiple values associated with the key Wall.

       TThhee get_dup() Method

       DDBB__FFiillee comes with a utility method, called get_dup, to
       assist in reading duplicate values from BTREE databases.
       The method can take the following forms:

           $count = $x->get_dup($key) ;
           @list  = $x->get_dup($key) ;
           %list  = $x->get_dup($key, 1) ;

       In a scalar context the method returns the number of

       values associated with the key, $key.

       In list context, it returns all the values which match
       $key. Note that the values will be returned in an
       apparently random order.

       In list context, if the second parameter is present and
       evaluates TRUE, the method returns an associative array.
       The keys of the associative array correspond to the values
       that matched in the BTREE and the values of the array are
       a count of the number of times that particular value
       occurred in the BTREE.

       So assuming the database created above, we can use get_dup
       like this:

           my $cnt  = $x->get_dup("Wall") ;
           print "Wall occurred $cnt times\n" ;

           my %hash = $x->get_dup("Wall", 1) ;
           print "Larry is there\n" if $hash{'Larry'} ;
           print "There are $hash{'Brick'} Brick Walls\n" ;

           my @list = $x->get_dup("Wall") ;
           print "Wall =>      [@list]\n" ;

           @list = $x->get_dup("Smith") ;
           print "Smith =>     [@list]\n" ;

           @list = $x->get_dup("Dog") ;
           print "Dog =>       [@list]\n" ;

       and it will print:

           Wall occurred 3 times
           Larry is there
           There are 2 Brick Walls
           Wall =>     [Brick Brick Larry]
           Smith =>    [John]
           Dog =>      []

       MMaattcchhiinngg PPaarrttiiaall KKeeyyss

       The BTREE interface has a feature which allows partial
       keys to be matched. This functionality is only available
       when the seq method is used along with the R_CURSOR flag.

           $x->seq($key, $value, R_CURSOR) ;

       Here is the relevant quote from the dbopen man page where
       it defines the use of the R_CURSOR flag with seq:

           Note, for the DB_BTREE access method, the returned key is not
           necessarily an exact match for the specified key. The returned key
           is the smallest key greater than or equal to the specified key,
           permitting partial key matches and range searches.

       In the example script below, the match sub uses this
       feature to find and print the first matching key/value
       pair given a partial key.

           use strict ;
           use DB_File ;
           use Fcntl ;

           use vars qw($filename $x %h $st $key $value) ;

           sub match
           {
               my $key = shift ;
               my $value = 0;
               my $orig_key = $key ;
               $x->seq($key, $value, R_CURSOR) ;
               print "$orig_key\t-> $key\t-> $value\n" ;
           }

           $filename = "tree" ;
           unlink $filename ;

           $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE
               or die "Cannot open $filename: $!\n";

           # Add some key/value pairs to the file
           $h{'mouse'} = 'mickey' ;
           $h{'Wall'} = 'Larry' ;
           $h{'Walls'} = 'Brick' ;
           $h{'Smith'} = 'John' ;

           $key = $value = 0 ;
           print "IN ORDER\n" ;
           for ($st = $x->seq($key, $value, R_FIRST) ;
                $st == 0 ;
                $st = $x->seq($key, $value, R_NEXT) )

             {  print "$key -> $value\n" }

           print "\nPARTIAL MATCH\n" ;

           match "Wa" ;
           match "A" ;
           match "a" ;

           undef $x ;
           untie %h ;

       Here is the output:

           IN ORDER
           Smith -> John
           Wall  -> Larry
           Walls -> Brick
           mouse -> mickey

           PARTIAL MATCH
           Wa -> Wall  -> Larry
           A  -> Smith -> John
           a  -> mouse -> mickey

DDBB__RREECCNNOO
       DB_RECNO provides an interface to flat text files. Both
       variable and fixed length records are supported.

       In order to make RECNO more compatible with Perl the array
       offset for all RECNO arrays begins at 0 rather than 1 as
       in Berkeley DB.

       As with normal Perl arrays, a RECNO array can be accessed
       using negative indexes. The index -1 refers to the last
       element of the array, -2 the second last, and so on.
       Attempting to access an element before the start of the
       array will raise a fatal run-time error.

       TThhee ''bbvvaall'' OOppttiioonn

       The operation of the bval option warrants some discussion.
       Here is the definition of bval from the Berkeley DB 1.85
       recno manual page:

           The delimiting byte to be used to mark  the  end  of  a
           record for variable-length records, and the pad charac-
           ter for fixed-length records.  If no  value  is  speci-
           fied,  newlines  (``\n'')  are  used to mark the end of
           variable-length records and  fixed-length  records  are
           padded with spaces.

       The second sentence is wrong. In actual fact bval will
       only default to "\n" when the openinfo parameter in dbopen
       is NULL. If a non-NULL openinfo parameter is used at all,
       the value that happens to be in bval will be used. That
       means you always have to specify bval when making use of
       any of the options in the openinfo parameter. This
       documentation error will be fixed in the next release of
       Berkeley DB.

       That clarifies the situation with regards Berkeley DB
       itself. What about DDBB__FFiillee? Well, the behavior defined in
       the quote above is quite useful, so DDBB__FFiillee conforms it.

       That means that you can specify other options (e.g.
       cachesize) and still have bval default to "\n" for
       variable length records, and space for fixed length
       records.

       AA SSiimmppllee EExxaammppllee

       Here is a simple example that uses RECNO.

           use strict ;
           use DB_File ;

           my @h ;
           tie @h, "DB_File", "text", O_RDWR|O_CREAT, 0640, $DB_RECNO
               or die "Cannot open file 'text': $!\n" ;

           # Add a few key/value pairs to the file
           $h[0] = "orange" ;
           $h[1] = "blue" ;
           $h[2] = "yellow" ;

           # Check for existence of a key
           print "Element 1 Exists with value $h[1]\n" if $h[1] ;

           # use a negative index
           print "The last element is $h[-1]\n" ;
           print "The 2nd last element is $h[-2]\n" ;

           untie @h ;

       Here is the output from the script:

           Element 1 Exists with value blue
           The last element is yellow
           The 2nd last element is blue

       EExxttrraa MMeetthhooddss

       As you can see from the example above, the tied array
       interface is quite limited. To make the interface more
       useful, a number of methods are supplied with DDBB__FFiillee to
       simulate the standard array operations that are not
       currently implemented in Perl's tied array interface. All
       these methods are accessed via the object returned from
       the tie call.

       Here are the methods:

       $$XX-->>>>ppuusshh((lliisstt)) ;;
            Pushes the elements of list to the end of the array.

       $$vvaalluuee == $$XX-->>>>ppoopp ;;
            Removes and returns the last element of the array.

       $$XX-->>>>sshhiifftt
            Removes and returns the first element of the array.

       $$XX-->>>>uunnsshhiifftt((lliisstt)) ;;
            Pushes the elements of list to the start of the
            array.

       $$XX-->>>>lleennggtthh
            Returns the number of elements in the array.

       AAnnootthheerr EExxaammppllee

       Here is a more complete example that makes use of some of
       the methods described above. It also makes use of the API
       interface directly (see the section on THE API INTERFACE).

           use strict ;
           use vars qw(@h $H $file $i) ;
           use DB_File ;
           use Fcntl ;

           $file = "text" ;

           unlink $file ;

           $H = tie @h, "DB_File", $file, O_RDWR|O_CREAT, 0640, $DB_RECNO
               or die "Cannot open file $file: $!\n" ;

           # first create a text file to play with
           $h[0] = "zero" ;
           $h[1] = "one" ;
           $h[2] = "two" ;
           $h[3] = "three" ;
           $h[4] = "four" ;

           # Print the records in order.
           #
           # The length method is needed here because evaluating a tied
           # array in a scalar context does not return the number of
           # elements in the array.

           print "\nORIGINAL\n" ;
           foreach $i (0 .. $H->length - 1) {
               print "$i: $h[$i]\n" ;
           }

           # use the push & pop methods
           $a = $H->pop ;
           $H->push("last") ;
           print "\nThe last record was [$a]\n" ;

           # and the shift & unshift methods
           $a = $H->shift ;
           $H->unshift("first") ;
           print "The first record was [$a]\n" ;

           # Use the API to add a new record after record 2.
           $i = 2 ;
           $H->put($i, "Newbie", R_IAFTER) ;

           # and a new record before record 1.
           $i = 1 ;
           $H->put($i, "New One", R_IBEFORE) ;

           # delete record 3
           $H->del(3) ;

           # now print the records in reverse order
           print "\nREVERSE\n" ;
           for ($i = $H->length - 1 ; $i >= 0 ; -- $i)
             { print "$i: $h[$i]\n" }

           # same again, but use the API functions instead
           print "\nREVERSE again\n" ;
           my ($s, $k, $v)  = (0, 0, 0) ;
           for ($s = $H->seq($k, $v, R_LAST) ;
                    $s == 0 ;
                    $s = $H->seq($k, $v, R_PREV))
             { print "$k: $v\n" }

           undef $H ;
           untie @h ;

       and this is what it outputs:

           ORIGINAL
           0: zero
           1: one
           2: two
           3: three
           4: four

           The last record was [four]
           The first record was [zero]

           REVERSE
           5: last
           4: three
           3: Newbie
           2: one
           1: New One
           0: first

           REVERSE again
           5: last
           4: three
           3: Newbie
           2: one
           1: New One
           0: first

       Notes:

       1.   Rather than iterating through the array, @h like
            this:
                foreach $i (@h)

            it is necessary to use either this:
                foreach $i (0 .. $H->length - 1)

            or this:
                for ($a = $H->get($k, $v, R_FIRST) ;
                     $a == 0 ;
                     $a = $H->get($k, $v, R_NEXT) )

       2.   Notice that both times the put method was used the
            record index was specified using a variable, $i,
            rather than the literal value itself. This is because
            put will return the record number of the inserted
            line via that parameter.

TTHHEE AAPPII IINNTTEERRFFAACCEE
       As well as accessing Berkeley DB using a tied hash or
       array, it is also possible to make direct use of most of
       the API functions defined in the Berkeley DB
       documentation.

       To do this you need to store a copy of the object returned
       from the tie.
               $db = tie %hash, "DB_File", "filename" ;

       Once you have done that, you can access the Berkeley DB
       API functions as DDBB__FFiillee methods directly like this:
               $db->put($key, $value, R_NOOVERWRITE) ;

       IImmppoorrttaanntt:: If you have saved a copy of the object returned
       from tie, the underlying database file will not be closed
       until both the tied variable is untied and all copies of
       the saved object are destroyed.

           use DB_File ;
           $db = tie %hash, "DB_File", "filename"
               or die "Cannot tie filename: $!" ;
           ...
           undef $db ;
           untie %hash ;

       See the section on The untie() Gotcha for more details.

       All the functions defined in the dbopen manpage are
       available except for close() and dbopen() itself. The
       DDBB__FFiillee method interface to the supported functions have
       been implemented to mirror the way Berkeley DB works
       whenever possible. In particular note that:

       +o    The methods return a status value. All return 0 on
            success.  All return -1 to signify an error and set
            $! to the exact error code. The return code 1
            generally (but not always) means that the key
            specified did not exist in the database.

            Other return codes are defined. See below and in the
            Berkeley DB documentation for details. The Berkeley
            DB documentation should be used as the definitive
            source.

       +o    Whenever a Berkeley DB function returns data via one
            of its parameters, the equivalent DDBB__FFiillee method does
            exactly the same.

       +o    If you are careful, it is possible to mix API calls
            with the tied hash/array interface in the same piece
            of code. Although only a few of the methods used to
            implement the tied interface currently make use of
            the cursor, you should always assume that the cursor
            has been changed any time the tied hash/array
            interface is used. As an example, this code will
            probably not do what you expect:
                $X = tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE
                    or die "Cannot tie $filename: $!" ;
                # Get the first key/value pair and set  the cursor
                $X->seq($key, $value, R_FIRST) ;
                # this line will modify the cursor
                $count = scalar keys %x ;
                # Get the second key/value pair.
                # oops, it didn't, it got the last key/value pair!
                $X->seq($key, $value, R_NEXT) ;

            The code above can be rearranged to get around the
            problem, like this:
                $X = tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE
                    or die "Cannot tie $filename: $!" ;
                # this line will modify the cursor
                $count = scalar keys %x ;
                # Get the first key/value pair and set  the cursor
                $X->seq($key, $value, R_FIRST) ;
                # Get the second key/value pair.
                # worked this time.
                $X->seq($key, $value, R_NEXT) ;

       All the constants defined in the dbopen manpage for use in
       the flags parameters in the methods defined below are also
       available. Refer to the Berkeley DB documentation for the
       precise meaning of the flags values.

       Below is a list of the methods available.

       $$ssttaattuuss == $$XX-->>>>ggeett(($$kkeeyy,, $$vvaalluuee [[,, $$ffllaaggss]])) ;;
            Given a key ($key) this method reads the value
            associated with it from the database. The value read
            from the database is returned in the $value
            parameter.

            If the key does not exist the method returns 1.

            No flags are currently defined for this method.

       $$ssttaattuuss == $$XX-->>>>ppuutt(($$kkeeyy,, $$vvaalluuee [[,, $$ffllaaggss]])) ;;
            Stores the key/value pair in the database.

            If you use either the R_IAFTER or R_IBEFORE flags,
            the $key parameter will have the record number of the
            inserted key/value pair set.

            Valid flags are R_CURSOR, R_IAFTER, R_IBEFORE,
            R_NOOVERWRITE and R_SETCURSOR.

       $$ssttaattuuss == $$XX-->>>>ddeell(($$kkeeyy [[,, $$ffllaaggss]])) ;;
            Removes all key/value pairs with key $key from the
            database.

            A return code of 1 means that the requested key was
            not in the database.

            R_CURSOR is the only valid flag at present.

       $$ssttaattuuss == $$XX-->>>>ffdd ;;
            Returns the file descriptor for the underlying
            database.

            See the section on Locking Databases for an example
            of how to make use of the fd method to lock your
            database.

       $$ssttaattuuss == $$XX-->>>>sseeqq(($$kkeeyy,, $$vvaalluuee,, $$ffllaaggss)) ;;
            This interface allows sequential retrieval from the
            database. See the dbopen manpage for full details.

            Both the $key and $value parameters will be set to
            the key/value pair read from the database.

            The flags parameter is mandatory. The valid flag
            values are R_CURSOR, R_FIRST, R_LAST, R_NEXT and
            R_PREV.

       $$ssttaattuuss == $$XX-->>>>ssyynncc(([[$$ffllaaggss]])) ;;
            Flushes any cached buffers to disk.

            R_RECNOSYNC is the only valid flag at present.

HHIINNTTSS AANNDD TTIIPPSS
       LLoocckkiinngg DDaattaabbaasseess

       Concurrent access of a read-write database by several
       parties requires them all to use some kind of locking.
       Here's an example of Tom's that uses the fd method to get
       the file descriptor, and then a careful open() to give
       something Perl will flock() for you.  Run this repeatedly
       in the background to watch the locks granted in proper
       order.

           use DB_File;

           use strict;

           sub LOCK_SH { 1 }
           sub LOCK_EX { 2 }
           sub LOCK_NB { 4 }
           sub LOCK_UN { 8 }

           my($oldval, $fd, $db, %db, $value, $key);

           $key = shift || 'default';
           $value = shift || 'magic';

           $value .= " $$";

           $db = tie(%db, 'DB_File', '/tmp/foo.db', O_CREAT|O_RDWR, 0644)
                   || die "dbcreat /tmp/foo.db $!";
           $fd = $db->fd;
           print "$$: db fd is $fd\n";
           open(DB_FH, "+<&=$fd") || die "dup $!";

           unless (flock (DB_FH, LOCK_SH | LOCK_NB)) {
               print "$$: CONTENTION; can't read during write update!
                           Waiting for read lock ($!) ....";
               unless (flock (DB_FH, LOCK_SH)) { die "flock: $!" }
           }
           print "$$: Read lock granted\n";

           $oldval = $db{$key};
           print "$$: Old value was $oldval\n";
           flock(DB_FH, LOCK_UN);

           unless (flock (DB_FH, LOCK_EX | LOCK_NB)) {
               print "$$: CONTENTION; must have exclusive lock!
                           Waiting for write lock ($!) ....";
               unless (flock (DB_FH, LOCK_EX)) { die "flock: $!" }
           }

           print "$$: Write lock granted\n";
           $db{$key} = $value;
           $db->sync;  # to flush
           sleep 10;

           flock(DB_FH, LOCK_UN);
           undef $db;
           untie %db;
           close(DB_FH);
           print "$$: Updated db to $key=$value\n";

       SShhaarriinngg DDaattaabbaasseess WWiitthh CC AApppplliiccaattiioonnss

       There is no technical reason why a Berkeley DB database
       cannot be shared by both a Perl and a C application.

       The vast majority of problems that are reported in this
       area boil down to the fact that C strings are NULL
       terminated, whilst Perl strings are not.

       Here is a real example. Netscape 2.0 keeps a record of the
       locations you visit along with the time you last visited
       them in a DB_HASH database.  This is usually stored in the
       file ~/.netscape/history.db. The key field in the database
       is the location string and the value field is the time the
       location was last visited stored as a 4 byte binary value.

       If you haven't already guessed, the location string is
       stored with a terminating NULL. This means you need to be
       careful when accessing the database.

       Here is a snippet of code that is loosely based on Tom
       Christiansen's ggh script (available from your nearest
       CPAN archive in authors/id/TOMC/scripts/nshist.gz).

           use strict ;
           use DB_File ;
           use Fcntl ;

           use vars qw( $dotdir $HISTORY %hist_db $href $binary_time $date ) ;
           $dotdir = $ENV{HOME} || $ENV{LOGNAME};

           $HISTORY = "$dotdir/.netscape/history.db";

           tie %hist_db, 'DB_File', $HISTORY
               or die "Cannot open $HISTORY: $!\n" ;;

           # Dump the complete database
           while ( ($href, $binary_time) = each %hist_db ) {
               # remove the terminating NULL
               $href =~ s/\x00$// ;
               # convert the binary time into a user friendly string
               $date = localtime unpack("V", $binary_time);
               print "$date $href\n" ;
           }

           # check for the existence of a specific key
           # remember to add the NULL
           if ( $binary_time = $hist_db{"http://mox.perl.com/\x00"} ) {
               $date = localtime unpack("V", $binary_time) ;
               print "Last visited mox.perl.com on $date\n" ;
           }
           else {
               print "Never visited mox.perl.com\n"
           }

           untie %hist_db ;

       TThhee untie() Gotcha

       If you make use of the Berkeley DB API, it is very
       strongly recommended that you read the section on The
       untie Gotcha in the perltie manpage.

       Even if you don't currently make use of the API interface,
       it is still worth reading it.

       Here is an example which illustrates the problem from a
       DDBB__FFiillee perspective:

           use DB_File ;
           use Fcntl ;

           my %x ;
           my $X ;

           $X = tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_TRUNC
               or die "Cannot tie first time: $!" ;

           $x{123} = 456 ;

           untie %x ;

           tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_CREAT
               or die "Cannot tie second time: $!" ;

           untie %x ;

       When run, the script will produce this error message:

           Cannot tie second time: Invalid argument at bad.file line 14.

       Although the error message above refers to the second
       tie() statement in the script, the source of the problem
       is really with the untie() statement that precedes it.

       Having read the perltie manpage you will probably have
       already guessed that the error is caused by the extra copy
       of the tied object stored in $X.  If you haven't, then the
       problem boils down to the fact that the DDBB__FFiillee
       destructor, DESTROY, will not be called until all
       references to the tied object are destroyed. Both the tied
       variable, %x, and $X above hold a reference to the object.
       The call to untie() will destroy the first, but $X still
       holds a valid reference, so the destructor will not get
       called and the database file tst.fil will remain open. The
       fact that Berkeley DB then reports the attempt to open a
       database that is alreday open via the catch-all "Invalid
       argument" doesn't help.

       If you run the script with the -w flag the error message
       becomes:

           untie attempted while 1 inner references still exist at bad.file line 12.
           Cannot tie second time: Invalid argument at bad.file line 14.

       which pinpoints the real problem. Finally the script can
       now be modified to fix the original problem by destroying
       the API object before the untie:

           ...
           $x{123} = 456 ;

           undef $X ;
           untie %x ;

           $X = tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_CREAT
           ...

CCOOMMMMOONN QQUUEESSTTIIOONNSS
       WWhhyy iiss tthheerree PPeerrll ssoouurrccee iinn mmyy ddaattaabbaassee??

       If you look at the contents of a database file created by
       DB_File, there can sometimes be part of a Perl script
       included in it.

       This happens because Berkeley DB uses dynamic memory to
       allocate buffers which will subsequently be written to the
       database file. Being dynamic, the memory could have been
       used for anything before DB malloced it. As Berkeley DB
       doesn't clear the memory once it has been allocated, the
       unused portions will contain random junk. In the case
       where a Perl script gets written to the database, the
       random junk will correspond to an area of dynamic memory
       that happened to be used during the compilation of the
       script.

       Unless you don't like the possibility of there being part
       of your Perl scripts embedded in a database file, this is
       nothing to worry about.

       HHooww ddoo II ssttoorree ccoommpplleexx ddaattaa ssttrruuccttuurreess wwiitthh DDBB__FFiillee??

       Although DDBB__FFiillee cannot do this directly, there is a
       module which can layer transparently over DDBB__FFiillee to
       accomplish this feat.

       Check out the MLDBM module, available on CPAN in the
       directory modules/by-module/MLDBM.

       WWhhaatt ddooeess """"IInnvvaalliidd AArrgguummeenntt"""" mmeeaann??

       You will get this error message when one of the parameters
       in the tie call is wrong. Unfortunately there are quite a
       few parameters to get wrong, so it can be difficult to
       figure out which one it is.

       Here are a couple of possibilities:

       1.   Attempting to reopen a database without closing it.

       2.   Using the O_WRONLY flag.

       WWhhaatt ddooeess """"BBaarreewwoorrdd ''DDBB__FFiillee'' nnoott aalllloowweedd"""" mmeeaann??

       You will encounter this particular error message when you
       have the strict 'subs' pragma (or the full strict pragma)
       in your script.  Consider this script:

           use strict ;
           use DB_File ;
           use vars qw(%x) ;
           tie %x, DB_File, "filename" ;

       Running it produces the error in question:

           Bareword "DB_File" not allowed while "strict subs" in use

       To get around the error, place the word DB_File in either
       single or double quotes, like this:

           tie %x, "DB_File", "filename" ;

       Although it might seem like a real pain, it is really
       worth the effort of having a use strict in all your
       scripts.

HHIISSTTOORRYY
       0.1  First Release.

       0.2  When DDBB__FFiillee is opening a database file it no longer
            terminates the process if dbopen returned an error.
            This allows file protection errors to be caught at
            run time. Thanks to Judith Grass
            lt;grass@cybercash.com for spotting the bug.

       0.3  Added prototype support for multiple btree compare
            callbacks.

       1.0  DDBB__FFiillee has been in use for over a year. To reflect
            that, the version number has been incremented to 1.0.

            Added complete support for multiple concurrent
            callbacks.

            Using the push method on an empty list didn't work
            properly. This has been fixed.

       1.01 Fixed a core dump problem with SunOS.

            The return value from TIEHASH wasn't set to NULL when
            dbopen returned an error.

       1.02 Merged OS/2 specific code into DB_File.xs

            Removed some redundant code in DB_File.xs.

            Documentation update.

            Allow negative subscripts with RECNO interface.

            Changed the default flags from O_RDWR to
            O_CREAT|O_RDWR.

            The example code which showed how to lock a database
            needed a call to sync added. Without it the resultant
            database file was empty.

            Added get_dup method.

       1.03 Documentation update.

            DDBB__FFiillee now imports the constants (O_RDWR, O_CREAT
            etc.) from Fcntl automatically.

            The standard hash function exists is now supported.

            Modified the behavior of get_dup. When it returns an
            associative array, the value is the count of the
            number of matching BTREE values.

       1.04 Minor documentation changes.

            Fixed a bug in hash_cb. Patches supplied by Dave
            Hammen, lt;hammen@gothamcity.jsc.nasa.gov.

            Fixed a bug with the constructors for
            DB_File::HASHINFO, DB_File::BTREEINFO and
            DB_File::RECNOINFO. Also tidied up the constructors
            to make them -w clean.

            Reworked part of the test harness to be more locale
            friendly.

       1.05 Made all scripts in the documentation strict and -w
            clean.

            Added logic to DB_File.xs to allow the module to be
            built after Perl is installed.

       1.06 Minor namespace cleanup: Localized PrintBtree.

       1.07 Fixed bug with RECNO, where bval wasn't defaulting to
            "\n".

       1.08 Documented operation of bval.

       1.09 Minor bug fix in DB_File::HASHINFO,
            DB_File::RECNOINFO and DB_File::BTREEINFO.

            Changed default mode to 0666.

       1.10 Fixed fd method so that it still returns -1 for in-
            memory files when db 1.86 is used.

       1.11 Documented the untie gotcha.

       1.12 Documented the incompatibility with version 2 of
            Berkeley DB.

       1.13 Minor changes to DB_FIle.xs and DB_File.pm

       1.14 Made it illegal to tie an associative array to a
            RECNO database and an ordinary array to a HASH or
            BTREE database.

       1.15 Patch from Gisle Aas lt;gisle@aas.no to suppress "use
            of undefined value" warning with db_get and db_seq.

            Patch from Gisle Aas lt;gisle@aas.no to make DB_File
            export only the O_* constants from Fcntl.

            Removed the DESTROY method from the DB_File::HASHINFO
            module.

            Previously DB_File hard-wired the class name of any
            object that it created to "DB_File". This makes sub-
            classing difficult. Now DB_File creats objects in the
            namespace of the package it has been inherited into.

BBUUGGSS
       Some older versions of Berkeley DB had problems with fixed
       length records using the RECNO file format. The newest
       version at the time of writing was 1.85 - this seems to
       have fixed the problems with RECNO.

       I am sure there are bugs in the code. If you do find any,
       or can suggest any enhancements, I would welcome your
       comments.

AAVVAAIILLAABBIILLIITTYY
       DDBB__FFiillee comes with the standard Perl source distribution.
       Look in the directory ext/DB_File.

       This version of DDBB__FFiillee will only work with version 1.x of
       Berkeley DB. It is not yet compatible with version 2.

       Version 1 of Berkeley DB is available at your nearest CPAN
       archive (see the section on CPAN in the perlmod manpage
       for a list) in src/misc/db.1.85.tar.gz, or via the host
       ftp.cs.berkeley.edu in /ucb/4bsd/db.tar.gz.
       Alternatively, check out the Berkeley DB home page at
       http://www.bostic.com/db. It is not under the GPL.

       If you are running IRIX, then get Berkeley DB from
       http://reality.sgi.com/ariel. It has the patches necessary
       to compile properly on IRIX 5.3.

       As of January 1997, version 1.86 of Berkeley DB is
       available from the Berkeley DB home page. Although this
       release does fix a number of bugs that were present in
       1.85 you should be aware of the following information
       (taken from the Berkeley DB home page) before you consider
       using it:

           DB version 1.86 includes a new implementation of the hash access
           method that fixes a variety of hashing problems found in DB version
           1.85. We are making it available as an interim solution until DB
           2.0 is available.

           PLEASE NOTE: the underlying file format for the hash access method
           changed between version 1.85 and version 1.86, so you will have to
           dump and reload all of your databases to convert from version 1.85
           to version 1.86. If you do not absolutely require the fixes from
           version 1.86, we strongly urge you to wait until DB 2.0 is released
           before upgrading from 1.85.

SSEEEE AALLSSOO
       the perl(1) manpage, the dbopen(3) manpage, the hash(3)
       manpage, the recno(3) manpage, the btree(3) manpage

AAUUTTHHOORR
       The DB_File interface was written by Paul Marquess
       lt;pmarquess@bfsec.bt.co.uk.  Questions about the DB system
       itself may be addressed to <db@sleepycat.com<gt>.


dbz Home Page Subroutines Index DefaultColormap