File Coverage

blib/lib/NTuples.pm
Criterion Covered Total %
statement 81 97 83.5
branch 12 22 54.5
condition n/a
subroutine 9 11 81.8
pod 0 10 0.0
total 102 140 72.8


line stmt bran cond sub pod time code
1             # NTuples
2             # Specialized intra-memory RDBMS
3             # Copyright (c) 2005, 2006, 2007 Charles Morris
4             # All rights reserved.
5             #
6             # This program is free software; you can redistribute it and/or
7             # modify it under the same terms as Perl itself.
8             #
9             # This module is the core association engine for a few projects
10             # based on fast access to network configuration information.
11             #
12             # There are generic wrappers available to you for use in your
13             # own projects. See the NTuples::wrap::* packages.
14             #
15             # For more information on my projects, check for news at:
16             # http://www.cs.odu.edu/~cmorris/
17             #
18             # Who says project creep should be avoided?
19              
20              
21             package NTuples;
22              
23             our @DATA;
24             our @FMT;
25             our %colname_to_colnum;
26             our %addr_to_loc;
27              
28             BEGIN {
29 1     1   1858 $VERSION = '0.11';
30             }
31              
32             sub debug_display
33             {
34 0     0 0 0 my $rownum = 0;
35 0         0 foreach my $row ( @DATA )
36             {
37 0         0 my $colnum = 0;
38 0         0 foreach my $val ( @{$row} )
  0         0  
39             {
40 0         0 print "$val:[$rownum][$colnum] ";
41 0         0 $colnum++;
42             }
43 0         0 $rownum++;
44 0         0 print "\n";
45             }
46             }
47              
48             #---------- Constructor ----------#
49             #static method
50             sub new {
51 1     1 0 107 my ($pkg) = shift;
52              
53 1         3 my $instance = bless( {}, $pkg );
54              
55 1         3 return $instance;
56             }
57              
58             ##########################
59             #--- object functions ---#
60              
61             # new_format()
62             # static method
63             # register format for any current or added data tuples.
64             sub new_format
65             {
66 1     1 0 36 my ($instance) = shift;
67 1 50       5 warn "expecting a ". __PACKAGE__ ."\n" unless $instance->isa(__PACKAGE__);
68              
69 1         3 @FMT = @_;
70              
71 1         1 my $i = 0;
72 1         2 my $x;
73 3         4 map{
74 1         1 $x = $_;
75 3 50       6 if($x){$colname_to_colnum{$x} = $i;}
  3         5  
76 3         5 $i++;
77             } @FMT;
78              
79 1         2 return $instance;
80             }
81              
82              
83             # new_data()
84             # static method
85             # register data (overwriting old data)
86             sub new_data
87             {
88 1     1 0 43 my ($instance) = shift;
89 1 50       4 warn "expecting a ". __PACKAGE__ ."\n" unless $instance->isa(__PACKAGE__);
90              
91 1         3 @DATA = @_;
92              
93             # probeably be made alot more efficient.
94             # any patches are welcome :)
95              
96             #use Time::HiRes;
97             #my $start = Time::HiRes::time();
98             #$last = $start;
99              
100 1         1 my $rownum = 0;
101 1         2 foreach my $row (@DATA)
102             {
103 13         12 my $colnum = 0;
104 13         12 foreach my $field (@{$row})
  13         14  
105             {
106 39         28 my $i = 0;
107              
108 39         39 foreach my $colname (@FMT)
109             {
110             #debugged, $field needs to be encapsulated with ''s.
111 117         101 $fieldrep = $field;
112 117         101 $fieldrep =~ s/'/\\\'/g;
113             # $code = '$lh_'. $FMT[$colnum] .'{\''. $fieldrep .'\'}{'. $colname .'} = '.
114             # '\$DATA[$rownum][$colname_to_colnum{$colname}];';
115              
116 117         274 $lh{ $FMT[$colnum] }{ $fieldrep }{ $colname } =
117             \$DATA[$rownum][$colname_to_colnum{$colname}];
118              
119             # eval "$code"; warn "$code: $@" if $@;
120             }
121              
122 39         120 $addr_to_loc{\$DATA[$rownum][$colnum]} = [ $rownum, $colnum ];
123              
124 39         47 $colnum++;
125             }
126 13         16 $rownum++;
127             }
128              
129             #$finish = Time::HiRes::time();
130             #print $finish - $start ."\n";
131              
132 1         3 return $instance;
133             }
134              
135              
136             # insert_data()
137             # static method
138             # register an array of data (pushes to the end of current data)
139             # INSERT INTO NTuples VALUES @data
140             sub insert_data
141             {
142 1     1 0 2 my ($instance) = shift;
143 1 50       4 warn "expecting a ". __PACKAGE__ ."\n" unless $instance->isa(__PACKAGE__);
144              
145 1         3 push(@DATA, @_);
146              
147             # we REALLLY dont need to remap the entire LoL........
148             # but thats how its happening right now until I have time to sit down and figure it out
149              
150 1         2 my $rownum = 0;
151 1         1 foreach my $row (@DATA)
152             {
153 14         19 my $colnum = 0;
154 14         28 foreach my $field (@{$row})
  14         26  
155             {
156 42         46 my $i = 0;
157 42         51 foreach my $colname (@FMT)
158             {
159             # $code = '$lh_'. $FMT[$colnum] .'{'. $field .'}{'. $colname .'} = '.
160             # '\$DATA[$rownum][$colname_to_colnum{$colname}];';
161              
162 126         357 $lh{ $FMT[$colnum] }{ $field }{ $colname } =
163             \$DATA[$rownum][$colname_to_colnum{$colname}];
164              
165             # eval "$code"; warn "$code: $@" if $@;
166             }
167              
168 42         120 $addr_to_loc{\$DATA[$rownum][$colnum]} = [ $rownum, $colnum ];
169              
170 42         84 $colnum++;
171             }
172 14         23 $rownum++;
173             }
174              
175 1         3 return $instance;
176             }
177              
178              
179             # select_row()
180             # SELECT * FROM NTuples WHERE $keyname = $key
181             sub select_row
182             {
183 2     2 0 56 my ($instance, $keyname, $key) = @_;
184 2 50       9 warn "expecting a ". __PACKAGE__ ."\n" unless $instance->isa(__PACKAGE__);
185              
186              
187             # This is faster (just an educated guess) but it returns crazy ordered results
188             # (ordered by the value of the hashed key.. I think)
189             # my %result;
190             # my $code = '%result = %{$lh_'. $keyname .'{'. $key .'}};';
191             # eval "$code"; warn $@ if $@;
192             # my @ret;
193             # map { push(@ret, ${$_}) } values %result;
194              
195             # So we do this instead.
196              
197 2         3 my @ret;
198 2         4 map { push(@ret, NTuples::select_value($instance, $keyname, $key, $_)) } @FMT;
  6         12  
199            
200 2         7 return @ret;
201             }
202              
203              
204             # update_row()
205             # static method
206             # updates row resolved by $keyname{$key}
207             # UPDATE NTuples SET * = @row WHERE $keyname = $key
208             sub update_row
209             {
210 0     0 0 0 my ($instance, $keyname, $key, @row) = @_;
211 0 0       0 warn "expecting a ". __PACKAGE__ ."\n" unless $instance->isa(__PACKAGE__);
212              
213 0         0 my $i = 0;
214 0         0 map { NTuples::update_value($instance, $keyname, $key, @FMT[$i], $_); $i++ } @row;
  0         0  
  0         0  
215              
216 0         0 return $instance;
217             }
218              
219              
220             # select_value()
221             # static method
222             # resolves value $valname from row resolved by $keyname{$key}
223             # SELECT $valname FROM NTuples WHERE $keyname = $key
224             sub select_value
225             {
226 14     14 0 69 my ($instance, $keyname, $key, $valname) = @_;
227 14 50       44 warn "expecting a ". __PACKAGE__ ."\n" unless $instance->isa(__PACKAGE__);
228              
229 14         14 my $result;
230             # my $code = '$result = $lh_'. $keyname .'{'. $key .'}{'. $valname .'};';
231             # eval "$code"; warn "$code: $@" if $@;
232              
233 14         28 $result = $lh{ $keyname }{ $key }{ $valname };
234              
235 14         14 return ${$result};
  14         59  
236             }
237              
238              
239             # update_value()
240             # static method
241             # updates value of $valname in row resolved by $keyname{$key} to $val
242             # UPDATE NTuples SET $valname = $val WHERE $keyname = $key
243             sub update_value
244             {
245 1     1 0 9 my ($instance, $keyname, $key, $valname, $val) = @_;
246 1 50       10 warn "expecting a ". __PACKAGE__ ."\n" unless $instance->isa(__PACKAGE__);
247              
248             #Step 1) Buffer old value
249             #Step 2) Alter actual value
250             #Step 3) Copy association based on $valname from $oldval to $val
251             #Step 4) Remove old association based on $oldval
252              
253             #ok, so now its at least only doing one scalar assignment and one eval{}
254             # my $code = '
255             # $oldvalue = ${$lh_'. $keyname .'{'. $key .'}{'. $valname .'}};
256             # ${$lh_'. $keyname .'{'. $key .'}{'. $valname .'}} = $val;
257             # $lh_'. $valname .'{'. $val .'} = $lh_'. $valname .'{$oldvalue};
258             # delete $lh_'. $valname .'{$oldvalue};
259             # ';
260             #codes and evaluates (using test.pl)
261             # $oldvalue = ${$lh_username{sys}{uid}};
262             # ${$lh_username{sys}{uid}} = $val;
263             # $lh_uid{17} = $lh_uid{$oldvalue};
264             # delete $lh_uid{$oldvalue};
265              
266             # print "eval: $code\n";
267             # eval "$code"; warn "$code: $@" if $@;
268            
269 1         2 $oldvalue = ${ $lh{ $keyname }{ $key }{ $valname } };
  1         3  
270             #print "$oldvalue = \${ \$lh{ $keyname }{ $key }{ $valname } }\n";
271            
272 1         1 ${ $lh{ $keyname }{ $key }{ $valname } } = $val;
  1         2  
273             #print "\${ \$lh{ $keyname }{ $key }{ $valname } } = $val\n";
274            
275 1         4 $lh{ $valname }{ $val } = $lh{ $valname }{ $oldvalue };
276             #print "\$lh{ $valname }{ $val } = \$lh{ $valname }{ $oldvalue }\n";
277            
278 1         2 delete $lh{ $valname }{ $oldvalue };
279              
280 1         9 return $instance;
281             }
282              
283              
284             # delete_row()
285             # static method
286             # deletes row resolved by $keyname{$key}
287             # DELETE FROM NTuples WHERE $keyname = $key
288             sub delete_row
289             {
290 2     2 0 4 my ($instance, $keyname, $key) = @_;
291 2 50       17 warn "expecting a ". __PACKAGE__ ."\n" unless $instance->isa(__PACKAGE__);
292              
293 2         3 my $result;
294             # my $code = '$result = $lh_'. $keyname .'{'. $key .'}{'. $keyname .'};';
295             # print "eval: $code\n";
296             # eval "$code"; warn "$code: $@" if $@;
297              
298 2         7 $result = $lh{ $keyname }{ $key }{ $keyname };
299              
300 2 100       7 if( $result )
301             {
302 1         1 splice( @DATA, @{$addr_to_loc{$result}}[0], 1 );
  1         5  
303            
304 1         3 my $i = 0;
305 1         4 my @row = NTuples::select_row($instance, $keyname, $key);
306            
307 1         3 foreach my $colname (@FMT)
308             {
309             # $code = 'delete $lh_'. $colname .'{'. $row[$i] .'};'; #if exists will not work with delete()
310             #eval "$code"; warn "$code: $@" if $@;
311              
312 3         8 delete $lh{$colname}{$row[$i]};
313              
314 3         8 $i++;
315             }
316             }
317              
318 2 100       12 return (defined($result)? '1' : '0');
319             }
320              
321             1;
322              
323             __END__