File Coverage

blib/lib/MLDBM/TinyDB.pm
Criterion Covered Total %
statement 355 546 65.0
branch 95 300 31.6
condition 11 133 8.2
subroutine 27 39 69.2
pod 17 25 68.0
total 505 1043 48.4


line stmt bran cond sub pod time code
1             package MLDBM::TinyDB;
2            
3 1     1   6932 use vars qw/$VERSION @ISA @EXPORT_OK/;
  1         2  
  1         94  
4             $VERSION = '0.20';#
5            
6 1     1   5 use strict;
  1         2  
  1         32  
7 1     1   5 use Exporter;
  1         6  
  1         55  
8             @ISA = qw(Exporter);
9             @EXPORT_OK = qw(db add_common);
10 1     1   942 use MLDBM qw/SDBM_File Storable/;## change SDBM_File for any other DBM file if you want
  1         3913  
  1         7  
11 1     1   904 use MLDBM::Serializer::Storable; ## p2x
  1         5168  
  1         31  
12 1     1   9 use Storable qw/dclone/;
  1         2  
  1         45  
13 1     1   861 use SDBM_File; ## p2x
  1         530  
  1         36  
14 1     1   6 use Fcntl;
  1         2  
  1         304  
15 1     1   835 use Carp::Heavy; ## p2x
  1         142  
  1         31  
16 1     1   760 use Tie::IxHash;
  1         3016  
  1         27  
17 1     1   12 use MLDBM::TinyDB;
  1         2  
  1         910  
