tall_man has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks,

I am having a problem with associated tables using the BerkeleyDB module. Here is a snippet of code:

my $table = BerkeleyDB::Btree->new( -Filename => "$home/$tableName/$tableName", -Compare => sub { my($a, $b) = @_; return $a <=> $b; }, # numeric -Flags => DB_CREATE, ) or die "Could not open \'$home/$tableName/$tableName\' ... "; my $db = BerkeleyDB::Btree->new( -Property => DB_DUP, -Flags => DB_CREATE, -Filename => "$home/$tableName/$dbName", -Compare => sub { my($a, $b) = @_; return $a cmp $b; }, # ascii ) or die "Could not open \'$home/$tableName/$dbName\' ... "; $table->associate($db, \&key_sub);
The key_sub extracts one field from the record using split, and I want to use that as a secondary index. I have no error messages when the first record is inserted, but when I insert a second record, I get error messages that indicate that the numeric comparison function, and not the ascii comparison function, is being used for the secondary table.
Argument "w61" isn't numeric in numeric comparison (<=>) at /home/Acct +Table.pm line 80. Argument "w60" isn't numeric in numeric comparison (<=>) at /home/Acct +Table.pm line 80.
The line number in the error messages above is the line where the numeric comparison is defined. Is this a bug in the perl BerkeleyDB module, or is it a bug in the db library itself? Is there a work-around for it? Thanks for your help.

Replies are listed 'Best First'.
Re: Associated BerkeleyDB table uses wrong compare?
by zby (Vicar) on Jun 11, 2003 at 07:34 UTC
    I can't get it: first clarify what does it mean that you define the numeric comparison - do you overload the <=> operator? Second you apparently have some numeric comparison in the line number 80, than you get an error saying that the numeric comparison is used - how is it suprising? Why should be a string comparison used when in the program there is a numeric comparison?
      I see that my code example was not sufficiently complete. Here is a full, runnable case:
      use strict; use warnings; use BerkeleyDB; my $home = "."; my $tableName = "testDB"; my $dbName = "testDex"; my $table = BerkeleyDB::Btree->new( -Filename => "$home/$tableName/$tableName", -Compare => sub { my($a, $b) = @_; return $a <=> $b; }, # numeric -Flags => DB_CREATE, ) or die "Could not open \'$home/$tableName/$tableName\' ... "; my $db = BerkeleyDB::Btree->new( -Property => DB_DUP, -Flags => DB_CREATE, -Filename => "$home/$tableName/$dbName", -Compare => sub { my($a, $b) = @_; return $a cmp $b; }, # ascii ) or die "Could not open \'$home/$tableName/$dbName\' ... "; sub key_sub { my $pkey = shift; my $pdata = shift; $_[0] = (split /\|/,$pdata)[1]; return 0; } $table->associate($db, \&key_sub); $table->db_put(1,"x|w60"); $table->db_put(2,"y|w61");
      The error messages in this case are:
      Argument "w60" isn't numeric in numeric comparison (<=>) at hhh.pl lin +e 11. Argument "w61" isn't numeric in numeric comparison (<=>) at hhh.pl lin +e 11. Argument "w60" isn't numeric in numeric comparison (<=>) at hhh.pl lin +e 11. Argument "w61" isn't numeric in numeric comparison (<=>) at hhh.pl lin +e 11.
      What I expect to happen is that whenever I do a "db_put" to the primary table, the key_sub will be called to extract a key (e.g. "w60") and that a secondary index will be made using that key.

      I expect to be able to specify a "-Compare" function for that secondary table that is appropriate for the ascii keys I am using. But for some reason the "-Compare" function of the first table is being used for the keys of the second table.

      I have a work-around for it for now, but I'd still like to find out where the problem is so that it can be fixed in the module. Here's my work-around:

      my $digits = qr/^\d+$/; sub eitherComp { my($a, $b) = @_; return $a <=> $b if ($a =~ $digits and $b =~ $digits); return $a cmp $b; }
      If I make the "-Compare" function for the first table a reference to eitherComp, the problem goes away.

      Update: I think I'm on the track of the bug. In the XS wrapper code for BerkeleyDB, I find the function btree_compare, which uses a global variable called CurrentDB. The comparison function is called as follows:

      count = perl_call_sv(CurrentDB->compare, G_SCALAR);
      Suppose that CurrentDB was set to the first table, and that it isn't changed when the associated tables are being updated. That would explain the bug I am seeing. I will email Paul Marquess about this.
Re: Associated BerkeleyDB table uses wrong compare?
by tall_man (Parson) on Jun 12, 2003 at 14:45 UTC
    I got an email back from Paul Marquess:

    Hi Dave,

    your analysis is 100% correct. The use of the CurrentDB global is the problem. Thankfully, it is fairly straightforward for me to fix this - I just need to find a free evening to make the change.

    Finally, I don't know if you've heard, but voting is taking place right now on the creation of a new Usenet group called comp.databases.berkeley-db. Its remit is to discuss all things to do with Berkeley DB, including, but by no means exclusively, the Perl interface.

    I think this newsgroup would be of real use to the Perl community. Although I don't mind getting mail directly about my Perl modules, I don't always have the time to respond as quickly as I would like. This new newsgroup would help fill that gap.

    If you are interested in the creation of this new group, please read the CFV that was posted to news.announce.newgroups and follow the instructions listed there to reply. You can access the article via your favourite news reader or via the following URL:

    http://groups.google.co.uk/groups?&selm=1054606314.6246%40isc.org

    Update: BerkeleyDB 0.23 has just been released, with a fix for the reported bug.