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

Greetings,

Late last week a co-worker asked me for some assistance with a set of perl CGI scripts that are being moved from a retiring HPUX box to another similar HPUX box (same OS level, same Perl, etc). fyi, the co-worker inhereited this system, and is exceedingly new to the world of perl.

The scripts in question were all accessing DBM files. all the scripts, while not failing, were returning very incomplete information on the new server.

(note that the following code is "as-is" from what I was shown, as you can see there are a few things that could be improved... including error handling on the open, using %HASH syntax on the open, and the regex should be referring to $notesInfo[0] not @notesInfo[0].)

if (dbmopen(DBDIR, '/wwwroot/test/groupweb/data/techExch/' . notesDir, + undef)) { foreach $notesDate (sort(keys (%DBDIR))) { $notesInfo = $DBDIR{$notesDate}; @notesInfo = split(/\|/, $notesInfo); @notesInfo[0] =~ s/([0-9]+)[\/](.*)/\2\/\1/; } }

So I isolated and tested the above from the command line on the new box, and sure enough I got the same incomplete info as the version running from the NES server on the same box. So I moved my test code over the original box and did another command-line test, and I ALSO got incomplete info. So my tests were behaving as follows:

             OrigBox       NewBox
CGI          PASS          FAIL
cmdline      FAIL          FAIL

So I did some digging around using perldoc -f dbmopen (and related) and came to the conclusion that at minimum, perhaps a simple:

use NDBM_File;
was in order.....but, I get the same incomplete data....so I try
use SDBM_File;
and all the magical data appears! (brute force sometimes has it's moments :)

After speaking at length with my sysadmins to determine what might be the reason this WORKS as CGI on the older box. but not anywhere else , they determined that I knew much more about this than they did, and could not provide anything useful. (from zero to "expert" in 30 minutes....yikes)

So.....I pose this to Perlmonks everywhere....

What could allow this appears-to-be-working-by-accident code to work properly (know the file is SDBM without being told) in the CGI environment, but not command-line? Is there an environment setting that manages this? Is it perhaps the way DBM was initially installed on the two HP's? (I have a hard time beleiving you even see references to DBM during an HPUX install, and this wouldn't explain discrepancies in command-line vs. CGI execution(or could it?)) Is there are default format for DBM files? (if so, I missed it in all the docs I located).

As far as all the failing scripts. adding the

use SDBM_File;
"fixed" all of them without exception or additional code changes.

My co-worker is a happy camper and is now able to continue her budding perl education in areas a little more relevent than dbm.

But me, I am having difficulty putting this to rest in my mind. I'd just like to have some insight as to what was going on here.

thanks!

Replies are listed 'Best First'.
Re: Seeking DBM wisdom
by jreades (Friar) on Dec 05, 2000 at 00:11 UTC

    The dbmopen() documentation offers some tantalizing clues:

    In older versions of Perl, if your system had neither DBM nor ndbm, calling `dbmopen' produced a fatal error; it now falls back to sdbm(3).
    You can control which DBM library you use by loading that library before you call dbmopen()

    What this suggests is that dbmopen() will, by default, attempt to open the dbm file using the ndbm library. If that attempt fails, then dbmopen() falls back on the SDBM lib. By process of deduction, it seems likely that the first HUPX box did not support the ndbm-style dbm files, while the second one did.

    Thus, calls on the first box fell back automagically on sdbm while calls on the second succeeded in using ndbm to open the files, it just happened to dump a good bit of your data.

    Well, I don't know if that's the case, but it sounds good don't it?

    Either case, I'd suggest switching the application over to tie() as the dbm functions are largely deprecated (and harder to use).

      thank you jreades. my dbmopen doc appears to be a bit dated...it doesn't have "in older versions of ..." text, here what I was reading.
      See also L<AnyDBM_File> for a more general description of the pros and
      cons of the various dbm approaches, as well as L<DB_File> for a particularly
      rich implementation.
      
      You can control which DBM library you use by loading that library
      before you call dbmopen():
          use DB_File;
          dbmopen(%NS_Hist, "$ENV{HOME}/.netscape/history.db")
              or die "Can't open netscape history file: $!";
      

      I had tried the above, but DB_File.pm is not installed.

      I finally found a pointer to the "use SDBM_File" by rooting through some ActiveState docs.

      I am not sure that this fully explains why it ran from the web, but not commandline on the original box, must be environmental issues involved as well. Perhaps NBDM is installed, just doesn't appear that way from the CGI script?

      On switching to tie(), I fully agree. Part of my testing provided my co-worker with an alternative version to hers using tie(), but in recently looking at the source, she appears to be sticking with dbmopen(). I know when I showed the code using tie(), she indicated she wasn't ready to start tackling yet-another-new-concept. One dragon at a time...