2

I'm trying to pass a tied hash using BerkeleyDB to a subroutine and modifying the contents of the database in the routine, but it's not working.

#!/usr/bin/perl

use warnings;
use strict;
use BerkeleyDB;

sub testdb($)
{
    my $dbptr = shift;
    my %db = %{$dbptr};

    print("inside foo: ", $db{'foo'}, "\n");

    $db{'biz'} = "baz";
    return 0;
}

my %database;
my $dbhand = tie %database, 'BerkeleyDB::Hash', -Filename => "test.db";

print "outside foo: ", $database{'foo'}, "\n";

testdb(\%database);
print "returned: ", $database{'biz'}, "\n";

$dbhand->db_close();
undef($dbhand);
untie %database;

exit(0);

But when I run it:

./dbtie
outside foo: foobar
inside foo: foobar
Use of uninitialized value in print at ./dbtie line 24.
returned:

So it appears that I can read from the database, but I cannot write to it. Why?

I tried doing a db_sync() at the end of the subroutine, but it made no difference.

This is Perl 5.14 using BerkeleyDB version 0.54. It is in turn using Berkeley DB version 6, creating a version 9 hashtable.

1 Answers1

1

Don't dereference your tied hash in your sub. Instead work with the reference:

sub testdb
{
    my $dbptr = shift;

    print("inside foo: ", $dbptr->{'foo'}, "\n");

    $dbptr->{'biz'} = "baz";
    return 0;
}

When you assign my %hash = %$dbptr you're creating a copy of all of your data and assigning it to a new basic hash data structure. Once the subroutine exits, any changes you made to %hash will be lost unless you intentionally do something with it.

Miller
  • 34,962
  • 4
  • 39
  • 60
  • Yes, but also *never use subroutine prototypes*. I think you should have rewritten the subroutine properly instead of just fixing the immediate problem – Borodin Apr 04 '14 at 23:17
  • I considered it of course, but decided to focus on the glaring issue instead of getting segued into a style lecture this time. Not to just pass the buck, but feel free to simply edit my answers. Unless you just get more pleasure out of commenting, which is fine too. *Cheers* – Miller Apr 04 '14 at 23:37
  • *"get more pleasure out of commenting"* is a little weird. I won't usually amend a solution without reason and explicit permission. But I see that you have removed the prototype without comment; that's a backward step! – Borodin Apr 04 '14 at 23:43
  • @JasonAndresen: Perl subroutine prototypes are a very specific tool that let you write subroutines that behave similarly to Perl operators. (Take a look at [`Try::Tiny`](https://metacpan.org/module/Try::Tiny) for instance.) They are not for general consumption. – Borodin Apr 05 '14 at 00:33
  • [`Why are Perl 5's function prototypes bad?`](http://stackoverflow.com/questions/297034/why-are-perl-5s-function-prototypes-bad) - Short answer is what Borodin said. Slightly longer answer is that they are syntactic sugar that most people don't actually need, and could potentially cause problems. I never need or use them, and advise others to avoid their use as well. – Miller Apr 05 '14 at 00:33