summaryrefslogtreecommitdiffstats
path: root/upstream/archlinux/man3/DB_File.3perl
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-15 19:43:11 +0000
commitfc22b3d6507c6745911b9dfcc68f1e665ae13dbc (patch)
treece1e3bce06471410239a6f41282e328770aa404a /upstream/archlinux/man3/DB_File.3perl
parentInitial commit. (diff)
downloadmanpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.tar.xz
manpages-l10n-fc22b3d6507c6745911b9dfcc68f1e665ae13dbc.zip
Adding upstream version 4.22.0.upstream/4.22.0
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'upstream/archlinux/man3/DB_File.3perl')
-rw-r--r--upstream/archlinux/man3/DB_File.3perl1791
1 files changed, 1791 insertions, 0 deletions
diff --git a/upstream/archlinux/man3/DB_File.3perl b/upstream/archlinux/man3/DB_File.3perl
new file mode 100644
index 00000000..de2a7bd1
--- /dev/null
+++ b/upstream/archlinux/man3/DB_File.3perl
@@ -0,0 +1,1791 @@
+.\" -*- mode: troff; coding: utf-8 -*-
+.\" Automatically generated by Pod::Man 5.01 (Pod::Simple 3.43)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" \*(C` and \*(C' are quotes in nroff, nothing in troff, for use with C<>.
+.ie n \{\
+. ds C` ""
+. ds C' ""
+'br\}
+.el\{\
+. ds C`
+. ds C'
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el .ds Aq '
+.\"
+.\" If the F register is >0, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD. Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.\"
+.\" Avoid warning from groff about undefined register 'F'.
+.de IX
+..
+.nr rF 0
+.if \n(.g .if rF .nr rF 1
+.if (\n(rF:(\n(.g==0)) \{\
+. if \nF \{\
+. de IX
+. tm Index:\\$1\t\\n%\t"\\$2"
+..
+. if !\nF==2 \{\
+. nr % 0
+. nr F 2
+. \}
+. \}
+.\}
+.rr rF
+.\" ========================================================================
+.\"
+.IX Title "DB_File 3perl"
+.TH DB_File 3perl 2024-02-11 "perl v5.38.2" "Perl Programmers Reference Guide"
+.\" For nroff, turn off justification. Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.if n .ad l
+.nh
+.SH NAME
+DB_File \- Perl5 access to Berkeley DB version 1.x
+.SH SYNOPSIS
+.IX Header "SYNOPSIS"
+.Vb 1
+\& use DB_File;
+\&
+\& [$X =] tie %hash, \*(AqDB_File\*(Aq, [$filename, $flags, $mode, $DB_HASH] ;
+\& [$X =] tie %hash, \*(AqDB_File\*(Aq, $filename, $flags, $mode, $DB_BTREE ;
+\& [$X =] tie @array, \*(AqDB_File\*(Aq, $filename, $flags, $mode, $DB_RECNO ;
+\&
+\& $status = $X\->del($key [, $flags]) ;
+\& $status = $X\->put($key, $value [, $flags]) ;
+\& $status = $X\->get($key, $value [, $flags]) ;
+\& $status = $X\->seq($key, $value, $flags) ;
+\& $status = $X\->sync([$flags]) ;
+\& $status = $X\->fd ;
+\&
+\& # BTREE only
+\& $count = $X\->get_dup($key) ;
+\& @list = $X\->get_dup($key) ;
+\& %list = $X\->get_dup($key, 1) ;
+\& $status = $X\->find_dup($key, $value) ;
+\& $status = $X\->del_dup($key, $value) ;
+\&
+\& # RECNO only
+\& $a = $X\->length;
+\& $a = $X\->pop ;
+\& $X\->push(list);
+\& $a = $X\->shift;
+\& $X\->unshift(list);
+\& @r = $X\->splice(offset, length, elements);
+\&
+\& # DBM Filters
+\& $old_filter = $db\->filter_store_key ( sub { ... } ) ;
+\& $old_filter = $db\->filter_store_value( sub { ... } ) ;
+\& $old_filter = $db\->filter_fetch_key ( sub { ... } ) ;
+\& $old_filter = $db\->filter_fetch_value( sub { ... } ) ;
+\&
+\& untie %hash ;
+\& untie @array ;
+.Ve
+.SH DESCRIPTION
+.IX Header "DESCRIPTION"
+\&\fBDB_File\fR is a module which allows Perl programs to make use of the
+facilities provided by Berkeley DB version 1.x (if you have a newer
+version of DB, see "Using DB_File with Berkeley DB version 2 or greater").
+It is assumed that you have a copy of the Berkeley DB manual pages at
+hand when reading this documentation. The interface defined here
+mirrors the Berkeley DB interface closely.
+.PP
+Berkeley DB is a C library which provides a consistent interface to a
+number of database formats. \fBDB_File\fR provides an interface to all
+three of the database types currently supported by Berkeley DB.
+.PP
+The file types are:
+.IP \fBDB_HASH\fR 5
+.IX Item "DB_HASH"
+This database type allows arbitrary key/value pairs to be stored in data
+files. This is equivalent to the functionality provided by other
+hashing packages like DBM, NDBM, ODBM, GDBM, and SDBM. Remember though,
+the files created using DB_HASH are not compatible with any of the
+other packages mentioned.
+.Sp
+A default hashing algorithm, which will be adequate for most
+applications, is built into Berkeley DB. If you do need to use your own
+hashing algorithm it is possible to write your own in Perl and have
+\&\fBDB_File\fR use it instead.
+.IP \fBDB_BTREE\fR 5
+.IX Item "DB_BTREE"
+The btree format allows arbitrary key/value pairs to be stored in a
+sorted, balanced binary tree.
+.Sp
+As with the DB_HASH format, it is possible to provide a user defined
+Perl routine to perform the comparison of keys. By default, though, the
+keys are stored in lexical order.
+.IP \fBDB_RECNO\fR 5
+.IX Item "DB_RECNO"
+DB_RECNO allows both fixed-length and variable-length flat text files
+to be manipulated using the same key/value pair interface as in DB_HASH
+and DB_BTREE. In this case the key will consist of a record (line)
+number.
+.SS "Using DB_File with Berkeley DB version 2 or greater"
+.IX Subsection "Using DB_File with Berkeley DB version 2 or greater"
+Although \fBDB_File\fR is intended to be used with Berkeley DB version 1,
+it can also be used with version 2, 3 or 4. In this case the interface is
+limited to the functionality provided by Berkeley DB 1.x. Anywhere the
+version 2 or greater interface differs, \fBDB_File\fR arranges for it to work
+like version 1. This feature allows \fBDB_File\fR scripts that were built
+with version 1 to be migrated to version 2 or greater without any changes.
+.PP
+If you want to make use of the new features available in Berkeley DB
+2.x or greater, use the Perl module BerkeleyDB <https://metacpan.org/pod/BerkeleyDB> instead.
+.PP
+\&\fBNote:\fR The database file format has changed multiple times in Berkeley
+DB version 2, 3 and 4. If you cannot recreate your databases, you
+must dump any existing databases with either the \f(CW\*(C`db_dump\*(C'\fR or the
+\&\f(CW\*(C`db_dump185\*(C'\fR utility that comes with Berkeley DB.
+Once you have rebuilt DB_File to use Berkeley DB version 2 or greater,
+your databases can be recreated using \f(CW\*(C`db_load\*(C'\fR. Refer to the Berkeley DB
+documentation for further details.
+.PP
+Please read "COPYRIGHT" before using version 2.x or greater of Berkeley
+DB with DB_File.
+.SS "Interface to Berkeley DB"
+.IX Subsection "Interface to Berkeley DB"
+\&\fBDB_File\fR allows access to Berkeley DB files using the \fBtie()\fR mechanism
+in Perl 5 (for full details, see "\fBtie()\fR" in perlfunc). This facility
+allows \fBDB_File\fR to access Berkeley DB files using either an
+associative array (for DB_HASH & DB_BTREE file types) or an ordinary
+array (for the DB_RECNO file type).
+.PP
+In addition to the \fBtie()\fR interface, it is also possible to access most
+of the functions provided in the Berkeley DB API directly.
+See "THE API INTERFACE".
+.SS "Opening a Berkeley DB Database File"
+.IX Subsection "Opening a Berkeley DB Database File"
+Berkeley DB uses the function \fBdbopen()\fR to open or create a database.
+Here is the C prototype for \fBdbopen()\fR:
+.PP
+.Vb 3
+\& DB*
+\& dbopen (const char * file, int flags, int mode,
+\& DBTYPE type, const void * openinfo)
+.Ve
+.PP
+The parameter \f(CW\*(C`type\*(C'\fR is an enumeration which specifies which of the 3
+interface methods (DB_HASH, DB_BTREE or DB_RECNO) is to be used.
+Depending on which of these is actually chosen, the final parameter,
+\&\fIopeninfo\fR points to a data structure which allows tailoring of the
+specific interface method.
+.PP
+This interface is handled slightly differently in \fBDB_File\fR. Here is
+an equivalent call using \fBDB_File\fR:
+.PP
+.Vb 1
+\& tie %array, \*(AqDB_File\*(Aq, $filename, $flags, $mode, $DB_HASH ;
+.Ve
+.PP
+The \f(CW\*(C`filename\*(C'\fR, \f(CW\*(C`flags\*(C'\fR and \f(CW\*(C`mode\*(C'\fR parameters are the direct
+equivalent of their \fBdbopen()\fR counterparts. The final parameter \f(CW$DB_HASH\fR
+performs the function of both the \f(CW\*(C`type\*(C'\fR and \f(CW\*(C`openinfo\*(C'\fR parameters in
+\&\fBdbopen()\fR.
+.PP
+In the example above \f(CW$DB_HASH\fR is actually a pre-defined reference to a
+hash object. \fBDB_File\fR has three of these pre-defined references.
+Apart from \f(CW$DB_HASH\fR, there is also \f(CW$DB_BTREE\fR and \f(CW$DB_RECNO\fR.
+.PP
+The keys allowed in each of these pre-defined references is limited to
+the names used in the equivalent C structure. So, for example, the
+\&\f(CW$DB_HASH\fR reference will only allow keys called \f(CW\*(C`bsize\*(C'\fR, \f(CW\*(C`cachesize\*(C'\fR,
+\&\f(CW\*(C`ffactor\*(C'\fR, \f(CW\*(C`hash\*(C'\fR, \f(CW\*(C`lorder\*(C'\fR and \f(CW\*(C`nelem\*(C'\fR.
+.PP
+To change one of these elements, just assign to it like this:
+.PP
+.Vb 1
+\& $DB_HASH\->{\*(Aqcachesize\*(Aq} = 10000 ;
+.Ve
+.PP
+The three predefined variables \f(CW$DB_HASH\fR, \f(CW$DB_BTREE\fR and \f(CW$DB_RECNO\fR are
+usually adequate for most applications. If you do need to create extra
+instances of these objects, constructors are available for each file
+type.
+.PP
+Here are examples of the constructors and the valid options available
+for DB_HASH, DB_BTREE and DB_RECNO respectively.
+.PP
+.Vb 7
+\& $a = DB_File::HASHINFO\->new();
+\& $a\->{\*(Aqbsize\*(Aq} ;
+\& $a\->{\*(Aqcachesize\*(Aq} ;
+\& $a\->{\*(Aqffactor\*(Aq};
+\& $a\->{\*(Aqhash\*(Aq} ;
+\& $a\->{\*(Aqlorder\*(Aq} ;
+\& $a\->{\*(Aqnelem\*(Aq} ;
+\&
+\& $b = DB_File::BTREEINFO\->new();
+\& $b\->{\*(Aqflags\*(Aq} ;
+\& $b\->{\*(Aqcachesize\*(Aq} ;
+\& $b\->{\*(Aqmaxkeypage\*(Aq} ;
+\& $b\->{\*(Aqminkeypage\*(Aq} ;
+\& $b\->{\*(Aqpsize\*(Aq} ;
+\& $b\->{\*(Aqcompare\*(Aq} ;
+\& $b\->{\*(Aqprefix\*(Aq} ;
+\& $b\->{\*(Aqlorder\*(Aq} ;
+\&
+\& $c = DB_File::RECNOINFO\->new();
+\& $c\->{\*(Aqbval\*(Aq} ;
+\& $c\->{\*(Aqcachesize\*(Aq} ;
+\& $c\->{\*(Aqpsize\*(Aq} ;
+\& $c\->{\*(Aqflags\*(Aq} ;
+\& $c\->{\*(Aqlorder\*(Aq} ;
+\& $c\->{\*(Aqreclen\*(Aq} ;
+\& $c\->{\*(Aqbfname\*(Aq} ;
+.Ve
+.PP
+The values stored in the hashes above are mostly the direct equivalent
+of their C counterpart. Like their C counterparts, all are set to a
+default values \- that means you don't have to set \fIall\fR of the
+values when you only want to change one. Here is an example:
+.PP
+.Vb 3
+\& $a = DB_File::HASHINFO\->new();
+\& $a\->{\*(Aqcachesize\*(Aq} = 12345 ;
+\& tie %y, \*(AqDB_File\*(Aq, "filename", $flags, 0777, $a ;
+.Ve
+.PP
+A few of the options need extra discussion here. When used, the C
+equivalent of the keys \f(CW\*(C`hash\*(C'\fR, \f(CW\*(C`compare\*(C'\fR and \f(CW\*(C`prefix\*(C'\fR store pointers
+to C functions. In \fBDB_File\fR these keys are used to store references
+to Perl subs. Below are templates for each of the subs:
+.PP
+.Vb 7
+\& sub hash
+\& {
+\& my ($data) = @_ ;
+\& ...
+\& # return the hash value for $data
+\& return $hash ;
+\& }
+\&
+\& sub compare
+\& {
+\& my ($key, $key2) = @_ ;
+\& ...
+\& # return 0 if $key1 eq $key2
+\& # \-1 if $key1 lt $key2
+\& # 1 if $key1 gt $key2
+\& return (\-1 , 0 or 1) ;
+\& }
+\&
+\& sub prefix
+\& {
+\& my ($key, $key2) = @_ ;
+\& ...
+\& # return number of bytes of $key2 which are
+\& # necessary to determine that it is greater than $key1
+\& return $bytes ;
+\& }
+.Ve
+.PP
+See "Changing the BTREE sort order" for an example of using the
+\&\f(CW\*(C`compare\*(C'\fR template.
+.PP
+If you are using the DB_RECNO interface and you intend making use of
+\&\f(CW\*(C`bval\*(C'\fR, you should check out "The 'bval' Option".
+.SS "Default Parameters"
+.IX Subsection "Default Parameters"
+It is possible to omit some or all of the final 4 parameters in the
+call to \f(CW\*(C`tie\*(C'\fR and let them take default values. As DB_HASH is the most
+common file format used, the call:
+.PP
+.Vb 1
+\& tie %A, "DB_File", "filename" ;
+.Ve
+.PP
+is equivalent to:
+.PP
+.Vb 1
+\& tie %A, "DB_File", "filename", O_CREAT|O_RDWR, 0666, $DB_HASH ;
+.Ve
+.PP
+It is also possible to omit the filename parameter as well, so the
+call:
+.PP
+.Vb 1
+\& tie %A, "DB_File" ;
+.Ve
+.PP
+is equivalent to:
+.PP
+.Vb 1
+\& tie %A, "DB_File", undef, O_CREAT|O_RDWR, 0666, $DB_HASH ;
+.Ve
+.PP
+See "In Memory Databases" for a discussion on the use of \f(CW\*(C`undef\*(C'\fR
+in place of a filename.
+.SS "In Memory Databases"
+.IX Subsection "In Memory Databases"
+Berkeley DB allows the creation of in-memory databases by using NULL
+(that is, a \f(CW\*(C`(char *)0\*(C'\fR in C) in place of the filename. \fBDB_File\fR
+uses \f(CW\*(C`undef\*(C'\fR instead of NULL to provide this functionality.
+.SH DB_HASH
+.IX Header "DB_HASH"
+The DB_HASH file format is probably the most commonly used of the three
+file formats that \fBDB_File\fR supports. It is also very straightforward
+to use.
+.SS "A Simple Example"
+.IX Subsection "A Simple Example"
+This example shows how to create a database, add key/value pairs to the
+database, delete keys/value pairs and finally how to enumerate the
+contents of the database.
+.PP
+.Vb 4
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\& our (%h, $k, $v) ;
+\&
+\& unlink "fruit" ;
+\& tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0666, $DB_HASH
+\& or die "Cannot open file \*(Aqfruit\*(Aq: $!\en";
+\&
+\& # Add a few key/value pairs to the file
+\& $h{"apple"} = "red" ;
+\& $h{"orange"} = "orange" ;
+\& $h{"banana"} = "yellow" ;
+\& $h{"tomato"} = "red" ;
+\&
+\& # Check for existence of a key
+\& print "Banana Exists\en\en" if $h{"banana"} ;
+\&
+\& # Delete a key/value pair.
+\& delete $h{"apple"} ;
+\&
+\& # print the contents of the file
+\& while (($k, $v) = each %h)
+\& { print "$k \-> $v\en" }
+\&
+\& untie %h ;
+.Ve
+.PP
+here is the output:
+.PP
+.Vb 1
+\& Banana Exists
+\&
+\& orange \-> orange
+\& tomato \-> red
+\& banana \-> yellow
+.Ve
+.PP
+Note that the like ordinary associative arrays, the order of the keys
+retrieved is in an apparently random order.
+.SH DB_BTREE
+.IX Header "DB_BTREE"
+The DB_BTREE format is useful when you want to store data in a given
+order. By default the keys will be stored in lexical order, but as you
+will see from the example shown in the next section, it is very easy to
+define your own sorting function.
+.SS "Changing the BTREE sort order"
+.IX Subsection "Changing the BTREE sort order"
+This script shows how to override the default sorting algorithm that
+BTREE uses. Instead of using the normal lexical ordering, a case
+insensitive compare function will be used.
+.PP
+.Vb 3
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\&
+\& my %h ;
+\&
+\& sub Compare
+\& {
+\& my ($key1, $key2) = @_ ;
+\& "\eL$key1" cmp "\eL$key2" ;
+\& }
+\&
+\& # specify the Perl sub that will do the comparison
+\& $DB_BTREE\->{\*(Aqcompare\*(Aq} = \e&Compare ;
+\&
+\& unlink "tree" ;
+\& tie %h, "DB_File", "tree", O_RDWR|O_CREAT, 0666, $DB_BTREE
+\& or die "Cannot open file \*(Aqtree\*(Aq: $!\en" ;
+\&
+\& # Add a key/value pair to the file
+\& $h{\*(AqWall\*(Aq} = \*(AqLarry\*(Aq ;
+\& $h{\*(AqSmith\*(Aq} = \*(AqJohn\*(Aq ;
+\& $h{\*(Aqmouse\*(Aq} = \*(Aqmickey\*(Aq ;
+\& $h{\*(Aqduck\*(Aq} = \*(Aqdonald\*(Aq ;
+\&
+\& # Delete
+\& delete $h{"duck"} ;
+\&
+\& # Cycle through the keys printing them in order.
+\& # Note it is not necessary to sort the keys as
+\& # the btree will have kept them in order automatically.
+\& foreach (keys %h)
+\& { print "$_\en" }
+\&
+\& untie %h ;
+.Ve
+.PP
+Here is the output from the code above.
+.PP
+.Vb 3
+\& mouse
+\& Smith
+\& Wall
+.Ve
+.PP
+There are a few point to bear in mind if you want to change the
+ordering in a BTREE database:
+.IP 1. 5
+The new compare function must be specified when you create the database.
+.IP 2. 5
+You cannot change the ordering once the database has been created. Thus
+you must use the same compare function every time you access the
+database.
+.IP 3. 5
+Duplicate keys are entirely defined by the comparison function.
+In the case-insensitive example above, the keys: 'KEY' and 'key'
+would be considered duplicates, and assigning to the second one
+would overwrite the first. If duplicates are allowed for (with the
+R_DUP flag discussed below), only a single copy of duplicate keys
+is stored in the database \-\-\- so (again with example above) assigning
+three values to the keys: 'KEY', 'Key', and 'key' would leave just
+the first key: 'KEY' in the database with three values. For some
+situations this results in information loss, so care should be taken
+to provide fully qualified comparison functions when necessary.
+For example, the above comparison routine could be modified to
+additionally compare case-sensitively if two keys are equal in the
+case insensitive comparison:
+.Sp
+.Vb 5
+\& sub compare {
+\& my($key1, $key2) = @_;
+\& lc $key1 cmp lc $key2 ||
+\& $key1 cmp $key2;
+\& }
+.Ve
+.Sp
+And now you will only have duplicates when the keys themselves
+are truly the same. (note: in versions of the db library prior to
+about November 1996, such duplicate keys were retained so it was
+possible to recover the original keys in sets of keys that
+compared as equal).
+.SS "Handling Duplicate Keys"
+.IX Subsection "Handling Duplicate Keys"
+The BTREE file type optionally allows a single key to be associated
+with an arbitrary number of values. This option is enabled by setting
+the flags element of \f(CW$DB_BTREE\fR to R_DUP when creating the database.
+.PP
+There are some difficulties in using the tied hash interface if you
+want to manipulate a BTREE database with duplicate keys. Consider this
+code:
+.PP
+.Vb 3
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\&
+\& my ($filename, %h) ;
+\&
+\& $filename = "tree" ;
+\& unlink $filename ;
+\&
+\& # Enable duplicate records
+\& $DB_BTREE\->{\*(Aqflags\*(Aq} = R_DUP ;
+\&
+\& tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
+\& or die "Cannot open $filename: $!\en";
+\&
+\& # Add some key/value pairs to the file
+\& $h{\*(AqWall\*(Aq} = \*(AqLarry\*(Aq ;
+\& $h{\*(AqWall\*(Aq} = \*(AqBrick\*(Aq ; # Note the duplicate key
+\& $h{\*(AqWall\*(Aq} = \*(AqBrick\*(Aq ; # Note the duplicate key and value
+\& $h{\*(AqSmith\*(Aq} = \*(AqJohn\*(Aq ;
+\& $h{\*(Aqmouse\*(Aq} = \*(Aqmickey\*(Aq ;
+\&
+\& # iterate through the associative array
+\& # and print each key/value pair.
+\& foreach (sort keys %h)
+\& { print "$_ \-> $h{$_}\en" }
+\&
+\& untie %h ;
+.Ve
+.PP
+Here is the output:
+.PP
+.Vb 5
+\& Smith \-> John
+\& Wall \-> Larry
+\& Wall \-> Larry
+\& Wall \-> Larry
+\& mouse \-> mickey
+.Ve
+.PP
+As you can see 3 records have been successfully created with key \f(CW\*(C`Wall\*(C'\fR
+\&\- the only thing is, when they are retrieved from the database they
+\&\fIseem\fR to have the same value, namely \f(CW\*(C`Larry\*(C'\fR. The problem is caused
+by the way that the associative array interface works. Basically, when
+the associative array interface is used to fetch the value associated
+with a given key, it will only ever retrieve the first value.
+.PP
+Although it may not be immediately obvious from the code above, the
+associative array interface can be used to write values with duplicate
+keys, but it cannot be used to read them back from the database.
+.PP
+The way to get around this problem is to use the Berkeley DB API method
+called \f(CW\*(C`seq\*(C'\fR. This method allows sequential access to key/value
+pairs. See "THE API INTERFACE" for details of both the \f(CW\*(C`seq\*(C'\fR method
+and the API in general.
+.PP
+Here is the script above rewritten using the \f(CW\*(C`seq\*(C'\fR API method.
+.PP
+.Vb 3
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\&
+\& my ($filename, $x, %h, $status, $key, $value) ;
+\&
+\& $filename = "tree" ;
+\& unlink $filename ;
+\&
+\& # Enable duplicate records
+\& $DB_BTREE\->{\*(Aqflags\*(Aq} = R_DUP ;
+\&
+\& $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
+\& or die "Cannot open $filename: $!\en";
+\&
+\& # Add some key/value pairs to the file
+\& $h{\*(AqWall\*(Aq} = \*(AqLarry\*(Aq ;
+\& $h{\*(AqWall\*(Aq} = \*(AqBrick\*(Aq ; # Note the duplicate key
+\& $h{\*(AqWall\*(Aq} = \*(AqBrick\*(Aq ; # Note the duplicate key and value
+\& $h{\*(AqSmith\*(Aq} = \*(AqJohn\*(Aq ;
+\& $h{\*(Aqmouse\*(Aq} = \*(Aqmickey\*(Aq ;
+\&
+\& # iterate through the btree using seq
+\& # and print each key/value pair.
+\& $key = $value = 0 ;
+\& for ($status = $x\->seq($key, $value, R_FIRST) ;
+\& $status == 0 ;
+\& $status = $x\->seq($key, $value, R_NEXT) )
+\& { print "$key \-> $value\en" }
+\&
+\& undef $x ;
+\& untie %h ;
+.Ve
+.PP
+that prints:
+.PP
+.Vb 5
+\& Smith \-> John
+\& Wall \-> Brick
+\& Wall \-> Brick
+\& Wall \-> Larry
+\& mouse \-> mickey
+.Ve
+.PP
+This time we have got all the key/value pairs, including the multiple
+values associated with the key \f(CW\*(C`Wall\*(C'\fR.
+.PP
+To make life easier when dealing with duplicate keys, \fBDB_File\fR comes with
+a few utility methods.
+.SS "The \fBget_dup()\fP Method"
+.IX Subsection "The get_dup() Method"
+The \f(CW\*(C`get_dup\*(C'\fR method assists in
+reading duplicate values from BTREE databases. The method can take the
+following forms:
+.PP
+.Vb 3
+\& $count = $x\->get_dup($key) ;
+\& @list = $x\->get_dup($key) ;
+\& %list = $x\->get_dup($key, 1) ;
+.Ve
+.PP
+In a scalar context the method returns the number of values associated
+with the key, \f(CW$key\fR.
+.PP
+In list context, it returns all the values which match \f(CW$key\fR. Note
+that the values will be returned in an apparently random order.
+.PP
+In list context, if the second parameter is present and evaluates
+TRUE, the method returns an associative array. The keys of the
+associative array correspond to the values that matched in the BTREE
+and the values of the array are a count of the number of times that
+particular value occurred in the BTREE.
+.PP
+So assuming the database created above, we can use \f(CW\*(C`get_dup\*(C'\fR like
+this:
+.PP
+.Vb 3
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\&
+\& my ($filename, $x, %h) ;
+\&
+\& $filename = "tree" ;
+\&
+\& # Enable duplicate records
+\& $DB_BTREE\->{\*(Aqflags\*(Aq} = R_DUP ;
+\&
+\& $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
+\& or die "Cannot open $filename: $!\en";
+\&
+\& my $cnt = $x\->get_dup("Wall") ;
+\& print "Wall occurred $cnt times\en" ;
+\&
+\& my %hash = $x\->get_dup("Wall", 1) ;
+\& print "Larry is there\en" if $hash{\*(AqLarry\*(Aq} ;
+\& print "There are $hash{\*(AqBrick\*(Aq} Brick Walls\en" ;
+\&
+\& my @list = sort $x\->get_dup("Wall") ;
+\& print "Wall => [@list]\en" ;
+\&
+\& @list = $x\->get_dup("Smith") ;
+\& print "Smith => [@list]\en" ;
+\&
+\& @list = $x\->get_dup("Dog") ;
+\& print "Dog => [@list]\en" ;
+.Ve
+.PP
+and it will print:
+.PP
+.Vb 6
+\& Wall occurred 3 times
+\& Larry is there
+\& There are 2 Brick Walls
+\& Wall => [Brick Brick Larry]
+\& Smith => [John]
+\& Dog => []
+.Ve
+.SS "The \fBfind_dup()\fP Method"
+.IX Subsection "The find_dup() Method"
+.Vb 1
+\& $status = $X\->find_dup($key, $value) ;
+.Ve
+.PP
+This method checks for the existence of a specific key/value pair. If the
+pair exists, the cursor is left pointing to the pair and the method
+returns 0. Otherwise the method returns a non-zero value.
+.PP
+Assuming the database from the previous example:
+.PP
+.Vb 3
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\&
+\& my ($filename, $x, %h, $found) ;
+\&
+\& $filename = "tree" ;
+\&
+\& # Enable duplicate records
+\& $DB_BTREE\->{\*(Aqflags\*(Aq} = R_DUP ;
+\&
+\& $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
+\& or die "Cannot open $filename: $!\en";
+\&
+\& $found = ( $x\->find_dup("Wall", "Larry") == 0 ? "" : "not") ;
+\& print "Larry Wall is $found there\en" ;
+\&
+\& $found = ( $x\->find_dup("Wall", "Harry") == 0 ? "" : "not") ;
+\& print "Harry Wall is $found there\en" ;
+\&
+\& undef $x ;
+\& untie %h ;
+.Ve
+.PP
+prints this
+.PP
+.Vb 2
+\& Larry Wall is there
+\& Harry Wall is not there
+.Ve
+.SS "The \fBdel_dup()\fP Method"
+.IX Subsection "The del_dup() Method"
+.Vb 1
+\& $status = $X\->del_dup($key, $value) ;
+.Ve
+.PP
+This method deletes a specific key/value pair. It returns
+0 if they exist and have been deleted successfully.
+Otherwise the method returns a non-zero value.
+.PP
+Again assuming the existence of the \f(CW\*(C`tree\*(C'\fR database
+.PP
+.Vb 3
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\&
+\& my ($filename, $x, %h, $found) ;
+\&
+\& $filename = "tree" ;
+\&
+\& # Enable duplicate records
+\& $DB_BTREE\->{\*(Aqflags\*(Aq} = R_DUP ;
+\&
+\& $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
+\& or die "Cannot open $filename: $!\en";
+\&
+\& $x\->del_dup("Wall", "Larry") ;
+\&
+\& $found = ( $x\->find_dup("Wall", "Larry") == 0 ? "" : "not") ;
+\& print "Larry Wall is $found there\en" ;
+\&
+\& undef $x ;
+\& untie %h ;
+.Ve
+.PP
+prints this
+.PP
+.Vb 1
+\& Larry Wall is not there
+.Ve
+.SS "Matching Partial Keys"
+.IX Subsection "Matching Partial Keys"
+The BTREE interface has a feature which allows partial keys to be
+matched. This functionality is \fIonly\fR available when the \f(CW\*(C`seq\*(C'\fR method
+is used along with the R_CURSOR flag.
+.PP
+.Vb 1
+\& $x\->seq($key, $value, R_CURSOR) ;
+.Ve
+.PP
+Here is the relevant quote from the dbopen man page where it defines
+the use of the R_CURSOR flag with seq:
+.PP
+.Vb 4
+\& Note, for the DB_BTREE access method, the returned key is not
+\& necessarily an exact match for the specified key. The returned key
+\& is the smallest key greater than or equal to the specified key,
+\& permitting partial key matches and range searches.
+.Ve
+.PP
+In the example script below, the \f(CW\*(C`match\*(C'\fR sub uses this feature to find
+and print the first matching key/value pair given a partial key.
+.PP
+.Vb 4
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\& use Fcntl ;
+\&
+\& my ($filename, $x, %h, $st, $key, $value) ;
+\&
+\& sub match
+\& {
+\& my $key = shift ;
+\& my $value = 0;
+\& my $orig_key = $key ;
+\& $x\->seq($key, $value, R_CURSOR) ;
+\& print "$orig_key\et\-> $key\et\-> $value\en" ;
+\& }
+\&
+\& $filename = "tree" ;
+\& unlink $filename ;
+\&
+\& $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_BTREE
+\& or die "Cannot open $filename: $!\en";
+\&
+\& # Add some key/value pairs to the file
+\& $h{\*(Aqmouse\*(Aq} = \*(Aqmickey\*(Aq ;
+\& $h{\*(AqWall\*(Aq} = \*(AqLarry\*(Aq ;
+\& $h{\*(AqWalls\*(Aq} = \*(AqBrick\*(Aq ;
+\& $h{\*(AqSmith\*(Aq} = \*(AqJohn\*(Aq ;
+\&
+\&
+\& $key = $value = 0 ;
+\& print "IN ORDER\en" ;
+\& for ($st = $x\->seq($key, $value, R_FIRST) ;
+\& $st == 0 ;
+\& $st = $x\->seq($key, $value, R_NEXT) )
+\&
+\& { print "$key \-> $value\en" }
+\&
+\& print "\enPARTIAL MATCH\en" ;
+\&
+\& match "Wa" ;
+\& match "A" ;
+\& match "a" ;
+\&
+\& undef $x ;
+\& untie %h ;
+.Ve
+.PP
+Here is the output:
+.PP
+.Vb 5
+\& IN ORDER
+\& Smith \-> John
+\& Wall \-> Larry
+\& Walls \-> Brick
+\& mouse \-> mickey
+\&
+\& PARTIAL MATCH
+\& Wa \-> Wall \-> Larry
+\& A \-> Smith \-> John
+\& a \-> mouse \-> mickey
+.Ve
+.SH DB_RECNO
+.IX Header "DB_RECNO"
+DB_RECNO provides an interface to flat text files. Both variable and
+fixed length records are supported.
+.PP
+In order to make RECNO more compatible with Perl, the array offset for
+all RECNO arrays begins at 0 rather than 1 as in Berkeley DB.
+.PP
+As with normal Perl arrays, a RECNO array can be accessed using
+negative indexes. The index \-1 refers to the last element of the array,
+\&\-2 the second last, and so on. Attempting to access an element before
+the start of the array will raise a fatal run-time error.
+.SS "The 'bval' Option"
+.IX Subsection "The 'bval' Option"
+The operation of the bval option warrants some discussion. Here is the
+definition of bval from the Berkeley DB 1.85 recno manual page:
+.PP
+.Vb 6
+\& The delimiting byte to be used to mark the end of a
+\& record for variable\-length records, and the pad charac\-
+\& ter for fixed\-length records. If no value is speci\-
+\& fied, newlines (\`\`\en\*(Aq\*(Aq) are used to mark the end of
+\& variable\-length records and fixed\-length records are
+\& padded with spaces.
+.Ve
+.PP
+The second sentence is wrong. In actual fact bval will only default to
+\&\f(CW"\en"\fR when the openinfo parameter in dbopen is NULL. If a non-NULL
+openinfo parameter is used at all, the value that happens to be in bval
+will be used. That means you always have to specify bval when making
+use of any of the options in the openinfo parameter. This documentation
+error will be fixed in the next release of Berkeley DB.
+.PP
+That clarifies the situation with regards Berkeley DB itself. What
+about \fBDB_File\fR? Well, the behavior defined in the quote above is
+quite useful, so \fBDB_File\fR conforms to it.
+.PP
+That means that you can specify other options (e.g. cachesize) and
+still have bval default to \f(CW"\en"\fR for variable length records, and
+space for fixed length records.
+.PP
+Also note that the bval option only allows you to specify a single byte
+as a delimiter.
+.SS "A Simple Example"
+.IX Subsection "A Simple Example"
+Here is a simple example that uses RECNO (if you are using a version
+of Perl earlier than 5.004_57 this example won't work \-\- see
+"Extra RECNO Methods" for a workaround).
+.PP
+.Vb 3
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\&
+\& my $filename = "text" ;
+\& unlink $filename ;
+\&
+\& my @h ;
+\& tie @h, "DB_File", $filename, O_RDWR|O_CREAT, 0666, $DB_RECNO
+\& or die "Cannot open file \*(Aqtext\*(Aq: $!\en" ;
+\&
+\& # Add a few key/value pairs to the file
+\& $h[0] = "orange" ;
+\& $h[1] = "blue" ;
+\& $h[2] = "yellow" ;
+\&
+\& push @h, "green", "black" ;
+\&
+\& my $elements = scalar @h ;
+\& print "The array contains $elements entries\en" ;
+\&
+\& my $last = pop @h ;
+\& print "popped $last\en" ;
+\&
+\& unshift @h, "white" ;
+\& my $first = shift @h ;
+\& print "shifted $first\en" ;
+\&
+\& # Check for existence of a key
+\& print "Element 1 Exists with value $h[1]\en" if $h[1] ;
+\&
+\& # use a negative index
+\& print "The last element is $h[\-1]\en" ;
+\& print "The 2nd last element is $h[\-2]\en" ;
+\&
+\& untie @h ;
+.Ve
+.PP
+Here is the output from the script:
+.PP
+.Vb 6
+\& The array contains 5 entries
+\& popped black
+\& shifted white
+\& Element 1 Exists with value blue
+\& The last element is green
+\& The 2nd last element is yellow
+.Ve
+.SS "Extra RECNO Methods"
+.IX Subsection "Extra RECNO Methods"
+If you are using a version of Perl earlier than 5.004_57, the tied
+array interface is quite limited. In the example script above
+\&\f(CW\*(C`push\*(C'\fR, \f(CW\*(C`pop\*(C'\fR, \f(CW\*(C`shift\*(C'\fR, \f(CW\*(C`unshift\*(C'\fR
+or determining the array length will not work with a tied array.
+.PP
+To make the interface more useful for older versions of Perl, a number
+of methods are supplied with \fBDB_File\fR to simulate the missing array
+operations. All these methods are accessed via the object returned from
+the tie call.
+.PP
+Here are the methods:
+.ie n .IP "\fR\fB$X\fR\fB\->push(list) ;\fR" 5
+.el .IP "\fR\f(CB$X\fR\fB\->push(list) ;\fR" 5
+.IX Item "$X->push(list) ;"
+Pushes the elements of \f(CW\*(C`list\*(C'\fR to the end of the array.
+.ie n .IP "\fR\fB$value\fR\fB = \fR\fB$X\fR\fB\->pop ;\fR" 5
+.el .IP "\fR\f(CB$value\fR\fB = \fR\f(CB$X\fR\fB\->pop ;\fR" 5
+.IX Item "$value = $X->pop ;"
+Removes and returns the last element of the array.
+.ie n .IP \fR\fB$X\fR\fB\->shift\fR 5
+.el .IP \fR\f(CB$X\fR\fB\->shift\fR 5
+.IX Item "$X->shift"
+Removes and returns the first element of the array.
+.ie n .IP "\fR\fB$X\fR\fB\->unshift(list) ;\fR" 5
+.el .IP "\fR\f(CB$X\fR\fB\->unshift(list) ;\fR" 5
+.IX Item "$X->unshift(list) ;"
+Pushes the elements of \f(CW\*(C`list\*(C'\fR to the start of the array.
+.ie n .IP \fR\fB$X\fR\fB\->length\fR 5
+.el .IP \fR\f(CB$X\fR\fB\->length\fR 5
+.IX Item "$X->length"
+Returns the number of elements in the array.
+.ie n .IP "\fR\fB$X\fR\fB\->splice(offset, length, elements);\fR" 5
+.el .IP "\fR\f(CB$X\fR\fB\->splice(offset, length, elements);\fR" 5
+.IX Item "$X->splice(offset, length, elements);"
+Returns a splice of the array.
+.SS "Another Example"
+.IX Subsection "Another Example"
+Here is a more complete example that makes use of some of the methods
+described above. It also makes use of the API interface directly (see
+"THE API INTERFACE").
+.PP
+.Vb 5
+\& use warnings ;
+\& use strict ;
+\& my (@h, $H, $file, $i) ;
+\& use DB_File ;
+\& use Fcntl ;
+\&
+\& $file = "text" ;
+\&
+\& unlink $file ;
+\&
+\& $H = tie @h, "DB_File", $file, O_RDWR|O_CREAT, 0666, $DB_RECNO
+\& or die "Cannot open file $file: $!\en" ;
+\&
+\& # first create a text file to play with
+\& $h[0] = "zero" ;
+\& $h[1] = "one" ;
+\& $h[2] = "two" ;
+\& $h[3] = "three" ;
+\& $h[4] = "four" ;
+\&
+\&
+\& # Print the records in order.
+\& #
+\& # The length method is needed here because evaluating a tied
+\& # array in a scalar context does not return the number of
+\& # elements in the array.
+\&
+\& print "\enORIGINAL\en" ;
+\& foreach $i (0 .. $H\->length \- 1) {
+\& print "$i: $h[$i]\en" ;
+\& }
+\&
+\& # use the push & pop methods
+\& $a = $H\->pop ;
+\& $H\->push("last") ;
+\& print "\enThe last record was [$a]\en" ;
+\&
+\& # and the shift & unshift methods
+\& $a = $H\->shift ;
+\& $H\->unshift("first") ;
+\& print "The first record was [$a]\en" ;
+\&
+\& # Use the API to add a new record after record 2.
+\& $i = 2 ;
+\& $H\->put($i, "Newbie", R_IAFTER) ;
+\&
+\& # and a new record before record 1.
+\& $i = 1 ;
+\& $H\->put($i, "New One", R_IBEFORE) ;
+\&
+\& # delete record 3
+\& $H\->del(3) ;
+\&
+\& # now print the records in reverse order
+\& print "\enREVERSE\en" ;
+\& for ($i = $H\->length \- 1 ; $i >= 0 ; \-\- $i)
+\& { print "$i: $h[$i]\en" }
+\&
+\& # same again, but use the API functions instead
+\& print "\enREVERSE again\en" ;
+\& my ($s, $k, $v) = (0, 0, 0) ;
+\& for ($s = $H\->seq($k, $v, R_LAST) ;
+\& $s == 0 ;
+\& $s = $H\->seq($k, $v, R_PREV))
+\& { print "$k: $v\en" }
+\&
+\& undef $H ;
+\& untie @h ;
+.Ve
+.PP
+and this is what it outputs:
+.PP
+.Vb 6
+\& ORIGINAL
+\& 0: zero
+\& 1: one
+\& 2: two
+\& 3: three
+\& 4: four
+\&
+\& The last record was [four]
+\& The first record was [zero]
+\&
+\& REVERSE
+\& 5: last
+\& 4: three
+\& 3: Newbie
+\& 2: one
+\& 1: New One
+\& 0: first
+\&
+\& REVERSE again
+\& 5: last
+\& 4: three
+\& 3: Newbie
+\& 2: one
+\& 1: New One
+\& 0: first
+.Ve
+.PP
+Notes:
+.IP 1. 5
+Rather than iterating through the array, \f(CW@h\fR like this:
+.Sp
+.Vb 1
+\& foreach $i (@h)
+.Ve
+.Sp
+it is necessary to use either this:
+.Sp
+.Vb 1
+\& foreach $i (0 .. $H\->length \- 1)
+.Ve
+.Sp
+or this:
+.Sp
+.Vb 3
+\& for ($a = $H\->get($k, $v, R_FIRST) ;
+\& $a == 0 ;
+\& $a = $H\->get($k, $v, R_NEXT) )
+.Ve
+.IP 2. 5
+Notice that both times the \f(CW\*(C`put\*(C'\fR method was used the record index was
+specified using a variable, \f(CW$i\fR, rather than the literal value
+itself. This is because \f(CW\*(C`put\*(C'\fR will return the record number of the
+inserted line via that parameter.
+.SH "THE API INTERFACE"
+.IX Header "THE API INTERFACE"
+As well as accessing Berkeley DB using a tied hash or array, it is also
+possible to make direct use of most of the API functions defined in the
+Berkeley DB documentation.
+.PP
+To do this you need to store a copy of the object returned from the tie.
+.PP
+.Vb 1
+\& $db = tie %hash, "DB_File", "filename" ;
+.Ve
+.PP
+Once you have done that, you can access the Berkeley DB API functions
+as \fBDB_File\fR methods directly like this:
+.PP
+.Vb 1
+\& $db\->put($key, $value, R_NOOVERWRITE) ;
+.Ve
+.PP
+\&\fBImportant:\fR If you have saved a copy of the object returned from
+\&\f(CW\*(C`tie\*(C'\fR, the underlying database file will \fInot\fR be closed until both
+the tied variable is untied and all copies of the saved object are
+destroyed.
+.PP
+.Vb 6
+\& use DB_File ;
+\& $db = tie %hash, "DB_File", "filename"
+\& or die "Cannot tie filename: $!" ;
+\& ...
+\& undef $db ;
+\& untie %hash ;
+.Ve
+.PP
+See "The \fBuntie()\fR Gotcha" for more details.
+.PP
+All the functions defined in dbopen are available except for
+\&\fBclose()\fR and \fBdbopen()\fR itself. The \fBDB_File\fR method interface to the
+supported functions have been implemented to mirror the way Berkeley DB
+works whenever possible. In particular note that:
+.IP \(bu 5
+The methods return a status value. All return 0 on success.
+All return \-1 to signify an error and set \f(CW$!\fR to the exact
+error code. The return code 1 generally (but not always) means that the
+key specified did not exist in the database.
+.Sp
+Other return codes are defined. See below and in the Berkeley DB
+documentation for details. The Berkeley DB documentation should be used
+as the definitive source.
+.IP \(bu 5
+Whenever a Berkeley DB function returns data via one of its parameters,
+the equivalent \fBDB_File\fR method does exactly the same.
+.IP \(bu 5
+If you are careful, it is possible to mix API calls with the tied
+hash/array interface in the same piece of code. Although only a few of
+the methods used to implement the tied interface currently make use of
+the cursor, you should always assume that the cursor has been changed
+any time the tied hash/array interface is used. As an example, this
+code will probably not do what you expect:
+.Sp
+.Vb 2
+\& $X = tie %x, \*(AqDB_File\*(Aq, $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE
+\& or die "Cannot tie $filename: $!" ;
+\&
+\& # Get the first key/value pair and set the cursor
+\& $X\->seq($key, $value, R_FIRST) ;
+\&
+\& # this line will modify the cursor
+\& $count = scalar keys %x ;
+\&
+\& # Get the second key/value pair.
+\& # oops, it didn\*(Aqt, it got the last key/value pair!
+\& $X\->seq($key, $value, R_NEXT) ;
+.Ve
+.Sp
+The code above can be rearranged to get around the problem, like this:
+.Sp
+.Vb 2
+\& $X = tie %x, \*(AqDB_File\*(Aq, $filename, O_RDWR|O_CREAT, 0777, $DB_BTREE
+\& or die "Cannot tie $filename: $!" ;
+\&
+\& # this line will modify the cursor
+\& $count = scalar keys %x ;
+\&
+\& # Get the first key/value pair and set the cursor
+\& $X\->seq($key, $value, R_FIRST) ;
+\&
+\& # Get the second key/value pair.
+\& # worked this time.
+\& $X\->seq($key, $value, R_NEXT) ;
+.Ve
+.PP
+All the constants defined in dbopen for use in the flags parameters
+in the methods defined below are also available. Refer to the Berkeley
+DB documentation for the precise meaning of the flags values.
+.PP
+Below is a list of the methods available.
+.ie n .IP "\fR\fB$status\fR\fB = \fR\fB$X\fR\fB\->get($key, \fR\fB$value\fR\fB [, \fR\fB$flags\fR\fB]) ;\fR" 5
+.el .IP "\fR\f(CB$status\fR\fB = \fR\f(CB$X\fR\fB\->get($key, \fR\f(CB$value\fR\fB [, \fR\f(CB$flags\fR\fB]) ;\fR" 5
+.IX Item "$status = $X->get($key, $value [, $flags]) ;"
+Given a key (\f(CW$key\fR) this method reads the value associated with it
+from the database. The value read from the database is returned in the
+\&\f(CW$value\fR parameter.
+.Sp
+If the key does not exist the method returns 1.
+.Sp
+No flags are currently defined for this method.
+.ie n .IP "\fR\fB$status\fR\fB = \fR\fB$X\fR\fB\->put($key, \fR\fB$value\fR\fB [, \fR\fB$flags\fR\fB]) ;\fR" 5
+.el .IP "\fR\f(CB$status\fR\fB = \fR\f(CB$X\fR\fB\->put($key, \fR\f(CB$value\fR\fB [, \fR\f(CB$flags\fR\fB]) ;\fR" 5
+.IX Item "$status = $X->put($key, $value [, $flags]) ;"
+Stores the key/value pair in the database.
+.Sp
+If you use either the R_IAFTER or R_IBEFORE flags, the \f(CW$key\fR parameter
+will have the record number of the inserted key/value pair set.
+.Sp
+Valid flags are R_CURSOR, R_IAFTER, R_IBEFORE, R_NOOVERWRITE and
+R_SETCURSOR.
+.ie n .IP "\fR\fB$status\fR\fB = \fR\fB$X\fR\fB\->del($key [, \fR\fB$flags\fR\fB]) ;\fR" 5
+.el .IP "\fR\f(CB$status\fR\fB = \fR\f(CB$X\fR\fB\->del($key [, \fR\f(CB$flags\fR\fB]) ;\fR" 5
+.IX Item "$status = $X->del($key [, $flags]) ;"
+Removes all key/value pairs with key \f(CW$key\fR from the database.
+.Sp
+A return code of 1 means that the requested key was not in the
+database.
+.Sp
+R_CURSOR is the only valid flag at present.
+.ie n .IP "\fR\fB$status\fR\fB = \fR\fB$X\fR\fB\->fd ;\fR" 5
+.el .IP "\fR\f(CB$status\fR\fB = \fR\f(CB$X\fR\fB\->fd ;\fR" 5
+.IX Item "$status = $X->fd ;"
+Returns the file descriptor for the underlying database.
+.Sp
+See "Locking: The Trouble with fd" for an explanation for why you should
+not use \f(CW\*(C`fd\*(C'\fR to lock your database.
+.ie n .IP "\fR\fB$status\fR\fB = \fR\fB$X\fR\fB\->seq($key, \fR\fB$value\fR\fB, \fR\fB$flags\fR\fB) ;\fR" 5
+.el .IP "\fR\f(CB$status\fR\fB = \fR\f(CB$X\fR\fB\->seq($key, \fR\f(CB$value\fR\fB, \fR\f(CB$flags\fR\fB) ;\fR" 5
+.IX Item "$status = $X->seq($key, $value, $flags) ;"
+This interface allows sequential retrieval from the database. See
+dbopen for full details.
+.Sp
+Both the \f(CW$key\fR and \f(CW$value\fR parameters will be set to the key/value
+pair read from the database.
+.Sp
+The flags parameter is mandatory. The valid flag values are R_CURSOR,
+R_FIRST, R_LAST, R_NEXT and R_PREV.
+.ie n .IP "\fR\fB$status\fR\fB = \fR\fB$X\fR\fB\->sync([$flags]) ;\fR" 5
+.el .IP "\fR\f(CB$status\fR\fB = \fR\f(CB$X\fR\fB\->sync([$flags]) ;\fR" 5
+.IX Item "$status = $X->sync([$flags]) ;"
+Flushes any cached buffers to disk.
+.Sp
+R_RECNOSYNC is the only valid flag at present.
+.SH "DBM FILTERS"
+.IX Header "DBM FILTERS"
+A DBM Filter is a piece of code that is be used when you \fIalways\fR want to
+make the same transformation to all keys and/or values in a DBM database.
+An example is when you need to encode your data in UTF\-8 before writing to
+the database and then decode the UTF\-8 when reading from the database file.
+.PP
+There are two ways to use a DBM Filter.
+.IP 1. 5
+Using the low-level API defined below.
+.IP 2. 5
+Using the DBM_Filter module.
+This module hides the complexity of the API defined below and comes
+with a number of "canned" filters that cover some of the common use-cases.
+.PP
+Use of the DBM_Filter module is recommended.
+.SS "DBM Filter Low-level API"
+.IX Subsection "DBM Filter Low-level API"
+There are four methods associated with DBM Filters. All work identically,
+and each is used to install (or uninstall) a single DBM Filter. Each
+expects a single parameter, namely a reference to a sub. The only
+difference between them is the place that the filter is installed.
+.PP
+To summarise:
+.IP \fBfilter_store_key\fR 5
+.IX Item "filter_store_key"
+If a filter has been installed with this method, it will be invoked
+every time you write a key to a DBM database.
+.IP \fBfilter_store_value\fR 5
+.IX Item "filter_store_value"
+If a filter has been installed with this method, it will be invoked
+every time you write a value to a DBM database.
+.IP \fBfilter_fetch_key\fR 5
+.IX Item "filter_fetch_key"
+If a filter has been installed with this method, it will be invoked
+every time you read a key from a DBM database.
+.IP \fBfilter_fetch_value\fR 5
+.IX Item "filter_fetch_value"
+If a filter has been installed with this method, it will be invoked
+every time you read a value from a DBM database.
+.PP
+You can use any combination of the methods, from none, to all four.
+.PP
+All filter methods return the existing filter, if present, or \f(CW\*(C`undef\*(C'\fR
+in not.
+.PP
+To delete a filter pass \f(CW\*(C`undef\*(C'\fR to it.
+.SS "The Filter"
+.IX Subsection "The Filter"
+When each filter is called by Perl, a local copy of \f(CW$_\fR will contain
+the key or value to be filtered. Filtering is achieved by modifying
+the contents of \f(CW$_\fR. The return code from the filter is ignored.
+.SS "An Example \-\- the NULL termination problem."
+.IX Subsection "An Example -- the NULL termination problem."
+Consider the following scenario. You have a DBM database
+that you need to share with a third-party C application. The C application
+assumes that \fIall\fR keys and values are NULL terminated. Unfortunately
+when Perl writes to DBM databases it doesn't use NULL termination, so
+your Perl application will have to manage NULL termination itself. When
+you write to the database you will have to use something like this:
+.PP
+.Vb 1
+\& $hash{"$key\e0"} = "$value\e0" ;
+.Ve
+.PP
+Similarly the NULL needs to be taken into account when you are considering
+the length of existing keys/values.
+.PP
+It would be much better if you could ignore the NULL terminations issue
+in the main application code and have a mechanism that automatically
+added the terminating NULL to all keys and values whenever you write to
+the database and have them removed when you read from the database. As I'm
+sure you have already guessed, this is a problem that DBM Filters can
+fix very easily.
+.PP
+.Vb 3
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\&
+\& my %hash ;
+\& my $filename = "filt" ;
+\& unlink $filename ;
+\&
+\& my $db = tie %hash, \*(AqDB_File\*(Aq, $filename, O_CREAT|O_RDWR, 0666, $DB_HASH
+\& or die "Cannot open $filename: $!\en" ;
+\&
+\& # Install DBM Filters
+\& $db\->filter_fetch_key ( sub { s/\e0$// } ) ;
+\& $db\->filter_store_key ( sub { $_ .= "\e0" } ) ;
+\& $db\->filter_fetch_value( sub { s/\e0$// } ) ;
+\& $db\->filter_store_value( sub { $_ .= "\e0" } ) ;
+\&
+\& $hash{"abc"} = "def" ;
+\& my $a = $hash{"ABC"} ;
+\& # ...
+\& undef $db ;
+\& untie %hash ;
+.Ve
+.PP
+Hopefully the contents of each of the filters should be
+self-explanatory. Both "fetch" filters remove the terminating NULL,
+and both "store" filters add a terminating NULL.
+.SS "Another Example \-\- Key is a C int."
+.IX Subsection "Another Example -- Key is a C int."
+Here is another real-life example. By default, whenever Perl writes to
+a DBM database it always writes the key and value as strings. So when
+you use this:
+.PP
+.Vb 1
+\& $hash{12345} = "something" ;
+.Ve
+.PP
+the key 12345 will get stored in the DBM database as the 5 byte string
+"12345". If you actually want the key to be stored in the DBM database
+as a C int, you will have to use \f(CW\*(C`pack\*(C'\fR when writing, and \f(CW\*(C`unpack\*(C'\fR
+when reading.
+.PP
+Here is a DBM Filter that does it:
+.PP
+.Vb 6
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\& my %hash ;
+\& my $filename = "filt" ;
+\& unlink $filename ;
+\&
+\&
+\& my $db = tie %hash, \*(AqDB_File\*(Aq, $filename, O_CREAT|O_RDWR, 0666, $DB_HASH
+\& or die "Cannot open $filename: $!\en" ;
+\&
+\& $db\->filter_fetch_key ( sub { $_ = unpack("i", $_) } ) ;
+\& $db\->filter_store_key ( sub { $_ = pack ("i", $_) } ) ;
+\& $hash{123} = "def" ;
+\& # ...
+\& undef $db ;
+\& untie %hash ;
+.Ve
+.PP
+This time only two filters have been used \-\- we only need to manipulate
+the contents of the key, so it wasn't necessary to install any value
+filters.
+.SH "HINTS AND TIPS"
+.IX Header "HINTS AND TIPS"
+.SS "Locking: The Trouble with fd"
+.IX Subsection "Locking: The Trouble with fd"
+Until version 1.72 of this module, the recommended technique for locking
+\&\fBDB_File\fR databases was to flock the filehandle returned from the "fd"
+function. Unfortunately this technique has been shown to be fundamentally
+flawed (Kudos to David Harris for tracking this down). Use it at your own
+peril!
+.PP
+The locking technique went like this.
+.PP
+.Vb 12
+\& $db = tie(%db, \*(AqDB_File\*(Aq, \*(Aqfoo.db\*(Aq, O_CREAT|O_RDWR, 0644)
+\& || die "dbcreat foo.db $!";
+\& $fd = $db\->fd;
+\& open(DB_FH, "+<&=$fd") || die "dup $!";
+\& flock (DB_FH, LOCK_EX) || die "flock: $!";
+\& ...
+\& $db{"Tom"} = "Jerry" ;
+\& ...
+\& flock(DB_FH, LOCK_UN);
+\& undef $db;
+\& untie %db;
+\& close(DB_FH);
+.Ve
+.PP
+In simple terms, this is what happens:
+.IP 1. 5
+Use "tie" to open the database.
+.IP 2. 5
+Lock the database with fd & flock.
+.IP 3. 5
+Read & Write to the database.
+.IP 4. 5
+Unlock and close the database.
+.PP
+Here is the crux of the problem. A side-effect of opening the \fBDB_File\fR
+database in step 2 is that an initial block from the database will get
+read from disk and cached in memory.
+.PP
+To see why this is a problem, consider what can happen when two processes,
+say "A" and "B", both want to update the same \fBDB_File\fR database
+using the locking steps outlined above. Assume process "A" has already
+opened the database and has a write lock, but it hasn't actually updated
+the database yet (it has finished step 2, but not started step 3 yet). Now
+process "B" tries to open the same database \- step 1 will succeed,
+but it will block on step 2 until process "A" releases the lock. The
+important thing to notice here is that at this point in time both
+processes will have cached identical initial blocks from the database.
+.PP
+Now process "A" updates the database and happens to change some of the
+data held in the initial buffer. Process "A" terminates, flushing
+all cached data to disk and releasing the database lock. At this point
+the database on disk will correctly reflect the changes made by process
+"A".
+.PP
+With the lock released, process "B" can now continue. It also updates the
+database and unfortunately it too modifies the data that was in its
+initial buffer. Once that data gets flushed to disk it will overwrite
+some/all of the changes process "A" made to the database.
+.PP
+The result of this scenario is at best a database that doesn't contain
+what you expect. At worst the database will corrupt.
+.PP
+The above won't happen every time competing process update the same
+\&\fBDB_File\fR database, but it does illustrate why the technique should
+not be used.
+.SS "Safe ways to lock a database"
+.IX Subsection "Safe ways to lock a database"
+Starting with version 2.x, Berkeley DB has internal support for locking.
+The companion module to this one, BerkeleyDB <https://metacpan.org/pod/BerkeleyDB>, provides an interface
+to this locking functionality. If you are serious about locking
+Berkeley DB databases, I strongly recommend using BerkeleyDB <https://metacpan.org/pod/BerkeleyDB>.
+.PP
+If using BerkeleyDB <https://metacpan.org/pod/BerkeleyDB> isn't an option, there are a number of modules
+available on CPAN that can be used to implement locking. Each one
+implements locking differently and has different goals in mind. It is
+therefore worth knowing the difference, so that you can pick the right
+one for your application. Here are the three locking wrappers:
+.IP \fBTie::DB_Lock\fR 5
+.IX Item "Tie::DB_Lock"
+A \fBDB_File\fR wrapper which creates copies of the database file for
+read access, so that you have a kind of a multiversioning concurrent read
+system. However, updates are still serial. Use for databases where reads
+may be lengthy and consistency problems may occur.
+.IP \fBTie::DB_LockFile\fR 5
+.IX Item "Tie::DB_LockFile"
+A \fBDB_File\fR wrapper that has the ability to lock and unlock the database
+while it is being used. Avoids the tie-before-flock problem by simply
+re-tie-ing the database when you get or drop a lock. Because of the
+flexibility in dropping and re-acquiring the lock in the middle of a
+session, this can be massaged into a system that will work with long
+updates and/or reads if the application follows the hints in the POD
+documentation.
+.IP \fBDB_File::Lock\fR 5
+.IX Item "DB_File::Lock"
+An extremely lightweight \fBDB_File\fR wrapper that simply flocks a lockfile
+before tie-ing the database and drops the lock after the untie. Allows
+one to use the same lockfile for multiple databases to avoid deadlock
+problems, if desired. Use for databases where updates are reads are
+quick and simple flock locking semantics are enough.
+.SS "Sharing Databases With C Applications"
+.IX Subsection "Sharing Databases With C Applications"
+There is no technical reason why a Berkeley DB database cannot be
+shared by both a Perl and a C application.
+.PP
+The vast majority of problems that are reported in this area boil down
+to the fact that C strings are NULL terminated, whilst Perl strings are
+not. See "DBM FILTERS" for a generic way to work around this problem.
+.PP
+Here is a real example. Netscape 2.0 keeps a record of the locations you
+visit along with the time you last visited them in a DB_HASH database.
+This is usually stored in the file \fI~/.netscape/history.db\fR. The key
+field in the database is the location string and the value field is the
+time the location was last visited stored as a 4 byte binary value.
+.PP
+If you haven't already guessed, the location string is stored with a
+terminating NULL. This means you need to be careful when accessing the
+database.
+.PP
+Here is a snippet of code that is loosely based on Tom Christiansen's
+\&\fIggh\fR script (available from your nearest CPAN archive in
+\&\fIauthors/id/TOMC/scripts/nshist.gz\fR).
+.PP
+.Vb 4
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\& use Fcntl ;
+\&
+\& my ($dotdir, $HISTORY, %hist_db, $href, $binary_time, $date) ;
+\& $dotdir = $ENV{HOME} || $ENV{LOGNAME};
+\&
+\& $HISTORY = "$dotdir/.netscape/history.db";
+\&
+\& tie %hist_db, \*(AqDB_File\*(Aq, $HISTORY
+\& or die "Cannot open $HISTORY: $!\en" ;;
+\&
+\& # Dump the complete database
+\& while ( ($href, $binary_time) = each %hist_db ) {
+\&
+\& # remove the terminating NULL
+\& $href =~ s/\ex00$// ;
+\&
+\& # convert the binary time into a user friendly string
+\& $date = localtime unpack("V", $binary_time);
+\& print "$date $href\en" ;
+\& }
+\&
+\& # check for the existence of a specific key
+\& # remember to add the NULL
+\& if ( $binary_time = $hist_db{"http://mox.perl.com/\ex00"} ) {
+\& $date = localtime unpack("V", $binary_time) ;
+\& print "Last visited mox.perl.com on $date\en" ;
+\& }
+\& else {
+\& print "Never visited mox.perl.com\en"
+\& }
+\&
+\& untie %hist_db ;
+.Ve
+.SS "The \fBuntie()\fP Gotcha"
+.IX Subsection "The untie() Gotcha"
+If you make use of the Berkeley DB API, it is \fIvery\fR strongly
+recommended that you read "The untie Gotcha" in perltie.
+.PP
+Even if you don't currently make use of the API interface, it is still
+worth reading it.
+.PP
+Here is an example which illustrates the problem from a \fBDB_File\fR
+perspective:
+.PP
+.Vb 2
+\& use DB_File ;
+\& use Fcntl ;
+\&
+\& my %x ;
+\& my $X ;
+\&
+\& $X = tie %x, \*(AqDB_File\*(Aq, \*(Aqtst.fil\*(Aq , O_RDWR|O_TRUNC
+\& or die "Cannot tie first time: $!" ;
+\&
+\& $x{123} = 456 ;
+\&
+\& untie %x ;
+\&
+\& tie %x, \*(AqDB_File\*(Aq, \*(Aqtst.fil\*(Aq , O_RDWR|O_CREAT
+\& or die "Cannot tie second time: $!" ;
+\&
+\& untie %x ;
+.Ve
+.PP
+When run, the script will produce this error message:
+.PP
+.Vb 1
+\& Cannot tie second time: Invalid argument at bad.file line 14.
+.Ve
+.PP
+Although the error message above refers to the second \fBtie()\fR statement
+in the script, the source of the problem is really with the \fBuntie()\fR
+statement that precedes it.
+.PP
+Having read perltie you will probably have already guessed that the
+error is caused by the extra copy of the tied object stored in \f(CW$X\fR.
+If you haven't, then the problem boils down to the fact that the
+\&\fBDB_File\fR destructor, DESTROY, will not be called until \fIall\fR
+references to the tied object are destroyed. Both the tied variable,
+\&\f(CW%x\fR, and \f(CW$X\fR above hold a reference to the object. The call to
+\&\fBuntie()\fR will destroy the first, but \f(CW$X\fR still holds a valid
+reference, so the destructor will not get called and the database file
+\&\fItst.fil\fR will remain open. The fact that Berkeley DB then reports the
+attempt to open a database that is already open via the catch-all
+"Invalid argument" doesn't help.
+.PP
+If you run the script with the \f(CW\*(C`\-w\*(C'\fR flag the error message becomes:
+.PP
+.Vb 2
+\& untie attempted while 1 inner references still exist at bad.file line 12.
+\& Cannot tie second time: Invalid argument at bad.file line 14.
+.Ve
+.PP
+which pinpoints the real problem. Finally the script can now be
+modified to fix the original problem by destroying the API object
+before the untie:
+.PP
+.Vb 2
+\& ...
+\& $x{123} = 456 ;
+\&
+\& undef $X ;
+\& untie %x ;
+\&
+\& $X = tie %x, \*(AqDB_File\*(Aq, \*(Aqtst.fil\*(Aq , O_RDWR|O_CREAT
+\& ...
+.Ve
+.SH "COMMON QUESTIONS"
+.IX Header "COMMON QUESTIONS"
+.SS "Why is there Perl source in my database?"
+.IX Subsection "Why is there Perl source in my database?"
+If you look at the contents of a database file created by DB_File,
+there can sometimes be part of a Perl script included in it.
+.PP
+This happens because Berkeley DB uses dynamic memory to allocate
+buffers which will subsequently be written to the database file. Being
+dynamic, the memory could have been used for anything before DB
+malloced it. As Berkeley DB doesn't clear the memory once it has been
+allocated, the unused portions will contain random junk. In the case
+where a Perl script gets written to the database, the random junk will
+correspond to an area of dynamic memory that happened to be used during
+the compilation of the script.
+.PP
+Unless you don't like the possibility of there being part of your Perl
+scripts embedded in a database file, this is nothing to worry about.
+.SS "How do I store complex data structures with DB_File?"
+.IX Subsection "How do I store complex data structures with DB_File?"
+Although \fBDB_File\fR cannot do this directly, there is a module which
+can layer transparently over \fBDB_File\fR to accomplish this feat.
+.PP
+Check out the MLDBM module, available on CPAN in the directory
+\&\fImodules/by\-module/MLDBM\fR.
+.SS "What does ""wide character in subroutine entry"" mean?"
+.IX Subsection "What does ""wide character in subroutine entry"" mean?"
+You will usually get this message if you are working with UTF\-8 data and
+want to read/write it from/to a Berkeley DB database file.
+.PP
+The easist way to deal with this issue is to use the pre-defined "utf8"
+\&\fBDBM_Filter\fR (see DBM_Filter) that was designed to deal with this
+situation.
+.PP
+The example below shows what you need if \fIboth\fR the key and value are
+expected to be in UTF\-8.
+.PP
+.Vb 2
+\& use DB_File;
+\& use DBM_Filter;
+\&
+\& my $db = tie %h, \*(AqDB_File\*(Aq, \*(Aq/tmp/try.db\*(Aq, O_CREAT|O_RDWR, 0666, $DB_BTREE;
+\& $db\->Filter_Key_Push(\*(Aqutf8\*(Aq);
+\& $db\->Filter_Value_Push(\*(Aqutf8\*(Aq);
+\&
+\& my $key = "\eN{LATIN SMALL LETTER A WITH ACUTE}";
+\& my $value = "\eN{LATIN SMALL LETTER E WITH ACUTE}";
+\& $h{ $key } = $value;
+.Ve
+.SS "What does ""Invalid Argument"" mean?"
+.IX Subsection "What does ""Invalid Argument"" mean?"
+You will get this error message when one of the parameters in the
+\&\f(CW\*(C`tie\*(C'\fR call is wrong. Unfortunately there are quite a few parameters to
+get wrong, so it can be difficult to figure out which one it is.
+.PP
+Here are a couple of possibilities:
+.IP 1. 5
+Attempting to reopen a database without closing it.
+.IP 2. 5
+Using the O_WRONLY flag.
+.SS "What does ""Bareword 'DB_File' not allowed"" mean?"
+.IX Subsection "What does ""Bareword 'DB_File' not allowed"" mean?"
+You will encounter this particular error message when you have the
+\&\f(CW\*(C`strict \*(Aqsubs\*(Aq\*(C'\fR pragma (or the full strict pragma) in your script.
+Consider this script:
+.PP
+.Vb 5
+\& use warnings ;
+\& use strict ;
+\& use DB_File ;
+\& my %x ;
+\& tie %x, DB_File, "filename" ;
+.Ve
+.PP
+Running it produces the error in question:
+.PP
+.Vb 1
+\& Bareword "DB_File" not allowed while "strict subs" in use
+.Ve
+.PP
+To get around the error, place the word \f(CW\*(C`DB_File\*(C'\fR in either single or
+double quotes, like this:
+.PP
+.Vb 1
+\& tie %x, "DB_File", "filename" ;
+.Ve
+.PP
+Although it might seem like a real pain, it is really worth the effort
+of having a \f(CW\*(C`use strict\*(C'\fR in all your scripts.
+.SH REFERENCES
+.IX Header "REFERENCES"
+Articles that are either about \fBDB_File\fR or make use of it.
+.IP 1. 5
+\&\fIFull-Text Searching in Perl\fR, Tim Kientzle (tkientzle@ddj.com),
+Dr. Dobb's Journal, Issue 295, January 1999, pp 34\-41
+.SH HISTORY
+.IX Header "HISTORY"
+Moved to the Changes file.
+.SH BUGS
+.IX Header "BUGS"
+Some older versions of Berkeley DB had problems with fixed length
+records using the RECNO file format. This problem has been fixed since
+version 1.85 of Berkeley DB.
+.PP
+I am sure there are bugs in the code. If you do find any, or can
+suggest any enhancements, I would welcome your comments.
+.SH SUPPORT
+.IX Header "SUPPORT"
+General feedback/questions/bug reports should be sent to
+<https://github.com/pmqs/DB_File/issues> (preferred) or
+<https://rt.cpan.org/Public/Dist/Display.html?Name=DB_File>.
+.SH AVAILABILITY
+.IX Header "AVAILABILITY"
+\&\fBDB_File\fR comes with the standard Perl source distribution. Look in
+the directory \fIext/DB_File\fR. Given the amount of time between releases
+of Perl the version that ships with Perl is quite likely to be out of
+date, so the most recent version can always be found on CPAN (see
+"CPAN" in perlmodlib for details), in the directory
+\&\fImodules/by\-module/DB_File\fR.
+.PP
+\&\fBDB_File\fR is designed to work with any version of Berkeley DB, but is limited to the functionality provided by
+version 1. If you want to make use of the new features available in Berkeley DB
+2.x, or greater, use the Perl module BerkeleyDB <https://metacpan.org/pod/BerkeleyDB> instead.
+.PP
+The official web site for Berkeley DB is <http://www.oracle.com/technology/products/berkeley\-db/db/index.html>.
+All versions of Berkeley DB are available there.
+.PP
+Alternatively, Berkeley DB version 1 is available at your nearest CPAN
+archive in \fIsrc/misc/db.1.85.tar.gz\fR.
+.SH COPYRIGHT
+.IX Header "COPYRIGHT"
+Copyright (c) 1995\-2022 Paul Marquess. All rights reserved. This program
+is free software; you can redistribute it and/or modify it under the
+same terms as Perl itself.
+.PP
+Although \fBDB_File\fR is covered by the Perl license, the library it
+makes use of, namely Berkeley DB, is not. Berkeley DB has its own
+copyright and its own license.
+See AGPL <https://www.oracle.com/downloads/licenses/berkeleydb-oslicense.html> for more details.
+Please take the time to read the Berkeley DB license and decide how it impacts your use of this Perl module.
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+perl, \fBdbopen\fR\|(3), \fBhash\fR\|(3), \fBrecno\fR\|(3), \fBbtree\fR\|(3),
+perldbmfilter, DBM_Filter
+.SH AUTHOR
+.IX Header "AUTHOR"
+The DB_File interface was written by Paul Marquess
+<pmqs@cpan.org>.