Upgrade to DB_File 1.811, by Paul Marquess
[p5sagit/p5-mst-13.2.git] / ext / DB_File / t / db-hash.t
1 #!./perl 
2
3 BEGIN {
4     unless(grep /blib/, @INC) {
5         chdir 't' if -d 't';
6         @INC = '../lib' if -d '../lib';
7     }
8 }
9  
10 use warnings;
11 use strict;
12 use Config;
13  
14 BEGIN {
15     if(-d "lib" && -f "TEST") {
16         if ($Config{'extensions'} !~ /\bDB_File\b/ ) {
17             print "1..0 # Skip: DB_File was not built\n";
18             exit 0;
19         }
20     }
21 }
22
23 use DB_File; 
24 use Fcntl;
25
26 print "1..166\n";
27
28 unlink glob "__db.*";
29
30 sub ok
31 {
32     my $no = shift ;
33     my $result = shift ;
34  
35     print "not " unless $result ;
36     print "ok $no\n" ;
37
38     return $result ;
39 }
40
41 {
42     package Redirect ;
43     use Symbol ;
44
45     sub new
46     {
47         my $class = shift ;
48         my $filename = shift ;
49         my $fh = gensym ;
50         open ($fh, ">$filename") || die "Cannot open $filename: $!" ;
51         my $real_stdout = select($fh) ;
52         return bless [$fh, $real_stdout ] ;
53
54     }
55     sub DESTROY
56     {
57         my $self = shift ;
58         close $self->[0] ;
59         select($self->[1]) ;
60     }
61 }
62
63 sub docat_del
64
65     my $file = shift;
66     local $/ = undef;
67     open(CAT,$file) || die "Cannot open $file: $!";
68     my $result = <CAT>;
69     close(CAT);
70     $result = normalise($result) ;
71     unlink $file ;
72     return $result;
73 }   
74
75 sub normalise
76 {
77     my $data = shift ;
78     $data =~ s#\r\n#\n#g 
79         if $^O eq 'cygwin' ;
80     return $data ;
81 }
82
83 sub safeUntie
84 {
85     my $hashref = shift ;
86     my $no_inner = 1;
87     local $SIG{__WARN__} = sub {-- $no_inner } ;
88     untie %$hashref;
89     return $no_inner;
90 }
91
92
93 my $Dfile = "dbhash.tmp";
94 my $Dfile2 = "dbhash2.tmp";
95 my $null_keys_allowed = ($DB_File::db_ver < 2.004010 
96                                 || $DB_File::db_ver >= 3.1 );
97
98 unlink $Dfile;
99
100 umask(0);
101
102 # Check the interface to HASHINFO
103
104 my $dbh = new DB_File::HASHINFO ;
105
106 ok(1, ! defined $dbh->{bsize}) ;
107 ok(2, ! defined $dbh->{ffactor}) ;
108 ok(3, ! defined $dbh->{nelem}) ;
109 ok(4, ! defined $dbh->{cachesize}) ;
110 ok(5, ! defined $dbh->{hash}) ;
111 ok(6, ! defined $dbh->{lorder}) ;
112
113 $dbh->{bsize} = 3000 ;
114 ok(7, $dbh->{bsize} == 3000 );
115
116 $dbh->{ffactor} = 9000 ;
117 ok(8, $dbh->{ffactor} == 9000 );
118
119 $dbh->{nelem} = 400 ;
120 ok(9, $dbh->{nelem} == 400 );
121
122 $dbh->{cachesize} = 65 ;
123 ok(10, $dbh->{cachesize} == 65 );
124
125 my $some_sub = sub {} ;
126 $dbh->{hash} = $some_sub;
127 ok(11, $dbh->{hash} eq $some_sub );
128
129 $dbh->{lorder} = 1234 ;
130 ok(12, $dbh->{lorder} == 1234 );
131
132 # Check that an invalid entry is caught both for store & fetch
133 eval '$dbh->{fred} = 1234' ;
134 ok(13, $@ =~ /^DB_File::HASHINFO::STORE - Unknown element 'fred' at/ );
135 eval 'my $q = $dbh->{fred}' ;
136 ok(14, $@ =~ /^DB_File::HASHINFO::FETCH - Unknown element 'fred' at/ );
137
138
139 # Now check the interface to HASH
140 my ($X, %h);
141 ok(15, $X = tie(%h, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
142 die "Could not tie: $!" unless $X;
143
144 my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
145    $blksize,$blocks) = stat($Dfile);
146
147 my %noMode = map { $_, 1} qw( amigaos MSWin32 NetWare cygwin ) ;
148
149 ok(16, ($mode & 0777) == (($^O eq 'os2' || $^O eq 'MacOS') ? 0666 : 0640) ||
150    $noMode{$^O} );
151
152 my ($key, $value, $i);
153 while (($key,$value) = each(%h)) {
154     $i++;
155 }
156 ok(17, !$i );
157
158 $h{'goner1'} = 'snork';
159
160 $h{'abc'} = 'ABC';
161 ok(18, $h{'abc'} eq 'ABC' );
162 ok(19, !defined $h{'jimmy'} );
163 ok(20, !exists $h{'jimmy'} );
164 ok(21, exists $h{'abc'} );
165
166 $h{'def'} = 'DEF';
167 $h{'jkl','mno'} = "JKL\034MNO";
168 $h{'a',2,3,4,5} = join("\034",'A',2,3,4,5);
169 $h{'a'} = 'A';
170
171 #$h{'b'} = 'B';
172 $X->STORE('b', 'B') ;
173
174 $h{'c'} = 'C';
175
176 #$h{'d'} = 'D';
177 $X->put('d', 'D') ;
178
179 $h{'e'} = 'E';
180 $h{'f'} = 'F';
181 $h{'g'} = 'X';
182 $h{'h'} = 'H';
183 $h{'i'} = 'I';
184
185 $h{'goner2'} = 'snork';
186 delete $h{'goner2'};
187
188
189 # IMPORTANT - $X must be undefined before the untie otherwise the
190 #             underlying DB close routine will not get called.
191 undef $X ;
192 untie(%h);
193
194
195 # tie to the same file again, do not supply a type - should default to HASH
196 ok(22, $X = tie(%h,'DB_File',$Dfile, O_RDWR, 0640) );
197
198 # Modify an entry from the previous tie
199 $h{'g'} = 'G';
200
201 $h{'j'} = 'J';
202 $h{'k'} = 'K';
203 $h{'l'} = 'L';
204 $h{'m'} = 'M';
205 $h{'n'} = 'N';
206 $h{'o'} = 'O';
207 $h{'p'} = 'P';
208 $h{'q'} = 'Q';
209 $h{'r'} = 'R';
210 $h{'s'} = 'S';
211 $h{'t'} = 'T';
212 $h{'u'} = 'U';
213 $h{'v'} = 'V';
214 $h{'w'} = 'W';
215 $h{'x'} = 'X';
216 $h{'y'} = 'Y';
217 $h{'z'} = 'Z';
218
219 $h{'goner3'} = 'snork';
220
221 delete $h{'goner1'};
222 $X->DELETE('goner3');
223
224 my @keys = keys(%h);
225 my @values = values(%h);
226
227 ok(23, $#keys == 29 && $#values == 29) ;
228
229 $i = 0 ;
230 while (($key,$value) = each(%h)) {
231     if ($key eq $keys[$i] && $value eq $values[$i] && $key eq lc($value)) {
232         $key =~ y/a-z/A-Z/;
233         $i++ if $key eq $value;
234     }
235 }
236
237 ok(24, $i == 30) ;
238
239 @keys = ('blurfl', keys(%h), 'dyick');
240 ok(25, $#keys == 31) ;
241
242 $h{'foo'} = '';
243 ok(26, $h{'foo'} eq '' );
244
245 # Berkeley DB from version 2.4.10 to 3.0 does not allow null keys.
246 # This feature was reenabled in version 3.1 of Berkeley DB.
247 my $result = 0 ;
248 if ($null_keys_allowed) {
249     $h{''} = 'bar';
250     $result = ( $h{''} eq 'bar' );
251 }
252 else
253   { $result = 1 }
254 ok(27, $result) ;
255
256 # check cache overflow and numeric keys and contents
257 my $ok = 1;
258 for ($i = 1; $i < 200; $i++) { $h{$i + 0} = $i + 0; }
259 for ($i = 1; $i < 200; $i++) { $ok = 0 unless $h{$i} == $i; }
260 ok(28, $ok );
261
262 ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
263    $blksize,$blocks) = stat($Dfile);
264 ok(29, $size > 0 );
265
266 @h{0..200} = 200..400;
267 my @foo = @h{0..200};
268 ok(30, join(':',200..400) eq join(':',@foo) );
269
270
271 # Now check all the non-tie specific stuff
272
273 # Check NOOVERWRITE will make put fail when attempting to overwrite
274 # an existing record.
275  
276 my $status = $X->put( 'x', 'newvalue', R_NOOVERWRITE) ;
277 ok(31, $status == 1 );
278  
279 # check that the value of the key 'x' has not been changed by the 
280 # previous test
281 ok(32, $h{'x'} eq 'X' );
282
283 # standard put
284 $status = $X->put('key', 'value') ;
285 ok(33, $status == 0 );
286
287 #check that previous put can be retrieved
288 $value = 0 ;
289 $status = $X->get('key', $value) ;
290 ok(34, $status == 0 );
291 ok(35, $value eq 'value' );
292
293 # Attempting to delete an existing key should work
294
295 $status = $X->del('q') ;
296 ok(36, $status == 0 );
297
298 # Make sure that the key deleted, cannot be retrieved
299 {
300     no warnings 'uninitialized' ;
301     ok(37, $h{'q'} eq undef );
302 }
303
304 # Attempting to delete a non-existant key should fail
305
306 $status = $X->del('joe') ;
307 ok(38, $status == 1 );
308
309 # Check the get interface
310
311 # First a non-existing key
312 $status = $X->get('aaaa', $value) ;
313 ok(39, $status == 1 );
314
315 # Next an existing key
316 $status = $X->get('a', $value) ;
317 ok(40, $status == 0 );
318 ok(41, $value eq 'A' );
319
320 # seq
321 # ###
322
323 # ditto, but use put to replace the key/value pair.
324
325 # use seq to walk backwards through a file - check that this reversed is
326
327 # check seq FIRST/LAST
328
329 # sync
330 # ####
331
332 $status = $X->sync ;
333 ok(42, $status == 0 );
334
335
336 # fd
337 # ##
338
339 $status = $X->fd ;
340 ok(43, $status != 0 );
341
342 undef $X ;
343 untie %h ;
344
345 unlink $Dfile;
346
347 # clear
348 # #####
349
350 ok(44, tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
351 foreach (1 .. 10)
352   { $h{$_} = $_ * 100 }
353
354 # check that there are 10 elements in the hash
355 $i = 0 ;
356 while (($key,$value) = each(%h)) {
357     $i++;
358 }
359 ok(45, $i == 10);
360
361 # now clear the hash
362 %h = () ;
363
364 # check it is empty
365 $i = 0 ;
366 while (($key,$value) = each(%h)) {
367     $i++;
368 }
369 ok(46, $i == 0);
370
371 untie %h ;
372 unlink $Dfile ;
373
374
375 # Now try an in memory file
376 ok(47, $X = tie(%h, 'DB_File',undef, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
377
378 # fd with an in memory file should return fail
379 $status = $X->fd ;
380 ok(48, $status == -1 );
381
382 undef $X ;
383 untie %h ;
384
385 {
386     # check ability to override the default hashing
387     my %x ;
388     my $filename = "xyz" ;
389     my $hi = new DB_File::HASHINFO ;
390     $::count = 0 ;
391     $hi->{hash} = sub { ++$::count ; length $_[0] } ;
392     ok(49, tie %x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $hi ) ;
393     $h{"abc"} = 123 ;
394     ok(50, $h{"abc"} == 123) ;
395     untie %x ;
396     unlink $filename ;
397     ok(51, $::count >0) ;
398 }
399
400 {
401     # check that attempting to tie an array to a DB_HASH will fail
402
403     my $filename = "xyz" ;
404     my @x ;
405     eval { tie @x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $DB_HASH ; } ;
406     ok(52, $@ =~ /^DB_File can only tie an associative array to a DB_HASH database/) ;
407     unlink $filename ;
408 }
409
410 {
411    # sub-class test
412
413    package Another ;
414
415    use warnings ;
416    use strict ;
417
418    open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ;
419    print FILE <<'EOM' ;
420
421    package SubDB ;
422
423    use warnings ;
424    use strict ;
425    our (@ISA, @EXPORT);
426
427    require Exporter ;
428    use DB_File;
429    @ISA=qw(DB_File);
430    @EXPORT = @DB_File::EXPORT ;
431
432    sub STORE { 
433         my $self = shift ;
434         my $key = shift ;
435         my $value = shift ;
436         $self->SUPER::STORE($key, $value * 2) ;
437    }
438
439    sub FETCH { 
440         my $self = shift ;
441         my $key = shift ;
442         $self->SUPER::FETCH($key) - 1 ;
443    }
444
445    sub put { 
446         my $self = shift ;
447         my $key = shift ;
448         my $value = shift ;
449         $self->SUPER::put($key, $value * 3) ;
450    }
451
452    sub get { 
453         my $self = shift ;
454         $self->SUPER::get($_[0], $_[1]) ;
455         $_[1] -= 2 ;
456    }
457
458    sub A_new_method
459    {
460         my $self = shift ;
461         my $key = shift ;
462         my $value = $self->FETCH($key) ;
463         return "[[$value]]" ;
464    }
465
466    1 ;
467 EOM
468
469     close FILE ;
470
471     BEGIN { push @INC, '.'; }             
472     eval 'use SubDB ; ';
473     main::ok(53, $@ eq "") ;
474     my %h ;
475     my $X ;
476     eval '
477         $X = tie(%h, "SubDB","dbhash.tmp", O_RDWR|O_CREAT, 0640, $DB_HASH );
478         ' ;
479
480     main::ok(54, $@ eq "") ;
481
482     my $ret = eval '$h{"fred"} = 3 ; return $h{"fred"} ' ;
483     main::ok(55, $@ eq "") ;
484     main::ok(56, $ret == 5) ;
485
486     my $value = 0;
487     $ret = eval '$X->put("joe", 4) ; $X->get("joe", $value) ; return $value' ;
488     main::ok(57, $@ eq "") ;
489     main::ok(58, $ret == 10) ;
490
491     $ret = eval ' R_NEXT eq main::R_NEXT ' ;
492     main::ok(59, $@ eq "" ) ;
493     main::ok(60, $ret == 1) ;
494
495     $ret = eval '$X->A_new_method("joe") ' ;
496     main::ok(61, $@ eq "") ;
497     main::ok(62, $ret eq "[[11]]") ;
498
499     undef $X;
500     untie(%h);
501     unlink "SubDB.pm", "dbhash.tmp" ;
502
503 }
504
505 {
506    # DBM Filter tests
507    use warnings ;
508    use strict ;
509    my (%h, $db) ;
510    my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
511    unlink $Dfile;
512
513    sub checkOutput
514    {
515        no warnings 'uninitialized';
516        my($fk, $sk, $fv, $sv) = @_ ;
517
518        print "# Fetch Key   : expected '$fk' got '$fetch_key'\n" 
519            if $fetch_key ne $fk ;
520        print "# Fetch Value : expected '$fv' got '$fetch_value'\n" 
521            if $fetch_value ne $fv ;
522        print "# Store Key   : expected '$sk' got '$store_key'\n" 
523            if $store_key ne $sk ;
524        print "# Store Value : expected '$sv' got '$store_value'\n" 
525            if $store_value ne $sv ;
526        print "# \$_          : expected 'original' got '$_'\n" 
527            if $_ ne 'original' ;
528
529        return
530            $fetch_key   eq $fk && $store_key   eq $sk && 
531            $fetch_value eq $fv && $store_value eq $sv &&
532            $_ eq 'original' ;
533    }
534    
535    ok(63, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
536
537    $db->filter_fetch_key   (sub { $fetch_key = $_ }) ;
538    $db->filter_store_key   (sub { $store_key = $_ }) ;
539    $db->filter_fetch_value (sub { $fetch_value = $_}) ;
540    $db->filter_store_value (sub { $store_value = $_ }) ;
541
542    $_ = "original" ;
543
544    $h{"fred"} = "joe" ;
545    #                   fk   sk     fv   sv
546    ok(64, checkOutput( "", "fred", "", "joe")) ;
547
548    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
549    ok(65, $h{"fred"} eq "joe");
550    #                   fk    sk     fv    sv
551    ok(66, checkOutput( "", "fred", "joe", "")) ;
552
553    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
554    my ($k, $v) ;
555    $k = 'fred';
556    ok(67, ! $db->seq($k, $v, R_FIRST) ) ;
557    ok(68, $k eq "fred") ;
558    ok(69, $v eq "joe") ;
559    #                    fk     sk  fv  sv
560    ok(70, checkOutput( "fred", "fred", "joe", "")) ;
561
562    # replace the filters, but remember the previous set
563    my ($old_fk) = $db->filter_fetch_key   
564                         (sub { $_ = uc $_ ; $fetch_key = $_ }) ;
565    my ($old_sk) = $db->filter_store_key   
566                         (sub { $_ = lc $_ ; $store_key = $_ }) ;
567    my ($old_fv) = $db->filter_fetch_value 
568                         (sub { $_ = "[$_]"; $fetch_value = $_ }) ;
569    my ($old_sv) = $db->filter_store_value 
570                         (sub { s/o/x/g; $store_value = $_ }) ;
571    
572    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
573    $h{"Fred"} = "Joe" ;
574    #                   fk   sk     fv    sv
575    ok(71, checkOutput( "", "fred", "", "Jxe")) ;
576
577    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
578    ok(72, $h{"Fred"} eq "[Jxe]");
579    #                   fk   sk     fv    sv
580    ok(73, checkOutput( "", "fred", "[Jxe]", "")) ;
581
582    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
583    $k = 'Fred'; $v ='';
584    ok(74, ! $db->seq($k, $v, R_FIRST) ) ;
585    ok(75, $k eq "FRED") or 
586     print "# k [$k]\n" ;
587    ok(76, $v eq "[Jxe]") ;
588    #                   fk   sk     fv    sv
589    ok(77, checkOutput( "FRED", "fred", "[Jxe]", "")) ;
590
591    # put the original filters back
592    $db->filter_fetch_key   ($old_fk);
593    $db->filter_store_key   ($old_sk);
594    $db->filter_fetch_value ($old_fv);
595    $db->filter_store_value ($old_sv);
596
597    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
598    $h{"fred"} = "joe" ;
599    ok(78, checkOutput( "", "fred", "", "joe")) ;
600
601    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
602    ok(79, $h{"fred"} eq "joe");
603    ok(80, checkOutput( "", "fred", "joe", "")) ;
604
605    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
606    #ok(77, $db->FIRSTKEY() eq "fred") ;
607    $k = 'fred';
608    ok(81, ! $db->seq($k, $v, R_FIRST) ) ;
609    ok(82, $k eq "fred") ;
610    ok(83, $v eq "joe") ;
611    #                   fk   sk     fv    sv
612    ok(84, checkOutput( "fred", "fred", "joe", "")) ;
613
614    # delete the filters
615    $db->filter_fetch_key   (undef);
616    $db->filter_store_key   (undef);
617    $db->filter_fetch_value (undef);
618    $db->filter_store_value (undef);
619
620    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
621    $h{"fred"} = "joe" ;
622    ok(85, checkOutput( "", "", "", "")) ;
623
624    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
625    ok(86, $h{"fred"} eq "joe");
626    ok(87, checkOutput( "", "", "", "")) ;
627
628    ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
629    $k = 'fred';
630    ok(88, ! $db->seq($k, $v, R_FIRST) ) ;
631    ok(89, $k eq "fred") ;
632    ok(90, $v eq "joe") ;
633    ok(91, checkOutput( "", "", "", "")) ;
634
635    undef $db ;
636    untie %h;
637    unlink $Dfile;
638 }
639
640 {    
641     # DBM Filter with a closure
642
643     use warnings ;
644     use strict ;
645     my (%h, $db) ;
646
647     unlink $Dfile;
648     ok(92, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
649
650     my %result = () ;
651
652     sub Closure
653     {
654         my ($name) = @_ ;
655         my $count = 0 ;
656         my @kept = () ;
657
658         return sub { ++$count ; 
659                      push @kept, $_ ; 
660                      $result{$name} = "$name - $count: [@kept]" ;
661                    }
662     }
663
664     $db->filter_store_key(Closure("store key")) ;
665     $db->filter_store_value(Closure("store value")) ;
666     $db->filter_fetch_key(Closure("fetch key")) ;
667     $db->filter_fetch_value(Closure("fetch value")) ;
668
669     $_ = "original" ;
670
671     $h{"fred"} = "joe" ;
672     ok(93, $result{"store key"} eq "store key - 1: [fred]");
673     ok(94, $result{"store value"} eq "store value - 1: [joe]");
674     ok(95, ! defined $result{"fetch key"} );
675     ok(96, ! defined $result{"fetch value"} );
676     ok(97, $_ eq "original") ;
677
678     ok(98, $db->FIRSTKEY() eq "fred") ;
679     ok(99, $result{"store key"} eq "store key - 1: [fred]");
680     ok(100, $result{"store value"} eq "store value - 1: [joe]");
681     ok(101, $result{"fetch key"} eq "fetch key - 1: [fred]");
682     ok(102, ! defined $result{"fetch value"} );
683     ok(103, $_ eq "original") ;
684
685     $h{"jim"}  = "john" ;
686     ok(104, $result{"store key"} eq "store key - 2: [fred jim]");
687     ok(105, $result{"store value"} eq "store value - 2: [joe john]");
688     ok(106, $result{"fetch key"} eq "fetch key - 1: [fred]");
689     ok(107, ! defined $result{"fetch value"} );
690     ok(108, $_ eq "original") ;
691
692     ok(109, $h{"fred"} eq "joe");
693     ok(110, $result{"store key"} eq "store key - 3: [fred jim fred]");
694     ok(111, $result{"store value"} eq "store value - 2: [joe john]");
695     ok(112, $result{"fetch key"} eq "fetch key - 1: [fred]");
696     ok(113, $result{"fetch value"} eq "fetch value - 1: [joe]");
697     ok(114, $_ eq "original") ;
698
699     undef $db ;
700     untie %h;
701     unlink $Dfile;
702 }               
703
704 {
705    # DBM Filter recursion detection
706    use warnings ;
707    use strict ;
708    my (%h, $db) ;
709    unlink $Dfile;
710
711    ok(115, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
712
713    $db->filter_store_key (sub { $_ = $h{$_} }) ;
714
715    eval '$h{1} = 1234' ;
716    ok(116, $@ =~ /^recursion detected in filter_store_key at/ );
717    
718    undef $db ;
719    untie %h;
720    unlink $Dfile;
721 }
722
723
724 {
725    # Examples from the POD
726
727   my $file = "xyzt" ;
728   {
729     my $redirect = new Redirect $file ;
730
731     use warnings FATAL => qw(all);
732     use strict ;
733     use DB_File ;
734     our (%h, $k, $v);
735
736     unlink "fruit" ;
737     tie %h, "DB_File", "fruit", O_RDWR|O_CREAT, 0640, $DB_HASH 
738         or die "Cannot open file 'fruit': $!\n";
739
740     # Add a few key/value pairs to the file
741     $h{"apple"} = "red" ;
742     $h{"orange"} = "orange" ;
743     $h{"banana"} = "yellow" ;
744     $h{"tomato"} = "red" ;
745
746     # Check for existence of a key
747     print "Banana Exists\n\n" if $h{"banana"} ;
748
749     # Delete a key/value pair.
750     delete $h{"apple"} ;
751
752     # print the contents of the file
753     while (($k, $v) = each %h)
754       { print "$k -> $v\n" }
755
756     untie %h ;
757
758     unlink "fruit" ;
759   }  
760
761   ok(117, docat_del($file) eq <<'EOM') ;
762 Banana Exists
763
764 orange -> orange
765 tomato -> red
766 banana -> yellow
767 EOM
768    
769 }
770
771 {
772     # Bug ID 20001013.009
773     #
774     # test that $hash{KEY} = undef doesn't produce the warning
775     #     Use of uninitialized value in null operation 
776     use warnings ;
777     use strict ;
778     use DB_File ;
779
780     unlink $Dfile;
781     my %h ;
782     my $a = "";
783     local $SIG{__WARN__} = sub {$a = $_[0]} ;
784     
785     tie %h, 'DB_File', $Dfile or die "Can't open file: $!\n" ;
786     $h{ABC} = undef;
787     ok(118, $a eq "") ;
788     untie %h ;
789     unlink $Dfile;
790 }
791
792 {
793     # test that %hash = () doesn't produce the warning
794     #     Argument "" isn't numeric in entersub
795     use warnings ;
796     use strict ;
797     use DB_File ;
798
799     unlink $Dfile;
800     my %h ;
801     my $a = "";
802     local $SIG{__WARN__} = sub {$a = $_[0]} ;
803     
804     tie %h, 'DB_File', $Dfile or die "Can't open file: $!\n" ;
805     %h = (); ;
806     ok(119, $a eq "") ;
807     untie %h ;
808     unlink $Dfile;
809 }
810
811 {
812     # When iterating over a tied hash using "each", the key passed to FETCH
813     # will be recycled and passed to NEXTKEY. If a Source Filter modifies the
814     # key in FETCH via a filter_fetch_key method we need to check that the
815     # modified key doesn't get passed to NEXTKEY.
816     # Also Test "keys" & "values" while we are at it.
817
818     use warnings ;
819     use strict ;
820     use DB_File ;
821
822     unlink $Dfile;
823     my $bad_key = 0 ;
824     my %h = () ;
825     my $db ;
826     ok(120, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
827     $db->filter_fetch_key (sub { $_ =~ s/^Beta_/Alpha_/ if defined $_}) ;
828     $db->filter_store_key (sub { $bad_key = 1 if /^Beta_/ ; $_ =~ s/^Alpha_/Beta_/}) ;
829
830     $h{'Alpha_ABC'} = 2 ;
831     $h{'Alpha_DEF'} = 5 ;
832
833     ok(121, $h{'Alpha_ABC'} == 2);
834     ok(122, $h{'Alpha_DEF'} == 5);
835
836     my ($k, $v) = ("","");
837     while (($k, $v) = each %h) {}
838     ok(123, $bad_key == 0);
839
840     $bad_key = 0 ;
841     foreach $k (keys %h) {}
842     ok(124, $bad_key == 0);
843
844     $bad_key = 0 ;
845     foreach $v (values %h) {}
846     ok(125, $bad_key == 0);
847
848     undef $db ;
849     untie %h ;
850     unlink $Dfile;
851 }
852
853 {
854     # now an error to pass 'hash' a non-code reference
855     my $dbh = new DB_File::HASHINFO ;
856
857     eval { $dbh->{hash} = 2 };
858     ok(126, $@ =~ /^Key 'hash' not associated with a code reference at/);
859
860 }
861
862
863 #{
864 #    # recursion detection in hash
865 #    my %hash ;
866 #    my $Dfile = "xxx.db";
867 #    unlink $Dfile;
868 #    my $dbh = new DB_File::HASHINFO ;
869 #    $dbh->{hash} = sub { $hash{3} = 4 ; length $_[0] } ;
870
871
872 #    ok(127, tie(%hash, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $dbh ) );
873 #
874 #    eval {     $hash{1} = 2;
875 #               $hash{4} = 5;
876 #        };
877 #
878 #    ok(128, $@ =~ /^DB_File hash callback: recursion detected/);
879 #    {
880 #        no warnings;
881 #        untie %hash;
882 #    }
883 #    unlink $Dfile;
884 #}
885
886 #ok(127, 1);
887 #ok(128, 1);
888
889 {
890     # Check that two hash's don't interact
891     my %hash1 ;
892     my %hash2 ;
893     my $h1_count = 0;
894     my $h2_count = 0;
895     unlink $Dfile, $Dfile2;
896     my $dbh1 = new DB_File::HASHINFO ;
897     $dbh1->{hash} = sub { ++ $h1_count ; length $_[0] } ;
898
899     my $dbh2 = new DB_File::HASHINFO ;
900     $dbh2->{hash} = sub { ++ $h2_count ; length $_[0] } ;
901  
902  
903  
904     my (%h);
905     ok(127, tie(%hash1, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $dbh1 ) );
906     ok(128, tie(%hash2, 'DB_File',$Dfile2, O_RDWR|O_CREAT, 0640, $dbh2 ) );
907
908     $hash1{DEFG} = 5;
909     $hash1{XYZ} = 2;
910     $hash1{ABCDE} = 5;
911
912     $hash2{defg} = 5;
913     $hash2{xyz} = 2;
914     $hash2{abcde} = 5;
915
916     ok(129, $h1_count > 0);
917     ok(130, $h1_count == $h2_count);
918
919     ok(131, safeUntie \%hash1);
920     ok(132, safeUntie \%hash2);
921     unlink $Dfile, $Dfile2;
922 }
923
924 {
925     # Passing undef for flags and/or mode when calling tie could cause 
926     #     Use of uninitialized value in subroutine entry
927     
928
929     my $warn_count = 0 ;
930     #local $SIG{__WARN__} = sub { ++ $warn_count };
931     my %hash1;
932     unlink $Dfile;
933
934     tie %hash1, 'DB_File',$Dfile, undef;
935     ok(133, $warn_count == 0);
936     $warn_count = 0;
937     untie %hash1;
938     unlink $Dfile;
939     tie %hash1, 'DB_File',$Dfile, O_RDWR|O_CREAT, undef;
940     ok(134, $warn_count == 0);
941     untie %hash1;
942     unlink $Dfile;
943     tie %hash1, 'DB_File',$Dfile, undef, undef;
944     ok(135, $warn_count == 0);
945     $warn_count = 0;
946
947     untie %hash1;
948     unlink $Dfile;
949 }
950
951 {
952    # Check that DBM Filter can cope with read-only $_
953
954    use warnings ;
955    use strict ;
956    my (%h, $db) ;
957    my $Dfile = "xxy.db";
958    unlink $Dfile;
959
960    ok(136, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
961
962    $db->filter_fetch_key   (sub { }) ;
963    $db->filter_store_key   (sub { }) ;
964    $db->filter_fetch_value (sub { }) ;
965    $db->filter_store_value (sub { }) ;
966
967    $_ = "original" ;
968
969    $h{"fred"} = "joe" ;
970    ok(137, $h{"fred"} eq "joe");
971
972    eval { grep { $h{$_} } (1, 2, 3) };
973    ok (138, ! $@);
974
975
976    # delete the filters
977    $db->filter_fetch_key   (undef);
978    $db->filter_store_key   (undef);
979    $db->filter_fetch_value (undef);
980    $db->filter_store_value (undef);
981
982    $h{"fred"} = "joe" ;
983
984    ok(139, $h{"fred"} eq "joe");
985
986    ok(140, $db->FIRSTKEY() eq "fred") ;
987    
988    eval { grep { $h{$_} } (1, 2, 3) };
989    ok (141, ! $@);
990
991    undef $db ;
992    untie %h;
993    unlink $Dfile;
994 }
995
996 {
997    # Check low-level API works with filter
998
999    use warnings ;
1000    use strict ;
1001    my (%h, $db) ;
1002    my $Dfile = "xxy.db";
1003    unlink $Dfile;
1004
1005    ok(142, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
1006
1007
1008    $db->filter_fetch_key   (sub { $_ = unpack("i", $_) } );
1009    $db->filter_store_key   (sub { $_ = pack("i", $_) } );
1010    $db->filter_fetch_value (sub { $_ = unpack("i", $_) } );
1011    $db->filter_store_value (sub { $_ = pack("i", $_) } );
1012
1013    $_ = 'fred';
1014
1015    my $key = 22 ;
1016    my $value = 34 ;
1017
1018    $db->put($key, $value) ;
1019    ok 143, $key == 22;
1020    ok 144, $value == 34 ;
1021    ok 145, $_ eq 'fred';
1022    #print "k [$key][$value]\n" ;
1023
1024    my $val ;
1025    $db->get($key, $val) ;
1026    ok 146, $key == 22;
1027    ok 147, $val == 34 ;
1028    ok 148, $_ eq 'fred';
1029
1030    $key = 51 ;
1031    $value = 454;
1032    $h{$key} = $value ;
1033    ok 149, $key == 51;
1034    ok 150, $value == 454 ;
1035    ok 151, $_ eq 'fred';
1036
1037    undef $db ;
1038    untie %h;
1039    unlink $Dfile;
1040 }
1041
1042
1043 {
1044     # Regression Test for bug 30237
1045     # Check that substr can be used in the key to db_put
1046     # and that db_put does not trigger the warning
1047     # 
1048     #     Use of uninitialized value in subroutine entry
1049
1050
1051     use warnings ;
1052     use strict ;
1053     my (%h, $db) ;
1054     my $Dfile = "xxy.db";
1055     unlink $Dfile;
1056
1057     ok(152, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
1058
1059     my $warned = '';
1060     local $SIG{__WARN__} = sub {$warned = $_[0]} ;
1061
1062     # db-put with substr of key
1063     my %remember = () ;
1064     for my $ix ( 1 .. 2 )
1065     {
1066         my $key = $ix . "data" ;
1067         my $value = "value$ix" ;
1068         $remember{$key} = $value ;
1069         $db->put(substr($key,0), $value) ;
1070     }
1071
1072     ok 153, $warned eq '' 
1073       or print "# Caught warning [$warned]\n" ;
1074
1075     # db-put with substr of value
1076     $warned = '';
1077     for my $ix ( 10 .. 12 )
1078     {
1079         my $key = $ix . "data" ;
1080         my $value = "value$ix" ;
1081         $remember{$key} = $value ;
1082         $db->put($key, substr($value,0)) ;
1083     }
1084
1085     ok 154, $warned eq '' 
1086       or print "# Caught warning [$warned]\n" ;
1087
1088     # via the tied hash is not a problem, but check anyway
1089     # substr of key
1090     $warned = '';
1091     for my $ix ( 30 .. 32 )
1092     {
1093         my $key = $ix . "data" ;
1094         my $value = "value$ix" ;
1095         $remember{$key} = $value ;
1096         $h{substr($key,0)} = $value ;
1097     }
1098
1099     ok 155, $warned eq '' 
1100       or print "# Caught warning [$warned]\n" ;
1101
1102     # via the tied hash is not a problem, but check anyway
1103     # substr of value
1104     $warned = '';
1105     for my $ix ( 40 .. 42 )
1106     {
1107         my $key = $ix . "data" ;
1108         my $value = "value$ix" ;
1109         $remember{$key} = $value ;
1110         $h{$key} = substr($value,0) ;
1111     }
1112
1113     ok 156, $warned eq '' 
1114       or print "# Caught warning [$warned]\n" ;
1115
1116     my %bad = () ;
1117     $key = '';
1118     for ($status = $db->seq(substr($key,0), substr($value,0), R_FIRST ) ;
1119          $status == 0 ;
1120          $status = $db->seq(substr($key,0), substr($value,0), R_NEXT ) ) {
1121
1122         #print "# key [$key] value [$value]\n" ;
1123         if (defined $remember{$key} && defined $value && 
1124              $remember{$key} eq $value) {
1125             delete $remember{$key} ;
1126         }
1127         else {
1128             $bad{$key} = $value ;
1129         }
1130     }
1131     
1132     ok 157, keys %bad == 0 ;
1133     ok 158, keys %remember == 0 ;
1134
1135     print "# missing -- $key=>$value\n" while ($key, $value) = each %remember;
1136     print "# bad     -- $key=>$value\n" while ($key, $value) = each %bad;
1137
1138     # Make sure this fix does not break code to handle an undef key
1139     # Berkeley DB undef key is broken between versions 2.3.16 and 3.1
1140     my $value = 'fred';
1141     $warned = '';
1142     $db->put(undef, $value) ;
1143     ok 159, $warned eq '' 
1144       or print "# Caught warning [$warned]\n" ;
1145     $warned = '';
1146
1147     my $no_NULL = ($DB_File::db_ver >= 2.003016 && $DB_File::db_ver < 3.001) ;
1148     print "# db_ver $DB_File::db_ver\n";
1149     $value = '' ;
1150     $db->get(undef, $value) ;
1151     ok 160, $no_NULL || $value eq 'fred' or print "# got [$value]\n" ;
1152     ok 161, $warned eq '' 
1153       or print "# Caught warning [$warned]\n" ;
1154     $warned = '';
1155
1156     undef $db ;
1157     untie %h;
1158     unlink $Dfile;
1159 }
1160
1161 {
1162    # Check filter + substr
1163
1164    use warnings ;
1165    use strict ;
1166    my (%h, $db) ;
1167    my $Dfile = "xxy.db";
1168    unlink $Dfile;
1169
1170    ok(162, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_HASH ) );
1171
1172
1173    {
1174        $db->filter_fetch_key   (sub { lc $_ } );
1175        $db->filter_store_key   (sub { uc $_ } );
1176        $db->filter_fetch_value (sub { lc $_ } );
1177        $db->filter_store_value (sub { uc $_ } );
1178    }
1179
1180    $_ = 'fred';
1181
1182     # db-put with substr of key
1183     my %remember = () ;
1184     my $status = 0 ;
1185     for my $ix ( 1 .. 2 )
1186     {
1187         my $key = $ix . "data" ;
1188         my $value = "value$ix" ;
1189         $remember{$key} = $value ;
1190         $status += $db->put(substr($key,0), substr($value,0)) ;
1191     }
1192
1193     ok 163, $status == 0 or print "# Status $status\n" ;
1194
1195     if (1)
1196     {
1197        $db->filter_fetch_key   (undef);
1198        $db->filter_store_key   (undef);
1199        $db->filter_fetch_value (undef);
1200        $db->filter_store_value (undef);
1201     }
1202
1203     my %bad = () ;
1204     my $key = '';
1205     my $value = '';
1206     for ($status = $db->seq($key, $value, R_FIRST ) ;
1207          $status == 0 ;
1208          $status = $db->seq($key, $value, R_NEXT ) ) {
1209
1210         #print "# key [$key] value [$value]\n" ;
1211         if (defined $remember{$key} && defined $value && 
1212              $remember{$key} eq $value) {
1213             delete $remember{$key} ;
1214         }
1215         else {
1216             $bad{$key} = $value ;
1217         }
1218     }
1219     
1220     ok 164, $_ eq 'fred';
1221     ok 165, keys %bad == 0 ;
1222     ok 166, keys %remember == 0 ;
1223
1224     print "# missing -- $key $value\n" while ($key, $value) = each %remember;
1225     print "# bad     -- $key $value\n" while ($key, $value) = each %bad;
1226    undef $db ;
1227    untie %h;
1228    unlink $Dfile;
1229 }
1230
1231 exit ;