1#!./perl -w 2 3use strict ; 4 5 6use lib 't' ; 7 8use BerkeleyDB; 9use util ; 10 11use Test::More ; 12 13plan(skip_all => "this needs Berkeley DB 4.8.x or better\n" ) 14 if $BerkeleyDB::db_version < 4.8; 15 16plan tests => 58; 17 18my $Dfile = "dbhash.tmp"; 19 20umask(0); 21 22{ 23 # db->associate_foreign -- DB_FOREIGN_CASCADE 24 25 sub sec_key 26 { 27 #print "in sec_key\n"; 28 my $pkey = shift ; 29 my $pdata = shift ; 30 31 $_[0] = $pdata ; 32 return 0; 33 } 34 35 my ($Dfile1, $Dfile2, $Dfile3); 36 my $lex = new LexFile $Dfile1, $Dfile2, $Dfile3 ; 37 my %hash ; 38 my $status; 39 my ($k, $v, $pk) = ('','',''); 40 41 # create primary database 42 ok my $primary = new BerkeleyDB::Hash -Filename => $Dfile1, 43 -Flags => DB_CREATE ; 44 45 # create secondary database 46 ok my $secondary = new BerkeleyDB::Hash -Filename => $Dfile2, 47 -Flags => DB_CREATE ; 48 49 # associate primary with secondary 50 ok $primary->associate($secondary, \&sec_key) == 0; 51 52 # create secondary database 53 ok my $foreign = new BerkeleyDB::Hash -Filename => $Dfile3, 54 -Flags => DB_CREATE ; 55 56 # associate primary with secondary 57 ok $foreign->associate_foreign($secondary, undef, DB_FOREIGN_CASCADE) == 0; 58 59 # add data to the primary 60 my %data = ( 61 "red" => "flag", 62 "green" => "house", 63 "blue" => "sea", 64 ) ; 65 66 my $ret = 0 ; 67 while (($k, $v) = each %data) { 68 my $r = $foreign->db_put($v, 1) ; 69 #print "put $r $BerkeleyDB::Error\n"; 70 $ret += $r; 71 } 72 ok $ret == 0 ; 73 74 while (($k, $v) = each %data) { 75 my $r = $primary->db_put($k, $v) ; 76 #print "put $r $BerkeleyDB::Error\n"; 77 $ret += $r; 78 } 79 ok $ret == 0 ; 80 81 # check the records in the secondary 82 is countRecords($primary), 3 ; 83 is countRecords($secondary), 3 ; 84 is countRecords($foreign), 3 ; 85 86 # deleting from the foreign will cascade 87 ok $foreign->db_del("flag") == 0; 88 is countRecords($primary), 2 ; 89 is countRecords($secondary), 2 ; 90 is countRecords($foreign), 2 ; 91 92 cmp_ok $foreign->db_get("flag", $v), '==', DB_NOTFOUND; 93 cmp_ok $secondary->db_get("flag", $v), '==', DB_NOTFOUND; 94 cmp_ok $primary->db_get("red", $v), '==', DB_NOTFOUND; 95 96 # adding to the primary when no foreign key will fail 97 cmp_ok $primary->db_put("hello", "world"), '==', DB_FOREIGN_CONFLICT; 98 99 ok $foreign->db_put("world", "hello") == 0; 100 101 ok $primary->db_put("hello", "world") == '0'; 102 103 is countRecords($primary), 3 ; 104 is countRecords($secondary), 3 ; 105 is countRecords($foreign), 3 ; 106} 107 108{ 109 # db->associate_foreign -- DB_FOREIGN_ABORT 110 111 sub sec_key2 112 { 113 #print "in sec_key\n"; 114 my $pkey = shift ; 115 my $pdata = shift ; 116 117 $_[0] = $pdata ; 118 return 0; 119 } 120 121 my ($Dfile1, $Dfile2, $Dfile3); 122 my $lex = new LexFile $Dfile1, $Dfile2, $Dfile3 ; 123 my %hash ; 124 my $status; 125 my ($k, $v, $pk) = ('','',''); 126 127 # create primary database 128 ok my $primary = new BerkeleyDB::Hash -Filename => $Dfile1, 129 -Flags => DB_CREATE ; 130 131 # create secondary database 132 ok my $secondary = new BerkeleyDB::Hash -Filename => $Dfile2, 133 -Flags => DB_CREATE ; 134 135 # associate primary with secondary 136 ok $primary->associate($secondary, \&sec_key2) == 0; 137 138 # create secondary database 139 ok my $foreign = new BerkeleyDB::Hash -Filename => $Dfile3, 140 -Flags => DB_CREATE ; 141 142 # associate primary with secondary 143 ok $foreign->associate_foreign($secondary, undef, DB_FOREIGN_ABORT) == 0; 144 145 # add data to the primary 146 my %data = ( 147 "red" => "flag", 148 "green" => "house", 149 "blue" => "sea", 150 ) ; 151 152 my $ret = 0 ; 153 while (($k, $v) = each %data) { 154 my $r = $foreign->db_put($v, 1) ; 155 #print "put $r $BerkeleyDB::Error\n"; 156 $ret += $r; 157 } 158 ok $ret == 0 ; 159 160 while (($k, $v) = each %data) { 161 my $r = $primary->db_put($k, $v) ; 162 #print "put $r $BerkeleyDB::Error\n"; 163 $ret += $r; 164 } 165 ok $ret == 0 ; 166 167 # check the records in the secondary 168 is countRecords($primary), 3 ; 169 is countRecords($secondary), 3 ; 170 is countRecords($foreign), 3 ; 171 172 # deleting from the foreign will fail 173 cmp_ok $foreign->db_del("flag"), '==', DB_FOREIGN_CONFLICT; 174 is countRecords($primary), 3 ; 175 is countRecords($secondary), 3 ; 176 is countRecords($foreign), 3 ; 177 178} 179 180{ 181 # db->associate_foreign -- DB_FOREIGN_NULLIFY 182 183 use constant INVALID => "invalid"; 184 185 sub sec_key3 186 { 187 #print "in sec_key\n"; 188 my $pkey = shift ; 189 my $pdata = shift ; 190 191 if ($pdata eq INVALID) 192 { 193 #print "BAD\n"; 194 return DB_DONOTINDEX; 195 } 196 197 $_[0] = $pdata ; 198 return 0; 199 } 200 201 sub nullify_cb 202 { 203 my $key = \$_[0]; 204 my $value = \$_[1]; 205 my $foreignkey = \$_[2]; 206 my $changed = \$_[3] ; 207 208 #print "key[$$key], value[$$value], foreign[$$foreignkey], changed[$$changed]\n"; 209 210 if ($$value eq 'sea') 211 { 212 #print "SEA\n"; 213 $$value = INVALID; 214 $$changed = 1; 215 return 0; 216 } 217 218 $$changed = 0; 219 return 0; 220 } 221 222 my ($Dfile1, $Dfile2, $Dfile3); 223 my $lex = new LexFile $Dfile1, $Dfile2, $Dfile3 ; 224 my %hash ; 225 my $status; 226 my ($k, $v, $pk) = ('','',''); 227 228 # create primary database 229 ok my $primary = new BerkeleyDB::Hash -Filename => $Dfile1, 230 -Flags => DB_CREATE ; 231 232 # create secondary database 233 ok my $secondary = new BerkeleyDB::Hash -Filename => $Dfile2, 234 -Flags => DB_CREATE ; 235 236 # associate primary with secondary 237 ok $primary->associate($secondary, \&sec_key3) == 0; 238 239 # create secondary database 240 ok my $foreign = new BerkeleyDB::Hash -Filename => $Dfile3, 241 -Flags => DB_CREATE ; 242 243 # associate primary with secondary 244 cmp_ok $foreign->associate_foreign($secondary, \&nullify_cb, DB_FOREIGN_NULLIFY), '==', 0 245 or diag "$BerkeleyDB::Error\n"; 246 247 # add data to the primary 248 my %data = ( 249 "red" => "flag", 250 "green" => "house", 251 "blue" => "sea", 252 ) ; 253 254 my $ret = 0 ; 255 while (($k, $v) = each %data) { 256 my $r = $foreign->db_put($v, 1) ; 257 #print "put $r $BerkeleyDB::Error\n"; 258 $ret += $r; 259 } 260 ok $ret == 0 ; 261 262 while (($k, $v) = each %data) { 263 my $r = $primary->db_put($k, $v) ; 264 #print "put $r $BerkeleyDB::Error\n"; 265 $ret += $r; 266 } 267 ok $ret == 0 ; 268 269 # check the records in the secondary 270 is countRecords($primary), 3 ; 271 is countRecords($secondary), 3 ; 272 is countRecords($foreign), 3, "count is 3" ; 273 274 # deleting from the foreign will pass, but the other dbs will not be 275 # affected 276 cmp_ok $foreign->db_del("sea"), '==', 0, "delete" 277 or diag "$BerkeleyDB::Error\n"; 278 is countRecords($primary), 3 ; 279 is countRecords($secondary), 2 ; 280 is countRecords($foreign), 2 ; 281 282 283 # deleting from the foreign will pass, but the other dbs will not be 284 # affected 285 cmp_ok $foreign->db_del("flag"), '==', 0, "delete" 286 or diag "$BerkeleyDB::Error\n"; 287 is countRecords($primary), 3 ; 288 is countRecords($secondary), 2 ; 289 is countRecords($foreign), 1 ; 290 291} 292 293{ 294 # db->set_bt_compress 295 296 my ($Dfile1, $Dfile2, $Dfile3); 297 my $lex = new LexFile $Dfile1, $Dfile2, $Dfile3 ; 298 my %hash ; 299 my $status; 300 my ($k, $v, $pk) = ('','',''); 301 302 # create primary database 303 ok my $primary = new BerkeleyDB::Btree -Filename => $Dfile1, 304 -set_bt_compress => 1, 305 -Flags => DB_CREATE ; 306 307 # add data to the primary 308 my %data = ( 309 "red" => "flag", 310 "green" => "house", 311 "blue" => "sea", 312 ) ; 313 314 my $ret = 0 ; 315 while (($k, $v) = each %data) { 316 my $r = $primary->db_put($k, $v); 317 #print "put $r $BerkeleyDB::Error\n"; 318 $ret += $r; 319 } 320 ok $ret == 0 ; 321 322 # check the records in the secondary 323 is countRecords($primary), 3 ; 324} 325