Search code examples
perlberkeley-db

Is it possible to delay loading BerkeleyDB?


As suggested in a previous question, one way to delay loading modules would be to use require. I would like to delay loading BerkeleyDB until it is necessary, instead of loading it every time my application runs. It would also be nice to test if BerkeleyDB is available. Here is my attempt, which seems to work with every other module I tried (calling the script 'load_bdb.pl'):

#!/usr/bin/env perl

use 5.010;
use strict;
use warnings;

my %hash;

eval {
    require BerkeleyDB;
    BerkeleyDB->import();
    1;
} or do {
    my $error = $@;
    die "\nERROR: Couldn't load BerkeleyDB" if $error;
};

tie %hash, 'BerkeleyDB::Btree', -Filename => 'db_file', -Flags => DB_CREATE
    or die "\nERROR: Could not open DBM file: db_file: $! $BerkeleyDB::Error\n";

This generates the following error:

Bareword "DB_CREATE" not allowed while "strict subs" in use at load_bdb.pl line 18. Execution of load_bdb.pl aborted due to compilation errors.

Suppressing the errors does not solve the problem because I then get:

Name "BerkeleyDB::Error" used only once: possible typo at load_bdb.pl line 20.

ERROR: Could not open DBM file: db_file: No such file or directory

This suggests to me that the require and import statements above are not importing BerkeleyDB correctly, whereas this works fine with use. So, why does require not work with this particular module and is there another solution?


Solution

  • When you run a perl script the execution goes through several phases. One of the first is compilation. During compilation it tries to resolve words such as DB_CREATE to decide what they are. In the case where BerkelyDB has not been loaded in advance (by use) then the first time it is encountered in the tie statement, perl does not know what it is.

    In this case it is actually a constant sub which will be later defined and imported, when you require BerkelyDB. Note that use is a compile time operation, while require normally occurs at run time. To avoid the error you can put a & in front of the name so perl knows it is actually a sub (eg. &DB_CREATE)

    The other warning if similar. You are reading a variable which would normally belong to the BerkeleyDB package, but since you did not load it, the variable is not referenced anywhere except in the one place. That leads perl to think it might be a typo in your script.

    You could resolve that by setting it to something (eg. Undef) at the top of the script.