Blame DB_File.pm

Packit bc69c3
# DB_File.pm -- Perl 5 interface to Berkeley DB 
Packit bc69c3
#
Packit bc69c3
# Written by Paul Marquess (pmqs@cpan.org)
Packit bc69c3
#
Packit bc69c3
#     Copyright (c) 1995-2018 Paul Marquess. All rights reserved.
Packit bc69c3
#     This program is free software; you can redistribute it and/or
Packit bc69c3
#     modify it under the same terms as Perl itself.
Packit bc69c3
Packit bc69c3
Packit bc69c3
package DB_File::HASHINFO ;
Packit bc69c3
Packit bc69c3
require 5.008003;
Packit bc69c3
Packit bc69c3
use warnings;
Packit bc69c3
use strict;
Packit bc69c3
use Carp;
Packit bc69c3
require Tie::Hash;
Packit bc69c3
@DB_File::HASHINFO::ISA = qw(Tie::Hash);
Packit bc69c3
Packit bc69c3
sub new
Packit bc69c3
{
Packit bc69c3
    my $pkg = shift ;
Packit bc69c3
    my %x ;
Packit bc69c3
    tie %x, $pkg ;
Packit bc69c3
    bless \%x, $pkg ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
Packit bc69c3
sub TIEHASH
Packit bc69c3
{
Packit bc69c3
    my $pkg = shift ;
Packit bc69c3
Packit bc69c3
    bless { VALID => { 
Packit bc69c3
		       	bsize	  => 1,
Packit bc69c3
			ffactor	  => 1,
Packit bc69c3
			nelem	  => 1,
Packit bc69c3
			cachesize => 1,
Packit bc69c3
			hash	  => 2,
Packit bc69c3
			lorder	  => 1,
Packit bc69c3
		     }, 
Packit bc69c3
	    GOT   => {}
Packit bc69c3
          }, $pkg ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
Packit bc69c3
sub FETCH 
Packit bc69c3
{  
Packit bc69c3
    my $self  = shift ;
Packit bc69c3
    my $key   = shift ;
Packit bc69c3
Packit bc69c3
    return $self->{GOT}{$key} if exists $self->{VALID}{$key}  ;
Packit bc69c3
Packit bc69c3
    my $pkg = ref $self ;
Packit bc69c3
    croak "${pkg}::FETCH - Unknown element '$key'" ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
Packit bc69c3
sub STORE 
Packit bc69c3
{
Packit bc69c3
    my $self  = shift ;
Packit bc69c3
    my $key   = shift ;
Packit bc69c3
    my $value = shift ;
Packit bc69c3
Packit bc69c3
    my $type = $self->{VALID}{$key};
Packit bc69c3
Packit bc69c3
    if ( $type )
Packit bc69c3
    {
Packit bc69c3
    	croak "Key '$key' not associated with a code reference" 
Packit bc69c3
	    if $type == 2 && !ref $value && ref $value ne 'CODE';
Packit bc69c3
        $self->{GOT}{$key} = $value ;
Packit bc69c3
        return ;
Packit bc69c3
    }
Packit bc69c3
    
Packit bc69c3
    my $pkg = ref $self ;
Packit bc69c3
    croak "${pkg}::STORE - Unknown element '$key'" ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub DELETE 
Packit bc69c3
{
Packit bc69c3
    my $self = shift ;
Packit bc69c3
    my $key  = shift ;
Packit bc69c3
Packit bc69c3
    if ( exists $self->{VALID}{$key} )
Packit bc69c3
    {
Packit bc69c3
        delete $self->{GOT}{$key} ;
Packit bc69c3
        return ;
Packit bc69c3
    }
Packit bc69c3
    
Packit bc69c3
    my $pkg = ref $self ;
Packit bc69c3
    croak "DB_File::HASHINFO::DELETE - Unknown element '$key'" ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub EXISTS
Packit bc69c3
{
Packit bc69c3
    my $self = shift ;
Packit bc69c3
    my $key  = shift ;
Packit bc69c3
Packit bc69c3
    exists $self->{VALID}{$key} ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub NotHere
Packit bc69c3
{
Packit bc69c3
    my $self = shift ;
Packit bc69c3
    my $method = shift ;
Packit bc69c3
Packit bc69c3
    croak ref($self) . " does not define the method ${method}" ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub FIRSTKEY { my $self = shift ; $self->NotHere("FIRSTKEY") }
Packit bc69c3
sub NEXTKEY  { my $self = shift ; $self->NotHere("NEXTKEY") }
Packit bc69c3
sub CLEAR    { my $self = shift ; $self->NotHere("CLEAR") }
Packit bc69c3
Packit bc69c3
package DB_File::RECNOINFO ;
Packit bc69c3
Packit bc69c3
use warnings;
Packit bc69c3
use strict ;
Packit bc69c3
Packit bc69c3
@DB_File::RECNOINFO::ISA = qw(DB_File::HASHINFO) ;
Packit bc69c3
Packit bc69c3
sub TIEHASH
Packit bc69c3
{
Packit bc69c3
    my $pkg = shift ;
Packit bc69c3
Packit bc69c3
    bless { VALID => { map {$_, 1} 
Packit bc69c3
		       qw( bval cachesize psize flags lorder reclen bfname )
Packit bc69c3
		     },
Packit bc69c3
	    GOT   => {},
Packit bc69c3
          }, $pkg ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
package DB_File::BTREEINFO ;
Packit bc69c3
Packit bc69c3
use warnings;
Packit bc69c3
use strict ;
Packit bc69c3
Packit bc69c3
@DB_File::BTREEINFO::ISA = qw(DB_File::HASHINFO) ;
Packit bc69c3
Packit bc69c3
sub TIEHASH
Packit bc69c3
{
Packit bc69c3
    my $pkg = shift ;
Packit bc69c3
Packit bc69c3
    bless { VALID => { 
Packit bc69c3
		      	flags	   => 1,
Packit bc69c3
			cachesize  => 1,
Packit bc69c3
			maxkeypage => 1,
Packit bc69c3
			minkeypage => 1,
Packit bc69c3
			psize	   => 1,
Packit bc69c3
			compare	   => 2,
Packit bc69c3
			prefix	   => 2,
Packit bc69c3
			lorder	   => 1,
Packit bc69c3
	    	     },
Packit bc69c3
	    GOT   => {},
Packit bc69c3
          }, $pkg ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
Packit bc69c3
package DB_File ;
Packit bc69c3
Packit bc69c3
use warnings;
Packit bc69c3
use strict;
Packit bc69c3
our ($VERSION, @ISA, @EXPORT, $AUTOLOAD, $DB_BTREE, $DB_HASH, $DB_RECNO);
Packit bc69c3
our ($db_version, $use_XSLoader, $splice_end_array_no_length, $splice_end_array, $Error);
Packit bc69c3
use Carp;
Packit bc69c3
Packit bc69c3
# Module not thread safe, so don't clone
Packit bc69c3
sub CLONE_SKIP { 1 } 
Packit bc69c3
Packit bc69c3
$VERSION = "1.842" ;
Packit bc69c3
$VERSION = eval $VERSION; # needed for dev releases
Packit bc69c3
Packit bc69c3
{
Packit bc69c3
    local $SIG{__WARN__} = sub {$splice_end_array_no_length = join(" ",@_);};
Packit bc69c3
    my @a =(1); splice(@a, 3);
Packit bc69c3
    $splice_end_array_no_length = 
Packit bc69c3
        ($splice_end_array_no_length =~ /^splice\(\) offset past end of array at /);
Packit bc69c3
}      
Packit bc69c3
{
Packit bc69c3
    local $SIG{__WARN__} = sub {$splice_end_array = join(" ", @_);};
Packit bc69c3
    my @a =(1); splice(@a, 3, 1);
Packit bc69c3
    $splice_end_array = 
Packit bc69c3
        ($splice_end_array =~ /^splice\(\) offset past end of array at /);
Packit bc69c3
}      
Packit bc69c3
Packit bc69c3
#typedef enum { DB_BTREE, DB_HASH, DB_RECNO } DBTYPE;
Packit bc69c3
$DB_BTREE = new DB_File::BTREEINFO ;
Packit bc69c3
$DB_HASH  = new DB_File::HASHINFO ;
Packit bc69c3
$DB_RECNO = new DB_File::RECNOINFO ;
Packit bc69c3
Packit bc69c3
require Tie::Hash;
Packit bc69c3
require Exporter;
Packit bc69c3
BEGIN {
Packit bc69c3
    $use_XSLoader = 1 ;
Packit bc69c3
    { local $SIG{__DIE__} ; eval { require XSLoader } ; }
Packit bc69c3
Packit bc69c3
    if ($@) {
Packit bc69c3
        $use_XSLoader = 0 ;
Packit bc69c3
        require DynaLoader;
Packit bc69c3
        @ISA = qw(DynaLoader);
Packit bc69c3
    }
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
push @ISA, qw(Tie::Hash Exporter);
Packit bc69c3
@EXPORT = qw(
Packit bc69c3
        $DB_BTREE $DB_HASH $DB_RECNO 
Packit bc69c3
Packit bc69c3
	BTREEMAGIC
Packit bc69c3
	BTREEVERSION
Packit bc69c3
	DB_LOCK
Packit bc69c3
	DB_SHMEM
Packit bc69c3
	DB_TXN
Packit bc69c3
	HASHMAGIC
Packit bc69c3
	HASHVERSION
Packit bc69c3
	MAX_PAGE_NUMBER
Packit bc69c3
	MAX_PAGE_OFFSET
Packit bc69c3
	MAX_REC_NUMBER
Packit bc69c3
	RET_ERROR
Packit bc69c3
	RET_SPECIAL
Packit bc69c3
	RET_SUCCESS
Packit bc69c3
	R_CURSOR
Packit bc69c3
	R_DUP
Packit bc69c3
	R_FIRST
Packit bc69c3
	R_FIXEDLEN
Packit bc69c3
	R_IAFTER
Packit bc69c3
	R_IBEFORE
Packit bc69c3
	R_LAST
Packit bc69c3
	R_NEXT
Packit bc69c3
	R_NOKEY
Packit bc69c3
	R_NOOVERWRITE
Packit bc69c3
	R_PREV
Packit bc69c3
	R_RECNOSYNC
Packit bc69c3
	R_SETCURSOR
Packit bc69c3
	R_SNAPSHOT
Packit bc69c3
	__R_UNUSED
Packit bc69c3
Packit bc69c3
);
Packit bc69c3
Packit bc69c3
sub AUTOLOAD {
Packit bc69c3
    my($constname);
Packit bc69c3
    ($constname = $AUTOLOAD) =~ s/.*:://;
Packit bc69c3
    my ($error, $val) = constant($constname);
Packit bc69c3
    Carp::croak $error if $error;
Packit bc69c3
    no strict 'refs';
Packit bc69c3
    *{$AUTOLOAD} = sub { $val };
Packit bc69c3
    goto &{$AUTOLOAD};
Packit bc69c3
}           
Packit bc69c3
Packit bc69c3
Packit bc69c3
eval {
Packit bc69c3
    # Make all Fcntl O_XXX constants available for importing
Packit bc69c3
    require Fcntl;
Packit bc69c3
    my @O = grep /^O_/, @Fcntl::EXPORT;
Packit bc69c3
    Fcntl->import(@O);  # first we import what we want to export
Packit bc69c3
    push(@EXPORT, @O);
Packit bc69c3
};
Packit bc69c3
Packit bc69c3
if ($use_XSLoader)
Packit bc69c3
  { XSLoader::load("DB_File", $VERSION)}
Packit bc69c3
else
Packit bc69c3
  { bootstrap DB_File $VERSION }
Packit bc69c3
Packit bc69c3
sub tie_hash_or_array
Packit bc69c3
{
Packit bc69c3
    my (@arg) = @_ ;
Packit bc69c3
    my $tieHASH = ( (caller(1))[3] =~ /TIEHASH/ ) ;
Packit bc69c3
Packit bc69c3
    use File::Spec;
Packit bc69c3
    $arg[1] = File::Spec->rel2abs($arg[1]) 
Packit bc69c3
        if defined $arg[1] ;
Packit bc69c3
Packit bc69c3
    $arg[4] = tied %{ $arg[4] } 
Packit bc69c3
	if @arg >= 5 && ref $arg[4] && $arg[4] =~ /=HASH/ && tied %{ $arg[4] } ;
Packit bc69c3
Packit bc69c3
    $arg[2] = O_CREAT()|O_RDWR() if @arg >=3 && ! defined $arg[2];
Packit bc69c3
    $arg[3] = 0666               if @arg >=4 && ! defined $arg[3];
Packit bc69c3
Packit bc69c3
    # make recno in Berkeley DB version 2 (or better) work like 
Packit bc69c3
    # recno in version 1.
Packit bc69c3
    if ($db_version >= 4 and ! $tieHASH) {
Packit bc69c3
        $arg[2] |= O_CREAT();
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    if ($db_version > 1 and defined $arg[4] and $arg[4] =~ /RECNO/ and 
Packit bc69c3
	$arg[1] and ! -e $arg[1]) {
Packit bc69c3
	open(FH, ">$arg[1]") or return undef ;
Packit bc69c3
	close FH ;
Packit bc69c3
	chmod $arg[3] ? $arg[3] : 0666 , $arg[1] ;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    DoTie_($tieHASH, @arg) ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub TIEHASH
Packit bc69c3
{
Packit bc69c3
    tie_hash_or_array(@_) ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub TIEARRAY
Packit bc69c3
{
Packit bc69c3
    tie_hash_or_array(@_) ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub CLEAR 
Packit bc69c3
{
Packit bc69c3
    my $self = shift;
Packit bc69c3
    my $key = 0 ;
Packit bc69c3
    my $value = "" ;
Packit bc69c3
    my $status = $self->seq($key, $value, R_FIRST());
Packit bc69c3
    my @keys;
Packit bc69c3
 
Packit bc69c3
    while ($status == 0) {
Packit bc69c3
        push @keys, $key;
Packit bc69c3
        $status = $self->seq($key, $value, R_NEXT());
Packit bc69c3
    }
Packit bc69c3
    foreach $key (reverse @keys) {
Packit bc69c3
        my $s = $self->del($key); 
Packit bc69c3
    }
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub EXTEND { }
Packit bc69c3
Packit bc69c3
sub STORESIZE
Packit bc69c3
{
Packit bc69c3
    my $self = shift;
Packit bc69c3
    my $length = shift ;
Packit bc69c3
    my $current_length = $self->length() ;
Packit bc69c3
Packit bc69c3
    if ($length < $current_length) {
Packit bc69c3
	my $key ;
Packit bc69c3
        for ($key = $current_length - 1 ; $key >= $length ; -- $key)
Packit bc69c3
	  { $self->del($key) }
Packit bc69c3
    }
Packit bc69c3
    elsif ($length > $current_length) {
Packit bc69c3
        $self->put($length-1, "") ;
Packit bc69c3
    }
Packit bc69c3
}
Packit bc69c3
 
Packit bc69c3
Packit bc69c3
sub SPLICE
Packit bc69c3
{
Packit bc69c3
    my $self = shift;
Packit bc69c3
    my $offset = shift;
Packit bc69c3
    if (not defined $offset) {
Packit bc69c3
	warnings::warnif('uninitialized', 'Use of uninitialized value in splice');
Packit bc69c3
	$offset = 0;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    my $has_length = @_;
Packit bc69c3
    my $length = @_ ? shift : 0;
Packit bc69c3
    # Carping about definedness comes _after_ the OFFSET sanity check.
Packit bc69c3
    # This is so we get the same error messages as Perl's splice().
Packit bc69c3
    # 
Packit bc69c3
Packit bc69c3
    my @list = @_;
Packit bc69c3
Packit bc69c3
    my $size = $self->FETCHSIZE();
Packit bc69c3
    
Packit bc69c3
    # 'If OFFSET is negative then it start that far from the end of
Packit bc69c3
    # the array.'
Packit bc69c3
    # 
Packit bc69c3
    if ($offset < 0) {
Packit bc69c3
	my $new_offset = $size + $offset;
Packit bc69c3
	if ($new_offset < 0) {
Packit bc69c3
	    die "Modification of non-creatable array value attempted, "
Packit bc69c3
	      . "subscript $offset";
Packit bc69c3
	}
Packit bc69c3
	$offset = $new_offset;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    if (not defined $length) {
Packit bc69c3
	warnings::warnif('uninitialized', 'Use of uninitialized value in splice');
Packit bc69c3
	$length = 0;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    if ($offset > $size) {
Packit bc69c3
 	$offset = $size;
Packit bc69c3
	warnings::warnif('misc', 'splice() offset past end of array')
Packit bc69c3
            if $has_length ? $splice_end_array : $splice_end_array_no_length;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    # 'If LENGTH is omitted, removes everything from OFFSET onward.'
Packit bc69c3
    if (not defined $length) {
Packit bc69c3
	$length = $size - $offset;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    # 'If LENGTH is negative, leave that many elements off the end of
Packit bc69c3
    # the array.'
Packit bc69c3
    # 
Packit bc69c3
    if ($length < 0) {
Packit bc69c3
	$length = $size - $offset + $length;
Packit bc69c3
Packit bc69c3
	if ($length < 0) {
Packit bc69c3
	    # The user must have specified a length bigger than the
Packit bc69c3
	    # length of the array passed in.  But perl's splice()
Packit bc69c3
	    # doesn't catch this, it just behaves as for length=0.
Packit bc69c3
	    # 
Packit bc69c3
	    $length = 0;
Packit bc69c3
	}
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    if ($length > $size - $offset) {
Packit bc69c3
	$length = $size - $offset;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    # $num_elems holds the current number of elements in the database.
Packit bc69c3
    my $num_elems = $size;
Packit bc69c3
Packit bc69c3
    # 'Removes the elements designated by OFFSET and LENGTH from an
Packit bc69c3
    # array,'...
Packit bc69c3
    # 
Packit bc69c3
    my @removed = ();
Packit bc69c3
    foreach (0 .. $length - 1) {
Packit bc69c3
	my $old;
Packit bc69c3
	my $status = $self->get($offset, $old);
Packit bc69c3
	if ($status != 0) {
Packit bc69c3
	    my $msg = "error from Berkeley DB on get($offset, \$old)";
Packit bc69c3
	    if ($status == 1) {
Packit bc69c3
		$msg .= ' (no such element?)';
Packit bc69c3
	    }
Packit bc69c3
	    else {
Packit bc69c3
		$msg .= ": error status $status";
Packit bc69c3
		if (defined $! and $! ne '') {
Packit bc69c3
		    $msg .= ", message $!";
Packit bc69c3
		}
Packit bc69c3
	    }
Packit bc69c3
	    die $msg;
Packit bc69c3
	}
Packit bc69c3
	push @removed, $old;
Packit bc69c3
Packit bc69c3
	$status = $self->del($offset);
Packit bc69c3
	if ($status != 0) {
Packit bc69c3
	    my $msg = "error from Berkeley DB on del($offset)";
Packit bc69c3
	    if ($status == 1) {
Packit bc69c3
		$msg .= ' (no such element?)';
Packit bc69c3
	    }
Packit bc69c3
	    else {
Packit bc69c3
		$msg .= ": error status $status";
Packit bc69c3
		if (defined $! and $! ne '') {
Packit bc69c3
		    $msg .= ", message $!";
Packit bc69c3
		}
Packit bc69c3
	    }
Packit bc69c3
	    die $msg;
Packit bc69c3
	}
Packit bc69c3
Packit bc69c3
	-- $num_elems;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    # ...'and replaces them with the elements of LIST, if any.'
Packit bc69c3
    my $pos = $offset;
Packit bc69c3
    while (defined (my $elem = shift @list)) {
Packit bc69c3
	my $old_pos = $pos;
Packit bc69c3
	my $status;
Packit bc69c3
	if ($pos >= $num_elems) {
Packit bc69c3
	    $status = $self->put($pos, $elem);
Packit bc69c3
	}
Packit bc69c3
	else {
Packit bc69c3
	    $status = $self->put($pos, $elem, $self->R_IBEFORE);
Packit bc69c3
	}
Packit bc69c3
Packit bc69c3
	if ($status != 0) {
Packit bc69c3
	    my $msg = "error from Berkeley DB on put($pos, $elem, ...)";
Packit bc69c3
	    if ($status == 1) {
Packit bc69c3
		$msg .= ' (no such element?)';
Packit bc69c3
	    }
Packit bc69c3
	    else {
Packit bc69c3
		$msg .= ", error status $status";
Packit bc69c3
		if (defined $! and $! ne '') {
Packit bc69c3
		    $msg .= ", message $!";
Packit bc69c3
		}
Packit bc69c3
	    }
Packit bc69c3
	    die $msg;
Packit bc69c3
	}
Packit bc69c3
Packit bc69c3
	die "pos unexpectedly changed from $old_pos to $pos with R_IBEFORE"
Packit bc69c3
	  if $old_pos != $pos;
Packit bc69c3
Packit bc69c3
	++ $pos;
Packit bc69c3
	++ $num_elems;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    if (wantarray) {
Packit bc69c3
	# 'In list context, returns the elements removed from the
Packit bc69c3
	# array.'
Packit bc69c3
	# 
Packit bc69c3
	return @removed;
Packit bc69c3
    }
Packit bc69c3
    elsif (defined wantarray and not wantarray) {
Packit bc69c3
	# 'In scalar context, returns the last element removed, or
Packit bc69c3
	# undef if no elements are removed.'
Packit bc69c3
	# 
Packit bc69c3
	if (@removed) {
Packit bc69c3
	    my $last = pop @removed;
Packit bc69c3
	    return "$last";
Packit bc69c3
	}
Packit bc69c3
	else {
Packit bc69c3
	    return undef;
Packit bc69c3
	}
Packit bc69c3
    }
Packit bc69c3
    elsif (not defined wantarray) {
Packit bc69c3
	# Void context
Packit bc69c3
    }
Packit bc69c3
    else { die }
Packit bc69c3
}
Packit bc69c3
sub ::DB_File::splice { &SPLICE }
Packit bc69c3
Packit bc69c3
sub find_dup
Packit bc69c3
{
Packit bc69c3
    croak "Usage: \$db->find_dup(key,value)\n"
Packit bc69c3
        unless @_ == 3 ;
Packit bc69c3
 
Packit bc69c3
    my $db        = shift ;
Packit bc69c3
    my ($origkey, $value_wanted) = @_ ;
Packit bc69c3
    my ($key, $value) = ($origkey, 0);
Packit bc69c3
    my ($status) = 0 ;
Packit bc69c3
Packit bc69c3
    for ($status = $db->seq($key, $value, R_CURSOR() ) ;
Packit bc69c3
         $status == 0 ;
Packit bc69c3
         $status = $db->seq($key, $value, R_NEXT() ) ) {
Packit bc69c3
Packit bc69c3
        return 0 if $key eq $origkey and $value eq $value_wanted ;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    return $status ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub del_dup
Packit bc69c3
{
Packit bc69c3
    croak "Usage: \$db->del_dup(key,value)\n"
Packit bc69c3
        unless @_ == 3 ;
Packit bc69c3
 
Packit bc69c3
    my $db        = shift ;
Packit bc69c3
    my ($key, $value) = @_ ;
Packit bc69c3
    my ($status) = $db->find_dup($key, $value) ;
Packit bc69c3
    return $status if $status != 0 ;
Packit bc69c3
Packit bc69c3
    $status = $db->del($key, R_CURSOR() ) ;
Packit bc69c3
    return $status ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub get_dup
Packit bc69c3
{
Packit bc69c3
    croak "Usage: \$db->get_dup(key [,flag])\n"
Packit bc69c3
        unless @_ == 2 or @_ == 3 ;
Packit bc69c3
 
Packit bc69c3
    my $db        = shift ;
Packit bc69c3
    my $key       = shift ;
Packit bc69c3
    my $flag	  = shift ;
Packit bc69c3
    my $value 	  = 0 ;
Packit bc69c3
    my $origkey   = $key ;
Packit bc69c3
    my $wantarray = wantarray ;
Packit bc69c3
    my %values	  = () ;
Packit bc69c3
    my @values    = () ;
Packit bc69c3
    my $counter   = 0 ;
Packit bc69c3
    my $status    = 0 ;
Packit bc69c3
 
Packit bc69c3
    # iterate through the database until either EOF ($status == 0)
Packit bc69c3
    # or a different key is encountered ($key ne $origkey).
Packit bc69c3
    for ($status = $db->seq($key, $value, R_CURSOR()) ;
Packit bc69c3
	 $status == 0 and $key eq $origkey ;
Packit bc69c3
         $status = $db->seq($key, $value, R_NEXT()) ) {
Packit bc69c3
 
Packit bc69c3
        # save the value or count number of matches
Packit bc69c3
        if ($wantarray) {
Packit bc69c3
	    if ($flag)
Packit bc69c3
                { ++ $values{$value} }
Packit bc69c3
	    else
Packit bc69c3
                { push (@values, $value) }
Packit bc69c3
	}
Packit bc69c3
        else
Packit bc69c3
            { ++ $counter }
Packit bc69c3
     
Packit bc69c3
    }
Packit bc69c3
 
Packit bc69c3
    return ($wantarray ? ($flag ? %values : @values) : $counter) ;
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
Packit bc69c3
sub STORABLE_freeze
Packit bc69c3
{
Packit bc69c3
    my $type = ref shift;
Packit bc69c3
    croak "Cannot freeze $type object\n";
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
sub STORABLE_thaw
Packit bc69c3
{
Packit bc69c3
    my $type = ref shift;
Packit bc69c3
    croak "Cannot thaw $type object\n";
Packit bc69c3
}
Packit bc69c3
Packit bc69c3
Packit bc69c3
Packit bc69c3
1;
Packit bc69c3
__END__
Packit bc69c3
Packit bc69c3
=head1 NAME
Packit bc69c3
Packit bc69c3
DB_File - Perl5 access to Berkeley DB version 1.x
Packit bc69c3
Packit bc69c3
=head1 SYNOPSIS
Packit bc69c3
Packit bc69c3
 use DB_File;
Packit bc69c3
Packit bc69c3
 [$X =] tie %hash,  'DB_File', [$filename, $flags, $mode, $DB_HASH] ;
Packit bc69c3
 [$X =] tie %hash,  'DB_File', $filename, $flags, $mode, $DB_BTREE ;
Packit bc69c3
 [$X =] tie @array, 'DB_File', $filename, $flags, $mode, $DB_RECNO ;
Packit bc69c3
Packit bc69c3
 $status = $X->del($key [, $flags]) ;
Packit bc69c3
 $status = $X->put($key, $value [, $flags]) ;
Packit bc69c3
 $status = $X->get($key, $value [, $flags]) ;
Packit bc69c3
 $status = $X->seq($key, $value, $flags) ;
Packit bc69c3
 $status = $X->sync([$flags]) ;
Packit bc69c3
 $status = $X->fd ;
Packit bc69c3
Packit bc69c3
 # BTREE only
Packit bc69c3
 $count = $X->get_dup($key) ;
Packit bc69c3
 @list  = $X->get_dup($key) ;
Packit bc69c3
 %list  = $X->get_dup($key, 1) ;
Packit bc69c3
 $status = $X->find_dup($key, $value) ;
Packit bc69c3
 $status = $X->del_dup($key, $value) ;
Packit bc69c3
Packit bc69c3
 # RECNO only
Packit bc69c3
 $a = $X->length;
Packit bc69c3
 $a = $X->pop ;
Packit bc69c3
 $X->push(list);
Packit bc69c3
 $a = $X->shift;
Packit bc69c3
 $X->unshift(list);
Packit bc69c3
 @r = $X->splice(offset, length, elements);
Packit bc69c3
Packit bc69c3
 # DBM Filters
Packit bc69c3
 $old_filter = $db->filter_store_key  ( sub { ... } ) ;
Packit bc69c3
 $old_filter = $db->filter_store_value( sub { ... } ) ;
Packit bc69c3
 $old_filter = $db->filter_fetch_key  ( sub { ... } ) ;
Packit bc69c3
 $old_filter = $db->filter_fetch_value( sub { ... } ) ;
Packit bc69c3
Packit bc69c3
 untie %hash ;
Packit bc69c3
 untie @array ;
Packit bc69c3
Packit bc69c3
=head1 DESCRIPTION
Packit bc69c3
Packit bc69c3
B<DB_File> is a module which allows Perl programs to make use of the
Packit bc69c3
facilities provided by Berkeley DB version 1.x (if you have a newer
Packit bc69c3
version of DB, see L<Using DB_File with Berkeley DB version 2 or greater>).
Packit bc69c3
It is assumed that you have a copy of the Berkeley DB manual pages at
Packit bc69c3
hand when reading this documentation. The interface defined here
Packit bc69c3
mirrors the Berkeley DB interface closely.
Packit bc69c3
Packit bc69c3
Berkeley DB is a C library which provides a consistent interface to a
Packit bc69c3
number of database formats.  B<DB_File> provides an interface to all
Packit bc69c3
three of the database types currently supported by Berkeley DB.
Packit bc69c3
Packit bc69c3
The file types are:
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item B<DB_HASH>
Packit bc69c3
Packit bc69c3
This database type allows arbitrary key/value pairs to be stored in data
Packit bc69c3
files. This is equivalent to the functionality provided by other
Packit bc69c3
hashing packages like DBM, NDBM, ODBM, GDBM, and SDBM. Remember though,
Packit bc69c3
the files created using DB_HASH are not compatible with any of the
Packit bc69c3
other packages mentioned.
Packit bc69c3
Packit bc69c3
A default hashing algorithm, which will be adequate for most
Packit bc69c3
applications, is built into Berkeley DB. If you do need to use your own
Packit bc69c3
hashing algorithm it is possible to write your own in Perl and have
Packit bc69c3
B<DB_File> use it instead.
Packit bc69c3
Packit bc69c3
=item B<DB_BTREE>
Packit bc69c3
Packit bc69c3
The btree format allows arbitrary key/value pairs to be stored in a
Packit bc69c3
sorted, balanced binary tree.
Packit bc69c3
Packit bc69c3
As with the DB_HASH format, it is possible to provide a user defined
Packit bc69c3
Perl routine to perform the comparison of keys. By default, though, the
Packit bc69c3
keys are stored in lexical order.
Packit bc69c3
Packit bc69c3
=item B<DB_RECNO>
Packit bc69c3
Packit bc69c3
DB_RECNO allows both fixed-length and variable-length flat text files
Packit bc69c3
to be manipulated using the same key/value pair interface as in DB_HASH
Packit bc69c3
and DB_BTREE.  In this case the key will consist of a record (line)
Packit bc69c3
number.
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
=head2 Using DB_File with Berkeley DB version 2 or greater
Packit bc69c3
Packit bc69c3
Although B<DB_File> is intended to be used with Berkeley DB version 1,
Packit bc69c3
it can also be used with version 2, 3 or 4. In this case the interface is
Packit bc69c3
limited to the functionality provided by Berkeley DB 1.x. Anywhere the
Packit bc69c3
version 2 or greater interface differs, B<DB_File> arranges for it to work
Packit bc69c3
like version 1. This feature allows B<DB_File> scripts that were built
Packit bc69c3
with version 1 to be migrated to version 2 or greater without any changes.
Packit bc69c3
Packit bc69c3
If you want to make use of the new features available in Berkeley DB
Packit bc69c3
2.x or greater, use the Perl module B<BerkeleyDB> instead.
Packit bc69c3
Packit bc69c3
B<Note:> The database file format has changed multiple times in Berkeley
Packit bc69c3
DB version 2, 3 and 4. If you cannot recreate your databases, you
Packit bc69c3
must dump any existing databases with either the C<db_dump> or the
Packit bc69c3
C<db_dump185> utility that comes with Berkeley DB.
Packit bc69c3
Once you have rebuilt DB_File to use Berkeley DB version 2 or greater,
Packit bc69c3
your databases can be recreated using C<db_load>. Refer to the Berkeley DB
Packit bc69c3
documentation for further details.
Packit bc69c3
Packit bc69c3
Please read L<"COPYRIGHT"> before using version 2.x or greater of Berkeley
Packit bc69c3
DB with DB_File.
Packit bc69c3
Packit bc69c3
=head2 Interface to Berkeley DB
Packit bc69c3
Packit bc69c3
B<DB_File> allows access to Berkeley DB files using the tie() mechanism
Packit bc69c3
in Perl 5 (for full details, see L<perlfunc/tie()>). This facility
Packit bc69c3
allows B<DB_File> to access Berkeley DB files using either an
Packit bc69c3
associative array (for DB_HASH & DB_BTREE file types) or an ordinary
Packit bc69c3
array (for the DB_RECNO file type).
Packit bc69c3
Packit bc69c3
In addition to the tie() interface, it is also possible to access most
Packit bc69c3
of the functions provided in the Berkeley DB API directly.
Packit bc69c3
See L<THE API INTERFACE>.
Packit bc69c3
Packit bc69c3
=head2 Opening a Berkeley DB Database File
Packit bc69c3
Packit bc69c3
Berkeley DB uses the function dbopen() to open or create a database.
Packit bc69c3
Here is the C prototype for dbopen():
Packit bc69c3
Packit bc69c3
      DB*
Packit bc69c3
      dbopen (const char * file, int flags, int mode, 
Packit bc69c3
              DBTYPE type, const void * openinfo)
Packit bc69c3
Packit bc69c3
The parameter C<type> is an enumeration which specifies which of the 3
Packit bc69c3
interface methods (DB_HASH, DB_BTREE or DB_RECNO) is to be used.
Packit bc69c3
Depending on which of these is actually chosen, the final parameter,
Packit bc69c3
I<openinfo> points to a data structure which allows tailoring of the
Packit bc69c3
specific interface method.
Packit bc69c3
Packit bc69c3
This interface is handled slightly differently in B<DB_File>. Here is
Packit bc69c3
an equivalent call using B<DB_File>:
Packit bc69c3
Packit bc69c3
        tie %array, 'DB_File', $filename, $flags, $mode, $DB_HASH ;
Packit bc69c3
Packit bc69c3
The C<filename>, C<flags> and C<mode> parameters are the direct
Packit bc69c3
equivalent of their dbopen() counterparts. The final parameter $DB_HASH
Packit bc69c3
performs the function of both the C<type> and C<openinfo> parameters in
Packit bc69c3
dbopen().
Packit bc69c3
Packit bc69c3
In the example above $DB_HASH is actually a pre-defined reference to a
Packit bc69c3
hash object. B<DB_File> has three of these pre-defined references.
Packit bc69c3
Apart from $DB_HASH, there is also $DB_BTREE and $DB_RECNO.
Packit bc69c3
Packit bc69c3
The keys allowed in each of these pre-defined references is limited to
Packit bc69c3
the names used in the equivalent C structure. So, for example, the
Packit bc69c3
$DB_HASH reference will only allow keys called C<bsize>, C<cachesize>,
Packit bc69c3
C<ffactor>, C<hash>, C<lorder> and C<nelem>. 
Packit bc69c3
Packit bc69c3
To change one of these elements, just assign to it like this:
Packit bc69c3
Packit bc69c3
	$DB_HASH->{'cachesize'} = 10000 ;
Packit bc69c3
Packit bc69c3
The three predefined variables $DB_HASH, $DB_BTREE and $DB_RECNO are
Packit bc69c3
usually adequate for most applications.  If you do need to create extra
Packit bc69c3
instances of these objects, constructors are available for each file
Packit bc69c3
type.
Packit bc69c3
Packit bc69c3
Here are examples of the constructors and the valid options available
Packit bc69c3
for DB_HASH, DB_BTREE and DB_RECNO respectively.
Packit bc69c3
Packit bc69c3
     $a = new DB_File::HASHINFO ;
Packit bc69c3
     $a->{'bsize'} ;
Packit bc69c3
     $a->{'cachesize'} ;
Packit bc69c3
     $a->{'ffactor'};
Packit bc69c3
     $a->{'hash'} ;
Packit bc69c3
     $a->{'lorder'} ;
Packit bc69c3
     $a->{'nelem'} ;
Packit bc69c3
Packit bc69c3
     $b = new DB_File::BTREEINFO ;
Packit bc69c3
     $b->{'flags'} ;
Packit bc69c3
     $b->{'cachesize'} ;
Packit bc69c3
     $b->{'maxkeypage'} ;
Packit bc69c3
     $b->{'minkeypage'} ;
Packit bc69c3
     $b->{'psize'} ;
Packit bc69c3
     $b->{'compare'} ;
Packit bc69c3
     $b->{'prefix'} ;
Packit bc69c3
     $b->{'lorder'} ;
Packit bc69c3
Packit bc69c3
     $c = new DB_File::RECNOINFO ;
Packit bc69c3
     $c->{'bval'} ;
Packit bc69c3
     $c->{'cachesize'} ;
Packit bc69c3
     $c->{'psize'} ;
Packit bc69c3
     $c->{'flags'} ;
Packit bc69c3
     $c->{'lorder'} ;
Packit bc69c3
     $c->{'reclen'} ;
Packit bc69c3
     $c->{'bfname'} ;
Packit bc69c3
Packit bc69c3
The values stored in the hashes above are mostly the direct equivalent
Packit bc69c3
of their C counterpart. Like their C counterparts, all are set to a
Packit bc69c3
default values - that means you don't have to set I<all> of the
Packit bc69c3
values when you only want to change one. Here is an example:
Packit bc69c3
Packit bc69c3
     $a = new DB_File::HASHINFO ;
Packit bc69c3
     $a->{'cachesize'} =  12345 ;
Packit bc69c3
     tie %y, 'DB_File', "filename", $flags, 0777, $a ;
Packit bc69c3
Packit bc69c3
A few of the options need extra discussion here. When used, the C
Packit bc69c3
equivalent of the keys C<hash>, C<compare> and C<prefix> store pointers
Packit bc69c3
to C functions. In B<DB_File> these keys are used to store references
Packit bc69c3
to Perl subs. Below are templates for each of the subs:
Packit bc69c3
Packit bc69c3
    sub hash
Packit bc69c3
    {
Packit bc69c3
        my ($data) = @_ ;
Packit bc69c3
        ...
Packit bc69c3
        # return the hash value for $data
Packit bc69c3
	return $hash ;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    sub compare
Packit bc69c3
    {
Packit bc69c3
	my ($key, $key2) = @_ ;
Packit bc69c3
        ...
Packit bc69c3
        # return  0 if $key1 eq $key2
Packit bc69c3
        #        -1 if $key1 lt $key2
Packit bc69c3
        #         1 if $key1 gt $key2
Packit bc69c3
        return (-1 , 0 or 1) ;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    sub prefix
Packit bc69c3
    {
Packit bc69c3
	my ($key, $key2) = @_ ;
Packit bc69c3
        ...
Packit bc69c3
        # return number of bytes of $key2 which are 
Packit bc69c3
        # necessary to determine that it is greater than $key1
Packit bc69c3
        return $bytes ;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
See L<Changing the BTREE sort order> for an example of using the
Packit bc69c3
C<compare> template.
Packit bc69c3
Packit bc69c3
If you are using the DB_RECNO interface and you intend making use of
Packit bc69c3
C<bval>, you should check out L<The 'bval' Option>.
Packit bc69c3
Packit bc69c3
=head2 Default Parameters
Packit bc69c3
Packit bc69c3
It is possible to omit some or all of the final 4 parameters in the
Packit bc69c3
call to C<tie> and let them take default values. As DB_HASH is the most
Packit bc69c3
common file format used, the call:
Packit bc69c3
Packit bc69c3
    tie %A, "DB_File", "filename" ;
Packit bc69c3
Packit bc69c3
is equivalent to:
Packit bc69c3
Packit bc69c3
    tie %A, "DB_File", "filename", O_CREAT|O_RDWR, 0666, $DB_HASH ;
Packit bc69c3
Packit bc69c3
It is also possible to omit the filename parameter as well, so the
Packit bc69c3
call:
Packit bc69c3
Packit bc69c3
    tie %A, "DB_File" ;
Packit bc69c3
Packit bc69c3
is equivalent to:
Packit bc69c3
Packit bc69c3
    tie %A, "DB_File", undef, O_CREAT|O_RDWR, 0666, $DB_HASH ;
Packit bc69c3
Packit bc69c3
See L<In Memory Databases> for a discussion on the use of C<undef>
Packit bc69c3
in place of a filename.
Packit bc69c3
Packit bc69c3
=head2 In Memory Databases
Packit bc69c3
Packit bc69c3
Berkeley DB allows the creation of in-memory databases by using NULL
Packit bc69c3
(that is, a C<(char *)0> in C) in place of the filename.  B<DB_File>
Packit bc69c3
uses C<undef> instead of NULL to provide this functionality.
Packit bc69c3
Packit bc69c3
=head1 DB_HASH
Packit bc69c3
Packit bc69c3
The DB_HASH file format is probably the most commonly used of the three
Packit bc69c3
file formats that B<DB_File> supports. It is also very straightforward
Packit bc69c3
to use.
Packit bc69c3
Packit bc69c3
=head2 A Simple Example
Packit bc69c3
Packit bc69c3
This example shows how to create a database, add key/value pairs to the
Packit bc69c3
database, delete keys/value pairs and finally how to enumerate the
Packit bc69c3
contents of the database.
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
    our (%h, $k, $v) ;
Packit bc69c3
Packit bc69c3
    unlink "fruit" ;
Packit bc69c3
    tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0666, $DB_HASH 
Packit bc69c3
        or die "Cannot open file 'fruit': $!\n";
Packit bc69c3
Packit bc69c3
    # Add a few key/value pairs to the file
Packit bc69c3
    $h{"apple"} = "red" ;
Packit bc69c3
    $h{"orange"} = "orange" ;
Packit bc69c3
    $h{"banana"} = "yellow" ;
Packit bc69c3
    $h{"tomato"} = "red" ;
Packit bc69c3
Packit bc69c3
    # Check for existence of a key
Packit bc69c3
    print "Banana Exists\n\n" if $h{"banana"} ;
Packit bc69c3
Packit bc69c3
    # Delete a key/value pair.
Packit bc69c3
    delete $h{"apple"} ;
Packit bc69c3
Packit bc69c3
    # print the contents of the file
Packit bc69c3
    while (($k, $v) = each %h)
Packit bc69c3
      { print "$k -> $v\n" }
Packit bc69c3
Packit bc69c3
    untie %h ;
Packit bc69c3
Packit bc69c3
here is the output:
Packit bc69c3
Packit bc69c3
    Banana Exists
Packit bc69c3
Packit bc69c3
    orange -> orange
Packit bc69c3
    tomato -> red
Packit bc69c3
    banana -> yellow
Packit bc69c3
Packit bc69c3
Note that the like ordinary associative arrays, the order of the keys
Packit bc69c3
retrieved is in an apparently random order.
Packit bc69c3
Packit bc69c3
=head1 DB_BTREE
Packit bc69c3
Packit bc69c3
The DB_BTREE format is useful when you want to store data in a given
Packit bc69c3
order. By default the keys will be stored in lexical order, but as you
Packit bc69c3
will see from the example shown in the next section, it is very easy to
Packit bc69c3
define your own sorting function.
Packit bc69c3
Packit bc69c3
=head2 Changing the BTREE sort order
Packit bc69c3
Packit bc69c3
This script shows how to override the default sorting algorithm that
Packit bc69c3
BTREE uses. Instead of using the normal lexical ordering, a case
Packit bc69c3
insensitive compare function will be used.
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
Packit bc69c3
    my %h ;
Packit bc69c3
Packit bc69c3
    sub Compare
Packit bc69c3
    {
Packit bc69c3
        my ($key1, $key2) = @_ ;
Packit bc69c3
        "\L$key1" cmp "\L$key2" ;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    # specify the Perl sub that will do the comparison
Packit bc69c3
    $DB_BTREE->{'compare'} = \&Compare ;
Packit bc69c3
Packit bc69c3
    unlink "tree" ;
Packit bc69c3
    tie %h, "DB_File", "tree", O_RDWR|O_CREAT, 0666, $DB_BTREE 
Packit bc69c3
        or die "Cannot open file 'tree': $!\n" ;
Packit bc69c3
Packit bc69c3
    # Add a key/value pair to the file
Packit bc69c3
    $h{'Wall'} = 'Larry' ;
Packit bc69c3
    $h{'Smith'} = 'John' ;
Packit bc69c3
    $h{'mouse'} = 'mickey' ;
Packit bc69c3
    $h{'duck'}  = 'donald' ;
Packit bc69c3
Packit bc69c3
    # Delete
Packit bc69c3
    delete $h{"duck"} ;
Packit bc69c3
Packit bc69c3
    # Cycle through the keys printing them in order.
Packit bc69c3
    # Note it is not necessary to sort the keys as
Packit bc69c3
    # the btree will have kept them in order automatically.
Packit bc69c3
    foreach (keys %h)
Packit bc69c3
      { print "$_\n" }
Packit bc69c3
Packit bc69c3
    untie %h ;
Packit bc69c3
Packit bc69c3
Here is the output from the code above.
Packit bc69c3
Packit bc69c3
    mouse
Packit bc69c3
    Smith
Packit bc69c3
    Wall
Packit bc69c3
Packit bc69c3
There are a few point to bear in mind if you want to change the
Packit bc69c3
ordering in a BTREE database:
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item 1.
Packit bc69c3
Packit bc69c3
The new compare function must be specified when you create the database.
Packit bc69c3
Packit bc69c3
=item 2.
Packit bc69c3
Packit bc69c3
You cannot change the ordering once the database has been created. Thus
Packit bc69c3
you must use the same compare function every time you access the
Packit bc69c3
database.
Packit bc69c3
Packit bc69c3
=item 3
Packit bc69c3
Packit bc69c3
Duplicate keys are entirely defined by the comparison function.
Packit bc69c3
In the case-insensitive example above, the keys: 'KEY' and 'key'
Packit bc69c3
would be considered duplicates, and assigning to the second one
Packit bc69c3
would overwrite the first. If duplicates are allowed for (with the
Packit bc69c3
R_DUP flag discussed below), only a single copy of duplicate keys
Packit bc69c3
is stored in the database --- so (again with example above) assigning
Packit bc69c3
three values to the keys: 'KEY', 'Key', and 'key' would leave just
Packit bc69c3
the first key: 'KEY' in the database with three values. For some
Packit bc69c3
situations this results in information loss, so care should be taken
Packit bc69c3
to provide fully qualified comparison functions when necessary.
Packit bc69c3
For example, the above comparison routine could be modified to
Packit bc69c3
additionally compare case-sensitively if two keys are equal in the
Packit bc69c3
case insensitive comparison:
Packit bc69c3
Packit bc69c3
    sub compare {
Packit bc69c3
        my($key1, $key2) = @_;
Packit bc69c3
        lc $key1 cmp lc $key2 ||
Packit bc69c3
        $key1 cmp $key2;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
And now you will only have duplicates when the keys themselves
Packit bc69c3
are truly the same. (note: in versions of the db library prior to
Packit bc69c3
about November 1996, such duplicate keys were retained so it was
Packit bc69c3
possible to recover the original keys in sets of keys that
Packit bc69c3
compared as equal).
Packit bc69c3
Packit bc69c3
Packit bc69c3
=back 
Packit bc69c3
Packit bc69c3
=head2 Handling Duplicate Keys 
Packit bc69c3
Packit bc69c3
The BTREE file type optionally allows a single key to be associated
Packit bc69c3
with an arbitrary number of values. This option is enabled by setting
Packit bc69c3
the flags element of C<$DB_BTREE> to R_DUP when creating the database.
Packit bc69c3
Packit bc69c3
There are some difficulties in using the tied hash interface if you
Packit bc69c3
want to manipulate a BTREE database with duplicate keys. Consider this
Packit bc69c3
code:
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
Packit bc69c3
    my ($filename, %h) ;
Packit bc69c3
Packit bc69c3
    $filename = "tree" ;
Packit bc69c3
    unlink $filename ;
Packit bc69c3
Packit bc69c3
    # Enable duplicate records
Packit bc69c3
    $DB_BTREE->{'flags'} = R_DUP ;
Packit bc69c3
Packit bc69c3
    tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE 
Packit bc69c3
	or die "Cannot open $filename: $!\n";
Packit bc69c3
Packit bc69c3
    # Add some key/value pairs to the file
Packit bc69c3
    $h{'Wall'} = 'Larry' ;
Packit bc69c3
    $h{'Wall'} = 'Brick' ; # Note the duplicate key
Packit bc69c3
    $h{'Wall'} = 'Brick' ; # Note the duplicate key and value
Packit bc69c3
    $h{'Smith'} = 'John' ;
Packit bc69c3
    $h{'mouse'} = 'mickey' ;
Packit bc69c3
Packit bc69c3
    # iterate through the associative array
Packit bc69c3
    # and print each key/value pair.
Packit bc69c3
    foreach (sort keys %h)
Packit bc69c3
      { print "$_  -> $h{$_}\n" }
Packit bc69c3
Packit bc69c3
    untie %h ;
Packit bc69c3
Packit bc69c3
Here is the output:
Packit bc69c3
Packit bc69c3
    Smith   -> John
Packit bc69c3
    Wall    -> Larry
Packit bc69c3
    Wall    -> Larry
Packit bc69c3
    Wall    -> Larry
Packit bc69c3
    mouse   -> mickey
Packit bc69c3
Packit bc69c3
As you can see 3 records have been successfully created with key C<Wall>
Packit bc69c3
- the only thing is, when they are retrieved from the database they
Packit bc69c3
I<seem> to have the same value, namely C<Larry>. The problem is caused
Packit bc69c3
by the way that the associative array interface works. Basically, when
Packit bc69c3
the associative array interface is used to fetch the value associated
Packit bc69c3
with a given key, it will only ever retrieve the first value.
Packit bc69c3
Packit bc69c3
Although it may not be immediately obvious from the code above, the
Packit bc69c3
associative array interface can be used to write values with duplicate
Packit bc69c3
keys, but it cannot be used to read them back from the database.
Packit bc69c3
Packit bc69c3
The way to get around this problem is to use the Berkeley DB API method
Packit bc69c3
called C<seq>.  This method allows sequential access to key/value
Packit bc69c3
pairs. See L<THE API INTERFACE> for details of both the C<seq> method
Packit bc69c3
and the API in general.
Packit bc69c3
Packit bc69c3
Here is the script above rewritten using the C<seq> API method.
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
Packit bc69c3
    my ($filename, $x, %h, $status, $key, $value) ;
Packit bc69c3
Packit bc69c3
    $filename = "tree" ;
Packit bc69c3
    unlink $filename ;
Packit bc69c3
Packit bc69c3
    # Enable duplicate records
Packit bc69c3
    $DB_BTREE->{'flags'} = R_DUP ;
Packit bc69c3
Packit bc69c3
    $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE 
Packit bc69c3
	or die "Cannot open $filename: $!\n";
Packit bc69c3
Packit bc69c3
    # Add some key/value pairs to the file
Packit bc69c3
    $h{'Wall'} = 'Larry' ;
Packit bc69c3
    $h{'Wall'} = 'Brick' ; # Note the duplicate key
Packit bc69c3
    $h{'Wall'} = 'Brick' ; # Note the duplicate key and value
Packit bc69c3
    $h{'Smith'} = 'John' ;
Packit bc69c3
    $h{'mouse'} = 'mickey' ;
Packit bc69c3
Packit bc69c3
    # iterate through the btree using seq
Packit bc69c3
    # and print each key/value pair.
Packit bc69c3
    $key = $value = 0 ;
Packit bc69c3
    for ($status = $x->seq($key, $value, R_FIRST) ;
Packit bc69c3
         $status == 0 ;
Packit bc69c3
         $status = $x->seq($key, $value, R_NEXT) )
Packit bc69c3
      {  print "$key -> $value\n" }
Packit bc69c3
Packit bc69c3
    undef $x ;
Packit bc69c3
    untie %h ;
Packit bc69c3
Packit bc69c3
that prints:
Packit bc69c3
Packit bc69c3
    Smith   -> John
Packit bc69c3
    Wall    -> Brick
Packit bc69c3
    Wall    -> Brick
Packit bc69c3
    Wall    -> Larry
Packit bc69c3
    mouse   -> mickey
Packit bc69c3
Packit bc69c3
This time we have got all the key/value pairs, including the multiple
Packit bc69c3
values associated with the key C<Wall>.
Packit bc69c3
Packit bc69c3
To make life easier when dealing with duplicate keys, B<DB_File> comes with 
Packit bc69c3
a few utility methods.
Packit bc69c3
Packit bc69c3
=head2 The get_dup() Method
Packit bc69c3
Packit bc69c3
The C<get_dup> method assists in
Packit bc69c3
reading duplicate values from BTREE databases. The method can take the
Packit bc69c3
following forms:
Packit bc69c3
Packit bc69c3
    $count = $x->get_dup($key) ;
Packit bc69c3
    @list  = $x->get_dup($key) ;
Packit bc69c3
    %list  = $x->get_dup($key, 1) ;
Packit bc69c3
Packit bc69c3
In a scalar context the method returns the number of values associated
Packit bc69c3
with the key, C<$key>.
Packit bc69c3
Packit bc69c3
In list context, it returns all the values which match C<$key>. Note
Packit bc69c3
that the values will be returned in an apparently random order.
Packit bc69c3
Packit bc69c3
In list context, if the second parameter is present and evaluates
Packit bc69c3
TRUE, the method returns an associative array. The keys of the
Packit bc69c3
associative array correspond to the values that matched in the BTREE
Packit bc69c3
and the values of the array are a count of the number of times that
Packit bc69c3
particular value occurred in the BTREE.
Packit bc69c3
Packit bc69c3
So assuming the database created above, we can use C<get_dup> like
Packit bc69c3
this:
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
Packit bc69c3
    my ($filename, $x, %h) ;
Packit bc69c3
Packit bc69c3
    $filename = "tree" ;
Packit bc69c3
Packit bc69c3
    # Enable duplicate records
Packit bc69c3
    $DB_BTREE->{'flags'} = R_DUP ;
Packit bc69c3
Packit bc69c3
    $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE 
Packit bc69c3
	or die "Cannot open $filename: $!\n";
Packit bc69c3
Packit bc69c3
    my $cnt  = $x->get_dup("Wall") ;
Packit bc69c3
    print "Wall occurred $cnt times\n" ;
Packit bc69c3
Packit bc69c3
    my %hash = $x->get_dup("Wall", 1) ;
Packit bc69c3
    print "Larry is there\n" if $hash{'Larry'} ;
Packit bc69c3
    print "There are $hash{'Brick'} Brick Walls\n" ;
Packit bc69c3
Packit bc69c3
    my @list = sort $x->get_dup("Wall") ;
Packit bc69c3
    print "Wall =>	[@list]\n" ;
Packit bc69c3
Packit bc69c3
    @list = $x->get_dup("Smith") ;
Packit bc69c3
    print "Smith =>	[@list]\n" ;
Packit bc69c3
Packit bc69c3
    @list = $x->get_dup("Dog") ;
Packit bc69c3
    print "Dog =>	[@list]\n" ;
Packit bc69c3
Packit bc69c3
Packit bc69c3
and it will print:
Packit bc69c3
Packit bc69c3
    Wall occurred 3 times
Packit bc69c3
    Larry is there
Packit bc69c3
    There are 2 Brick Walls
Packit bc69c3
    Wall =>	[Brick Brick Larry]
Packit bc69c3
    Smith =>	[John]
Packit bc69c3
    Dog =>	[]
Packit bc69c3
Packit bc69c3
=head2 The find_dup() Method
Packit bc69c3
Packit bc69c3
    $status = $X->find_dup($key, $value) ;
Packit bc69c3
Packit bc69c3
This method checks for the existence of a specific key/value pair. If the
Packit bc69c3
pair exists, the cursor is left pointing to the pair and the method 
Packit bc69c3
returns 0. Otherwise the method returns a non-zero value.
Packit bc69c3
Packit bc69c3
Assuming the database from the previous example:
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
Packit bc69c3
    my ($filename, $x, %h, $found) ;
Packit bc69c3
Packit bc69c3
    $filename = "tree" ;
Packit bc69c3
Packit bc69c3
    # Enable duplicate records
Packit bc69c3
    $DB_BTREE->{'flags'} = R_DUP ;
Packit bc69c3
Packit bc69c3
    $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE 
Packit bc69c3
	or die "Cannot open $filename: $!\n";
Packit bc69c3
Packit bc69c3
    $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ; 
Packit bc69c3
    print "Larry Wall is $found there\n" ;
Packit bc69c3
Packit bc69c3
    $found = ( $x->find_dup("Wall", "Harry") == 0 ? "" : "not") ; 
Packit bc69c3
    print "Harry Wall is $found there\n" ;
Packit bc69c3
Packit bc69c3
    undef $x ;
Packit bc69c3
    untie %h ;
Packit bc69c3
Packit bc69c3
prints this
Packit bc69c3
Packit bc69c3
    Larry Wall is  there
Packit bc69c3
    Harry Wall is not there
Packit bc69c3
Packit bc69c3
Packit bc69c3
=head2 The del_dup() Method
Packit bc69c3
Packit bc69c3
    $status = $X->del_dup($key, $value) ;
Packit bc69c3
Packit bc69c3
This method deletes a specific key/value pair. It returns
Packit bc69c3
0 if they exist and have been deleted successfully.
Packit bc69c3
Otherwise the method returns a non-zero value.
Packit bc69c3
Packit bc69c3
Again assuming the existence of the C<tree> database
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
Packit bc69c3
    my ($filename, $x, %h, $found) ;
Packit bc69c3
Packit bc69c3
    $filename = "tree" ;
Packit bc69c3
Packit bc69c3
    # Enable duplicate records
Packit bc69c3
    $DB_BTREE->{'flags'} = R_DUP ;
Packit bc69c3
Packit bc69c3
    $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE 
Packit bc69c3
	or die "Cannot open $filename: $!\n";
Packit bc69c3
Packit bc69c3
    $x->del_dup("Wall", "Larry") ;
Packit bc69c3
Packit bc69c3
    $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ; 
Packit bc69c3
    print "Larry Wall is $found there\n" ;
Packit bc69c3
Packit bc69c3
    undef $x ;
Packit bc69c3
    untie %h ;
Packit bc69c3
Packit bc69c3
prints this
Packit bc69c3
Packit bc69c3
    Larry Wall is not there
Packit bc69c3
Packit bc69c3
=head2 Matching Partial Keys 
Packit bc69c3
Packit bc69c3
The BTREE interface has a feature which allows partial keys to be
Packit bc69c3
matched. This functionality is I<only> available when the C<seq> method
Packit bc69c3
is used along with the R_CURSOR flag.
Packit bc69c3
Packit bc69c3
    $x->seq($key, $value, R_CURSOR) ;
Packit bc69c3
Packit bc69c3
Here is the relevant quote from the dbopen man page where it defines
Packit bc69c3
the use of the R_CURSOR flag with seq:
Packit bc69c3
Packit bc69c3
    Note, for the DB_BTREE access method, the returned key is not
Packit bc69c3
    necessarily an exact match for the specified key. The returned key
Packit bc69c3
    is the smallest key greater than or equal to the specified key,
Packit bc69c3
    permitting partial key matches and range searches.
Packit bc69c3
Packit bc69c3
In the example script below, the C<match> sub uses this feature to find
Packit bc69c3
and print the first matching key/value pair given a partial key.
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
    use Fcntl ;
Packit bc69c3
Packit bc69c3
    my ($filename, $x, %h, $st, $key, $value) ;
Packit bc69c3
Packit bc69c3
    sub match
Packit bc69c3
    {
Packit bc69c3
        my $key = shift ;
Packit bc69c3
        my $value = 0;
Packit bc69c3
        my $orig_key = $key ;
Packit bc69c3
        $x->seq($key, $value, R_CURSOR) ;
Packit bc69c3
        print "$orig_key\t-> $key\t-> $value\n" ;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    $filename = "tree" ;
Packit bc69c3
    unlink $filename ;
Packit bc69c3
Packit bc69c3
    $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
Packit bc69c3
        or die "Cannot open $filename: $!\n";
Packit bc69c3
Packit bc69c3
    # Add some key/value pairs to the file
Packit bc69c3
    $h{'mouse'} = 'mickey' ;
Packit bc69c3
    $h{'Wall'} = 'Larry' ;
Packit bc69c3
    $h{'Walls'} = 'Brick' ; 
Packit bc69c3
    $h{'Smith'} = 'John' ;
Packit bc69c3
Packit bc69c3
Packit bc69c3
    $key = $value = 0 ;
Packit bc69c3
    print "IN ORDER\n" ;
Packit bc69c3
    for ($st = $x->seq($key, $value, R_FIRST) ;
Packit bc69c3
	 $st == 0 ;
Packit bc69c3
         $st = $x->seq($key, $value, R_NEXT) )
Packit bc69c3
Packit bc69c3
      {  print "$key	-> $value\n" }
Packit bc69c3
Packit bc69c3
    print "\nPARTIAL MATCH\n" ;
Packit bc69c3
Packit bc69c3
    match "Wa" ;
Packit bc69c3
    match "A" ;
Packit bc69c3
    match "a" ;
Packit bc69c3
Packit bc69c3
    undef $x ;
Packit bc69c3
    untie %h ;
Packit bc69c3
Packit bc69c3
Here is the output:
Packit bc69c3
Packit bc69c3
    IN ORDER
Packit bc69c3
    Smith -> John
Packit bc69c3
    Wall  -> Larry
Packit bc69c3
    Walls -> Brick
Packit bc69c3
    mouse -> mickey
Packit bc69c3
Packit bc69c3
    PARTIAL MATCH
Packit bc69c3
    Wa -> Wall  -> Larry
Packit bc69c3
    A  -> Smith -> John
Packit bc69c3
    a  -> mouse -> mickey
Packit bc69c3
Packit bc69c3
=head1 DB_RECNO
Packit bc69c3
Packit bc69c3
DB_RECNO provides an interface to flat text files. Both variable and
Packit bc69c3
fixed length records are supported.
Packit bc69c3
Packit bc69c3
In order to make RECNO more compatible with Perl, the array offset for
Packit bc69c3
all RECNO arrays begins at 0 rather than 1 as in Berkeley DB.
Packit bc69c3
Packit bc69c3
As with normal Perl arrays, a RECNO array can be accessed using
Packit bc69c3
negative indexes. The index -1 refers to the last element of the array,
Packit bc69c3
-2 the second last, and so on. Attempting to access an element before
Packit bc69c3
the start of the array will raise a fatal run-time error.
Packit bc69c3
Packit bc69c3
=head2 The 'bval' Option
Packit bc69c3
Packit bc69c3
The operation of the bval option warrants some discussion. Here is the
Packit bc69c3
definition of bval from the Berkeley DB 1.85 recno manual page:
Packit bc69c3
Packit bc69c3
    The delimiting byte to be used to mark  the  end  of  a
Packit bc69c3
    record for variable-length records, and the pad charac-
Packit bc69c3
    ter for fixed-length records.  If no  value  is  speci-
Packit bc69c3
    fied,  newlines  (``\n'')  are  used to mark the end of
Packit bc69c3
    variable-length records and  fixed-length  records  are
Packit bc69c3
    padded with spaces.
Packit bc69c3
Packit bc69c3
The second sentence is wrong. In actual fact bval will only default to
Packit bc69c3
C<"\n"> when the openinfo parameter in dbopen is NULL. If a non-NULL
Packit bc69c3
openinfo parameter is used at all, the value that happens to be in bval
Packit bc69c3
will be used. That means you always have to specify bval when making
Packit bc69c3
use of any of the options in the openinfo parameter. This documentation
Packit bc69c3
error will be fixed in the next release of Berkeley DB.
Packit bc69c3
Packit bc69c3
That clarifies the situation with regards Berkeley DB itself. What
Packit bc69c3
about B<DB_File>? Well, the behavior defined in the quote above is
Packit bc69c3
quite useful, so B<DB_File> conforms to it.
Packit bc69c3
Packit bc69c3
That means that you can specify other options (e.g. cachesize) and
Packit bc69c3
still have bval default to C<"\n"> for variable length records, and
Packit bc69c3
space for fixed length records.
Packit bc69c3
Packit bc69c3
Also note that the bval option only allows you to specify a single byte
Packit bc69c3
as a delimiter.
Packit bc69c3
Packit bc69c3
=head2 A Simple Example
Packit bc69c3
Packit bc69c3
Here is a simple example that uses RECNO (if you are using a version 
Packit bc69c3
of Perl earlier than 5.004_57 this example won't work -- see 
Packit bc69c3
L<Extra RECNO Methods> for a workaround).
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
Packit bc69c3
    my $filename = "text" ;
Packit bc69c3
    unlink $filename ;
Packit bc69c3
Packit bc69c3
    my @h ;
Packit bc69c3
    tie @h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_RECNO 
Packit bc69c3
        or die "Cannot open file 'text': $!\n" ;
Packit bc69c3
Packit bc69c3
    # Add a few key/value pairs to the file
Packit bc69c3
    $h[0] = "orange" ;
Packit bc69c3
    $h[1] = "blue" ;
Packit bc69c3
    $h[2] = "yellow" ;
Packit bc69c3
Packit bc69c3
    push @h, "green", "black" ;
Packit bc69c3
Packit bc69c3
    my $elements = scalar @h ;
Packit bc69c3
    print "The array contains $elements entries\n" ;
Packit bc69c3
Packit bc69c3
    my $last = pop @h ;
Packit bc69c3
    print "popped $last\n" ;
Packit bc69c3
Packit bc69c3
    unshift @h, "white" ;
Packit bc69c3
    my $first = shift @h ;
Packit bc69c3
    print "shifted $first\n" ;
Packit bc69c3
Packit bc69c3
    # Check for existence of a key
Packit bc69c3
    print "Element 1 Exists with value $h[1]\n" if $h[1] ;
Packit bc69c3
Packit bc69c3
    # use a negative index
Packit bc69c3
    print "The last element is $h[-1]\n" ;
Packit bc69c3
    print "The 2nd last element is $h[-2]\n" ;
Packit bc69c3
Packit bc69c3
    untie @h ;
Packit bc69c3
Packit bc69c3
Here is the output from the script:
Packit bc69c3
Packit bc69c3
    The array contains 5 entries
Packit bc69c3
    popped black
Packit bc69c3
    shifted white
Packit bc69c3
    Element 1 Exists with value blue
Packit bc69c3
    The last element is green
Packit bc69c3
    The 2nd last element is yellow
Packit bc69c3
Packit bc69c3
=head2 Extra RECNO Methods
Packit bc69c3
Packit bc69c3
If you are using a version of Perl earlier than 5.004_57, the tied
Packit bc69c3
array interface is quite limited. In the example script above
Packit bc69c3
C<push>, C<pop>, C<shift>, C<unshift>
Packit bc69c3
or determining the array length will not work with a tied array.
Packit bc69c3
Packit bc69c3
To make the interface more useful for older versions of Perl, a number
Packit bc69c3
of methods are supplied with B<DB_File> to simulate the missing array
Packit bc69c3
operations. All these methods are accessed via the object returned from
Packit bc69c3
the tie call.
Packit bc69c3
Packit bc69c3
Here are the methods:
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item B<$X-E<gt>push(list) ;>
Packit bc69c3
Packit bc69c3
Pushes the elements of C<list> to the end of the array.
Packit bc69c3
Packit bc69c3
=item B<$value = $X-E<gt>pop ;>
Packit bc69c3
Packit bc69c3
Removes and returns the last element of the array.
Packit bc69c3
Packit bc69c3
=item B<$X-E<gt>shift>
Packit bc69c3
Packit bc69c3
Removes and returns the first element of the array.
Packit bc69c3
Packit bc69c3
=item B<$X-E<gt>unshift(list) ;>
Packit bc69c3
Packit bc69c3
Pushes the elements of C<list> to the start of the array.
Packit bc69c3
Packit bc69c3
=item B<$X-E<gt>length>
Packit bc69c3
Packit bc69c3
Returns the number of elements in the array.
Packit bc69c3
Packit bc69c3
=item B<$X-E<gt>splice(offset, length, elements);>
Packit bc69c3
Packit bc69c3
Returns a splice of the array.
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
=head2 Another Example
Packit bc69c3
Packit bc69c3
Here is a more complete example that makes use of some of the methods
Packit bc69c3
described above. It also makes use of the API interface directly (see 
Packit bc69c3
L<THE API INTERFACE>).
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    my (@h, $H, $file, $i) ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
    use Fcntl ;
Packit bc69c3
Packit bc69c3
    $file = "text" ;
Packit bc69c3
Packit bc69c3
    unlink $file ;
Packit bc69c3
Packit bc69c3
    $H = tie @h, "DB_File", $file, O_RDWR|O_CREAT, 0666, $DB_RECNO 
Packit bc69c3
        or die "Cannot open file $file: $!\n" ;
Packit bc69c3
Packit bc69c3
    # first create a text file to play with
Packit bc69c3
    $h[0] = "zero" ;
Packit bc69c3
    $h[1] = "one" ;
Packit bc69c3
    $h[2] = "two" ;
Packit bc69c3
    $h[3] = "three" ;
Packit bc69c3
    $h[4] = "four" ;
Packit bc69c3
Packit bc69c3
Packit bc69c3
    # Print the records in order.
Packit bc69c3
    #
Packit bc69c3
    # The length method is needed here because evaluating a tied
Packit bc69c3
    # array in a scalar context does not return the number of
Packit bc69c3
    # elements in the array.  
Packit bc69c3
Packit bc69c3
    print "\nORIGINAL\n" ;
Packit bc69c3
    foreach $i (0 .. $H->length - 1) {
Packit bc69c3
        print "$i: $h[$i]\n" ;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    # use the push & pop methods
Packit bc69c3
    $a = $H->pop ;
Packit bc69c3
    $H->push("last") ;
Packit bc69c3
    print "\nThe last record was [$a]\n" ;
Packit bc69c3
Packit bc69c3
    # and the shift & unshift methods
Packit bc69c3
    $a = $H->shift ;
Packit bc69c3
    $H->unshift("first") ;
Packit bc69c3
    print "The first record was [$a]\n" ;
Packit bc69c3
Packit bc69c3
    # Use the API to add a new record after record 2.
Packit bc69c3
    $i = 2 ;
Packit bc69c3
    $H->put($i, "Newbie", R_IAFTER) ;
Packit bc69c3
Packit bc69c3
    # and a new record before record 1.
Packit bc69c3
    $i = 1 ;
Packit bc69c3
    $H->put($i, "New One", R_IBEFORE) ;
Packit bc69c3
Packit bc69c3
    # delete record 3
Packit bc69c3
    $H->del(3) ;
Packit bc69c3
Packit bc69c3
    # now print the records in reverse order
Packit bc69c3
    print "\nREVERSE\n" ;
Packit bc69c3
    for ($i = $H->length - 1 ; $i >= 0 ; -- $i)
Packit bc69c3
      { print "$i: $h[$i]\n" }
Packit bc69c3
Packit bc69c3
    # same again, but use the API functions instead
Packit bc69c3
    print "\nREVERSE again\n" ;
Packit bc69c3
    my ($s, $k, $v)  = (0, 0, 0) ;
Packit bc69c3
    for ($s = $H->seq($k, $v, R_LAST) ; 
Packit bc69c3
             $s == 0 ; 
Packit bc69c3
             $s = $H->seq($k, $v, R_PREV))
Packit bc69c3
      { print "$k: $v\n" }
Packit bc69c3
Packit bc69c3
    undef $H ;
Packit bc69c3
    untie @h ;
Packit bc69c3
Packit bc69c3
and this is what it outputs:
Packit bc69c3
Packit bc69c3
    ORIGINAL
Packit bc69c3
    0: zero
Packit bc69c3
    1: one
Packit bc69c3
    2: two
Packit bc69c3
    3: three
Packit bc69c3
    4: four
Packit bc69c3
Packit bc69c3
    The last record was [four]
Packit bc69c3
    The first record was [zero]
Packit bc69c3
Packit bc69c3
    REVERSE
Packit bc69c3
    5: last
Packit bc69c3
    4: three
Packit bc69c3
    3: Newbie
Packit bc69c3
    2: one
Packit bc69c3
    1: New One
Packit bc69c3
    0: first
Packit bc69c3
Packit bc69c3
    REVERSE again
Packit bc69c3
    5: last
Packit bc69c3
    4: three
Packit bc69c3
    3: Newbie
Packit bc69c3
    2: one
Packit bc69c3
    1: New One
Packit bc69c3
    0: first
Packit bc69c3
Packit bc69c3
Notes:
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item 1.
Packit bc69c3
Packit bc69c3
Rather than iterating through the array, C<@h> like this:
Packit bc69c3
Packit bc69c3
    foreach $i (@h)
Packit bc69c3
Packit bc69c3
it is necessary to use either this:
Packit bc69c3
Packit bc69c3
    foreach $i (0 .. $H->length - 1) 
Packit bc69c3
Packit bc69c3
or this:
Packit bc69c3
Packit bc69c3
    for ($a = $H->get($k, $v, R_FIRST) ;
Packit bc69c3
         $a == 0 ;
Packit bc69c3
         $a = $H->get($k, $v, R_NEXT) )
Packit bc69c3
Packit bc69c3
=item 2.
Packit bc69c3
Packit bc69c3
Notice that both times the C<put> method was used the record index was
Packit bc69c3
specified using a variable, C<$i>, rather than the literal value
Packit bc69c3
itself. This is because C<put> will return the record number of the
Packit bc69c3
inserted line via that parameter.
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
=head1 THE API INTERFACE
Packit bc69c3
Packit bc69c3
As well as accessing Berkeley DB using a tied hash or array, it is also
Packit bc69c3
possible to make direct use of most of the API functions defined in the
Packit bc69c3
Berkeley DB documentation.
Packit bc69c3
Packit bc69c3
To do this you need to store a copy of the object returned from the tie.
Packit bc69c3
Packit bc69c3
	$db = tie %hash, "DB_File", "filename" ;
Packit bc69c3
Packit bc69c3
Once you have done that, you can access the Berkeley DB API functions
Packit bc69c3
as B<DB_File> methods directly like this:
Packit bc69c3
Packit bc69c3
	$db->put($key, $value, R_NOOVERWRITE) ;
Packit bc69c3
Packit bc69c3
B<Important:> If you have saved a copy of the object returned from
Packit bc69c3
C<tie>, the underlying database file will I<not> be closed until both
Packit bc69c3
the tied variable is untied and all copies of the saved object are
Packit bc69c3
destroyed. 
Packit bc69c3
Packit bc69c3
    use DB_File ;
Packit bc69c3
    $db = tie %hash, "DB_File", "filename" 
Packit bc69c3
        or die "Cannot tie filename: $!" ;
Packit bc69c3
    ...
Packit bc69c3
    undef $db ;
Packit bc69c3
    untie %hash ;
Packit bc69c3
Packit bc69c3
See L<The untie() Gotcha> for more details.
Packit bc69c3
Packit bc69c3
All the functions defined in L<dbopen> are available except for
Packit bc69c3
close() and dbopen() itself. The B<DB_File> method interface to the
Packit bc69c3
supported functions have been implemented to mirror the way Berkeley DB
Packit bc69c3
works whenever possible. In particular note that:
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item *
Packit bc69c3
Packit bc69c3
The methods return a status value. All return 0 on success.
Packit bc69c3
All return -1 to signify an error and set C<$!> to the exact
Packit bc69c3
error code. The return code 1 generally (but not always) means that the
Packit bc69c3
key specified did not exist in the database.
Packit bc69c3
Packit bc69c3
Other return codes are defined. See below and in the Berkeley DB
Packit bc69c3
documentation for details. The Berkeley DB documentation should be used
Packit bc69c3
as the definitive source.
Packit bc69c3
Packit bc69c3
=item *
Packit bc69c3
Packit bc69c3
Whenever a Berkeley DB function returns data via one of its parameters,
Packit bc69c3
the equivalent B<DB_File> method does exactly the same.
Packit bc69c3
Packit bc69c3
=item *
Packit bc69c3
Packit bc69c3
If you are careful, it is possible to mix API calls with the tied
Packit bc69c3
hash/array interface in the same piece of code. Although only a few of
Packit bc69c3
the methods used to implement the tied interface currently make use of
Packit bc69c3
the cursor, you should always assume that the cursor has been changed
Packit bc69c3
any time the tied hash/array interface is used. As an example, this
Packit bc69c3
code will probably not do what you expect:
Packit bc69c3
Packit bc69c3
    $X = tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE
Packit bc69c3
        or die "Cannot tie $filename: $!" ;
Packit bc69c3
Packit bc69c3
    # Get the first key/value pair and set  the cursor
Packit bc69c3
    $X->seq($key, $value, R_FIRST) ;
Packit bc69c3
Packit bc69c3
    # this line will modify the cursor
Packit bc69c3
    $count = scalar keys %x ; 
Packit bc69c3
Packit bc69c3
    # Get the second key/value pair.
Packit bc69c3
    # oops, it didn't, it got the last key/value pair!
Packit bc69c3
    $X->seq($key, $value, R_NEXT) ;
Packit bc69c3
Packit bc69c3
The code above can be rearranged to get around the problem, like this:
Packit bc69c3
Packit bc69c3
    $X = tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE
Packit bc69c3
        or die "Cannot tie $filename: $!" ;
Packit bc69c3
Packit bc69c3
    # this line will modify the cursor
Packit bc69c3
    $count = scalar keys %x ; 
Packit bc69c3
Packit bc69c3
    # Get the first key/value pair and set  the cursor
Packit bc69c3
    $X->seq($key, $value, R_FIRST) ;
Packit bc69c3
Packit bc69c3
    # Get the second key/value pair.
Packit bc69c3
    # worked this time.
Packit bc69c3
    $X->seq($key, $value, R_NEXT) ;
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
All the constants defined in L<dbopen> for use in the flags parameters
Packit bc69c3
in the methods defined below are also available. Refer to the Berkeley
Packit bc69c3
DB documentation for the precise meaning of the flags values.
Packit bc69c3
Packit bc69c3
Below is a list of the methods available.
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item B<$status = $X-E<gt>get($key, $value [, $flags]) ;>
Packit bc69c3
Packit bc69c3
Given a key (C<$key>) this method reads the value associated with it
Packit bc69c3
from the database. The value read from the database is returned in the
Packit bc69c3
C<$value> parameter.
Packit bc69c3
Packit bc69c3
If the key does not exist the method returns 1.
Packit bc69c3
Packit bc69c3
No flags are currently defined for this method.
Packit bc69c3
Packit bc69c3
=item B<$status = $X-E<gt>put($key, $value [, $flags]) ;>
Packit bc69c3
Packit bc69c3
Stores the key/value pair in the database.
Packit bc69c3
Packit bc69c3
If you use either the R_IAFTER or R_IBEFORE flags, the C<$key> parameter
Packit bc69c3
will have the record number of the inserted key/value pair set.
Packit bc69c3
Packit bc69c3
Valid flags are R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE and
Packit bc69c3
R_SETCURSOR.
Packit bc69c3
Packit bc69c3
=item B<$status = $X-E<gt>del($key [, $flags]) ;>
Packit bc69c3
Packit bc69c3
Removes all key/value pairs with key C<$key> from the database.
Packit bc69c3
Packit bc69c3
A return code of 1 means that the requested key was not in the
Packit bc69c3
database.
Packit bc69c3
Packit bc69c3
R_CURSOR is the only valid flag at present.
Packit bc69c3
Packit bc69c3
=item B<$status = $X-E<gt>fd ;>
Packit bc69c3
Packit bc69c3
Returns the file descriptor for the underlying database.
Packit bc69c3
Packit bc69c3
See L<Locking: The Trouble with fd> for an explanation for why you should
Packit bc69c3
not use C<fd> to lock your database.
Packit bc69c3
Packit bc69c3
=item B<$status = $X-E<gt>seq($key, $value, $flags) ;>
Packit bc69c3
Packit bc69c3
This interface allows sequential retrieval from the database. See
Packit bc69c3
L<dbopen> for full details.
Packit bc69c3
Packit bc69c3
Both the C<$key> and C<$value> parameters will be set to the key/value
Packit bc69c3
pair read from the database.
Packit bc69c3
Packit bc69c3
The flags parameter is mandatory. The valid flag values are R_CURSOR,
Packit bc69c3
R_FIRST, R_LAST, R_NEXT and R_PREV.
Packit bc69c3
Packit bc69c3
=item B<$status = $X-E<gt>sync([$flags]) ;>
Packit bc69c3
Packit bc69c3
Flushes any cached buffers to disk.
Packit bc69c3
Packit bc69c3
R_RECNOSYNC is the only valid flag at present.
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
=head1 DBM FILTERS
Packit bc69c3
Packit bc69c3
A DBM Filter is a piece of code that is be used when you I<always> want to
Packit bc69c3
make the same transformation to all keys and/or values in a DBM database.
Packit bc69c3
An example is when you need to encode your data in UTF-8 before writing to
Packit bc69c3
the database and then decode the UTF-8 when reading from the database file.
Packit bc69c3
Packit bc69c3
There are two ways to use a DBM Filter.
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item 1.
Packit bc69c3
Packit bc69c3
Using the low-level API defined below.
Packit bc69c3
Packit bc69c3
=item 2.
Packit bc69c3
Packit bc69c3
Using the L<DBM_Filter> module. 
Packit bc69c3
This module hides the complexity of the API defined below and comes
Packit bc69c3
with a number of "canned" filters that cover some of the common use-cases.
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
Use of the L<DBM_Filter> module is recommended.
Packit bc69c3
Packit bc69c3
=head2 DBM Filter Low-level API
Packit bc69c3
Packit bc69c3
There are four methods associated with DBM Filters. All work identically,
Packit bc69c3
and each is used to install (or uninstall) a single DBM Filter. Each
Packit bc69c3
expects a single parameter, namely a reference to a sub. The only
Packit bc69c3
difference between them is the place that the filter is installed.
Packit bc69c3
Packit bc69c3
To summarise:
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item B<filter_store_key>
Packit bc69c3
Packit bc69c3
If a filter has been installed with this method, it will be invoked
Packit bc69c3
every time you write a key to a DBM database.
Packit bc69c3
Packit bc69c3
=item B<filter_store_value>
Packit bc69c3
Packit bc69c3
If a filter has been installed with this method, it will be invoked
Packit bc69c3
every time you write a value to a DBM database.
Packit bc69c3
Packit bc69c3
Packit bc69c3
=item B<filter_fetch_key>
Packit bc69c3
Packit bc69c3
If a filter has been installed with this method, it will be invoked
Packit bc69c3
every time you read a key from a DBM database.
Packit bc69c3
Packit bc69c3
=item B<filter_fetch_value>
Packit bc69c3
Packit bc69c3
If a filter has been installed with this method, it will be invoked
Packit bc69c3
every time you read a value from a DBM database.
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
You can use any combination of the methods, from none, to all four.
Packit bc69c3
Packit bc69c3
All filter methods return the existing filter, if present, or C<undef>
Packit bc69c3
in not.
Packit bc69c3
Packit bc69c3
To delete a filter pass C<undef> to it.
Packit bc69c3
Packit bc69c3
=head2 The Filter
Packit bc69c3
Packit bc69c3
When each filter is called by Perl, a local copy of C<$_> will contain
Packit bc69c3
the key or value to be filtered. Filtering is achieved by modifying
Packit bc69c3
the contents of C<$_>. The return code from the filter is ignored.
Packit bc69c3
Packit bc69c3
=head2 An Example -- the NULL termination problem.
Packit bc69c3
Packit bc69c3
Consider the following scenario. You have a DBM database
Packit bc69c3
that you need to share with a third-party C application. The C application
Packit bc69c3
assumes that I<all> keys and values are NULL terminated. Unfortunately
Packit bc69c3
when Perl writes to DBM databases it doesn't use NULL termination, so
Packit bc69c3
your Perl application will have to manage NULL termination itself. When
Packit bc69c3
you write to the database you will have to use something like this:
Packit bc69c3
Packit bc69c3
    $hash{"$key\0"} = "$value\0" ;
Packit bc69c3
Packit bc69c3
Similarly the NULL needs to be taken into account when you are considering
Packit bc69c3
the length of existing keys/values.
Packit bc69c3
Packit bc69c3
It would be much better if you could ignore the NULL terminations issue
Packit bc69c3
in the main application code and have a mechanism that automatically
Packit bc69c3
added the terminating NULL to all keys and values whenever you write to
Packit bc69c3
the database and have them removed when you read from the database. As I'm
Packit bc69c3
sure you have already guessed, this is a problem that DBM Filters can
Packit bc69c3
fix very easily.
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
Packit bc69c3
    my %hash ;
Packit bc69c3
    my $filename = "filt" ;
Packit bc69c3
    unlink $filename ;
Packit bc69c3
Packit bc69c3
    my $db = tie %hash, 'DB_File', $filename, O_CREAT|O_RDWR, 0666, $DB_HASH 
Packit bc69c3
      or die "Cannot open $filename: $!\n" ;
Packit bc69c3
Packit bc69c3
    # Install DBM Filters
Packit bc69c3
    $db->filter_fetch_key  ( sub { s/\0$//    } ) ;
Packit bc69c3
    $db->filter_store_key  ( sub { $_ .= "\0" } ) ;
Packit bc69c3
    $db->filter_fetch_value( sub { s/\0$//    } ) ;
Packit bc69c3
    $db->filter_store_value( sub { $_ .= "\0" } ) ;
Packit bc69c3
Packit bc69c3
    $hash{"abc"} = "def" ;
Packit bc69c3
    my $a = $hash{"ABC"} ;
Packit bc69c3
    # ...
Packit bc69c3
    undef $db ;
Packit bc69c3
    untie %hash ;
Packit bc69c3
Packit bc69c3
Hopefully the contents of each of the filters should be
Packit bc69c3
self-explanatory. Both "fetch" filters remove the terminating NULL,
Packit bc69c3
and both "store" filters add a terminating NULL.
Packit bc69c3
Packit bc69c3
Packit bc69c3
=head2 Another Example -- Key is a C int.
Packit bc69c3
Packit bc69c3
Here is another real-life example. By default, whenever Perl writes to
Packit bc69c3
a DBM database it always writes the key and value as strings. So when
Packit bc69c3
you use this:
Packit bc69c3
Packit bc69c3
    $hash{12345} = "something" ;
Packit bc69c3
Packit bc69c3
the key 12345 will get stored in the DBM database as the 5 byte string
Packit bc69c3
"12345". If you actually want the key to be stored in the DBM database
Packit bc69c3
as a C int, you will have to use C<pack> when writing, and C<unpack>
Packit bc69c3
when reading.
Packit bc69c3
Packit bc69c3
Here is a DBM Filter that does it:
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
    my %hash ;
Packit bc69c3
    my $filename = "filt" ;
Packit bc69c3
    unlink $filename ;
Packit bc69c3
Packit bc69c3
Packit bc69c3
    my $db = tie %hash, 'DB_File', $filename, O_CREAT|O_RDWR, 0666, $DB_HASH 
Packit bc69c3
      or die "Cannot open $filename: $!\n" ;
Packit bc69c3
Packit bc69c3
    $db->filter_fetch_key  ( sub { $_ = unpack("i", $_) } ) ;
Packit bc69c3
    $db->filter_store_key  ( sub { $_ = pack ("i", $_) } ) ;
Packit bc69c3
    $hash{123} = "def" ;
Packit bc69c3
    # ...
Packit bc69c3
    undef $db ;
Packit bc69c3
    untie %hash ;
Packit bc69c3
Packit bc69c3
This time only two filters have been used -- we only need to manipulate
Packit bc69c3
the contents of the key, so it wasn't necessary to install any value
Packit bc69c3
filters.
Packit bc69c3
Packit bc69c3
=head1 HINTS AND TIPS 
Packit bc69c3
Packit bc69c3
Packit bc69c3
=head2 Locking: The Trouble with fd
Packit bc69c3
Packit bc69c3
Until version 1.72 of this module, the recommended technique for locking
Packit bc69c3
B<DB_File> databases was to flock the filehandle returned from the "fd"
Packit bc69c3
function. Unfortunately this technique has been shown to be fundamentally
Packit bc69c3
flawed (Kudos to David Harris for tracking this down). Use it at your own
Packit bc69c3
peril!
Packit bc69c3
Packit bc69c3
The locking technique went like this. 
Packit bc69c3
Packit bc69c3
    $db = tie(%db, 'DB_File', 'foo.db', O_CREAT|O_RDWR, 0644)
Packit bc69c3
        || die "dbcreat foo.db $!";
Packit bc69c3
    $fd = $db->fd;
Packit bc69c3
    open(DB_FH, "+<&=$fd") || die "dup $!";
Packit bc69c3
    flock (DB_FH, LOCK_EX) || die "flock: $!";
Packit bc69c3
    ...
Packit bc69c3
    $db{"Tom"} = "Jerry" ;
Packit bc69c3
    ...
Packit bc69c3
    flock(DB_FH, LOCK_UN);
Packit bc69c3
    undef $db;
Packit bc69c3
    untie %db;
Packit bc69c3
    close(DB_FH);
Packit bc69c3
Packit bc69c3
In simple terms, this is what happens:
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item 1.
Packit bc69c3
Packit bc69c3
Use "tie" to open the database.
Packit bc69c3
Packit bc69c3
=item 2.
Packit bc69c3
Packit bc69c3
Lock the database with fd & flock.
Packit bc69c3
Packit bc69c3
=item 3.
Packit bc69c3
Packit bc69c3
Read & Write to the database.
Packit bc69c3
Packit bc69c3
=item 4.
Packit bc69c3
Packit bc69c3
Unlock and close the database.
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
Here is the crux of the problem. A side-effect of opening the B<DB_File>
Packit bc69c3
database in step 2 is that an initial block from the database will get
Packit bc69c3
read from disk and cached in memory.
Packit bc69c3
Packit bc69c3
To see why this is a problem, consider what can happen when two processes,
Packit bc69c3
say "A" and "B", both want to update the same B<DB_File> database
Packit bc69c3
using the locking steps outlined above. Assume process "A" has already
Packit bc69c3
opened the database and has a write lock, but it hasn't actually updated
Packit bc69c3
the database yet (it has finished step 2, but not started step 3 yet). Now
Packit bc69c3
process "B" tries to open the same database - step 1 will succeed,
Packit bc69c3
but it will block on step 2 until process "A" releases the lock. The
Packit bc69c3
important thing to notice here is that at this point in time both
Packit bc69c3
processes will have cached identical initial blocks from the database.
Packit bc69c3
Packit bc69c3
Now process "A" updates the database and happens to change some of the
Packit bc69c3
data held in the initial buffer. Process "A" terminates, flushing
Packit bc69c3
all cached data to disk and releasing the database lock. At this point
Packit bc69c3
the database on disk will correctly reflect the changes made by process
Packit bc69c3
"A".
Packit bc69c3
Packit bc69c3
With the lock released, process "B" can now continue. It also updates the
Packit bc69c3
database and unfortunately it too modifies the data that was in its
Packit bc69c3
initial buffer. Once that data gets flushed to disk it will overwrite
Packit bc69c3
some/all of the changes process "A" made to the database.
Packit bc69c3
Packit bc69c3
The result of this scenario is at best a database that doesn't contain
Packit bc69c3
what you expect. At worst the database will corrupt.
Packit bc69c3
Packit bc69c3
The above won't happen every time competing process update the same
Packit bc69c3
B<DB_File> database, but it does illustrate why the technique should
Packit bc69c3
not be used.
Packit bc69c3
Packit bc69c3
=head2 Safe ways to lock a database
Packit bc69c3
Packit bc69c3
Starting with version 2.x, Berkeley DB  has internal support for locking.
Packit bc69c3
The companion module to this one, B<BerkeleyDB>, provides an interface
Packit bc69c3
to this locking functionality. If you are serious about locking
Packit bc69c3
Berkeley DB databases, I strongly recommend using B<BerkeleyDB>.
Packit bc69c3
Packit bc69c3
If using B<BerkeleyDB> isn't an option, there are a number of modules
Packit bc69c3
available on CPAN that can be used to implement locking. Each one
Packit bc69c3
implements locking differently and has different goals in mind. It is
Packit bc69c3
therefore worth knowing the difference, so that you can pick the right
Packit bc69c3
one for your application. Here are the three locking wrappers:
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item B<Tie::DB_Lock>
Packit bc69c3
Packit bc69c3
A B<DB_File> wrapper which creates copies of the database file for
Packit bc69c3
read access, so that you have a kind of a multiversioning concurrent read
Packit bc69c3
system. However, updates are still serial. Use for databases where reads
Packit bc69c3
may be lengthy and consistency problems may occur.
Packit bc69c3
Packit bc69c3
=item B<Tie::DB_LockFile> 
Packit bc69c3
Packit bc69c3
A B<DB_File> wrapper that has the ability to lock and unlock the database
Packit bc69c3
while it is being used. Avoids the tie-before-flock problem by simply
Packit bc69c3
re-tie-ing the database when you get or drop a lock.  Because of the
Packit bc69c3
flexibility in dropping and re-acquiring the lock in the middle of a
Packit bc69c3
session, this can be massaged into a system that will work with long
Packit bc69c3
updates and/or reads if the application follows the hints in the POD
Packit bc69c3
documentation.
Packit bc69c3
Packit bc69c3
=item B<DB_File::Lock> 
Packit bc69c3
Packit bc69c3
An extremely lightweight B<DB_File> wrapper that simply flocks a lockfile
Packit bc69c3
before tie-ing the database and drops the lock after the untie. Allows
Packit bc69c3
one to use the same lockfile for multiple databases to avoid deadlock
Packit bc69c3
problems, if desired. Use for databases where updates are reads are
Packit bc69c3
quick and simple flock locking semantics are enough.
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
=head2 Sharing Databases With C Applications
Packit bc69c3
Packit bc69c3
There is no technical reason why a Berkeley DB database cannot be
Packit bc69c3
shared by both a Perl and a C application.
Packit bc69c3
Packit bc69c3
The vast majority of problems that are reported in this area boil down
Packit bc69c3
to the fact that C strings are NULL terminated, whilst Perl strings are
Packit bc69c3
not. See L<DBM FILTERS> for a generic way to work around this problem.
Packit bc69c3
Packit bc69c3
Here is a real example. Netscape 2.0 keeps a record of the locations you
Packit bc69c3
visit along with the time you last visited them in a DB_HASH database.
Packit bc69c3
This is usually stored in the file F<~/.netscape/history.db>. The key
Packit bc69c3
field in the database is the location string and the value field is the
Packit bc69c3
time the location was last visited stored as a 4 byte binary value.
Packit bc69c3
Packit bc69c3
If you haven't already guessed, the location string is stored with a
Packit bc69c3
terminating NULL. This means you need to be careful when accessing the
Packit bc69c3
database.
Packit bc69c3
Packit bc69c3
Here is a snippet of code that is loosely based on Tom Christiansen's
Packit bc69c3
I<ggh> script (available from your nearest CPAN archive in
Packit bc69c3
F<authors/id/TOMC/scripts/nshist.gz>).
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
    use Fcntl ;
Packit bc69c3
Packit bc69c3
    my ($dotdir, $HISTORY, %hist_db, $href, $binary_time, $date) ;
Packit bc69c3
    $dotdir = $ENV{HOME} || $ENV{LOGNAME};
Packit bc69c3
Packit bc69c3
    $HISTORY = "$dotdir/.netscape/history.db";
Packit bc69c3
Packit bc69c3
    tie %hist_db, 'DB_File', $HISTORY
Packit bc69c3
        or die "Cannot open $HISTORY: $!\n" ;;
Packit bc69c3
Packit bc69c3
    # Dump the complete database
Packit bc69c3
    while ( ($href, $binary_time) = each %hist_db ) {
Packit bc69c3
Packit bc69c3
        # remove the terminating NULL
Packit bc69c3
        $href =~ s/\x00$// ;
Packit bc69c3
Packit bc69c3
        # convert the binary time into a user friendly string
Packit bc69c3
        $date = localtime unpack("V", $binary_time);
Packit bc69c3
        print "$date $href\n" ;
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    # check for the existence of a specific key
Packit bc69c3
    # remember to add the NULL
Packit bc69c3
    if ( $binary_time = $hist_db{"http://mox.perl.com/\x00"} ) {
Packit bc69c3
        $date = localtime unpack("V", $binary_time) ;
Packit bc69c3
        print "Last visited mox.perl.com on $date\n" ;
Packit bc69c3
    }
Packit bc69c3
    else {
Packit bc69c3
        print "Never visited mox.perl.com\n"
Packit bc69c3
    }
Packit bc69c3
Packit bc69c3
    untie %hist_db ;
Packit bc69c3
Packit bc69c3
=head2 The untie() Gotcha
Packit bc69c3
Packit bc69c3
If you make use of the Berkeley DB API, it is I<very> strongly
Packit bc69c3
recommended that you read L<perltie/The untie Gotcha>. 
Packit bc69c3
Packit bc69c3
Even if you don't currently make use of the API interface, it is still
Packit bc69c3
worth reading it.
Packit bc69c3
Packit bc69c3
Here is an example which illustrates the problem from a B<DB_File>
Packit bc69c3
perspective:
Packit bc69c3
Packit bc69c3
    use DB_File ;
Packit bc69c3
    use Fcntl ;
Packit bc69c3
Packit bc69c3
    my %x ;
Packit bc69c3
    my $X ;
Packit bc69c3
Packit bc69c3
    $X = tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_TRUNC
Packit bc69c3
        or die "Cannot tie first time: $!" ;
Packit bc69c3
Packit bc69c3
    $x{123} = 456 ;
Packit bc69c3
Packit bc69c3
    untie %x ;
Packit bc69c3
Packit bc69c3
    tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_CREAT
Packit bc69c3
        or die "Cannot tie second time: $!" ;
Packit bc69c3
Packit bc69c3
    untie %x ;
Packit bc69c3
Packit bc69c3
When run, the script will produce this error message:
Packit bc69c3
Packit bc69c3
    Cannot tie second time: Invalid argument at bad.file line 14.
Packit bc69c3
Packit bc69c3
Although the error message above refers to the second tie() statement
Packit bc69c3
in the script, the source of the problem is really with the untie()
Packit bc69c3
statement that precedes it.
Packit bc69c3
Packit bc69c3
Having read L<perltie> you will probably have already guessed that the
Packit bc69c3
error is caused by the extra copy of the tied object stored in C<$X>.
Packit bc69c3
If you haven't, then the problem boils down to the fact that the
Packit bc69c3
B<DB_File> destructor, DESTROY, will not be called until I<all>
Packit bc69c3
references to the tied object are destroyed. Both the tied variable,
Packit bc69c3
C<%x>, and C<$X> above hold a reference to the object. The call to
Packit bc69c3
untie() will destroy the first, but C<$X> still holds a valid
Packit bc69c3
reference, so the destructor will not get called and the database file
Packit bc69c3
F<tst.fil> will remain open. The fact that Berkeley DB then reports the
Packit bc69c3
attempt to open a database that is already open via the catch-all
Packit bc69c3
"Invalid argument" doesn't help.
Packit bc69c3
Packit bc69c3
If you run the script with the C<-w> flag the error message becomes:
Packit bc69c3
Packit bc69c3
    untie attempted while 1 inner references still exist at bad.file line 12.
Packit bc69c3
    Cannot tie second time: Invalid argument at bad.file line 14.
Packit bc69c3
Packit bc69c3
which pinpoints the real problem. Finally the script can now be
Packit bc69c3
modified to fix the original problem by destroying the API object
Packit bc69c3
before the untie:
Packit bc69c3
Packit bc69c3
    ...
Packit bc69c3
    $x{123} = 456 ;
Packit bc69c3
Packit bc69c3
    undef $X ;
Packit bc69c3
    untie %x ;
Packit bc69c3
Packit bc69c3
    $X = tie %x, 'DB_File', 'tst.fil' , O_RDWR|O_CREAT
Packit bc69c3
    ...
Packit bc69c3
Packit bc69c3
Packit bc69c3
=head1 COMMON QUESTIONS
Packit bc69c3
Packit bc69c3
=head2 Why is there Perl source in my database?
Packit bc69c3
Packit bc69c3
If you look at the contents of a database file created by DB_File,
Packit bc69c3
there can sometimes be part of a Perl script included in it.
Packit bc69c3
Packit bc69c3
This happens because Berkeley DB uses dynamic memory to allocate
Packit bc69c3
buffers which will subsequently be written to the database file. Being
Packit bc69c3
dynamic, the memory could have been used for anything before DB
Packit bc69c3
malloced it. As Berkeley DB doesn't clear the memory once it has been
Packit bc69c3
allocated, the unused portions will contain random junk. In the case
Packit bc69c3
where a Perl script gets written to the database, the random junk will
Packit bc69c3
correspond to an area of dynamic memory that happened to be used during
Packit bc69c3
the compilation of the script.
Packit bc69c3
Packit bc69c3
Unless you don't like the possibility of there being part of your Perl
Packit bc69c3
scripts embedded in a database file, this is nothing to worry about.
Packit bc69c3
Packit bc69c3
=head2 How do I store complex data structures with DB_File?
Packit bc69c3
Packit bc69c3
Although B<DB_File> cannot do this directly, there is a module which
Packit bc69c3
can layer transparently over B<DB_File> to accomplish this feat.
Packit bc69c3
Packit bc69c3
Check out the MLDBM module, available on CPAN in the directory
Packit bc69c3
F<modules/by-module/MLDBM>.
Packit bc69c3
Packit bc69c3
=head2 What does "wide character in subroutine entry" mean?
Packit bc69c3
Packit bc69c3
You will usually get this message if you are working with UTF-8 data and
Packit bc69c3
want to read/write it from/to a Berkeley DB database file.
Packit bc69c3
Packit bc69c3
The easist way to deal with this issue is to use the pre-defined "utf8"
Packit bc69c3
B<DBM_Filter> (see L<DBM_Filter>) that was designed to deal with this
Packit bc69c3
situation.
Packit bc69c3
Packit bc69c3
The example below shows what you need if I<both> the key and value are
Packit bc69c3
expected to be in UTF-8. 
Packit bc69c3
Packit bc69c3
    use DB_File;
Packit bc69c3
    use DBM_Filter; 
Packit bc69c3
Packit bc69c3
    my $db = tie %h, 'DB_File', '/tmp/try.db', O_CREAT|O_RDWR, 0666, $DB_BTREE; 
Packit bc69c3
    $db->Filter_Key_Push('utf8');
Packit bc69c3
    $db->Filter_Value_Push('utf8');
Packit bc69c3
Packit bc69c3
    my $key = "\N{LATIN SMALL LETTER A WITH ACUTE}";
Packit bc69c3
    my $value = "\N{LATIN SMALL LETTER E WITH ACUTE}";
Packit bc69c3
    $h{ $key } = $value;
Packit bc69c3
Packit bc69c3
=head2 What does "Invalid Argument" mean?
Packit bc69c3
Packit bc69c3
You will get this error message when one of the parameters in the
Packit bc69c3
C<tie> call is wrong. Unfortunately there are quite a few parameters to
Packit bc69c3
get wrong, so it can be difficult to figure out which one it is.
Packit bc69c3
Packit bc69c3
Here are a couple of possibilities:
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item 1.
Packit bc69c3
Packit bc69c3
Attempting to reopen a database without closing it. 
Packit bc69c3
Packit bc69c3
=item 2.
Packit bc69c3
Packit bc69c3
Using the O_WRONLY flag.
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
=head2 What does "Bareword 'DB_File' not allowed" mean? 
Packit bc69c3
Packit bc69c3
You will encounter this particular error message when you have the
Packit bc69c3
C<strict 'subs'> pragma (or the full strict pragma) in your script.
Packit bc69c3
Consider this script:
Packit bc69c3
Packit bc69c3
    use warnings ;
Packit bc69c3
    use strict ;
Packit bc69c3
    use DB_File ;
Packit bc69c3
    my %x ;
Packit bc69c3
    tie %x, DB_File, "filename" ;
Packit bc69c3
Packit bc69c3
Running it produces the error in question:
Packit bc69c3
Packit bc69c3
    Bareword "DB_File" not allowed while "strict subs" in use 
Packit bc69c3
Packit bc69c3
To get around the error, place the word C<DB_File> in either single or
Packit bc69c3
double quotes, like this:
Packit bc69c3
Packit bc69c3
    tie %x, "DB_File", "filename" ;
Packit bc69c3
Packit bc69c3
Although it might seem like a real pain, it is really worth the effort
Packit bc69c3
of having a C<use strict> in all your scripts.
Packit bc69c3
Packit bc69c3
=head1 REFERENCES
Packit bc69c3
Packit bc69c3
Articles that are either about B<DB_File> or make use of it.
Packit bc69c3
Packit bc69c3
=over 5
Packit bc69c3
Packit bc69c3
=item 1.
Packit bc69c3
Packit bc69c3
I<Full-Text Searching in Perl>, Tim Kientzle (tkientzle@ddj.com),
Packit bc69c3
Dr. Dobb's Journal, Issue 295, January 1999, pp 34-41
Packit bc69c3
Packit bc69c3
=back
Packit bc69c3
Packit bc69c3
=head1 HISTORY
Packit bc69c3
Packit bc69c3
Moved to the Changes file.
Packit bc69c3
Packit bc69c3
=head1 BUGS
Packit bc69c3
Packit bc69c3
Some older versions of Berkeley DB had problems with fixed length
Packit bc69c3
records using the RECNO file format. This problem has been fixed since
Packit bc69c3
version 1.85 of Berkeley DB.
Packit bc69c3
Packit bc69c3
I am sure there are bugs in the code. If you do find any, or can
Packit bc69c3
suggest any enhancements, I would welcome your comments.
Packit bc69c3
Packit bc69c3
=head1 AVAILABILITY
Packit bc69c3
Packit bc69c3
B<DB_File> comes with the standard Perl source distribution. Look in
Packit bc69c3
the directory F<ext/DB_File>. Given the amount of time between releases
Packit bc69c3
of Perl the version that ships with Perl is quite likely to be out of
Packit bc69c3
date, so the most recent version can always be found on CPAN (see
Packit bc69c3
L<perlmodlib/CPAN> for details), in the directory
Packit bc69c3
F<modules/by-module/DB_File>.
Packit bc69c3
Packit bc69c3
This version of B<DB_File> will work with either version 1.x, 2.x or
Packit bc69c3
3.x of Berkeley DB, but is limited to the functionality provided by
Packit bc69c3
version 1.
Packit bc69c3
Packit bc69c3
The official web site for Berkeley DB is F<http://www.oracle.com/technology/products/berkeley-db/db/index.html>.
Packit bc69c3
All versions of Berkeley DB are available there.
Packit bc69c3
Packit bc69c3
Alternatively, Berkeley DB version 1 is available at your nearest CPAN
Packit bc69c3
archive in F<src/misc/db.1.85.tar.gz>.
Packit bc69c3
Packit bc69c3
=head1 COPYRIGHT
Packit bc69c3
Packit bc69c3
Copyright (c) 1995-2016 Paul Marquess. All rights reserved. This program
Packit bc69c3
is free software; you can redistribute it and/or modify it under the
Packit bc69c3
same terms as Perl itself.
Packit bc69c3
Packit bc69c3
Although B<DB_File> is covered by the Perl license, the library it
Packit bc69c3
makes use of, namely Berkeley DB, is not. Berkeley DB has its own
Packit bc69c3
copyright and its own license. Please take the time to read it.
Packit bc69c3
Packit bc69c3
Here are a few words taken from the Berkeley DB FAQ (at
Packit bc69c3
F<http://www.oracle.com/technology/products/berkeley-db/db/index.html>) regarding the license:
Packit bc69c3
Packit bc69c3
    Do I have to license DB to use it in Perl scripts? 
Packit bc69c3
Packit bc69c3
    No. The Berkeley DB license requires that software that uses
Packit bc69c3
    Berkeley DB be freely redistributable. In the case of Perl, that
Packit bc69c3
    software is Perl, and not your scripts. Any Perl scripts that you
Packit bc69c3
    write are your property, including scripts that make use of
Packit bc69c3
    Berkeley DB. Neither the Perl license nor the Berkeley DB license
Packit bc69c3
    place any restriction on what you may do with them.
Packit bc69c3
Packit bc69c3
If you are in any doubt about the license situation, contact either the
Packit bc69c3
Berkeley DB authors or the author of DB_File. See L<"AUTHOR"> for details.
Packit bc69c3
Packit bc69c3
Packit bc69c3
=head1 SEE ALSO
Packit bc69c3
Packit bc69c3
L<perl>, L<dbopen(3)>, L<hash(3)>, L<recno(3)>, L<btree(3)>,
Packit bc69c3
L<perldbmfilter>, L<DBM_Filter>
Packit bc69c3
Packit bc69c3
=head1 AUTHOR
Packit bc69c3
Packit bc69c3
The DB_File interface was written by Paul Marquess
Packit bc69c3
E<lt>pmqs@cpan.orgE<gt>.
Packit bc69c3
Packit bc69c3
=cut