X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=ext%2FDB_File%2FDB_File.pm;h=b00b5008841c645b4aa0ef5d42ec2921796ed68e;hb=07200f1b93ada43b41fbed10c30b4e657f5b0c60;hp=fcc84c3c69e0269c185c12351613a88c89790150;hpb=610ab055100fa571cc7f544c38118f901cbd0eaf;p=p5sagit%2Fp5-mst-13.2.git diff --git a/ext/DB_File/DB_File.pm b/ext/DB_File/DB_File.pm index fcc84c3..b00b500 100644 --- a/ext/DB_File/DB_File.pm +++ b/ext/DB_File/DB_File.pm @@ -1,13 +1,19 @@ # DB_File.pm -- Perl 5 interface to Berkeley DB # -# written by Paul Marquess (pmarquess@bfsec.bt.co.uk) -# last modified 10th Nov 1996 -# version 1.05 +# written by Paul Marquess (Paul.Marquess@btinternet.com) +# last modified 23rd Nov 2001 +# version 1.800 +# +# Copyright (c) 1995-2001 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. + package DB_File::HASHINFO ; -require 5.003 ; +require 5.00404; +use warnings; use strict; use Carp; require Tie::Hash; @@ -26,13 +32,11 @@ sub TIEHASH { my $pkg = shift ; - bless { 'bsize' => 0, - 'ffactor' => 0, - 'nelem' => 0, - 'cachesize' => 0, - 'hash' => undef, - 'lorder' => 0, - }, $pkg ; + bless { VALID => { map {$_, 1} + qw( bsize ffactor nelem cachesize hash lorder) + }, + GOT => {} + }, $pkg ; } @@ -41,7 +45,7 @@ sub FETCH my $self = shift ; my $key = shift ; - return $self->{$key} if exists $self->{$key} ; + return $self->{GOT}{$key} if exists $self->{VALID}{$key} ; my $pkg = ref $self ; croak "${pkg}::FETCH - Unknown element '$key'" ; @@ -54,9 +58,9 @@ sub STORE my $key = shift ; my $value = shift ; - if ( exists $self->{$key} ) + if ( exists $self->{VALID}{$key} ) { - $self->{$key} = $value ; + $self->{GOT}{$key} = $value ; return ; } @@ -69,9 +73,9 @@ sub DELETE my $self = shift ; my $key = shift ; - if ( exists $self->{$key} ) + if ( exists $self->{VALID}{$key} ) { - delete $self->{$key} ; + delete $self->{GOT}{$key} ; return ; } @@ -84,24 +88,24 @@ sub EXISTS my $self = shift ; my $key = shift ; - exists $self->{$key} ; + exists $self->{VALID}{$key} ; } sub NotHere { - my $pkg = shift ; + my $self = shift ; my $method = shift ; - croak "${pkg} does not define the method ${method}" ; + croak ref($self) . " does not define the method ${method}" ; } -sub DESTROY { undef %{$_[0]} } -sub FIRSTKEY { my $self = shift ; $self->NotHere(ref $self, "FIRSTKEY") } -sub NEXTKEY { my $self = shift ; $self->NotHere(ref $self, "NEXTKEY") } -sub CLEAR { my $self = shift ; $self->NotHere(ref $self, "CLEAR") } +sub FIRSTKEY { my $self = shift ; $self->NotHere("FIRSTKEY") } +sub NEXTKEY { my $self = shift ; $self->NotHere("NEXTKEY") } +sub CLEAR { my $self = shift ; $self->NotHere("CLEAR") } package DB_File::RECNOINFO ; +use warnings; use strict ; @DB_File::RECNOINFO::ISA = qw(DB_File::HASHINFO) ; @@ -110,18 +114,16 @@ sub TIEHASH { my $pkg = shift ; - bless { 'bval' => 0, - 'cachesize' => 0, - 'psize' => 0, - 'flags' => 0, - 'lorder' => 0, - 'reclen' => 0, - 'bfname' => "", - }, $pkg ; + bless { VALID => { map {$_, 1} + qw( bval cachesize psize flags lorder reclen bfname ) + }, + GOT => {}, + }, $pkg ; } package DB_File::BTREEINFO ; +use warnings; use strict ; @DB_File::BTREEINFO::ISA = qw(DB_File::HASHINFO) ; @@ -130,26 +132,25 @@ sub TIEHASH { my $pkg = shift ; - bless { 'flags' => 0, - 'cachesize' => 0, - 'maxkeypage' => 0, - 'minkeypage' => 0, - 'psize' => 0, - 'compare' => undef, - 'prefix' => undef, - 'lorder' => 0, - }, $pkg ; + bless { VALID => { map {$_, 1} + qw( flags cachesize maxkeypage minkeypage psize + compare prefix lorder ) + }, + GOT => {}, + }, $pkg ; } package DB_File ; +use warnings; use strict; -use vars qw($VERSION @ISA @EXPORT $AUTOLOAD $DB_BTREE $DB_HASH $DB_RECNO) ; +our ($VERSION, @ISA, @EXPORT, $AUTOLOAD, $DB_BTREE, $DB_HASH, $DB_RECNO); +our ($db_version, $use_XSLoader); use Carp; -$VERSION = "1.05" ; +$VERSION = "1.800" ; #typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE; $DB_BTREE = new DB_File::BTREEINFO ; @@ -159,8 +160,18 @@ $DB_RECNO = new DB_File::RECNOINFO ; require Tie::Hash; require Exporter; use AutoLoader; -require DynaLoader; -@ISA = qw(Tie::Hash Exporter DynaLoader); +BEGIN { + $use_XSLoader = 1 ; + { local $SIG{__DIE__} ; eval { require XSLoader } ; } + + if ($@) { + $use_XSLoader = 0 ; + require DynaLoader; + @ISA = qw(DynaLoader); + } +} + +push @ISA, qw(Tie::Hash Exporter); @EXPORT = qw( $DB_BTREE $DB_HASH $DB_RECNO @@ -198,51 +209,292 @@ require DynaLoader; sub AUTOLOAD { my($constname); ($constname = $AUTOLOAD) =~ s/.*:://; - my $val = constant($constname, @_ ? $_[0] : 0); - if ($! != 0) { - if ($! =~ /Invalid/) { - $AutoLoader::AUTOLOAD = $AUTOLOAD; - goto &AutoLoader::AUTOLOAD; - } - else { - my($pack,$file,$line) = caller; - croak "Your vendor has not defined DB macro $constname, used at $file line $line. -"; - } + my ($error, $val) = constant($constname); + Carp::croak $error if $error; + no strict 'refs'; + *{$AUTOLOAD} = sub { $val }; + goto &{$AUTOLOAD}; +} + + +eval { + # Make all Fcntl O_XXX constants available for importing + require Fcntl; + my @O = grep /^O_/, @Fcntl::EXPORT; + Fcntl->import(@O); # first we import what we want to export + push(@EXPORT, @O); +}; + +if ($use_XSLoader) + { XSLoader::load("DB_File", $VERSION)} +else + { bootstrap DB_File $VERSION } + +# Preloaded methods go here. Autoload methods go after __END__, and are +# processed by the autosplit program. + +sub tie_hash_or_array +{ + my (@arg) = @_ ; + my $tieHASH = ( (caller(1))[3] =~ /TIEHASH/ ) ; + + $arg[4] = tied %{ $arg[4] } + if @arg >= 5 && ref $arg[4] && $arg[4] =~ /=HASH/ && tied %{ $arg[4] } ; + + # make recno in Berkeley DB version 2 work like recno in version 1. + if ($db_version > 1 and defined $arg[4] and $arg[4] =~ /RECNO/ and + $arg[1] and ! -e $arg[1]) { + open(FH, ">$arg[1]") or return undef ; + close FH ; + chmod $arg[3] ? $arg[3] : 0666 , $arg[1] ; } - eval "sub $AUTOLOAD { $val }"; - goto &$AUTOLOAD; + + DoTie_($tieHASH, @arg) ; +} + +sub TIEHASH +{ + tie_hash_or_array(@_) ; } +sub TIEARRAY +{ + tie_hash_or_array(@_) ; +} -# import borrowed from IO::File -# exports Fcntl constants if available. -sub import { - my $pkg = shift; - my $callpkg = caller; - Exporter::export $pkg, $callpkg; - eval { - require Fcntl; - Exporter::export 'Fcntl', $callpkg; - }; +sub CLEAR +{ + my $self = shift; + my $key = 0 ; + my $value = "" ; + my $status = $self->seq($key, $value, R_FIRST()); + my @keys; + + while ($status == 0) { + push @keys, $key; + $status = $self->seq($key, $value, R_NEXT()); + } + foreach $key (reverse @keys) { + my $s = $self->del($key); + } } -bootstrap DB_File $VERSION; +sub EXTEND { } -# Preloaded methods go here. Autoload methods go after __END__, and are -# processed by the autosplit program. +sub STORESIZE +{ + my $self = shift; + my $length = shift ; + my $current_length = $self->length() ; + + if ($length < $current_length) { + my $key ; + for ($key = $current_length - 1 ; $key >= $length ; -- $key) + { $self->del($key) } + } + elsif ($length > $current_length) { + $self->put($length-1, "") ; + } +} + -sub TIEHASH +sub SPLICE { - my (@arg) = @_ ; + my $self = shift; + my $offset = shift; + if (not defined $offset) { + carp 'Use of uninitialized value in splice'; + $offset = 0; + } - $arg[4] = tied %{ $arg[4] } - if @arg >= 5 && ref $arg[4] && $arg[4] =~ /=HASH/ && tied %{ $arg[4] } ; + my $length = @_ ? shift : 0; + # Carping about definedness comes _after_ the OFFSET sanity check. + # This is so we get the same error messages as Perl's splice(). + # + + my @list = @_; + + my $size = $self->FETCHSIZE(); + + # 'If OFFSET is negative then it start that far from the end of + # the array.' + # + if ($offset < 0) { + my $new_offset = $size + $offset; + if ($new_offset < 0) { + die "Modification of non-creatable array value attempted, " + . "subscript $offset"; + } + $offset = $new_offset; + } + + if ($offset > $size) { + $offset = $size; + } + + if (not defined $length) { + carp 'Use of uninitialized value in splice'; + $length = 0; + } + + # 'If LENGTH is omitted, removes everything from OFFSET onward.' + if (not defined $length) { + $length = $size - $offset; + } + + # 'If LENGTH is negative, leave that many elements off the end of + # the array.' + # + if ($length < 0) { + $length = $size - $offset + $length; + + if ($length < 0) { + # The user must have specified a length bigger than the + # length of the array passed in. But perl's splice() + # doesn't catch this, it just behaves as for length=0. + # + $length = 0; + } + } + + if ($length > $size - $offset) { + $length = $size - $offset; + } + + # $num_elems holds the current number of elements in the database. + my $num_elems = $size; + + # 'Removes the elements designated by OFFSET and LENGTH from an + # array,'... + # + my @removed = (); + foreach (0 .. $length - 1) { + my $old; + my $status = $self->get($offset, $old); + if ($status != 0) { + my $msg = "error from Berkeley DB on get($offset, \$old)"; + if ($status == 1) { + $msg .= ' (no such element?)'; + } + else { + $msg .= ": error status $status"; + if (defined $! and $! ne '') { + $msg .= ", message $!"; + } + } + die $msg; + } + push @removed, $old; + + $status = $self->del($offset); + if ($status != 0) { + my $msg = "error from Berkeley DB on del($offset)"; + if ($status == 1) { + $msg .= ' (no such element?)'; + } + else { + $msg .= ": error status $status"; + if (defined $! and $! ne '') { + $msg .= ", message $!"; + } + } + die $msg; + } + + -- $num_elems; + } + + # ...'and replaces them with the elements of LIST, if any.' + my $pos = $offset; + while (defined (my $elem = shift @list)) { + my $old_pos = $pos; + my $status; + if ($pos >= $num_elems) { + $status = $self->put($pos, $elem); + } + else { + $status = $self->put($pos, $elem, $self->R_IBEFORE); + } + + if ($status != 0) { + my $msg = "error from Berkeley DB on put($pos, $elem, ...)"; + if ($status == 1) { + $msg .= ' (no such element?)'; + } + else { + $msg .= ", error status $status"; + if (defined $! and $! ne '') { + $msg .= ", message $!"; + } + } + die $msg; + } + + die "pos unexpectedly changed from $old_pos to $pos with R_IBEFORE" + if $old_pos != $pos; + + ++ $pos; + ++ $num_elems; + } - DoTie_(@arg) ; + if (wantarray) { + # 'In list context, returns the elements removed from the + # array.' + # + return @removed; + } + elsif (defined wantarray and not wantarray) { + # 'In scalar context, returns the last element removed, or + # undef if no elements are removed.' + # + if (@removed) { + my $last = pop @removed; + return "$last"; + } + else { + return undef; + } + } + elsif (not defined wantarray) { + # Void context + } + else { die } } +sub ::DB_File::splice { &SPLICE } + +sub find_dup +{ + croak "Usage: \$db->find_dup(key,value)\n" + unless @_ == 3 ; + + my $db = shift ; + my ($origkey, $value_wanted) = @_ ; + my ($key, $value) = ($origkey, 0); + my ($status) = 0 ; + + for ($status = $db->seq($key, $value, R_CURSOR() ) ; + $status == 0 ; + $status = $db->seq($key, $value, R_NEXT() ) ) { + + return 0 if $key eq $origkey and $value eq $value_wanted ; + } + + return $status ; +} + +sub del_dup +{ + croak "Usage: \$db->del_dup(key,value)\n" + unless @_ == 3 ; + + my $db = shift ; + my ($key, $value) = @_ ; + my ($status) = $db->find_dup($key, $value) ; + return $status if $status != 0 ; -*TIEARRAY = \&TIEHASH ; + $status = $db->del($key, R_CURSOR() ) ; + return $status ; +} sub get_dup { @@ -285,16 +537,14 @@ sub get_dup 1; __END__ -=cut - =head1 NAME -DB_File - Perl5 access to Berkeley DB +DB_File - Perl5 access to Berkeley DB version 1.x =head1 SYNOPSIS - use DB_File ; - + 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 ; @@ -310,6 +560,8 @@ DB_File - Perl5 access to Berkeley DB $count = $X->get_dup($key) ; @list = $X->get_dup($key) ; %list = $X->get_dup($key, 1) ; + $status = $X->find_dup($key, $value) ; + $status = $X->del_dup($key, $value) ; # RECNO only $a = $X->length; @@ -317,6 +569,13 @@ DB_File - Perl5 access to Berkeley DB $X->push(list); $a = $X->shift; $X->unshift(list); + @r = $X->splice(offset, length, elements); + + # DBM Filters + $old_filter = $db->filter_store_key ( sub { ... } ) ; + $old_filter = $db->filter_store_value( sub { ... } ) ; + $old_filter = $db->filter_fetch_key ( sub { ... } ) ; + $old_filter = $db->filter_fetch_value( sub { ... } ) ; untie %hash ; untie @array ; @@ -324,10 +583,11 @@ DB_File - Perl5 access to Berkeley DB =head1 DESCRIPTION B 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. +facilities provided by Berkeley DB version 1.x (if you have a newer +version of DB, see L). +It is assumed that you have a copy of the Berkeley DB manual pages at +hand when reading this documentation. The interface defined here +mirrors the Berkeley DB interface closely. Berkeley DB is a C library which provides a consistent interface to a number of database formats. B provides an interface to all @@ -368,7 +628,30 @@ number. =back -=head2 How does DB_File interface to Berkeley DB? +=head2 Using DB_File with Berkeley DB version 2 or greater + +Although B is intended to be used with Berkeley DB version 1, +it can also be used with version 2, 3 or 4. In this case the interface is +limited to the functionality provided by Berkeley DB 1.x. Anywhere the +version 2 or greater interface differs, B arranges for it to work +like version 1. This feature allows B scripts that were built +with version 1 to be migrated to version 2 or greater without any changes. + +If you want to make use of the new features available in Berkeley DB +2.x or greater, use the Perl module B instead. + +B The database file format has changed multiple times in Berkeley +DB version 2, 3 and 4. If you cannot recreate your databases, you +must dump any existing databases with either the C or the +C utility that comes with Berkeley DB. +Once you have rebuilt DB_File to use Berkeley DB version 2 or greater, +your databases can be recreated using C. Refer to the Berkeley DB +documentation for further details. + +Please read L<"COPYRIGHT"> before using version 2.x or greater of Berkeley +DB with DB_File. + +=head2 Interface to Berkeley DB B allows access to Berkeley DB files using the tie() mechanism in Perl 5 (for full details, see L). This facility @@ -462,7 +745,7 @@ values when you only want to change one. Here is an example: $a->{'cachesize'} = 12345 ; tie %y, 'DB_File', "filename", $flags, 0777, $a ; -A few of the values need extra discussion here. When used, the C +A few of the options need extra discussion here. When used, the C equivalent of the keys C, C and C store pointers to C functions. In B these keys are used to store references to Perl subs. Below are templates for each of the subs: @@ -497,6 +780,9 @@ to Perl subs. Below are templates for each of the subs: See L for an example of using the C template. +If you are using the DB_RECNO interface and you intend making use of +C, you should check out L. + =head2 Default Parameters It is possible to omit some or all of the final 4 parameters in the @@ -507,7 +793,7 @@ common file format used, the call: is equivalent to: - tie %A, "DB_File", "filename", O_CREAT|O_RDWR, 0640, $DB_HASH ; + 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: @@ -516,7 +802,7 @@ call: is equivalent to: - tie %A, "DB_File", undef, O_CREAT|O_RDWR, 0640, $DB_HASH ; + tie %A, "DB_File", undef, O_CREAT|O_RDWR, 0666, $DB_HASH ; See L for a discussion on the use of C in place of a filename. @@ -533,17 +819,19 @@ The DB_HASH file format is probably the most commonly used of the three file formats that B supports. It is also very straightforward to use. -=head2 A Simple Example. +=head2 A Simple Example 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 warnings ; use strict ; use DB_File ; - use vars qw( %h $k $v ) ; + our (%h, $k, $v) ; - tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0640, $DB_HASH + unlink "fruit" ; + tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0666, $DB_HASH or die "Cannot open file 'fruit': $!\n"; # Add a few key/value pairs to the file @@ -567,7 +855,7 @@ contents of the database. here is the output: Banana Exists - + orange -> orange tomato -> red banana -> yellow @@ -588,6 +876,7 @@ 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 warnings ; use strict ; use DB_File ; @@ -602,7 +891,8 @@ insensitive compare function will be used. # 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 + unlink "tree" ; + tie %h, "DB_File", "tree", O_RDWR|O_CREAT, 0666, $DB_BTREE or die "Cannot open file 'tree': $!\n" ; # Add a key/value pair to the file @@ -643,9 +933,38 @@ 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. +=item 3 + +Duplicate keys are entirely defined by the comparison function. +In the case-insensitive example above, the keys: 'KEY' and 'key' +would be considered duplicates, and assigning to the second one +would overwrite the first. If duplicates are allowed for (with the +R_DUPS flag discussed below), only a single copy of duplicate keys +is stored in the database --- so (again with example above) assigning +three values to the keys: 'KEY', 'Key', and 'key' would leave just +the first key: 'KEY' in the database with three values. For some +situations this results in information loss, so care should be taken +to provide fully qualified comparison functions when necessary. +For example, the above comparison routine could be modified to +additionally compare case-sensitively if two keys are equal in the +case insensitive comparison: + + sub compare { + my($key1, $key2) = @_; + lc $key1 cmp lc $key2 || + $key1 cmp $key2; + } + +And now you will only have duplicates when the keys themselves +are truly the same. (note: in versions of the db library prior to +about November 1996, such duplicate keys were retained so it was +possible to recover the original keys in sets of keys that +compared as equal). + + =back -=head2 Handling duplicate keys +=head2 Handling Duplicate Keys The BTREE file type optionally allows a single key to be associated with an arbitrary number of values. This option is enabled by setting @@ -655,20 +974,21 @@ 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 warnings ; use strict ; use DB_File ; - use vars qw($filename %h ) ; + our ($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 + + tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $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 @@ -678,7 +998,7 @@ code: # iterate through the associative array # and print each key/value pair. - foreach (keys %h) + foreach (sort keys %h) { print "$_ -> $h{$_}\n" } untie %h ; @@ -709,27 +1029,28 @@ and the API in general. Here is the script above rewritten using the C API method. + use warnings ; use strict ; use DB_File ; - - use vars qw($filename $x %h $status $key $value) ; + + our ($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 + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $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 ; @@ -737,7 +1058,7 @@ Here is the script above rewritten using the C API method. $status == 0 ; $status = $x->seq($key, $value, R_NEXT) ) { print "$key -> $value\n" } - + undef $x ; untie %h ; @@ -752,9 +1073,12 @@ that prints: This time we have got all the key/value pairs, including the multiple values associated with the key C. -=head2 The get_dup method. +To make life easier when dealing with duplicate keys, B comes with +a few utility methods. + +=head2 The get_dup() Method -B comes with a utility method, called C, to assist in +The C method assists in reading duplicate values from BTREE databases. The method can take the following forms: @@ -768,15 +1092,29 @@ with the key, C<$key>. In list context, it returns all the values which match C<$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 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. +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 C like this: + use warnings ; + use strict ; + use DB_File ; + + our ($filename, $x, %h) ; + + $filename = "tree" ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE + or die "Cannot open $filename: $!\n"; + my $cnt = $x->get_dup("Wall") ; print "Wall occurred $cnt times\n" ; @@ -784,12 +1122,12 @@ this: print "Larry is there\n" if $hash{'Larry'} ; print "There are $hash{'Brick'} Brick Walls\n" ; - my @list = $x->get_dup("Wall") ; + my @list = sort $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" ; @@ -803,6 +1141,81 @@ and it will print: Smith => [John] Dog => [] +=head2 The find_dup() Method + + $status = $X->find_dup($key, $value) ; + +This method checks for the existence of a specific key/value pair. If the +pair exists, the cursor is left pointing to the pair and the method +returns 0. Otherwise the method returns a non-zero value. + +Assuming the database from the previous example: + + use warnings ; + use strict ; + use DB_File ; + + our ($filename, $x, %h, $found) ; + + $filename = "tree" ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ; + print "Larry Wall is $found there\n" ; + + $found = ( $x->find_dup("Wall", "Harry") == 0 ? "" : "not") ; + print "Harry Wall is $found there\n" ; + + undef $x ; + untie %h ; + +prints this + + Larry Wall is there + Harry Wall is not there + + +=head2 The del_dup() Method + + $status = $X->del_dup($key, $value) ; + +This method deletes a specific key/value pair. It returns +0 if they exist and have been deleted successfully. +Otherwise the method returns a non-zero value. + +Again assuming the existence of the C database + + use warnings ; + use strict ; + use DB_File ; + + our ($filename, $x, %h, $found) ; + + $filename = "tree" ; + + # Enable duplicate records + $DB_BTREE->{'flags'} = R_DUP ; + + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE + or die "Cannot open $filename: $!\n"; + + $x->del_dup("Wall", "Larry") ; + + $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ; + print "Larry Wall is $found there\n" ; + + undef $x ; + untie %h ; + +prints this + + Larry Wall is not there + =head2 Matching Partial Keys The BTREE interface has a feature which allows partial keys to be @@ -822,11 +1235,12 @@ the use of the R_CURSOR flag with seq: In the example script below, the C sub uses this feature to find and print the first matching key/value pair given a partial key. + use warnings ; use strict ; use DB_File ; use Fcntl ; - use vars qw($filename $x %h $st $key $value) ; + our ($filename, $x, %h, $st, $key, $value) ; sub match { @@ -840,24 +1254,24 @@ and print the first matching key/value pair given a partial key. $filename = "tree" ; unlink $filename ; - $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE + $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $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 "$key -> $value\n" } + print "\nPARTIAL MATCH\n" ; match "Wa" ; @@ -885,7 +1299,7 @@ Here is the output: 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 +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 @@ -893,15 +1307,51 @@ 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. +=head2 The 'bval' Option + +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 +C<"\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 B? Well, the behavior defined in the quote above is +quite useful, so B conforms to it. + +That means that you can specify other options (e.g. cachesize) and +still have bval default to C<"\n"> for variable length records, and +space for fixed length records. + +Also note that the bval option only allows you to specify a single byte +as a delimeter. + =head2 A Simple Example -Here is a simple example that uses RECNO. +Here is a simple example that uses RECNO (if you are using a version +of Perl earlier than 5.004_57 this example won't work -- see +L for a workaround). + use warnings ; use strict ; use DB_File ; + my $filename = "text" ; + unlink $filename ; + my @h ; - tie @h, "DB_File", "text", O_RDWR|O_CREAT, 0640, $DB_RECNO + tie @h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_RECNO or die "Cannot open file 'text': $!\n" ; # Add a few key/value pairs to the file @@ -909,6 +1359,18 @@ Here is a simple example that uses RECNO. $h[1] = "blue" ; $h[2] = "yellow" ; + push @h, "green", "black" ; + + my $elements = scalar @h ; + print "The array contains $elements entries\n" ; + + my $last = pop @h ; + print "popped $last\n" ; + + unshift @h, "white" ; + my $first = shift @h ; + print "shifted $first\n" ; + # Check for existence of a key print "Element 1 Exists with value $h[1]\n" if $h[1] ; @@ -920,18 +1382,24 @@ Here is a simple example that uses RECNO. Here is the output from the script: - + The array contains 5 entries + popped black + shifted white Element 1 Exists with value blue - The last element is yellow - The 2nd last element is blue + The last element is green + The 2nd last element is yellow + +=head2 Extra RECNO Methods -=head2 Extra Methods +If you are using a version of Perl earlier than 5.004_57, the tied +array interface is quite limited. In the example script above +C, C, C, C +or determining the array length will not work with a tied array. -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 B 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. +To make the interface more useful for older versions of Perl, a number +of methods are supplied with B to simulate the missing array +operations. All these methods are accessed via the object returned from +the tie call. Here are the methods: @@ -957,6 +1425,10 @@ Pushes the elements of C to the start of the array. Returns the number of elements in the array. +=item B<$X-Esplice(offset, length, elements);> + +Returns a splice of the the array. + =back =head2 Another Example @@ -965,18 +1437,19 @@ 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 L). + use warnings ; use strict ; - use vars qw(@h $H $file $i) ; + our (@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 + $H = tie @h, "DB_File", $file, O_RDWR|O_CREAT, 0666, $DB_RECNO or die "Cannot open file $file: $!\n" ; - + # first create a text file to play with $h[0] = "zero" ; $h[1] = "one" ; @@ -984,7 +1457,7 @@ L). $h[3] = "three" ; $h[4] = "four" ; - + # Print the records in order. # # The length method is needed here because evaluating a tied @@ -1117,6 +1590,8 @@ destroyed. undef $db ; untie %hash ; +See L for more details. + All the functions defined in L are available except for close() and dbopen() itself. The B method interface to the supported functions have been implemented to mirror the way Berkeley DB @@ -1220,8 +1695,8 @@ R_CURSOR is the only valid flag at present. Returns the file descriptor for the underlying database. -See L for an example of how to make use of the -C method to lock your database. +See L for an explanation for why you should +not use C to lock your database. =item B<$status = $X-Eseq($key, $value, $flags) ;> @@ -1242,76 +1717,273 @@ R_RECNOSYNC is the only valid flag at present. =back -=head1 HINTS AND TIPS +=head1 DBM FILTERS +A DBM Filter is a piece of code that is be used when you I +want to make the same transformation to all keys and/or values in a +DBM database. -=head2 Locking Databases +There are four methods associated with DBM Filters. All work identically, +and each is used to install (or uninstall) a single DBM Filter. Each +expects a single parameter, namely a reference to a sub. The only +difference between them is the place that the filter is installed. -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 I 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. +To summarise: - use DB_File; +=over 5 - use strict; +=item B - sub LOCK_SH { 1 } - sub LOCK_EX { 2 } - sub LOCK_NB { 4 } - sub LOCK_UN { 8 } +If a filter has been installed with this method, it will be invoked +every time you write a key to a DBM database. - my($oldval, $fd, $db, %db, $value, $key); +=item B - $key = shift || 'default'; - $value = shift || 'magic'; +If a filter has been installed with this method, it will be invoked +every time you write a value to a DBM database. - $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 $!"; +=item B +If a filter has been installed with this method, it will be invoked +every time you read a key from a DBM database. - 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"; +=item B - $oldval = $db{$key}; - print "$$: Old value was $oldval\n"; - flock(DB_FH, LOCK_UN); +If a filter has been installed with this method, it will be invoked +every time you read a value from a DBM database. + +=back + +You can use any combination of the methods, from none, to all four. - 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: $!" } - } +All filter methods return the existing filter, if present, or C +in not. - print "$$: Write lock granted\n"; - $db{$key} = $value; - $db->sync; # to flush - sleep 10; +To delete a filter pass C to it. +=head2 The Filter + +When each filter is called by Perl, a local copy of C<$_> will contain +the key or value to be filtered. Filtering is achieved by modifying +the contents of C<$_>. The return code from the filter is ignored. + +=head2 An Example -- the NULL termination problem. + +Consider the following scenario. You have a DBM database +that you need to share with a third-party C application. The C application +assumes that I keys and values are NULL terminated. Unfortunately +when Perl writes to DBM databases it doesn't use NULL termination, so +your Perl application will have to manage NULL termination itself. When +you write to the database you will have to use something like this: + + $hash{"$key\0"} = "$value\0" ; + +Similarly the NULL needs to be taken into account when you are considering +the length of existing keys/values. + +It would be much better if you could ignore the NULL terminations issue +in the main application code and have a mechanism that automatically +added the terminating NULL to all keys and values whenever you write to +the database and have them removed when you read from the database. As I'm +sure you have already guessed, this is a problem that DBM Filters can +fix very easily. + + use warnings ; + use strict ; + use DB_File ; + + my %hash ; + my $filename = "/tmp/filt" ; + unlink $filename ; + + my $db = tie %hash, 'DB_File', $filename, O_CREAT|O_RDWR, 0666, $DB_HASH + or die "Cannot open $filename: $!\n" ; + + # Install DBM Filters + $db->filter_fetch_key ( sub { s/\0$// } ) ; + $db->filter_store_key ( sub { $_ .= "\0" } ) ; + $db->filter_fetch_value( sub { s/\0$// } ) ; + $db->filter_store_value( sub { $_ .= "\0" } ) ; + + $hash{"abc"} = "def" ; + my $a = $hash{"ABC"} ; + # ... + undef $db ; + untie %hash ; + +Hopefully the contents of each of the filters should be +self-explanatory. Both "fetch" filters remove the terminating NULL, +and both "store" filters add a terminating NULL. + + +=head2 Another Example -- Key is a C int. + +Here is another real-life example. By default, whenever Perl writes to +a DBM database it always writes the key and value as strings. So when +you use this: + + $hash{12345} = "soemthing" ; + +the key 12345 will get stored in the DBM database as the 5 byte string +"12345". If you actually want the key to be stored in the DBM database +as a C int, you will have to use C when writing, and C +when reading. + +Here is a DBM Filter that does it: + + use warnings ; + use strict ; + use DB_File ; + my %hash ; + my $filename = "/tmp/filt" ; + unlink $filename ; + + + my $db = tie %hash, 'DB_File', $filename, O_CREAT|O_RDWR, 0666, $DB_HASH + or die "Cannot open $filename: $!\n" ; + + $db->filter_fetch_key ( sub { $_ = unpack("i", $_) } ) ; + $db->filter_store_key ( sub { $_ = pack ("i", $_) } ) ; + $hash{123} = "def" ; + # ... + undef $db ; + untie %hash ; + +This time only two filters have been used -- we only need to manipulate +the contents of the key, so it wasn't necessary to install any value +filters. + +=head1 HINTS AND TIPS + + +=head2 Locking: The Trouble with fd + +Until version 1.72 of this module, the recommended technique for locking +B databases was to flock the filehandle returned from the "fd" +function. Unfortunately this technique has been shown to be fundamentally +flawed (Kudos to David Harris for tracking this down). Use it at your own +peril! + +The locking technique went like this. + + $db = tie(%db, 'DB_File', '/tmp/foo.db', O_CREAT|O_RDWR, 0666) + || die "dbcreat /tmp/foo.db $!"; + $fd = $db->fd; + open(DB_FH, "+<&=$fd") || die "dup $!"; + flock (DB_FH, LOCK_EX) || die "flock: $!"; + ... + $db{"Tom"} = "Jerry" ; + ... flock(DB_FH, LOCK_UN); undef $db; untie %db; close(DB_FH); - print "$$: Updated db to $key=$value\n"; -=head2 Sharing databases with C applications +In simple terms, this is what happens: + +=over 5 + +=item 1. + +Use "tie" to open the database. + +=item 2. + +Lock the database with fd & flock. + +=item 3. + +Read & Write to the database. + +=item 4. + +Unlock and close the database. + +=back + +Here is the crux of the problem. A side-effect of opening the B +database in step 2 is that an initial block from the database will get +read from disk and cached in memory. + +To see why this is a problem, consider what can happen when two processes, +say "A" and "B", both want to update the same B database +using the locking steps outlined above. Assume process "A" has already +opened the database and has a write lock, but it hasn't actually updated +the database yet (it has finished step 2, but not started step 3 yet). Now +process "B" tries to open the same database - step 1 will succeed, +but it will block on step 2 until process "A" releases the lock. The +important thing to notice here is that at this point in time both +processes will have cached identical initial blocks from the database. + +Now process "A" updates the database and happens to change some of the +data held in the initial buffer. Process "A" terminates, flushing +all cached data to disk and releasing the database lock. At this point +the database on disk will correctly reflect the changes made by process +"A". + +With the lock released, process "B" can now continue. It also updates the +database and unfortunately it too modifies the data that was in its +initial buffer. Once that data gets flushed to disk it will overwrite +some/all of the changes process "A" made to the database. + +The result of this scenario is at best a database that doesn't contain +what you expect. At worst the database will corrupt. + +The above won't happen every time competing process update the same +B database, but it does illustrate why the technique should +not be used. + +=head2 Safe ways to lock a database + +Starting with version 2.x, Berkeley DB has internal support for locking. +The companion module to this one, B, provides an interface +to this locking functionality. If you are serious about locking +Berkeley DB databases, I strongly recommend using B. + +If using B isn't an option, there are a number of modules +available on CPAN that can be used to implement locking. Each one +implements locking differently and has different goals in mind. It is +therefore worth knowing the difference, so that you can pick the right +one for your application. Here are the three locking wrappers: + +=over 5 + +=item B + +A B wrapper which creates copies of the database file for +read access, so that you have a kind of a multiversioning concurrent read +system. However, updates are still serial. Use for databases where reads +may be lengthy and consistency problems may occur. + +=item B + +A B wrapper that has the ability to lock and unlock the database +while it is being used. Avoids the tie-before-flock problem by simply +re-tie-ing the database when you get or drop a lock. Because of the +flexibility in dropping and re-acquiring the lock in the middle of a +session, this can be massaged into a system that will work with long +updates and/or reads if the application follows the hints in the POD +documentation. + +=item B + +An extremely lightweight B wrapper that simply flocks a lockfile +before tie-ing the database and drops the lock after the untie. Allows +one to use the same lockfile for multiple databases to avoid deadlock +problems, if desired. Use for databases where updates are reads are +quick and simple flock locking semantics are enough. + +=back + +=head2 Sharing Databases With C Applications 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. +not. See L for a generic way to work around this problem. 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. @@ -1327,11 +1999,12 @@ Here is a snippet of code that is loosely based on Tom Christiansen's I script (available from your nearest CPAN archive in F). + use warnings ; use strict ; use DB_File ; use Fcntl ; - use vars qw( $dotdir $HISTORY %hist_db $href $binary_time $date ) ; + our ($dotdir, $HISTORY, %hist_db, $href, $binary_time, $date) ; $dotdir = $ENV{HOME} || $ENV{LOGNAME}; $HISTORY = "$dotdir/.netscape/history.db"; @@ -1362,6 +2035,73 @@ F). untie %hist_db ; +=head2 The untie() Gotcha + +If you make use of the Berkeley DB API, it is I strongly +recommended that you read L. + +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 B +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 L you will probably have already guessed that the +error is caused by the extra copy of the tied object stored in C<$X>. +If you haven't, then the problem boils down to the fact that the +B destructor, DESTROY, will not be called until I +references to the tied object are destroyed. Both the tied variable, +C<%x>, and C<$X> above hold a reference to the object. The call to +untie() will destroy the first, but C<$X> still holds a valid +reference, so the destructor will not get called and the database file +F will remain open. The fact that Berkeley DB then reports the +attempt to open a database that is already open via the catch-all +"Invalid argument" doesn't help. + +If you run the script with the C<-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 + ... + =head1 COMMON QUESTIONS @@ -1416,9 +2156,10 @@ You will encounter this particular error message when you have the C pragma (or the full strict pragma) in your script. Consider this script: + use warnings ; use strict ; use DB_File ; - use vars qw(%x) ; + my %x ; tie %x, DB_File, "filename" ; Running it produces the error in question: @@ -1433,126 +2174,91 @@ double quotes, like this: Although it might seem like a real pain, it is really worth the effort of having a C in all your scripts. -=head1 HISTORY - -=over - -=item 0.1 - -First Release. - -=item 0.2 - -When B is opening a database file it no longer terminates the -process if I returned an error. This allows file protection -errors to be caught at run time. Thanks to Judith Grass -Egrass@cybercash.comE for spotting the bug. - -=item 0.3 - -Added prototype support for multiple btree compare callbacks. - -=item 1.0 - -B 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 I method on an empty list didn't work properly. This -has been fixed. - -=item 1.01 - -Fixed a core dump problem with SunOS. - -The return value from TIEHASH wasn't set to NULL when dbopen returned -an error. - -=item 1.02 - -Merged OS/2 specific code into DB_File.xs - -Removed some redundant code in DB_File.xs. +=head1 REFERENCES -Documentation update. +Articles that are either about B or make use of it. -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 -C added. Without it the resultant database file was empty. +=over 5 -Added get_dup method. +=item 1. -=item 1.03 +I, Tim Kientzle (tkientzle@ddj.com), +Dr. Dobb's Journal, Issue 295, January 1999, pp 34-41 -Documentation update. +=back -B now imports the constants (O_RDWR, O_CREAT etc.) from Fcntl -automatically. +=head1 HISTORY -The standard hash function C is now supported. +Moved to the Changes file. -Modified the behavior of get_dup. When it returns an associative -array, the value is the count of the number of matching BTREE values. +=head1 BUGS -=item 1.04 +Some older versions of Berkeley DB had problems with fixed length +records using the RECNO file format. This problem has been fixed since +version 1.85 of Berkeley DB. -Minor documentation changes. +I am sure there are bugs in the code. If you do find any, or can +suggest any enhancements, I would welcome your comments. -Fixed a bug in hash_cb. Patches supplied by Dave Hammen, -Ehammen@gothamcity.jsc.nasa.govE. +=head1 AVAILABILITY -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 C<-w> clean. +B comes with the standard Perl source distribution. Look in +the directory F. Given the amount of time between releases +of Perl the version that ships with Perl is quite likely to be out of +date, so the most recent version can always be found on CPAN (see +L for details), in the directory +F. -Reworked part of the test harness to be more locale friendly. +This version of B will work with either version 1.x, 2.x or +3.x of Berkeley DB, but is limited to the functionality provided by +version 1. -=item 1.05 +The official web site for Berkeley DB is F. +All versions of Berkeley DB are available there. -Made all scripts in the documentation C and C<-w> clean. +Alternatively, Berkeley DB version 1 is available at your nearest CPAN +archive in F. -Added logic to F to allow the module to be built after Perl -is installed. +If you are running IRIX, then get Berkeley DB version 1 from +F. It has the patches necessary to +compile properly on IRIX 5.3. -=back +=head1 COPYRIGHT -=head1 BUGS +Copyright (c) 1995-2001 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. -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. +Although B is covered by the Perl license, the library it +makes use of, namely Berkeley DB, is not. Berkeley DB has its own +copyright and its own license. Please take the time to read it. -I am sure there are bugs in the code. If you do find any, or can -suggest any enhancements, I would welcome your comments. +Here are are few words taken from the Berkeley DB FAQ (at +F) regarding the license: -=head1 AVAILABILITY + Do I have to license DB to use it in Perl scripts? -B comes with the standard Perl source distribution. Look in -the directory F. + No. The Berkeley DB license requires that software that uses + Berkeley DB be freely redistributable. In the case of Perl, that + software is Perl, and not your scripts. Any Perl scripts that you + write are your property, including scripts that make use of + Berkeley DB. Neither the Perl license nor the Berkeley DB license + place any restriction on what you may do with them. -Berkeley DB is available at your nearest CPAN archive (see -L for a list) in F, or via the -host F in F. Alternatively, -check out the Berkeley DB home page at F. It -is I under the GPL. +If you are in any doubt about the license situation, contact either the +Berkeley DB authors or the author of DB_File. See L<"AUTHOR"> for details. -If you are running IRIX, then get Berkeley DB from -F. It has the patches necessary to -compile properly on IRIX 5.3. =head1 SEE ALSO -L, L, L, L, L +L, L, L, L, L, +L =head1 AUTHOR The DB_File interface was written by Paul Marquess -Epmarquess@bfsec.bt.co.ukE. -Questions about the DB system itself may be addressed to Keith Bostic -Ebostic@cs.berkeley.eduE. +EPaul.Marquess@btinternet.comE. +Questions about the DB system itself may be addressed to +Edb@sleepycat.com. =cut