diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 19:43:11 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-15 19:43:11 +0000 |
commit | fc22b3d6507c6745911b9dfcc68f1e665ae13dbc (patch) | |
tree | ce1e3bce06471410239a6f41282e328770aa404a /upstream/archlinux/man3/DB_File.3perl | |
parent | Initial commit. (diff) | |
download | manpages-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.3perl | 1791 |
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>. |