This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
The first big import towards 5.8.1, @18078. Please do NOT
[perl5.git] / ext / DB_File / t / db-btree.t
CommitLineData
f6b705ef 1#!./perl -w
a0d0e21e 2
77fd2717
PM
3BEGIN {
4 unless(grep /blib/, @INC) {
5 chdir 't' if -d 't';
6 @INC = '../lib' if -d '../lib';
7 }
8}
9
bb50757b
RGS
10use warnings;
11use strict;
77fd2717
PM
12use Config;
13
a0d0e21e 14BEGIN {
77fd2717
PM
15 if(-d "lib" && -f "TEST") {
16 if ($Config{'extensions'} !~ /\bDB_File\b/ ) {
bb50757b 17 print "1..0 # Skip: DB_File was not built\n";
77fd2717
PM
18 exit 0;
19 }
a0d0e21e 20 }
3ebf0137
JH
21 if ($^O eq 'darwin'
22 && $Config{db_version_major} == 1
23 && $Config{db_version_minor} == 0
24 && $Config{db_version_patch} == 0) {
25 warn <<EOM;
26#
5b7ea690 27# This test is known to crash in Mac OS X versions 10.2 (or earlier)
3ebf0137
JH
28# because of the buggy Berkeley DB version included with the OS.
29#
30EOM
31 }
a0d0e21e
LW
32}
33
34use DB_File;
35use Fcntl;
36
5b7ea690
JH
37print "1..177\n";
38
39unlink glob "__db.*";
f6b705ef 40
41sub ok
42{
43 my $no = shift ;
44 my $result = shift ;
45
46 print "not " unless $result ;
47 print "ok $no\n" ;
48}
a0d0e21e 49
55497cff 50sub lexical
51{
52 my(@a) = unpack ("C*", $a) ;
53 my(@b) = unpack ("C*", $b) ;
54
55 my $len = (@a > @b ? @b : @a) ;
56 my $i = 0 ;
57
58 foreach $i ( 0 .. $len -1) {
59 return $a[$i] - $b[$i] if $a[$i] != $b[$i] ;
60 }
61
62 return @a - @b ;
63}
64
2c2d71f5
JH
65{
66 package Redirect ;
67 use Symbol ;
68
69 sub new
70 {
71 my $class = shift ;
72 my $filename = shift ;
73 my $fh = gensym ;
74 open ($fh, ">$filename") || die "Cannot open $filename: $!" ;
75 my $real_stdout = select($fh) ;
76 return bless [$fh, $real_stdout ] ;
77
78 }
79 sub DESTROY
80 {
81 my $self = shift ;
82 close $self->[0] ;
83 select($self->[1]) ;
84 }
85}
86
87sub docat
88{
89 my $file = shift;
77fd2717 90 local $/ = undef ;
2c2d71f5 91 open(CAT,$file) || die "Cannot open $file: $!";
77fd2717 92 my $result = <CAT>;
2c2d71f5 93 close(CAT);
77fd2717
PM
94 $result = normalise($result) ;
95 return $result ;
2c2d71f5
JH
96}
97
98sub docat_del
99{
100 my $file = shift;
77fd2717 101 my $result = docat($file);
2c2d71f5 102 unlink $file ;
77fd2717 103 return $result ;
2c2d71f5
JH
104}
105
77fd2717
PM
106sub normalise
107{
108 my $data = shift ;
109 $data =~ s#\r\n#\n#g
110 if $^O eq 'cygwin' ;
111
112 return $data ;
113}
114
5b7ea690
JH
115sub safeUntie
116{
117 my $hashref = shift ;
118 my $no_inner = 1;
119 local $SIG{__WARN__} = sub {-- $no_inner } ;
120 untie %$hashref;
121 return $no_inner;
122}
123
77fd2717 124
2c2d71f5 125
3245f058
PM
126my $db185mode = ($DB_File::db_version == 1 && ! $DB_File::db_185_compat) ;
127my $null_keys_allowed = ($DB_File::db_ver < 2.004010
128 || $DB_File::db_ver >= 3.1 );
039d031f 129
9fe6733a 130my $Dfile = "dbbtree.tmp";
a0d0e21e
LW
131unlink $Dfile;
132
133umask(0);
134
135# Check the interface to BTREEINFO
136
f6b705ef 137my $dbh = new DB_File::BTREEINFO ;
3fe9a6f1 138ok(1, ! defined $dbh->{flags}) ;
139ok(2, ! defined $dbh->{cachesize}) ;
140ok(3, ! defined $dbh->{psize}) ;
141ok(4, ! defined $dbh->{lorder}) ;
142ok(5, ! defined $dbh->{minkeypage}) ;
143ok(6, ! defined $dbh->{maxkeypage}) ;
144ok(7, ! defined $dbh->{compare}) ;
145ok(8, ! defined $dbh->{prefix}) ;
a0d0e21e
LW
146
147$dbh->{flags} = 3000 ;
f6b705ef 148ok(9, $dbh->{flags} == 3000) ;
a0d0e21e
LW
149
150$dbh->{cachesize} = 9000 ;
f6b705ef 151ok(10, $dbh->{cachesize} == 9000);
152
a0d0e21e 153$dbh->{psize} = 400 ;
f6b705ef 154ok(11, $dbh->{psize} == 400) ;
a0d0e21e
LW
155
156$dbh->{lorder} = 65 ;
f6b705ef 157ok(12, $dbh->{lorder} == 65) ;
a0d0e21e
LW
158
159$dbh->{minkeypage} = 123 ;
f6b705ef 160ok(13, $dbh->{minkeypage} == 123) ;
a0d0e21e
LW
161
162$dbh->{maxkeypage} = 1234 ;
f6b705ef 163ok(14, $dbh->{maxkeypage} == 1234 );
a0d0e21e 164
a0d0e21e
LW
165# Check that an invalid entry is caught both for store & fetch
166eval '$dbh->{fred} = 1234' ;
5b7ea690 167ok(15, $@ =~ /^DB_File::BTREEINFO::STORE - Unknown element 'fred' at/ ) ;
3245f058 168eval 'my $q = $dbh->{fred}' ;
5b7ea690 169ok(16, $@ =~ /^DB_File::BTREEINFO::FETCH - Unknown element 'fred' at/ ) ;
a0d0e21e
LW
170
171# Now check the interface to BTREE
172
3245f058 173my ($X, %h) ;
5b7ea690 174ok(17, $X = tie(%h, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE )) ;
05a54443 175die "Could not tie: $!" unless $X;
a0d0e21e 176
3245f058 177my ($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
a0d0e21e 178 $blksize,$blocks) = stat($Dfile);
77fd2717
PM
179
180my %noMode = map { $_, 1} qw( amigaos MSWin32 NetWare cygwin ) ;
181
5b7ea690 182ok(18, ($mode & 0777) == (($^O eq 'os2' || $^O eq 'MacOS') ? 0666 : 0640)
77fd2717 183 || $noMode{$^O} );
a0d0e21e 184
3245f058 185my ($key, $value, $i);
a0d0e21e
LW
186while (($key,$value) = each(%h)) {
187 $i++;
188}
5b7ea690 189ok(19, !$i ) ;
a0d0e21e
LW
190
191$h{'goner1'} = 'snork';
192
193$h{'abc'} = 'ABC';
5b7ea690
JH
194ok(20, $h{'abc'} eq 'ABC' );
195ok(21, ! defined $h{'jimmy'} ) ;
196ok(22, ! exists $h{'jimmy'} ) ;
197ok(23, defined $h{'abc'} ) ;
a0d0e21e
LW
198
199$h{'def'} = 'DEF';
200$h{'jkl','mno'} = "JKL\034MNO";
201$h{'a',2,3,4,5} = join("\034",'A',2,3,4,5);
202$h{'a'} = 'A';
203
204#$h{'b'} = 'B';
205$X->STORE('b', 'B') ;
206
207$h{'c'} = 'C';
208
209#$h{'d'} = 'D';
210$X->put('d', 'D') ;
211
212$h{'e'} = 'E';
213$h{'f'} = 'F';
214$h{'g'} = 'X';
215$h{'h'} = 'H';
216$h{'i'} = 'I';
217
218$h{'goner2'} = 'snork';
219delete $h{'goner2'};
220
221
222# IMPORTANT - $X must be undefined before the untie otherwise the
223# underlying DB close routine will not get called.
224undef $X ;
225untie(%h);
226
a0d0e21e 227# tie to the same file again
5b7ea690 228ok(24, $X = tie(%h,'DB_File',$Dfile, O_RDWR, 0640, $DB_BTREE)) ;
a0d0e21e
LW
229
230# Modify an entry from the previous tie
231$h{'g'} = 'G';
232
233$h{'j'} = 'J';
234$h{'k'} = 'K';
235$h{'l'} = 'L';
236$h{'m'} = 'M';
237$h{'n'} = 'N';
238$h{'o'} = 'O';
239$h{'p'} = 'P';
240$h{'q'} = 'Q';
241$h{'r'} = 'R';
242$h{'s'} = 'S';
243$h{'t'} = 'T';
244$h{'u'} = 'U';
245$h{'v'} = 'V';
246$h{'w'} = 'W';
247$h{'x'} = 'X';
248$h{'y'} = 'Y';
249$h{'z'} = 'Z';
250
251$h{'goner3'} = 'snork';
252
253delete $h{'goner1'};
254$X->DELETE('goner3');
255
3245f058
PM
256my @keys = keys(%h);
257my @values = values(%h);
a0d0e21e 258
5b7ea690 259ok(25, $#keys == 29 && $#values == 29) ;
a0d0e21e 260
f6b705ef 261$i = 0 ;
a0d0e21e 262while (($key,$value) = each(%h)) {
2f52a358 263 if ($key eq $keys[$i] && $value eq $values[$i] && $key eq lc($value)) {
a0d0e21e
LW
264 $key =~ y/a-z/A-Z/;
265 $i++ if $key eq $value;
266 }
267}
268
5b7ea690 269ok(26, $i == 30) ;
a0d0e21e 270
55d68b4a 271@keys = ('blurfl', keys(%h), 'dyick');
5b7ea690 272ok(27, $#keys == 31) ;
a0d0e21e
LW
273
274#Check that the keys can be retrieved in order
55497cff 275my @b = keys %h ;
276my @c = sort lexical @b ;
5b7ea690 277ok(28, ArrayCompare(\@b, \@c)) ;
a0d0e21e
LW
278
279$h{'foo'} = '';
5b7ea690 280ok(29, $h{'foo'} eq '' ) ;
a0d0e21e 281
3245f058
PM
282# Berkeley DB from version 2.4.10 to 3.0 does not allow null keys.
283# This feature was reenabled in version 3.1 of Berkeley DB.
284my $result = 0 ;
285if ($null_keys_allowed) {
286 $h{''} = 'bar';
287 $result = ( $h{''} eq 'bar' );
288}
289else
290 { $result = 1 }
5b7ea690 291ok(30, $result) ;
a0d0e21e
LW
292
293# check cache overflow and numeric keys and contents
3245f058 294my $ok = 1;
a0d0e21e
LW
295for ($i = 1; $i < 200; $i++) { $h{$i + 0} = $i + 0; }
296for ($i = 1; $i < 200; $i++) { $ok = 0 unless $h{$i} == $i; }
5b7ea690 297ok(31, $ok);
a0d0e21e
LW
298
299($dev,$ino,$mode,$nlink,$uid,$gid,$rdev,$size,$atime,$mtime,$ctime,
300 $blksize,$blocks) = stat($Dfile);
5b7ea690 301ok(32, $size > 0 );
a0d0e21e
LW
302
303@h{0..200} = 200..400;
3245f058 304my @foo = @h{0..200};
5b7ea690 305ok(33, join(':',200..400) eq join(':',@foo) );
a0d0e21e
LW
306
307# Now check all the non-tie specific stuff
308
309
310# Check R_NOOVERWRITE flag will make put fail when attempting to overwrite
311# an existing record.
312
3245f058 313my $status = $X->put( 'x', 'newvalue', R_NOOVERWRITE) ;
5b7ea690 314ok(34, $status == 1 );
a0d0e21e
LW
315
316# check that the value of the key 'x' has not been changed by the
317# previous test
5b7ea690 318ok(35, $h{'x'} eq 'X' );
a0d0e21e
LW
319
320# standard put
321$status = $X->put('key', 'value') ;
5b7ea690 322ok(36, $status == 0 );
a0d0e21e
LW
323
324#check that previous put can be retrieved
f6b705ef 325$value = 0 ;
a0d0e21e 326$status = $X->get('key', $value) ;
5b7ea690
JH
327ok(37, $status == 0 );
328ok(38, $value eq 'value' );
a0d0e21e
LW
329
330# Attempting to delete an existing key should work
331
332$status = $X->del('q') ;
5b7ea690 333ok(39, $status == 0 );
3245f058
PM
334if ($null_keys_allowed) {
335 $status = $X->del('') ;
336} else {
337 $status = 0 ;
338}
5b7ea690 339ok(40, $status == 0 );
a0d0e21e
LW
340
341# Make sure that the key deleted, cannot be retrieved
5b7ea690
JH
342ok(41, ! defined $h{'q'}) ;
343ok(42, ! defined $h{''}) ;
a0d0e21e
LW
344
345undef $X ;
346untie %h ;
347
5b7ea690 348ok(43, $X = tie(%h, 'DB_File',$Dfile, O_RDWR, 0640, $DB_BTREE ));
a0d0e21e
LW
349
350# Attempting to delete a non-existant key should fail
351
352$status = $X->del('joe') ;
5b7ea690 353ok(44, $status == 1 );
a0d0e21e
LW
354
355# Check the get interface
356
357# First a non-existing key
358$status = $X->get('aaaa', $value) ;
5b7ea690 359ok(45, $status == 1 );
a0d0e21e
LW
360
361# Next an existing key
362$status = $X->get('a', $value) ;
5b7ea690
JH
363ok(46, $status == 0 );
364ok(47, $value eq 'A' );
a0d0e21e
LW
365
366# seq
367# ###
368
369# use seq to find an approximate match
370$key = 'ke' ;
371$value = '' ;
372$status = $X->seq($key, $value, R_CURSOR) ;
5b7ea690
JH
373ok(48, $status == 0 );
374ok(49, $key eq 'key' );
375ok(50, $value eq 'value' );
a0d0e21e
LW
376
377# seq when the key does not match
378$key = 'zzz' ;
379$value = '' ;
380$status = $X->seq($key, $value, R_CURSOR) ;
5b7ea690 381ok(51, $status == 1 );
a0d0e21e
LW
382
383
384# use seq to set the cursor, then delete the record @ the cursor.
385
386$key = 'x' ;
387$value = '' ;
388$status = $X->seq($key, $value, R_CURSOR) ;
5b7ea690
JH
389ok(52, $status == 0 );
390ok(53, $key eq 'x' );
391ok(54, $value eq 'X' );
a0d0e21e 392$status = $X->del(0, R_CURSOR) ;
5b7ea690 393ok(55, $status == 0 );
a0d0e21e 394$status = $X->get('x', $value) ;
5b7ea690 395ok(56, $status == 1 );
a0d0e21e
LW
396
397# ditto, but use put to replace the key/value pair.
398$key = 'y' ;
399$value = '' ;
400$status = $X->seq($key, $value, R_CURSOR) ;
5b7ea690
JH
401ok(57, $status == 0 );
402ok(58, $key eq 'y' );
403ok(59, $value eq 'Y' );
a0d0e21e
LW
404
405$key = "replace key" ;
406$value = "replace value" ;
407$status = $X->put($key, $value, R_CURSOR) ;
5b7ea690
JH
408ok(60, $status == 0 );
409ok(61, $key eq 'replace key' );
410ok(62, $value eq 'replace value' );
a0d0e21e 411$status = $X->get('y', $value) ;
5b7ea690 412ok(63, 1) ; # hard-wire to always pass. the previous test ($status == 1)
a9fd575d 413 # only worked because of a bug in 1.85/6
a0d0e21e
LW
414
415# use seq to walk forwards through a file
416
417$status = $X->seq($key, $value, R_FIRST) ;
5b7ea690 418ok(64, $status == 0 );
3245f058 419my $previous = $key ;
a0d0e21e
LW
420
421$ok = 1 ;
422while (($status = $X->seq($key, $value, R_NEXT)) == 0)
423{
424 ($ok = 0), last if ($previous cmp $key) == 1 ;
425}
426
5b7ea690
JH
427ok(65, $status == 1 );
428ok(66, $ok == 1 );
a0d0e21e
LW
429
430# use seq to walk backwards through a file
431$status = $X->seq($key, $value, R_LAST) ;
5b7ea690 432ok(67, $status == 0 );
a0d0e21e
LW
433$previous = $key ;
434
435$ok = 1 ;
436while (($status = $X->seq($key, $value, R_PREV)) == 0)
437{
438 ($ok = 0), last if ($previous cmp $key) == -1 ;
439 #print "key = [$key] value = [$value]\n" ;
440}
441
5b7ea690
JH
442ok(68, $status == 1 );
443ok(69, $ok == 1 );
a0d0e21e
LW
444
445
446# check seq FIRST/LAST
447
448# sync
449# ####
450
451$status = $X->sync ;
5b7ea690 452ok(70, $status == 0 );
a0d0e21e
LW
453
454
455# fd
456# ##
457
458$status = $X->fd ;
5b7ea690 459ok(71, $status != 0 );
a0d0e21e
LW
460
461
462undef $X ;
463untie %h ;
464
465unlink $Dfile;
466
467# Now try an in memory file
3245f058 468my $Y;
5b7ea690 469ok(72, $Y = tie(%h, 'DB_File',undef, O_RDWR|O_CREAT, 0640, $DB_BTREE ));
a0d0e21e
LW
470
471# fd with an in memory file should return failure
472$status = $Y->fd ;
5b7ea690 473ok(73, $status == -1 );
a0d0e21e 474
55d68b4a 475
a0d0e21e
LW
476undef $Y ;
477untie %h ;
478
55d68b4a 479# Duplicate keys
480my $bt = new DB_File::BTREEINFO ;
481$bt->{flags} = R_DUP ;
3245f058 482my ($YY, %hh);
5b7ea690 483ok(74, $YY = tie(%hh, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $bt )) ;
55d68b4a 484
485$hh{'Wall'} = 'Larry' ;
486$hh{'Wall'} = 'Stone' ; # Note the duplicate key
487$hh{'Wall'} = 'Brick' ; # Note the duplicate key
f6b705ef 488$hh{'Wall'} = 'Brick' ; # Note the duplicate key and value
55d68b4a 489$hh{'Smith'} = 'John' ;
490$hh{'mouse'} = 'mickey' ;
491
492# first work in scalar context
5b7ea690
JH
493ok(75, scalar $YY->get_dup('Unknown') == 0 );
494ok(76, scalar $YY->get_dup('Smith') == 1 );
495ok(77, scalar $YY->get_dup('Wall') == 4 );
55d68b4a 496
497# now in list context
498my @unknown = $YY->get_dup('Unknown') ;
5b7ea690 499ok(78, "@unknown" eq "" );
55d68b4a 500
501my @smith = $YY->get_dup('Smith') ;
5b7ea690 502ok(79, "@smith" eq "John" );
55d68b4a 503
760ac839 504{
f6b705ef 505my @wall = $YY->get_dup('Wall') ;
506my %wall ;
507@wall{@wall} = @wall ;
5b7ea690 508ok(80, (@wall == 4 && $wall{'Larry'} && $wall{'Stone'} && $wall{'Brick'}) );
760ac839 509}
55d68b4a 510
511# hash
512my %unknown = $YY->get_dup('Unknown', 1) ;
5b7ea690 513ok(81, keys %unknown == 0 );
55d68b4a 514
515my %smith = $YY->get_dup('Smith', 1) ;
5b7ea690 516ok(82, keys %smith == 1 && $smith{'John'}) ;
55d68b4a 517
f6b705ef 518my %wall = $YY->get_dup('Wall', 1) ;
5b7ea690 519ok(83, keys %wall == 3 && $wall{'Larry'} == 1 && $wall{'Stone'} == 1
f6b705ef 520 && $wall{'Brick'} == 2);
55d68b4a 521
522undef $YY ;
523untie %hh ;
524unlink $Dfile;
525
526
8e07c86e 527# test multiple callbacks
3245f058
PM
528my $Dfile1 = "btree1" ;
529my $Dfile2 = "btree2" ;
530my $Dfile3 = "btree3" ;
8e07c86e 531
3245f058
PM
532my $dbh1 = new DB_File::BTREEINFO ;
533$dbh1->{compare} = sub {
534 no warnings 'numeric' ;
535 $_[0] <=> $_[1] } ;
8e07c86e 536
3245f058 537my $dbh2 = new DB_File::BTREEINFO ;
8e07c86e
AD
538$dbh2->{compare} = sub { $_[0] cmp $_[1] } ;
539
3245f058 540my $dbh3 = new DB_File::BTREEINFO ;
8e07c86e
AD
541$dbh3->{compare} = sub { length $_[0] <=> length $_[1] } ;
542
543
3245f058 544my (%g, %k);
05a54443
A
545tie(%h, 'DB_File',$Dfile1, O_RDWR|O_CREAT, 0640, $dbh1 ) or die $!;
546tie(%g, 'DB_File',$Dfile2, O_RDWR|O_CREAT, 0640, $dbh2 ) or die $!;
547tie(%k, 'DB_File',$Dfile3, O_RDWR|O_CREAT, 0640, $dbh3 ) or die $!;
8e07c86e 548
3245f058
PM
549my @Keys = qw( 0123 12 -1234 9 987654321 def ) ;
550my (@srt_1, @srt_2, @srt_3);
551{
552 no warnings 'numeric' ;
553 @srt_1 = sort { $a <=> $b } @Keys ;
554}
8e07c86e
AD
555@srt_2 = sort { $a cmp $b } @Keys ;
556@srt_3 = sort { length $a <=> length $b } @Keys ;
557
558foreach (@Keys) {
3245f058 559 $h{$_} = 1 ;
8e07c86e
AD
560 $g{$_} = 1 ;
561 $k{$_} = 1 ;
562}
563
564sub ArrayCompare
565{
566 my($a, $b) = @_ ;
567
568 return 0 if @$a != @$b ;
569
570 foreach (1 .. length @$a)
571 {
572 return 0 unless $$a[$_] eq $$b[$_] ;
573 }
574
575 1 ;
576}
577
5b7ea690
JH
578ok(84, ArrayCompare (\@srt_1, [keys %h]) );
579ok(85, ArrayCompare (\@srt_2, [keys %g]) );
580ok(86, ArrayCompare (\@srt_3, [keys %k]) );
8e07c86e
AD
581
582untie %h ;
583untie %g ;
584untie %k ;
585unlink $Dfile1, $Dfile2, $Dfile3 ;
586
f6b705ef 587# clear
588# #####
589
5b7ea690 590ok(87, tie(%h, 'DB_File', $Dfile1, O_RDWR|O_CREAT, 0640, $DB_BTREE ) );
f6b705ef 591foreach (1 .. 10)
592 { $h{$_} = $_ * 100 }
593
594# check that there are 10 elements in the hash
595$i = 0 ;
596while (($key,$value) = each(%h)) {
597 $i++;
598}
5b7ea690 599ok(88, $i == 10);
f6b705ef 600
601# now clear the hash
602%h = () ;
603
604# check it is empty
605$i = 0 ;
606while (($key,$value) = each(%h)) {
607 $i++;
608}
5b7ea690 609ok(89, $i == 0);
f6b705ef 610
611untie %h ;
612unlink $Dfile1 ;
613
05475680
PM
614{
615 # check that attempting to tie an array to a DB_BTREE will fail
616
617 my $filename = "xyz" ;
618 my @x ;
619 eval { tie @x, 'DB_File', $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE ; } ;
5b7ea690 620 ok(90, $@ =~ /^DB_File can only tie an associative array to a DB_BTREE database/) ;
05475680
PM
621 unlink $filename ;
622}
623
a6ed719b
PM
624{
625 # sub-class test
626
627 package Another ;
628
3245f058 629 use warnings ;
a6ed719b
PM
630 use strict ;
631
632 open(FILE, ">SubDB.pm") or die "Cannot open SubDB.pm: $!\n" ;
633 print FILE <<'EOM' ;
634
635 package SubDB ;
636
3245f058 637 use warnings ;
a6ed719b 638 use strict ;
07200f1b 639 our (@ISA, @EXPORT);
a6ed719b
PM
640
641 require Exporter ;
642 use DB_File;
643 @ISA=qw(DB_File);
644 @EXPORT = @DB_File::EXPORT ;
645
646 sub STORE {
647 my $self = shift ;
648 my $key = shift ;
649 my $value = shift ;
650 $self->SUPER::STORE($key, $value * 2) ;
651 }
652
653 sub FETCH {
654 my $self = shift ;
655 my $key = shift ;
656 $self->SUPER::FETCH($key) - 1 ;
657 }
658
659 sub put {
660 my $self = shift ;
661 my $key = shift ;
662 my $value = shift ;
663 $self->SUPER::put($key, $value * 3) ;
664 }
665
666 sub get {
667 my $self = shift ;
668 $self->SUPER::get($_[0], $_[1]) ;
669 $_[1] -= 2 ;
670 }
671
672 sub A_new_method
673 {
674 my $self = shift ;
675 my $key = shift ;
676 my $value = $self->FETCH($key) ;
677 return "[[$value]]" ;
678 }
679
680 1 ;
681EOM
682
683 close FILE ;
684
a9fd575d 685 BEGIN { push @INC, '.'; }
a6ed719b 686 eval 'use SubDB ; ';
5b7ea690 687 main::ok(91, $@ eq "") ;
a6ed719b
PM
688 my %h ;
689 my $X ;
690 eval '
691 $X = tie(%h, "SubDB","dbbtree.tmp", O_RDWR|O_CREAT, 0640, $DB_BTREE );
692 ' ;
693
5b7ea690 694 main::ok(92, $@ eq "") ;
a6ed719b
PM
695
696 my $ret = eval '$h{"fred"} = 3 ; return $h{"fred"} ' ;
5b7ea690
JH
697 main::ok(93, $@ eq "") ;
698 main::ok(94, $ret == 5) ;
a6ed719b
PM
699
700 my $value = 0;
701 $ret = eval '$X->put("joe", 4) ; $X->get("joe", $value) ; return $value' ;
5b7ea690
JH
702 main::ok(95, $@ eq "") ;
703 main::ok(96, $ret == 10) ;
a6ed719b
PM
704
705 $ret = eval ' R_NEXT eq main::R_NEXT ' ;
5b7ea690
JH
706 main::ok(97, $@ eq "" ) ;
707 main::ok(98, $ret == 1) ;
a6ed719b
PM
708
709 $ret = eval '$X->A_new_method("joe") ' ;
5b7ea690
JH
710 main::ok(99, $@ eq "") ;
711 main::ok(100, $ret eq "[[11]]") ;
a6ed719b 712
fac76ed7
MB
713 undef $X;
714 untie(%h);
a6ed719b
PM
715 unlink "SubDB.pm", "dbbtree.tmp" ;
716
717}
718
9fe6733a
PM
719{
720 # DBM Filter tests
3245f058 721 use warnings ;
9fe6733a
PM
722 use strict ;
723 my (%h, $db) ;
724 my ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
725 unlink $Dfile;
726
727 sub checkOutput
728 {
729 my($fk, $sk, $fv, $sv) = @_ ;
730 return
731 $fetch_key eq $fk && $store_key eq $sk &&
732 $fetch_value eq $fv && $store_value eq $sv &&
733 $_ eq 'original' ;
734 }
735
5b7ea690 736 ok(101, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) );
9fe6733a
PM
737
738 $db->filter_fetch_key (sub { $fetch_key = $_ }) ;
739 $db->filter_store_key (sub { $store_key = $_ }) ;
740 $db->filter_fetch_value (sub { $fetch_value = $_}) ;
741 $db->filter_store_value (sub { $store_value = $_ }) ;
742
743 $_ = "original" ;
744
745 $h{"fred"} = "joe" ;
746 # fk sk fv sv
5b7ea690 747 ok(102, checkOutput( "", "fred", "", "joe")) ;
9fe6733a
PM
748
749 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
5b7ea690 750 ok(103, $h{"fred"} eq "joe");
9fe6733a 751 # fk sk fv sv
5b7ea690 752 ok(104, checkOutput( "", "fred", "joe", "")) ;
9fe6733a
PM
753
754 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
5b7ea690 755 ok(105, $db->FIRSTKEY() eq "fred") ;
9fe6733a 756 # fk sk fv sv
5b7ea690 757 ok(106, checkOutput( "fred", "", "", "")) ;
9fe6733a
PM
758
759 # replace the filters, but remember the previous set
760 my ($old_fk) = $db->filter_fetch_key
761 (sub { $_ = uc $_ ; $fetch_key = $_ }) ;
762 my ($old_sk) = $db->filter_store_key
763 (sub { $_ = lc $_ ; $store_key = $_ }) ;
764 my ($old_fv) = $db->filter_fetch_value
765 (sub { $_ = "[$_]"; $fetch_value = $_ }) ;
766 my ($old_sv) = $db->filter_store_value
767 (sub { s/o/x/g; $store_value = $_ }) ;
768
769 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
770 $h{"Fred"} = "Joe" ;
771 # fk sk fv sv
5b7ea690 772 ok(107, checkOutput( "", "fred", "", "Jxe")) ;
9fe6733a
PM
773
774 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
5b7ea690 775 ok(108, $h{"Fred"} eq "[Jxe]");
9fe6733a 776 # fk sk fv sv
5b7ea690 777 ok(109, checkOutput( "", "fred", "[Jxe]", "")) ;
9fe6733a
PM
778
779 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
5b7ea690 780 ok(110, $db->FIRSTKEY() eq "FRED") ;
9fe6733a 781 # fk sk fv sv
5b7ea690 782 ok(111, checkOutput( "FRED", "", "", "")) ;
9fe6733a
PM
783
784 # put the original filters back
785 $db->filter_fetch_key ($old_fk);
786 $db->filter_store_key ($old_sk);
787 $db->filter_fetch_value ($old_fv);
788 $db->filter_store_value ($old_sv);
789
790 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
791 $h{"fred"} = "joe" ;
5b7ea690 792 ok(112, checkOutput( "", "fred", "", "joe")) ;
9fe6733a
PM
793
794 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
5b7ea690
JH
795 ok(113, $h{"fred"} eq "joe");
796 ok(114, checkOutput( "", "fred", "joe", "")) ;
9fe6733a
PM
797
798 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
5b7ea690
JH
799 ok(115, $db->FIRSTKEY() eq "fred") ;
800 ok(116, checkOutput( "fred", "", "", "")) ;
9fe6733a
PM
801
802 # delete the filters
803 $db->filter_fetch_key (undef);
804 $db->filter_store_key (undef);
805 $db->filter_fetch_value (undef);
806 $db->filter_store_value (undef);
807
808 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
809 $h{"fred"} = "joe" ;
5b7ea690 810 ok(117, checkOutput( "", "", "", "")) ;
9fe6733a
PM
811
812 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
5b7ea690
JH
813 ok(118, $h{"fred"} eq "joe");
814 ok(119, checkOutput( "", "", "", "")) ;
9fe6733a
PM
815
816 ($fetch_key, $store_key, $fetch_value, $store_value) = ("") x 4 ;
5b7ea690
JH
817 ok(120, $db->FIRSTKEY() eq "fred") ;
818 ok(121, checkOutput( "", "", "", "")) ;
9fe6733a
PM
819
820 undef $db ;
821 untie %h;
822 unlink $Dfile;
823}
824
825{
826 # DBM Filter with a closure
827
3245f058 828 use warnings ;
9fe6733a
PM
829 use strict ;
830 my (%h, $db) ;
831
832 unlink $Dfile;
5b7ea690 833 ok(122, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) );
9fe6733a
PM
834
835 my %result = () ;
836
837 sub Closure
838 {
839 my ($name) = @_ ;
840 my $count = 0 ;
841 my @kept = () ;
842
843 return sub { ++$count ;
844 push @kept, $_ ;
845 $result{$name} = "$name - $count: [@kept]" ;
846 }
847 }
848
849 $db->filter_store_key(Closure("store key")) ;
850 $db->filter_store_value(Closure("store value")) ;
851 $db->filter_fetch_key(Closure("fetch key")) ;
852 $db->filter_fetch_value(Closure("fetch value")) ;
853
854 $_ = "original" ;
855
856 $h{"fred"} = "joe" ;
5b7ea690
JH
857 ok(123, $result{"store key"} eq "store key - 1: [fred]");
858 ok(124, $result{"store value"} eq "store value - 1: [joe]");
859 ok(125, ! defined $result{"fetch key"} );
860 ok(126, ! defined $result{"fetch value"} );
861 ok(127, $_ eq "original") ;
862
863 ok(128, $db->FIRSTKEY() eq "fred") ;
864 ok(129, $result{"store key"} eq "store key - 1: [fred]");
865 ok(130, $result{"store value"} eq "store value - 1: [joe]");
866 ok(131, $result{"fetch key"} eq "fetch key - 1: [fred]");
867 ok(132, ! defined $result{"fetch value"} );
868 ok(133, $_ eq "original") ;
9fe6733a
PM
869
870 $h{"jim"} = "john" ;
5b7ea690
JH
871 ok(134, $result{"store key"} eq "store key - 2: [fred jim]");
872 ok(135, $result{"store value"} eq "store value - 2: [joe john]");
873 ok(136, $result{"fetch key"} eq "fetch key - 1: [fred]");
874 ok(137, ! defined $result{"fetch value"} );
875 ok(138, $_ eq "original") ;
876
877 ok(139, $h{"fred"} eq "joe");
878 ok(140, $result{"store key"} eq "store key - 3: [fred jim fred]");
879 ok(141, $result{"store value"} eq "store value - 2: [joe john]");
880 ok(142, $result{"fetch key"} eq "fetch key - 1: [fred]");
881 ok(143, $result{"fetch value"} eq "fetch value - 1: [joe]");
882 ok(144, $_ eq "original") ;
9fe6733a
PM
883
884 undef $db ;
885 untie %h;
886 unlink $Dfile;
887}
888
889{
890 # DBM Filter recursion detection
3245f058 891 use warnings ;
9fe6733a
PM
892 use strict ;
893 my (%h, $db) ;
894 unlink $Dfile;
895
5b7ea690 896 ok(145, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) );
9fe6733a
PM
897
898 $db->filter_store_key (sub { $_ = $h{$_} }) ;
899
900 eval '$h{1} = 1234' ;
5b7ea690 901 ok(146, $@ =~ /^recursion detected in filter_store_key at/ );
9fe6733a
PM
902
903 undef $db ;
904 untie %h;
905 unlink $Dfile;
906}
907
908
2c2d71f5
JH
909{
910 # Examples from the POD
911
912
913 my $file = "xyzt" ;
914 {
915 my $redirect = new Redirect $file ;
916
917 # BTREE example 1
918 ###
919
3245f058 920 use warnings FATAL => qw(all) ;
2c2d71f5
JH
921 use strict ;
922 use DB_File ;
923
924 my %h ;
925
926 sub Compare
927 {
928 my ($key1, $key2) = @_ ;
929 "\L$key1" cmp "\L$key2" ;
930 }
931
932 # specify the Perl sub that will do the comparison
933 $DB_BTREE->{'compare'} = \&Compare ;
934
935 unlink "tree" ;
936 tie %h, "DB_File", "tree", O_RDWR|O_CREAT, 0640, $DB_BTREE
937 or die "Cannot open file 'tree': $!\n" ;
938
939 # Add a key/value pair to the file
940 $h{'Wall'} = 'Larry' ;
941 $h{'Smith'} = 'John' ;
942 $h{'mouse'} = 'mickey' ;
943 $h{'duck'} = 'donald' ;
944
945 # Delete
946 delete $h{"duck"} ;
947
948 # Cycle through the keys printing them in order.
949 # Note it is not necessary to sort the keys as
950 # the btree will have kept them in order automatically.
951 foreach (keys %h)
952 { print "$_\n" }
953
954 untie %h ;
955
956 unlink "tree" ;
957 }
958
959 delete $DB_BTREE->{'compare'} ;
960
5b7ea690 961 ok(147, docat_del($file) eq <<'EOM') ;
2c2d71f5
JH
962mouse
963Smith
964Wall
965EOM
966
967 {
968 my $redirect = new Redirect $file ;
969
970 # BTREE example 2
971 ###
972
3245f058 973 use warnings FATAL => qw(all) ;
2c2d71f5
JH
974 use strict ;
975 use DB_File ;
976
962cee9f 977 my ($filename, %h);
2c2d71f5
JH
978
979 $filename = "tree" ;
980 unlink $filename ;
981
982 # Enable duplicate records
983 $DB_BTREE->{'flags'} = R_DUP ;
984
985 tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE
986 or die "Cannot open $filename: $!\n";
987
988 # Add some key/value pairs to the file
989 $h{'Wall'} = 'Larry' ;
990 $h{'Wall'} = 'Brick' ; # Note the duplicate key
991 $h{'Wall'} = 'Brick' ; # Note the duplicate key and value
992 $h{'Smith'} = 'John' ;
993 $h{'mouse'} = 'mickey' ;
994
995 # iterate through the associative array
996 # and print each key/value pair.
997 foreach (keys %h)
998 { print "$_ -> $h{$_}\n" }
999
1000 untie %h ;
1001
1002 unlink $filename ;
1003 }
1004
5b7ea690 1005 ok(148, docat_del($file) eq ($db185mode ? <<'EOM' : <<'EOM') ) ;
2c2d71f5
JH
1006Smith -> John
1007Wall -> Brick
1008Wall -> Brick
1009Wall -> Brick
1010mouse -> mickey
1011EOM
1012Smith -> John
1013Wall -> Larry
1014Wall -> Larry
1015Wall -> Larry
1016mouse -> mickey
1017EOM
1018
1019 {
1020 my $redirect = new Redirect $file ;
1021
1022 # BTREE example 3
1023 ###
1024
3245f058 1025 use warnings FATAL => qw(all) ;
2c2d71f5
JH
1026 use strict ;
1027 use DB_File ;
1028
962cee9f 1029 my ($filename, $x, %h, $status, $key, $value);
2c2d71f5
JH
1030
1031 $filename = "tree" ;
1032 unlink $filename ;
1033
1034 # Enable duplicate records
1035 $DB_BTREE->{'flags'} = R_DUP ;
1036
1037 $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE
1038 or die "Cannot open $filename: $!\n";
1039
1040 # Add some key/value pairs to the file
1041 $h{'Wall'} = 'Larry' ;
1042 $h{'Wall'} = 'Brick' ; # Note the duplicate key
1043 $h{'Wall'} = 'Brick' ; # Note the duplicate key and value
1044 $h{'Smith'} = 'John' ;
1045 $h{'mouse'} = 'mickey' ;
1046
1047 # iterate through the btree using seq
1048 # and print each key/value pair.
1049 $key = $value = 0 ;
1050 for ($status = $x->seq($key, $value, R_FIRST) ;
1051 $status == 0 ;
1052 $status = $x->seq($key, $value, R_NEXT) )
1053 { print "$key -> $value\n" }
1054
1055
1056 undef $x ;
1057 untie %h ;
1058 }
1059
5b7ea690 1060 ok(149, docat_del($file) eq ($db185mode == 1 ? <<'EOM' : <<'EOM') ) ;
2c2d71f5
JH
1061Smith -> John
1062Wall -> Brick
1063Wall -> Brick
1064Wall -> Larry
1065mouse -> mickey
1066EOM
1067Smith -> John
1068Wall -> Larry
1069Wall -> Brick
1070Wall -> Brick
1071mouse -> mickey
1072EOM
1073
1074
1075 {
1076 my $redirect = new Redirect $file ;
1077
1078 # BTREE example 4
1079 ###
1080
3245f058 1081 use warnings FATAL => qw(all) ;
2c2d71f5
JH
1082 use strict ;
1083 use DB_File ;
1084
962cee9f 1085 my ($filename, $x, %h);
2c2d71f5
JH
1086
1087 $filename = "tree" ;
1088
1089 # Enable duplicate records
1090 $DB_BTREE->{'flags'} = R_DUP ;
1091
1092 $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE
1093 or die "Cannot open $filename: $!\n";
1094
1095 my $cnt = $x->get_dup("Wall") ;
1096 print "Wall occurred $cnt times\n" ;
1097
1098 my %hash = $x->get_dup("Wall", 1) ;
1099 print "Larry is there\n" if $hash{'Larry'} ;
1100 print "There are $hash{'Brick'} Brick Walls\n" ;
1101
1102 my @list = sort $x->get_dup("Wall") ;
1103 print "Wall => [@list]\n" ;
1104
1105 @list = $x->get_dup("Smith") ;
1106 print "Smith => [@list]\n" ;
1107
1108 @list = $x->get_dup("Dog") ;
1109 print "Dog => [@list]\n" ;
1110
1111 undef $x ;
1112 untie %h ;
1113 }
1114
5b7ea690 1115 ok(150, docat_del($file) eq <<'EOM') ;
2c2d71f5
JH
1116Wall occurred 3 times
1117Larry is there
1118There are 2 Brick Walls
1119Wall => [Brick Brick Larry]
1120Smith => [John]
1121Dog => []
1122EOM
1123
1124 {
1125 my $redirect = new Redirect $file ;
1126
1127 # BTREE example 5
1128 ###
1129
3245f058 1130 use warnings FATAL => qw(all) ;
2c2d71f5
JH
1131 use strict ;
1132 use DB_File ;
1133
962cee9f 1134 my ($filename, $x, %h, $found);
2c2d71f5 1135
07200f1b 1136 $filename = "tree" ;
2c2d71f5
JH
1137
1138 # Enable duplicate records
1139 $DB_BTREE->{'flags'} = R_DUP ;
1140
1141 $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE
1142 or die "Cannot open $filename: $!\n";
1143
1144 $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ;
1145 print "Larry Wall is $found there\n" ;
1146
1147 $found = ( $x->find_dup("Wall", "Harry") == 0 ? "" : "not") ;
1148 print "Harry Wall is $found there\n" ;
1149
1150 undef $x ;
1151 untie %h ;
1152 }
1153
5b7ea690 1154 ok(151, docat_del($file) eq <<'EOM') ;
2c2d71f5
JH
1155Larry Wall is there
1156Harry Wall is not there
1157EOM
1158
1159 {
1160 my $redirect = new Redirect $file ;
1161
1162 # BTREE example 6
1163 ###
1164
3245f058 1165 use warnings FATAL => qw(all) ;
2c2d71f5
JH
1166 use strict ;
1167 use DB_File ;
1168
962cee9f 1169 my ($filename, $x, %h, $found);
2c2d71f5 1170
07200f1b 1171 $filename = "tree" ;
2c2d71f5
JH
1172
1173 # Enable duplicate records
1174 $DB_BTREE->{'flags'} = R_DUP ;
1175
1176 $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE
1177 or die "Cannot open $filename: $!\n";
1178
1179 $x->del_dup("Wall", "Larry") ;
1180
1181 $found = ( $x->find_dup("Wall", "Larry") == 0 ? "" : "not") ;
1182 print "Larry Wall is $found there\n" ;
1183
1184 undef $x ;
1185 untie %h ;
1186
1187 unlink $filename ;
1188 }
1189
5b7ea690 1190 ok(152, docat_del($file) eq <<'EOM') ;
2c2d71f5
JH
1191Larry Wall is not there
1192EOM
1193
1194 {
1195 my $redirect = new Redirect $file ;
1196
1197 # BTREE example 7
1198 ###
1199
3245f058 1200 use warnings FATAL => qw(all) ;
2c2d71f5
JH
1201 use strict ;
1202 use DB_File ;
1203 use Fcntl ;
1204
962cee9f 1205 my ($filename, $x, %h, $st, $key, $value);
2c2d71f5
JH
1206
1207 sub match
1208 {
1209 my $key = shift ;
1210 my $value = 0;
1211 my $orig_key = $key ;
1212 $x->seq($key, $value, R_CURSOR) ;
1213 print "$orig_key\t-> $key\t-> $value\n" ;
1214 }
1215
1216 $filename = "tree" ;
1217 unlink $filename ;
1218
1219 $x = tie %h, "DB_File", $filename, O_RDWR|O_CREAT, 0640, $DB_BTREE
1220 or die "Cannot open $filename: $!\n";
1221
1222 # Add some key/value pairs to the file
1223 $h{'mouse'} = 'mickey' ;
1224 $h{'Wall'} = 'Larry' ;
1225 $h{'Walls'} = 'Brick' ;
1226 $h{'Smith'} = 'John' ;
1227
1228
1229 $key = $value = 0 ;
1230 print "IN ORDER\n" ;
1231 for ($st = $x->seq($key, $value, R_FIRST) ;
1232 $st == 0 ;
1233 $st = $x->seq($key, $value, R_NEXT) )
1234
1235 { print "$key -> $value\n" }
1236
1237 print "\nPARTIAL MATCH\n" ;
1238
1239 match "Wa" ;
1240 match "A" ;
1241 match "a" ;
1242
1243 undef $x ;
1244 untie %h ;
1245
1246 unlink $filename ;
1247
1248 }
1249
5b7ea690 1250 ok(153, docat_del($file) eq <<'EOM') ;
2c2d71f5
JH
1251IN ORDER
1252Smith -> John
1253Wall -> Larry
1254Walls -> Brick
1255mouse -> mickey
1256
1257PARTIAL MATCH
1258Wa -> Wall -> Larry
1259A -> Smith -> John
1260a -> mouse -> mickey
1261EOM
1262
1263}
1264
a62982a8
PM
1265#{
1266# # R_SETCURSOR
1267# use strict ;
1268# my (%h, $db) ;
1269# unlink $Dfile;
1270#
1271# ok(156, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) );
1272#
1273# $h{abc} = 33 ;
1274# my $k = "newest" ;
1275# my $v = 44 ;
1276# my $status = $db->put($k, $v, R_SETCURSOR) ;
1277# print "status = [$status]\n" ;
1278# ok(157, $status == 0) ;
1279# $status = $db->del($k, R_CURSOR) ;
1280# print "status = [$status]\n" ;
1281# ok(158, $status == 0) ;
1282# $k = "newest" ;
1283# ok(159, $db->get($k, $v, R_CURSOR)) ;
1284#
1285# ok(160, keys %h == 1) ;
1286#
1287# undef $db ;
1288# untie %h;
1289# unlink $Dfile;
1290#}
1291
cbc5248d
PM
1292{
1293 # Bug ID 20001013.009
1294 #
1295 # test that $hash{KEY} = undef doesn't produce the warning
1296 # Use of uninitialized value in null operation
1297 use warnings ;
1298 use strict ;
1299 use DB_File ;
1300
1301 unlink $Dfile;
1302 my %h ;
1303 my $a = "";
1304 local $SIG{__WARN__} = sub {$a = $_[0]} ;
1305
3245f058 1306 tie %h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_BTREE
cbc5248d
PM
1307 or die "Can't open file: $!\n" ;
1308 $h{ABC} = undef;
5b7ea690 1309 ok(154, $a eq "") ;
cbc5248d
PM
1310 untie %h ;
1311 unlink $Dfile;
1312}
1313
3245f058
PM
1314{
1315 # test that %hash = () doesn't produce the warning
1316 # Argument "" isn't numeric in entersub
1317 use warnings ;
1318 use strict ;
1319 use DB_File ;
1320
1321 unlink $Dfile;
1322 my %h ;
1323 my $a = "";
1324 local $SIG{__WARN__} = sub {$a = $_[0]} ;
1325
1326 tie %h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0664, $DB_BTREE
1327 or die "Can't open file: $!\n" ;
1328 %h = (); ;
5b7ea690 1329 ok(155, $a eq "") ;
3245f058
PM
1330 untie %h ;
1331 unlink $Dfile;
1332}
1333
0bf2e707
PM
1334{
1335 # When iterating over a tied hash using "each", the key passed to FETCH
1336 # will be recycled and passed to NEXTKEY. If a Source Filter modifies the
1337 # key in FETCH via a filter_fetch_key method we need to check that the
1338 # modified key doesn't get passed to NEXTKEY.
1339 # Also Test "keys" & "values" while we are at it.
1340
1341 use warnings ;
1342 use strict ;
1343 use DB_File ;
1344
1345 unlink $Dfile;
1346 my $bad_key = 0 ;
1347 my %h = () ;
1348 my $db ;
5b7ea690 1349 ok(156, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) );
0bf2e707
PM
1350 $db->filter_fetch_key (sub { $_ =~ s/^Beta_/Alpha_/ if defined $_}) ;
1351 $db->filter_store_key (sub { $bad_key = 1 if /^Beta_/ ; $_ =~ s/^Alpha_/Beta_/}) ;
1352
1353 $h{'Alpha_ABC'} = 2 ;
1354 $h{'Alpha_DEF'} = 5 ;
1355
5b7ea690
JH
1356 ok(157, $h{'Alpha_ABC'} == 2);
1357 ok(158, $h{'Alpha_DEF'} == 5);
0bf2e707
PM
1358
1359 my ($k, $v) = ("","");
1360 while (($k, $v) = each %h) {}
5b7ea690 1361 ok(159, $bad_key == 0);
0bf2e707
PM
1362
1363 $bad_key = 0 ;
1364 foreach $k (keys %h) {}
5b7ea690 1365 ok(160, $bad_key == 0);
0bf2e707
PM
1366
1367 $bad_key = 0 ;
1368 foreach $v (values %h) {}
5b7ea690 1369 ok(161, $bad_key == 0);
0bf2e707
PM
1370
1371 undef $db ;
1372 untie %h ;
1373 unlink $Dfile;
1374}
1375
5b7ea690
JH
1376{
1377 # now an error to pass 'compare' a non-code reference
1378 my $dbh = new DB_File::BTREEINFO ;
1379
1380 eval { $dbh->{compare} = 2 };
1381 ok(162, $@ =~ /^Key 'compare' not associated with a code reference at/);
1382
1383 eval { $dbh->{prefix} = 2 };
1384 ok(163, $@ =~ /^Key 'prefix' not associated with a code reference at/);
1385
1386}
1387
1388
1389#{
1390# # recursion detection in btree
1391# my %hash ;
1392# unlink $Dfile;
1393# my $dbh = new DB_File::BTREEINFO ;
1394# $dbh->{compare} = sub { $hash{3} = 4 ; length $_[0] } ;
1395#
1396#
1397# my (%h);
1398# ok(164, tie(%hash, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $dbh ) );
1399#
1400# eval { $hash{1} = 2;
1401# $hash{4} = 5;
1402# };
1403#
1404# ok(165, $@ =~ /^DB_File btree_compare: recursion detected/);
1405# {
1406# no warnings;
1407# untie %hash;
1408# }
1409# unlink $Dfile;
1410#}
1411ok(164,1);
1412ok(165,1);
1413
1414{
1415 # Check that two callbacks don't interact
1416 my %hash1 ;
1417 my %hash2 ;
1418 my $h1_count = 0;
1419 my $h2_count = 0;
1420 unlink $Dfile, $Dfile2;
1421 my $dbh1 = new DB_File::BTREEINFO ;
1422 $dbh1->{compare} = sub { ++ $h1_count ; $_[0] cmp $_[1] } ;
1423
1424 my $dbh2 = new DB_File::BTREEINFO ;
1425 $dbh2->{compare} = sub { ;++ $h2_count ; $_[0] cmp $_[1] } ;
1426
1427
1428
1429 my (%h);
1430 ok(166, tie(%hash1, 'DB_File',$Dfile, O_RDWR|O_CREAT, 0640, $dbh1 ) );
1431 ok(167, tie(%hash2, 'DB_File',$Dfile2, O_RDWR|O_CREAT, 0640, $dbh2 ) );
1432
1433 $hash1{DEFG} = 5;
1434 $hash1{XYZ} = 2;
1435 $hash1{ABCDE} = 5;
1436
1437 $hash2{defg} = 5;
1438 $hash2{xyz} = 2;
1439 $hash2{abcde} = 5;
1440
1441 ok(168, $h1_count > 0);
1442 ok(169, $h1_count == $h2_count);
1443
1444 ok(170, safeUntie \%hash1);
1445 ok(171, safeUntie \%hash2);
1446 unlink $Dfile, $Dfile2;
1447}
1448
1449{
1450 # Check that DBM Filter can cope with read-only $_
1451
1452 use warnings ;
1453 use strict ;
1454 my (%h, $db) ;
1455 unlink $Dfile;
1456
1457 ok(172, $db = tie(%h, 'DB_File', $Dfile, O_RDWR|O_CREAT, 0640, $DB_BTREE ) );
1458
1459 $db->filter_fetch_key (sub { }) ;
1460 $db->filter_store_key (sub { }) ;
1461 $db->filter_fetch_value (sub { }) ;
1462 $db->filter_store_value (sub { }) ;
1463
1464 $_ = "original" ;
1465
1466 $h{"fred"} = "joe" ;
1467 ok(173, $h{"fred"} eq "joe");
1468
1469 eval { grep { $h{$_} } (1, 2, 3) };
1470 ok (174, ! $@);
1471
1472
1473 # delete the filters
1474 $db->filter_fetch_key (undef);
1475 $db->filter_store_key (undef);
1476 $db->filter_fetch_value (undef);
1477 $db->filter_store_value (undef);
1478
1479 $h{"fred"} = "joe" ;
1480
1481 ok(175, $h{"fred"} eq "joe");
1482
1483 ok(176, $db->FIRSTKEY() eq "fred") ;
1484
1485 eval { grep { $h{$_} } (1, 2, 3) };
1486 ok (177, ! $@);
1487
1488 undef $db ;
1489 untie %h;
1490 unlink $Dfile;
1491}
1492
a0d0e21e 1493exit ;