develooper Front page | perl.perl5.porters | Postings from April 2011

various DBM bugs

From:
Tom Christiansen
Date:
April 22, 2011 14:03
Subject:
various DBM bugs
Message ID:
1487.1303506187@chthon
What's the deal with GDBM_File?  It's in ext/, but it doesn't 
bother to build.  And you can't get it to install with 
perl -MCPAN -e 'install GDBM_File', either.

The AnyDBM_File manpage claims:

   Here's a partial table of features the different packages offer:

			    odbm    ndbm    sdbm    gdbm    bsd-db
			    ----    ----    ----    ----    ------
    Linkage comes w/ perl   yes     yes     yes     yes     yes
    Src comes w/ perl       no      no      yes     no      no
    Comes w/ many unix os   yes     yes[0]  no      no      no
    Builds ok on !unix      ?       ?       yes     yes     ?
    Code Size               ?       ?       small   big     big
    Database Size           ?       ?       small   big?    ok[1]
    Speed                   ?       ?       slow    ok      fast
    FTPable                 no      no      yes     yes     yes
    Easy to build          N/A     N/A      yes     yes     ok[2]
    Size limits             1k      4k      1k[3]   none    none
    Byte-order independent  no      no      no      no      yes
    Licensing restrictions  ?       ?       no      yes     no

I guess it must look for the library and if it is there, use it. 
Is that right?

    % perl -Mwarnings=FATAL,all -Mautodie -le 'dbmopen(%db, "/tmp/dbtest", 0666); $db{"\x{3b1}"} = 1; dbmclose %db'
    Wide character in subroutine entry at -e line 1.
    Exit 255

Um, *what* subroutine entry?

    % perl -Mdiagnostics -Mwarnings=FATAL,all -Mautodie -le 'dbmopen(%db, "/tmp/dbtest", 0666); $db{"\x{3b1}"} = 1; dbmclose %db'
    Wide character in subroutine entry at -e line 1 (#1)
	(S utf8) Perl met a wide character (>255) when it wasn't expecting
	one.  This warning is by default on for I/O (like print).  The easiest
	way to quiet this warning is simply to add the :utf8 layer to the
	output, e.g. binmode STDOUT, ':utf8'.  Another way to turn off the
	warning is to add no warnings 'utf8'; but that is often closer to
	cheating.  In general, you are supposed to explicitly mark the
	filehandle with an encoding, see open and perlfunc/binmode.
    
    Uncaught exception from user code:
	    Wide character in subroutine entry at -e line 1.
     at -e line 1
    Exit 255

I believe that is an inappropriate error message.  Nothing there tells
anybody what they have to do to make it happy.  How in the world would ever guess you have
to do this:

    % perl -Mdiagnostics -Mwarnings=FATAL,all -Mautodie -MEncode -le 'dbmopen(%db, "/tmp/dbtest", 0666); $db{encode("UTF-8", "\x{3b1}")} = 1; dbmclose %db'

Also, interestingly, I get one of these without having asked for it:

    % file /tmp/dbtest*
    /tmp/dbtest.db: Berkeley DB 1.85 (Hash, version 2, native byte-order)

That's on a Mac, which, like any other BSD system, of course comes
with DB_File.  I suggest that the AnyDBM_File manpage be updated
to state this.  (And yes, BerkeleyDB and DB_File are different.)

But why isn't that an ndbm file?  Weird.

Speaking of AnyDBM_File, the reason this is happening is because
it gets autmagically demand-loaded by the first call the dbmopen.

But this isn't admitted to in the dmmopen or AnyDBM_File manpages,
and it should be:

    =item dbmopen HASH,DBNAME,MASK
    X<dbmopen> X<dbm> X<ndbm> X<sdbm> X<gdbm>

    [This function has been largely superseded by the C<tie> function.]

    This binds a dbm(3), ndbm(3), sdbm(3), gdbm(3), or Berkeley DB file to a
    hash.  HASH is the name of the hash.  (Unlike normal C<open>, the first
    argument is I<not> a filehandle, even though it looks like one).  DBNAME
    is the name of the database (without the F<.dir> or F<.pag> extension if
    any).  If the database does not exist, it is created with protection
    specified by MASK (as modified by the C<umask>).  If your system supports
    only the older DBM functions, you may make only one C<dbmopen> call in your
    program.  In older versions of Perl, if your system had neither DBM nor
    ndbm, calling C<dbmopen> produced a fatal error; it now falls back to
    sdbm(3).

Also, it really seems like you should  be able to know what DBM you're
getting.

    our @ISA = qw(NDBM_File DB_File GDBM_File SDBM_File ODBM_File) unless @ISA;

    my $mod;
    for $mod (@ISA) {
	if (eval "require $mod") {
	    @ISA = ($mod);  # if we leave @ISA alone, warnings abound
	    return 1;
	}
    }

Oh, ok.  So it just gets the first one it loads.

      DB<2> 
    NDBM_File::(/usr/local/lib/perl5/5.12.3/darwin-thread-multi-2level/NDBM_File.pm:14):
    14:     1;
      DB<2> 
    AnyDBM_File::(/usr/local/lib/perl5/5.12.3/AnyDBM_File.pm:10):
    10:             @ISA = ($mod);  # if we leave @ISA alone, warnings abound
      DB<2> 
    AnyDBM_File::(/usr/local/lib/perl5/5.12.3/AnyDBM_File.pm:11):
    11:             return 1;
      DB<2> p @AnyDBM_File::ISA
    NDBM_File

Huh?  It claims NDBM_File, but makes a DB_File file!
Cuuurious.

Lots of non-obviousness going on here.

--tom



nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About