18            
19             our %db;
20            
21             sub db {
22 13     13 1 142 my $table = shift;
23 13 100       66 if (ref($db{$table}) =~ /MLDBM::TinyDB/) {
    50          
24 12         72 return $db{$table};
25             } elsif (ref($db{$table}) =~ /ARRAY/) {
26 1         2 return init(__PACKAGE__,$table, @{ $db{$table} });
  1         6  
27             } else {
28 0         0 return undef;#
29             }
30             }
31            
32             ## UNDOCUMENTED
33             sub free_dbh {
34 0     0 0 0 my $self = shift;
35 0         0 return (%db = ());
36             }
37            
38             sub init {
39 2     2 1 124 my $this = shift;
40 2   33     17 my $class = ref($this)||$this;
41 2         6 my ($table, $tree, $branch, $mode, $perms) = @_;
42 2         5 my $self = {};
43 2         6 $self->{TABLE} = $table;
44            
45 2   50     11 $mode ||= (O_CREAT|O_RDWR);
46 2   50     9 $perms ||= 0666;
47 2 50       3 tie %{$self->{TIEHASH}}, 'MLDBM', $table, $mode, $perms or die $!;
  2         22  
48            
49 2         536 my $proc;## to be processed unless $branch
50 2 50       4 unless ($proc = ${$self->{TIEHASH}}{tree}) {
  2         19  
51             ## save
52 2         77 ${$self->{TIEHASH}}{tree} = $tree;
  2         16  
53 2         361 $proc = $tree;
54             }
55            
56 2 50       9 return $proc if !defined($proc);
57            
58 2         4 my %tables;
59            
60 2 100       9 unless ($branch) {
61 1         37 my $clone = dclone($proc);
62 1         6 set_tables_data(\%tables, $proc);
63 1         25 my @extfiles = grep !/^$table$/, keys %tables;
64 1 50       5 if ( @extfiles>0 ) {
65             ## so there is at least one table related
66 1         3 foreach (@extfiles) {
67 1         5 $db{$_} = [$clone, $tables{$_} ];
68             }
69             }
70 1         2 @{$self->{FLDS}} = @{ $tables{$table}{FLDS} };
  1         3  
  1         3  
71 1         2 @{$self->{DOWN}} = @{ $tables{$table}{DOWN} };
  1         5  
  1         3  
72 1         5 $self->{UP} = $tables{$table}{UP};
73             } else {
74 1         3 @{$self->{FLDS}} = @{ $branch->{FLDS} };
  1         5  
  1         2  
75 1         2 @{$self->{DOWN}} = @{ $branch->{DOWN} };
  1         2  
  1         2  
76 1         3 $self->{UP} = $branch->{UP};
77             }
78             ## IMPLICITLY ADD FIELD IF EXISTS SUPERIOR TABLE - FIELD IS NOT CONTAINED IN $tree!!!
79             ## IT'S FOR delete
80 2 100       11 unshift(@{$self->{FLDS}}, "nodes")
  1         4  
81             if defined $self->{UP};
82            
83 2   33     4 my @numkeys = map {$_, undef} sort {$a<=>$b} grep /^\d+$/ && $_, keys %{$self->{TIEHASH}};
  0         0  
  0         0  
  2         13  
84 2         76 $self->{NUMKEYS} = Tie::IxHash->new( @numkeys );
85            
86 2         32 bless $self, $class;
87 2         4 $db{$table} = $self;
88 2         35 return $self;
89             }
90            
91             sub set_tables_data {
92 2     2 0 5 my ($tables, $reft, $up) = @_;
93 2         757 my $first = shift @$reft;
94 2         9 $tables->{$first}{UP} = $up;
95 2         3 @{$tables->{$first}{DOWN}} = ();
  2         6  
96 2         6 foreach (@$reft) {
97 5 100       31 if (ref($_) =~ /ARRAY/) {
98 1         2 push(@{$tables->{$first}{FLDS}}, $_->[0]);
  1         4  
99             ## array of ref
100 1         2 push(@{$tables->{$first}{DOWN}}, $tables->{$first}{FLDS}[-1]);
  1         3  
101 1         6 set_tables_data($tables, $_, $first);
102             } else {
103 4         6 push(@{$tables->{$first}{FLDS}}, $_);
  4         17  
104             }
105             }
106             }
107            
108             ## ultility
109             sub add_common {
110 0     0 1 0 my ($reft, $common) = @_;
111 0         0 my $first = shift @$reft;
112 0         0 unshift(@$reft, $first, @$common);
113 0         0 foreach (@$reft) {
114 0 0       0 if (ref($_) =~ /ARRAY/) {
115 0         0 add_common($_, $common);
116             }
117             }
118             }
119            
120             sub lsearch {
121 0     0 1 0 my ($self, $criteria, $limit) = @_;
122 1     1   799 use locale;## just that line added to sort method
  1         190  
  1         4  
123 0         0 my @found = ();
124 0         0 my @spec = $self->{NUMKEYS}->Keys;
125 0         0 my $str = join "|", @{$self->{FLDS}};
  0         0  
126 0         0 $str = '$criteria =~ s/(' . $str . ')/\'$hash{\' . $1 . \'}\'/ge';
127 0 0       0 unless (eval $str) {
128 0 0       0 warn "eval failed: $@" if $@;
129             }
130 0         0 my %hash = (); ##-
131 0         0 for(my $i=0; $i<=$#spec; $i++) {
132 0         0 @hash{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };
  0         0  
  0         0  
  0         0  
133 0 0       0 if (eval $criteria) {
    0          
134 0         0 push(@found, $i);
135 0 0 0     0 last if $limit && ($limit == @found);
136             } elsif ($@) {
137 0         0 warn "eval failed:$@";
138             }
139             }
140 0         0 return @found;
141             }
142            
143             sub search {
144 1     1 1 3 my ($self, $criteria, $limit) = @_;
145 1         2 my @found = ();
146 1         6 my @spec = $self->{NUMKEYS}->Keys;
147 1         11 my $str = join "|", @{$self->{FLDS}};
  1         5  
148 1         4 $str = '$criteria =~ s/(' . $str . ')/\'$hash{\' . $1 . \'}\'/ge';
149 1 50       130 unless (eval $str) {
150 0 0       0 warn "eval failed: $@" if $@;
151             }
152 1         4 my %hash = (); ##-
153 1         6 for(my $i=0; $i<=$#spec; $i++) {
154 5         8 @hash{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };
  5         174  
  5         7  
  5         32  
155 5 100       498 if (eval $criteria) {
    50          
156 3         5 push(@found, $i);
157 3 50 33     22 last if $limit && ($limit == @found);
158             } elsif ($@) {
159 0         0 warn "eval failed:$@";
160             }
161             }
162 1         12 return @found;
163             }
164            
165             sub lsort {
166 0     0 1 0 my ($self, $sform) = @_;
167 1     1   365 use locale;## just that line added to sort method
  1         7  
  1         4  
168 0         0 my $str;
169 0         0 my @spec = $self->{NUMKEYS}->Keys;
170 0         0 my $not = join "|", @{$self->{DOWN}}, 'nodes';
  0         0  
171 0         0 my @allowed = grep !/^$not$/, @{$self->{FLDS}};
  0         0  
172 0         0 my $allowed = join "|", @allowed;
173 0         0 my @reg = ();
174 0         0 my @sorted = ();
175 0         0 my %conv = ('ab'=>0, 'ba'=>1, 'cmp'=>0, '<=>'=>1);
176 0         0 $str = 'while ($sform =~ s/^(\w*)\s*(\(?)\s*([ab])\s*\(\s*('.$allowed.')\s*\)\s*(\)?)\s*(cmp|\<\=\>)\s*(\1)\s*(\2)\s*([ab])\s*\(\s*(\4)\s*\)\s*(\5)\s*(?:\|\|)?//){ push(@reg,[$1, $3, $4, $6, $9, ($conv{qq/$3$9/}<<1)|$conv{$6}]) if ($3 ne $9) && !$conv{$4}++; }';
177 0         0 eval $str;
178 0 0       0 die "eval failed: $@" if $@;
179 0 0       0 if (@reg == 0) {
180 0         0 return @sorted;
181             }
182 0         0 my @keys = map { $_->[2] } @reg;
  0         0  
183 0         0 my @indices = k2i($self->{FLDS},[@keys]);
184 0         0 my @ex = grep $_->[0], @reg;
185 0         0 for(my $i=0; $i<=$#spec; $i++) {
186 0         0 push(@sorted, [$i, @{ ${$self->{TIEHASH}}{$spec[$i]} }[@indices]]);
  0         0  
  0         0  
187             }
188 0 0 0     0 if (@ex == 0 && @keys == 1) {
    0 0        
189 0 0       0 @sorted = sort {$a->[1] cmp $b->[1]} @sorted if $reg[0]->[5] == 0;
  0         0  
190 0 0       0 @sorted = sort {$b->[1] cmp $a->[1]} @sorted if $reg[0]->[5] == 2;
  0         0  
191 0 0       0 @sorted = sort {$a->[1] <=> $b->[1]} @sorted if $reg[0]->[5] == 1;
  0         0  
192 0 0       0 @sorted = sort {$b->[1] <=> $a->[1]} @sorted if $reg[0]->[5] == 3;
  0         0  
193             } elsif (@ex == 0 && @keys == 2) {
194 0 0 0     0 @sorted = sort {$a->[1] cmp $b->[1]||
  0 0       0  
195             $a->[2] cmp $b->[2]} @sorted
196             if $reg[0]->[5] == 0 && $reg[1]->[5] == 0;
197 0 0 0     0 @sorted = sort {$a->[1] cmp $b->[1]||
  0 0       0  
198             $b->[2] cmp $a->[2]} @sorted
199             if $reg[0]->[5] == 0 && $reg[1]->[5] == 2;
200 0 0 0     0 @sorted = sort {$a->[1] cmp $b->[1]||
  0 0       0  
201             $a->[2] <=> $b->[2]} @sorted
202             if $reg[0]->[5] == 0 && $reg[1]->[5] == 1;
203 0 0 0     0 @sorted = sort {$a->[1] cmp $b->[1]||
  0 0       0  
204             $b->[2] <=> $a->[2]} @sorted
205             if $reg[0]->[5] == 0 && $reg[1]->[5] == 3;
206            
207 0 0 0     0 @sorted = sort {$b->[1] cmp $a->[1]||
  0 0       0  
208             $a->[2] cmp $b->[2]} @sorted
209             if $reg[0]->[5] == 2 && $reg[1]->[5] == 0;
210 0 0 0     0 @sorted = sort {$b->[1] cmp $a->[1]||
  0 0       0  
211             $b->[2] cmp $a->[2]} @sorted
212             if $reg[0]->[5] == 2 && $reg[1]->[5] == 2;
213 0 0 0     0 @sorted = sort {$b->[1] cmp $a->[1]||
  0 0       0  
214             $a->[2] <=> $b->[2]} @sorted
215             if $reg[0]->[5] == 2 && $reg[1]->[5] == 1;
216 0 0 0     0 @sorted = sort {$b->[1] cmp $a->[1]||
  0 0       0  
217             $b->[2] <=> $a->[2]} @sorted
218             if $reg[0]->[5] == 2 && $reg[1]->[5] == 3;
219            
220 0 0 0     0 @sorted = sort {$a->[1] <=> $b->[1]||
  0 0       0  
221             $a->[2] cmp $b->[2]} @sorted
222             if $reg[0]->[5] == 1 && $reg[1]->[5] == 0;
223 0 0 0     0 @sorted = sort {$a->[1] <=> $b->[1]||
  0 0       0  
224             $b->[2] cmp $a->[2]} @sorted
225             if $reg[0]->[5] == 1 && $reg[1]->[5] == 2;
226 0 0 0     0 @sorted = sort {$a->[1] <=> $b->[1]||
  0 0       0  
227             $a->[2] <=> $b->[2]} @sorted
228             if $reg[0]->[5] == 1 && $reg[1]->[5] == 1;
229 0 0 0     0 @sorted = sort {$a->[1] <=> $b->[1]||
  0 0       0  
230             $b->[2] <=> $a->[2]} @sorted
231             if $reg[0]->[5] == 1 && $reg[1]->[5] == 3;
232            
233 0 0 0     0 @sorted = sort {$b->[1] <=> $a->[1]||
  0 0       0  
234             $a->[2] cmp $b->[2]} @sorted
235             if $reg[0]->[5] == 3 && $reg[1]->[5] == 0;
236 0 0 0     0 @sorted = sort {$b->[1] <=> $a->[1]||
  0 0       0  
237             $b->[2] cmp $a->[2]} @sorted
238             if $reg[0]->[5] == 3 && $reg[1]->[5] == 2;
239 0 0 0     0 @sorted = sort {$b->[1] <=> $a->[1]||
  0 0       0  
240             $a->[2] <=> $b->[2]} @sorted
241             if $reg[0]->[5] == 3 && $reg[1]->[5] == 1;
242 0 0 0     0 @sorted = sort {$b->[1] <=> $a->[1]||
  0 0       0  
243             $b->[2] <=> $a->[2]} @sorted
244             if $reg[0]->[5] == 3 && $reg[1]->[5] == 3;
245             } else {
246 0         0 undef $sform;
247 0         0 my $i = 1;
248 0         0 foreach my $e (@reg) {
249 0 0       0 $sform .= $e->[0] if $e->[0];
250 0         0 $sform .= '$'.$e->[1].'->['.$i.']'.$e->[3];
251 0 0       0 $sform .= " $e->[0] " if $e->[0];
252 0         0 $sform .= '$'.$e->[4].'->['.$i.']';
253 0         0 $sform .= '||';
254 0         0 $i++;
255             }
256 0         0 chop $sform;
257 0         0 chop $sform;
258             #print "\$sform:$sform";
259 0         0 @sorted = sort { eval $sform } @sorted;
  0         0  
260             }
261 0         0 return @sorted;
262             }
263            
264             sub sort {
265 2     2 1 69 my ($self, $sform) = @_;
266 2         3 my $str;
267 2         7 my @spec = $self->{NUMKEYS}->Keys;
268 2         18 my $not = join "|", @{$self->{DOWN}}, 'nodes';
  2         6  
269 2         3 my @allowed = grep !/^$not$/, @{$self->{FLDS}};
  2         31  
270 2         6 my $allowed = join "|", @allowed;
271 2         3 my @reg = ();
272 2         3 my @sorted = ();
273 2         9 my %conv = ('ab'=>0, 'ba'=>1, 'cmp'=>0, '<=>'=>1);
274 2         5 $str = 'while ($sform =~ s/^(\w*)\s*(\(?)\s*([ab])\s*\(\s*('.$allowed.')\s*\)\s*(\)?)\s*(cmp|\<\=\>)\s*(\1)\s*(\2)\s*([ab])\s*\(\s*(\4)\s*\)\s*(\5)\s*(?:\|\|)?//){ push(@reg,[$1, $3, $4, $6, $9, ($conv{qq/$3$9/}<<1)|$conv{$6}]) if ($3 ne $9) && !$conv{$4}++; }';
275 2         807 eval $str;
276 2 50       10 die "eval failed: $@" if $@;
277 2 50       5 if (@reg == 0) {
278 0         0 return @sorted;
279             }
280 2         4 my @keys = map { $_->[2] } @reg;
  3         10  
281 2         9 my @indices = k2i($self->{FLDS},[@keys]);
282 2         8 my @ex = grep $_->[0], @reg;
283 2         8 for(my $i=0; $i<=$#spec; $i++) {
284 10         297 push(@sorted, [$i, @{ ${$self->{TIEHASH}}{$spec[$i]} }[@indices]]);
  10         10  
  10         50  
285             }
286 2 100 66     68 if (@ex == 0 && @keys == 1) {
    50 33        
287 1 50       7 @sorted = sort {$a->[1] cmp $b->[1]} @sorted if $reg[0]->[5] == 0;
  7         1417  
288 1 50       7 @sorted = sort {$b->[1] cmp $a->[1]} @sorted if $reg[0]->[5] == 2;
  0         0  
289 1 50       5 @sorted = sort {$a->[1] <=> $b->[1]} @sorted if $reg[0]->[5] == 1;
  0         0  
290 1 50       4 @sorted = sort {$b->[1] <=> $a->[1]} @sorted if $reg[0]->[5] == 3;
  0         0  
291             } elsif (@ex == 0 && @keys == 2) {
292 0 0 0     0 @sorted = sort {$a->[1] cmp $b->[1]||
  0 0       0  
293             $a->[2] cmp $b->[2]} @sorted
294             if $reg[0]->[5] == 0 && $reg[1]->[5] == 0;
295 0 0 0     0 @sorted = sort {$a->[1] cmp $b->[1]||
  0 0       0  
296             $b->[2] cmp $a->[2]} @sorted
297             if $reg[0]->[5] == 0 && $reg[1]->[5] == 2;
298 0 0 0     0 @sorted = sort {$a->[1] cmp $b->[1]||
  0 0       0  
299             $a->[2] <=> $b->[2]} @sorted
300             if $reg[0]->[5] == 0 && $reg[1]->[5] == 1;
301 0 0 0     0 @sorted = sort {$a->[1] cmp $b->[1]||
  0 0       0  
302             $b->[2] <=> $a->[2]} @sorted
303             if $reg[0]->[5] == 0 && $reg[1]->[5] == 3;
304            
305 0 0 0     0 @sorted = sort {$b->[1] cmp $a->[1]||
  0 0       0  
306             $a->[2] cmp $b->[2]} @sorted
307             if $reg[0]->[5] == 2 && $reg[1]->[5] == 0;
308 0 0 0     0 @sorted = sort {$b->[1] cmp $a->[1]||
  0 0       0  
309             $b->[2] cmp $a->[2]} @sorted
310             if $reg[0]->[5] == 2 && $reg[1]->[5] == 2;
311 0 0 0     0 @sorted = sort {$b->[1] cmp $a->[1]||
  0 0       0  
312             $a->[2] <=> $b->[2]} @sorted
313             if $reg[0]->[5] == 2 && $reg[1]->[5] == 1;
314 0 0 0     0 @sorted = sort {$b->[1] cmp $a->[1]||
  0 0       0  
315             $b->[2] <=> $a->[2]} @sorted
316             if $reg[0]->[5] == 2 && $reg[1]->[5] == 3;
317            
318 0 0 0     0 @sorted = sort {$a->[1] <=> $b->[1]||
  0 0       0  
319             $a->[2] cmp $b->[2]} @sorted
320             if $reg[0]->[5] == 1 && $reg[1]->[5] == 0;
321 0 0 0     0 @sorted = sort {$a->[1] <=> $b->[1]||
  0 0       0  
322             $b->[2] cmp $a->[2]} @sorted
323             if $reg[0]->[5] == 1 && $reg[1]->[5] == 2;
324 0 0 0     0 @sorted = sort {$a->[1] <=> $b->[1]||
  0 0       0  
325             $a->[2] <=> $b->[2]} @sorted
326             if $reg[0]->[5] == 1 && $reg[1]->[5] == 1;
327 0 0 0     0 @sorted = sort {$a->[1] <=> $b->[1]||
  0 0       0  
328             $b->[2] <=> $a->[2]} @sorted
329             if $reg[0]->[5] == 1 && $reg[1]->[5] == 3;
330            
331 0 0 0     0 @sorted = sort {$b->[1] <=> $a->[1]||
  0 0       0  
332             $a->[2] cmp $b->[2]} @sorted
333             if $reg[0]->[5] == 3 && $reg[1]->[5] == 0;
334 0 0 0     0 @sorted = sort {$b->[1] <=> $a->[1]||
  0 0       0  
335             $b->[2] cmp $a->[2]} @sorted
336             if $reg[0]->[5] == 3 && $reg[1]->[5] == 2;
337 0 0 0     0 @sorted = sort {$b->[1] <=> $a->[1]||
  0 0       0  
338             $a->[2] <=> $b->[2]} @sorted
339             if $reg[0]->[5] == 3 && $reg[1]->[5] == 1;
340 0 0 0     0 @sorted = sort {$b->[1] <=> $a->[1]||
  0 0       0  
341             $b->[2] <=> $a->[2]} @sorted
342             if $reg[0]->[5] == 3 && $reg[1]->[5] == 3;
343             } else {
344 1         3 undef $sform;
345 1         2 my $i = 1;
346 1         4 foreach my $e (@reg) {
347 2 100       9 $sform .= $e->[0] if $e->[0];
348 2         7 $sform .= '$'.$e->[1].'->['.$i.']'.$e->[3];
349 2 100       9 $sform .= " $e->[0] " if $e->[0];
350 2         6 $sform .= '$'.$e->[4].'->['.$i.']';
351 2         5 $sform .= '||';
352 2         4 $i++;
353             }
354 1         4 chop $sform;
355 1         2 chop $sform;
356             #print "\$sform:$sform";
357 1         4 @sorted = sort { eval $sform } @sorted;
  7         551  
358             }
359 2         20 return @sorted;
360             }
361            
362             sub _get_recs {
363             ## ext:true - get external values, false - don't
364 10     10   18 my ($self, $ext, @list) = @_;
365 10         12 my @indices = ();
366 10         14 my $ret = [];
367            
368 10         53 @list = grep /^\-?\d+$/, @list;
369            
370 10 100       32 @list = $self->{NUMKEYS}->Indices($self->{NUMKEYS}->Keys) if @list == 0;
371            
372 10         61 my @spec = $self->{NUMKEYS}->Keys( @list );
373            
374 10 100       89 if ( defined($self->{UP}) ) {
375 6 50       21 if (ref($db{$self->{UP}}) =~ /ARRAY/) {
376 0         0 init(__PACKAGE__, $self->{UP}, @{ $db{$self->{UP}} });
  0         0  
377             }
378 6 50       23 die "hash element \"$self->{UP}\" exists while superior table object doesn't"
379             unless defined $db{$self->{UP}};
380             }
381            
382 10         13 my @down = @{$self->{DOWN}};#0.17
  10         17  
383 10         28 for(my $i=0; $i<=$#spec; $i++) {
384 22 50       45 if (defined $spec[$i]) {
385 22         29 my $href = {}; ##-
386 22         23 @{$href}{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };
  22         90  
  22         538  
  22         22  
  22         104  
387             ##+ 0.09
388 22 100       84 if ( exists($href->{nodes}) ) {## && defined($href->{nodes})
389 16 50       41 if (defined $db{$self->{UP}}) {
390 16         42 my @temp = unpack "n*", $href->{nodes};
391 16         22 shift @temp;
392 16         33 $href->{nodes} = [@temp];
393 16 100       82 @{$href->{nodes}} = grep defined($_), $db{$self->{UP}}->{NUMKEYS}->Indices( @{$href->{nodes}} )
  10         90  
  10         38  
394             if @temp>0;
395             } else {
396 0         0 die "hash element \"nodes\" exists and isn't empty while superior table object doesn't exist";
397             }
398             } ##+ 0.09
399 22         40 foreach my $e (@down) {#0.17
400 6         18 my @temp = unpack "n*", $href->{$e};
401 6         7 shift @temp;
402 6         12 $href->{$e} = [@temp];
403 6 100       15 if (@temp) {
404 5 50       16 if (ref($db{$e}) =~ /ARRAY/) {
405 0         0 init(__PACKAGE__, $e, @{ $db{$e} });
  0         0  
406             }
407 5         9 @{$href->{$e}} = grep defined($_), $db{$e}->{NUMKEYS}->Indices( @{$href->{$e}} );
  5         38  
  5         17  
408 5 100 66     18 if ($ext && @{$href->{$e}}>0) {
  3         13  
409 3         5 @{$href->{$e}} = _get_recs($db{$e}, $ext, @{$href->{$e}});
  3         14  
  3         15  
410             }
411             }
412             }
413 22         37 push(@$ret, $href);
414 22         69 push(@indices, $list[$i]);
415             }
416             }
417 10 100       42 return wantarray?($ret, @indices):$ret;
418             }
419            
420             ## obj->get_recs(-1); obj->get_recs; obj->get_recs(0,3,5);
421             ## get extended records data
422             sub get_ext_recs {
423 1     1 1 3 my ($self, @list) = @_;
424 1         3 return _get_recs($self,1,@list);
425             }
426            
427             ## obj->get_recs(-1); obj->get_recs; obj->get_recs(0,3,5);
428             ## get records data
429             sub get_recs {
430 6     6 1 15 my ($self, @list) = @_;
431 6         16 return _get_recs($self,0,@list);
432             }
433            
434             ## obj->set_recs(to); append
435             ## obj->set_recs(to, -1); obj->set_recs(to, 1,3,5); override
436             ## if LIST supplied it sets every existed element for list
437             ## if LIST not supplied it sets every element supplied
438             sub set_recs {
439 3     3 1 9 my ($self, $to, @list) = @_;
440             ## you should check wheter it is non-duplicate elements list
441 3         6 my @set = ();
442            
443 3         18 @list = grep /^\-?\d+$/,@list;#+0.12
444 3 100       10 if (@list == 0) {
445 1         12 my $next = $self->{NUMKEYS}->Length;
446 1         11 @list = ($next..$next+$#{$to});
  1         4  
447             }
448 3         16 my @spec = $self->{NUMKEYS}->Keys( @list );
449            
450 3 100       54 if ( defined($self->{UP}) ) {
451 1 50       6 if (ref($db{$self->{UP}}) =~ /ARRAY/) {
452 0         0 init(__PACKAGE__, $self->{UP}, @{ $db{$self->{UP}} });
  0         0  
453             }
454 1 50       5 die "hash element \"$self->{UP}\" exists while superior table object doesn't"
455             unless defined $db{$self->{UP}};
456             }
457            
458 3         4 my %ext_set;
459             my %ext_del;
460 3         12 my ($created, $updated) = k2i($self->{FLDS},[qw/created updated/]);
461            
462 3         13 for(my $i=0; $i<@spec; $i++) {
463 9         14 my $aref = [];
464 9 50       22 if (defined $to->[$i]) {
465 9 100       19 if (!defined $spec[$i]) {
466 8         31 my ($last) = $self->{NUMKEYS}->Keys(-1);
467 8 100       53 $last = 0 unless defined $last;
468 8         27 my $last_index = $self->{NUMKEYS}->Length-1;
469 8 100       47 $spec[$i] = $last+($list[$i]<1?0:$list[$i])-$last_index;
470             ##print "\$last+(\$list[\$i]<1?0:\$list[\$i])-\$last_index\n";
471             ##print $last,"\+",($list[$i]<1?0:$list[$i]),"\-",$last_index,"\n";
472 8         26 foreach ($last+1..$spec[$i]-1) {
473             ## AUTOVIVIFICATION IF GAP!!!
474 1         3 ${ $self->{TIEHASH} }{$_} = [];
  1         7  
475 1         48 $self->{NUMKEYS}->Push($_=>undef);
476             }
477 8         47 $self->{NUMKEYS}->Push($spec[$i]=>undef);
478 8 50       169 $to->[$i]->{created} = time if defined $created;
479 8 50       19 $to->[$i]->{updated} = undef if defined $updated;#?
480             ## $to->[$i]->{nodes} = undef if exists $to->[$i]->{nodes};#?
481             #print "not defined created:$to->[$i]->{created} updated:$to->[$i]->{updated}\n"
482             } else {
483 1 50       2 if (@{$self->{DOWN}}) {
  1         5  
484             ## CLEAN external "nodes"
485 1         2 my $href = {};##+
486 1         2 @{$href}{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };##+
  1         3  
  1         29  
  1         2  
  1         6  
487 1         3 foreach my $e (@{$self->{DOWN}}) {
  1         3  
488 1 50       6 if ( defined($href->{$e}) ) {
489 0         0 my @temp = unpack "n*", $href->{$e};
490 0         0 shift @temp;
491 0         0 foreach my $el ( @temp ) {
492 0         0 push(@{ $ext_del{$e} }, [ $el, $spec[$i] ]);
  0         0  
493             }
494             }
495             }
496             }
497 1 50       5 $to->[$i]->{updated} = time if defined $updated;
498             #print "defined created:$to->[$i]->{created} updated:$to->[$i]->{updated}\n"
499             }
500 9 100       10 if (@{$self->{DOWN}}) {
  9         22  
501 4         5 foreach my $e (@{$self->{DOWN}}) {
  4         11  
502 4         5 my @temp;
503 4 50       28 if (!defined($to->[$i]->{$e})) {
    50          
504             ## implictly accept 'undef'
505            
506             ## array of indices of external record
507             } elsif (ref($to->[$i]->{$e}) =~ /ARRAY/) {
508 4 50       12 shift @{ $to->[$i]->{$e} }
  0         0  
509             if ref($to->[$i]->{$e}->[0]) =~ /ARRAY/;
510            
511 4 50       21 if (ref($db{$e}) =~ /ARRAY/) {
512 0         0 init(__PACKAGE__, $e, @{ $db{$e} });
  0         0  
513             }
514            
515 4 50       9 if (defined $db{$e}) {
516             ## get numkeys of supplied indices
517 4         7 @temp = $db{$e}->{NUMKEYS}->Keys( @{$to->[$i]->{$e}} );#0.12
  4         17  
518             } else {
519 0         0 die "hash element \"$e\" exists and isn't empty while superior table object doesn't exist";
520             }
521            
522 4         34 foreach my $el ( @temp ) {
523             ## external record numkey, record numkey
524 9         11 push(@{ $ext_set{$e} }, [ $el, $spec[$i] ]);
  9         31  
525             }
526             } else {
527 0         0 die "hash $e element should be array ref!!!";
528             }
529             #push(@temp, 0) if @temp==0;
530 4         17 @temp = grep $_, @temp;
531 4         9 unshift(@temp,0);
532 4         26 $to->[$i]->{$e} = pack "n*", @temp;
533             }
534             }
535             ##+ 0.09
536 9 100       23 if (defined $self->{UP}) {
537 5         5 my @temp;
538 5 50       13 if (!defined($to->[$i]->{nodes})) {
    0          
539             ## implicitly accept 'undef'
540             } elsif ( ref($to->[$i]->{nodes}) =~ /ARRAY/ ) {
541 0         0 @temp = $db{$self->{UP}}->{NUMKEYS}->Keys( @{$to->[$i]->{nodes}} );
  0         0  
542             } else {
543 0         0 die "hash \"nodes\" element should be array ref!!!";
544             }
545 5         9 @temp = grep $_, @temp;
546 5         7 unshift(@temp,0);
547 5         20 $to->[$i]->{nodes} = pack "n*", @temp;
548             } ##+ 0.09
549 9         11 @$aref = @{$to->[$i]}{ @{$self->{FLDS}} };
  9         32  
  9         14  
550             } else {
551 0         0 last;
552             }
553 9         11 ${ $self->{TIEHASH} }{$spec[$i]} = $aref;
  9         54  
554 9         562 push(@set, $list[$i]);
555             }
556            
557 3         10 ch_nodes(\%ext_del, 1); ## DELETE
558 3         6 ch_nodes(\%ext_set); ## SET
559             ## RETURNS ARRAY OF ROW ELEMENT INDICES
560 3         110 return @set;
561             }
562            
563             ## DELETE OR SET
564             sub ch_nodes {
565 8     8 0 15 my ($href, $what) = @_;
566 8         16 ch_field($href, $what, "nodes");
567             }
568            
569             ## DELETE OR SET
570             sub ch_field {
571 10     10 0 13 my $href = shift;
572 10         9 my $what = shift; ## false - SET, true - DELETE
573 10         13 my $field = shift;
574 10         88 my @files = keys %$href;
575 10 100       29 if (@files>0) {
576 4         8 foreach my $f (@files) {
577 4 50       16 if (ref($db{$f}) =~ /ARRAY/) {
578 0         0 init(__PACKAGE__, $f, @{ $db{$f} });
  0         0  
579             }
580 4         14 my $idx = k2i($db{$f}->{FLDS},[$field]);
581 4         7 foreach my $el ( @{$href->{$f}} ) {
  4         9  
582 13         414 my $temp = ${ $db{$f}->{TIEHASH} }{$el->[0]};
  13         64  
583 13         329 my @temp = unpack "n*", $temp->[$idx];
584 13 100       38 @temp = grep $_!=$el->[1], @temp
585             if $what; ## DELETE
586 13 100       29 push(@temp, $el->[1])
587             unless $what; ## SET
588 13   33     107 @temp = grep /^\d+/ && $_, @temp;##+0.11
589 13         23 unshift(@temp, 0);
590 13         25 $temp->[$idx] = pack "n*", @temp;
591 13         15 ${ $db{$f}->{TIEHASH} }{$el->[0]} = $temp;
  13         64  
592             }
593             }
594             }
595             }
596            
597             sub delete {
598 2     2 1 3 my ($self, @list) = @_;
599 2         3 my @indices; ##+$aref
600            
601 2         10 @list = grep /^\-?\d+$/, @list;#+0.12
602            
603 2 50       6 @list = $self->{NUMKEYS}->Indices($self->{NUMKEYS}->Keys) if @list == 0;
604            
605 2         8 my @spec = $self->{NUMKEYS}->Keys( @list );
606            
607 2         11 my %up_del;
608             my %down_del;
609            
610 2         6 for(my $i=0; $i<@spec; $i++) {
611 2 50       5 if (defined $spec[$i]) {
612 2         3 my $href = {}; ##-
613 2         3 @{$href}{ @{$self->{FLDS}} } = @{ ${$self->{TIEHASH}}{$spec[$i]} };
  2         7  
  2         44  
  2         3  
  2         9  
614 2 100       9 if (defined $self->{UP}) {
615 1 50       4 if ( exists($href->{nodes}) ) {#&& defined($href->{nodes})
616             ## fetch numkeys from pack'ed read structure
617 1         3 my @temp = unpack "n*", $href->{nodes};
618 1         2 shift @temp;
619 1         2 $href->{nodes} = [@temp];
620 1         2 foreach my $el ( @{$href->{nodes}} ) {
  1         2  
621             ## external records indentification keys, key to delete
622 1         1 push(@{ $up_del{$self->{UP}} }, [ $el, $spec[$i] ]);
  1         6  
623             }
624             }
625             }
626 2 100       4 if (@{$self->{DOWN}}) {
  2         5  
627             ## CLEAN "nodes"
628 1         2 foreach my $e (@{$self->{DOWN}}) {
  1         3  
629 1         1 my @temp = ();
630 1 50       4 if (defined $db{$e}) {
631 1         3 @temp = unpack "n*", $href->{$e};
632 1         2 shift @temp;
633             } else {
634 0         0 die "hash element \"$e\" exists while superior table object doesn't";
635             }
636 1         2 foreach my $el ( @temp ) {
637 3         2 push(@{ $down_del{$e} }, [ $el, $spec[$i] ]);
  3         11  
638             }
639             }
640             }
641 2         3 delete ${$self->{TIEHASH}}{$spec[$i]}; ## DELETE
  2         11  
642 2         43 $self->{NUMKEYS}->Delete( $spec[$i] ); ## 0.12
643 2         54 push(@indices, $list[$i]);
644             }
645             }
646 2         6 ch_field(\%up_del, 1, $self->{TABLE}); ## DELETE
647 2         49 ch_nodes(\%down_del, 1); ## DELETE
648 2         62 return @indices;
649             }
650            
651             sub key2idx {
652 0     0 0 0 my ($self, @args) = @_;
653 0         0 return k2i($self->{NUMKEYS},\@args);
654             }
655            
656             sub k2i {
657 9     9 0 15 my ($keys, $args) = @_;
658 9         13 my %conv = ();
659 9         14 @conv{ @$keys } = (0..$#{$keys});
  9         35  
660 9 100       42 return wantarray ? @conv{@$args} : $conv{$args->[0]};
661             }
662            
663             sub idx2key {
664 0     0 0 0 my ($self, @indices) = @_;
665 0   0     0 return grep /^\d+/ && $_, @{$self->{NUMKEYS}}[@indices];
  0         0  
666             }
667            
668             sub table {
669 0     0 1 0 my $self = shift;
670 0         0 return $self->{TABLE};
671             }
672            
673             sub flds {
674 1     1 1 7 my $self = shift;
675 1         1 return @{$self->{FLDS}};
  1         25  
676             }
677            
678             sub up {
679 0     0 1   my $self = shift;
680 0           return $self->{UP};
681             }
682            
683             sub down {
684 0     0 1   my $self = shift;
685 0           return @{$self->{DOWN}};
  0            
686             }
687            
688             sub numkeys {
689 0     0 0   my $self = shift;
690 0           return $self->{NUMKEYS}->Keys;
691             }
692            
693             sub last {
694 0     0 1   my $self = shift;
695 0           return $self->{NUMKEYS}->Length-1;
696             }
697            
698             sub name {
699 0     0 1   my $self = shift;
700 0 0         if (@_) {
701 0           $self->{NAME} = shift;
702             }
703 0           return $self->{NAME};
704             }
705            
706             1;
707             __END__