File Coverage

blib/lib/DBR/Interface/DBRv1.pm
Criterion Covered Total %
statement 187 234 79.9
branch 95 180 52.7
condition 19 39 48.7
subroutine 21 21 100.0
pod 0 5 0.0
total 322 479 67.2


line stmt bran cond sub pod time code
1             # the contents of this file are Copyright (c) 2004-2009 Daniel Norman
2             # This program is free software; you can redistribute it and/or
3             # modify it under the terms of the GNU General Public License as
4             # published by the Free Software Foundation.
5              
6             package DBR::Interface::DBRv1;
7              
8 18     18   167 use strict;
  18         38  
  18         6762  
9 18     18   109 use base 'DBR::Common';
  18         46  
  18         1697  
10 18     18   114 use DBR::Query::Select;
  18         41  
  18         423  
11 18     18   13929 use DBR::Query::Count;
  18         51  
  18         525  
12 18     18   142 use DBR::Query::Insert;
  18         39  
  18         583  
13 18     18   113 use DBR::Query::Update;
  18         44  
  18         668  
14 18     18   100 use DBR::Query::Delete;
  18         34  
  18         494  
15 18     18   11921 use DBR::Config::Field::Anon;
  18         54  
  18         606  
16 18     18   9378 use DBR::Config::Table::Anon;
  18         56  
  18         545  
17 18     18   133 use DBR::Query::Part;
  18         37  
  18         403  
18 18     18   101 use DBR::ResultSet;
  18         39  
  18         357  
19 18     18   95 use Carp;
  18         40  
  18         100198  
20              
21             sub new {
22 637     637 0 1823 my( $package ) = shift;
23 637         7274 my %params = @_;
24              
25 637         4313 my $self = {
26             instance => $params{instance},
27             session => $params{session},
28             };
29              
30 637         6929 bless( $self, $package );
31 637 50       2462 return $self->_error('instance object is required') unless $self->{instance};
32              
33 637         3972 return( $self );
34             }
35              
36              
37             ###################################################
38             ### Direct methods for DBRv1 ######################
39             ###################################################
40              
41             sub select {
42 498     498 0 1097 my $self = shift;
43 498         3016 my %params = @_;
44              
45 498 50 33     3584 my $tables = $self->_split( $params{-table} || $params{-tables} ) or
46             return $self->_error("No -table[s] parameter specified");
47              
48 498 50       2447 my $Qtables = $self->_tables($tables) or return $self->_error('tables failed');
49 498         900 my @Qfields;
50              
51 498 100       1784 if(!$params{'-count'}){
52 495 50 66     4040 my $fields = $self->_split( $params{-fields} || $params{-field}) or
53             return $self->_error('No -field[s] parameter specified');
54              
55 495         1681 foreach my $field (@$fields){
56 2360 50       12526 my $Qfield = DBR::Config::Field::Anon->new(
57             session => $self->{session},
58             name => $field
59             ) or return $self->_error('Failed to create field object');
60 2360         7753 push @Qfields, $Qfield;
61             }
62             }
63              
64 498         956 my $where;
65 498 100       2237 if($params{-where}){
66 480         12091 $where = $self->_where($params{-where});
67 480 50       1709 return $self->_error('failed to prep where') unless defined($where);
68             }
69              
70 498         2060 my $limit = $params{'-limit'};
71 498 50       1345 if(defined $limit){
72 0 0       0 return $self->_error('invalid limit') unless $limit =~ /^\d+$/;
73             }
74              
75 498 100       2581 my $class = 'DBR::Query::' . ($params{'-count'} ? 'Count':'Select');
76 498 50       17427 my $query = $class->new(
77             instance => $self->{instance},
78             session => $self->{session},
79              
80             fields => \@Qfields,
81             tables => $Qtables,
82             where => $where,
83             limit => $limit,
84             ) or return $self->_error('failed to create query object');
85              
86 498 100       5247 if ($params{-count}) {
    100          
    100          
87 3         15 return $query->run; # Returns the count directly
88              
89             } elsif ($params{-query}){
90 1         9 return $query;
91              
92             }elsif ($params{-rawsth}) {
93              
94 1 50       9 my $sth = $query->run or return $self->_error('failed to run');
95 1 50       371 $sth->execute() or croak('failed to execute sth');
96              
97 1         9 return $sth;
98              
99             } else {
100 493 50       1605 if ($params{'-object'}) { # new way - hybrid
101 0         0 return DBR::ResultSet->new( $query );
102             }
103              
104 493         2448 my $sth = $query->run;
105 493 50       93017 $sth->execute() or croak ('failed to execute sth');
106              
107 493 100       7596 if ($params{-arrayref}) {
    50          
    100          
108 34         3537 return $sth->fetchall_arrayref(); # ->finish is automatic
109             } elsif ($params{-keycol}) {
110 0         0 return $sth->fetchall_hashref($params{-keycol});
111             } elsif ($params{-single}) {
112 157         4205 my $row = $sth->fetchrow_hashref();
113 157         1172 $sth->finish;
114 157   50     1411 return $row || 0;
115             } else {
116 302         5302 return $sth->fetchall_arrayref({}); # ->finish is automatic
117             }
118             }
119              
120             }
121              
122             sub insert {
123 494     494 0 1958 my $self = shift;
124 494         2013 my %params = @_;
125              
126              
127 494   33     2090 my $table = $params{-table} || $params{-insert};
128 494         2696 my $fields = $params{-fields};
129              
130 494 50 33     6342 return $self->_error('No -table parameter specified') unless $table && $table =~ /^[A-Za-z0-9_-]+$/;
131 494 50       1806 return $self->_error('No proper -fields parameter specified') unless ref($fields) eq 'HASH';
132              
133 494 50       12591 my $Qtable = DBR::Config::Table::Anon->new(
134             session => $self->{session},
135             name => $table,
136             ) or return $self->_error('Failed to create table object');
137 494         1285 my @sets;
138 494         2302 foreach my $field (keys %$fields){
139 2025         4549 my $value = $fields->{$field};
140              
141 2025 50       8775 my $fieldobj = DBR::Config::Field::Anon->new(
142             session => $self->{session},
143             name => $field
144             ) or return $self->_error('Failed to create field object');
145              
146 2025 50       7029 my $valobj = $self->_value($value) or return $self->_error('_value failed');
147              
148 2025 50       10026 my $set = DBR::Query::Part::Set->new($fieldobj,$valobj) or return $self->_error('failed to create set object');
149 2025         9155 push @sets, $set;
150             }
151              
152 494 100       5866 my $query = DBR::Query::Insert->new(
    50          
153             instance => $self->{instance},
154             session => $self->{session},
155             sets => \@sets,
156             quiet_error => $params{-quiet} ? 1:0,
157             tables => $Qtable,
158             ) or return $self->_error('failed to create query object');
159              
160 494         2645 return $query->run();
161              
162             }
163              
164             sub update {
165 46     46 0 88 my $self = shift;
166 46         195 my %params = @_;
167              
168              
169 46   33     189 my $table = $params{-table} || $params{-update};
170 46         119 my $fields = $params{-fields};
171              
172 46 50       347 return $self->_error('No -table parameter specified') unless $table =~ /^[A-Za-z0-9_-]+$/;
173 46 50       173 return $self->_error('No proper -fields parameter specified') unless ref($fields) eq 'HASH';
174              
175 46 50       395 my $Qtable = DBR::Config::Table::Anon->new(
176             session => $self->{session},
177             name => $table,
178             ) or return $self->_error('Failed to create table object');
179 46         86 my $where;
180 46 50       316 if($params{-where}){
181 46 50       226 $where = $self->_where($params{-where}) or return $self->_error('failed to prep where');
182             }else{
183 0         0 return $self->_error('-where hashref/arrayref must be specified');
184             }
185              
186 46         93 my @sets;
187 46         253 foreach my $field (keys %$fields){
188 46         102 my $value = $fields->{$field};
189              
190 46 50       220 my $fieldobj = DBR::Config::Field::Anon->new(
191             session => $self->{session},
192             name => $field
193             ) or return $self->_error('Failed to create field object');
194              
195 46 50       146 my $valobj = $self->_value($value) or return $self->_error('_value failed');
196              
197 46 50       280 my $set = DBR::Query::Part::Set->new($fieldobj,$valobj) or return $self->_error('failed to create set object');
198              
199 46         153 push @sets, $set;
200             }
201              
202 46 50       884 my $query = DBR::Query::Update->new(
    50          
203             instance => $self->{instance},
204             session => $self->{session},
205             sets => \@sets,
206             tables => $Qtable,
207             where => $where,
208             quiet_error => $params{-quiet} ? 1:0,
209             ) or return $self->_error('failed to create query object');
210              
211 46         413 return $query->run();
212              
213             }
214             sub delete {
215 1     1 0 2 my $self = shift;
216 1         5 my %params = @_;
217              
218              
219 1   33     6 my $table = $params{-table} || $params{-delete};
220              
221 1 50       7 return $self->_error('No -table parameter specified') unless $table =~ /^[A-Za-z0-9_-]+$/;
222              
223 1 50       9 my $Qtable = DBR::Config::Table::Anon->new(
224             session => $self->{session},
225             name => $table,
226             ) or return $self->_error('Failed to create table object');
227 1         3 my $where;
228 1 50       5 if($params{-where}){
229 1 50       11 $where = $self->_where($params{-where}) or return $self->_error('failed to prep where');
230             }else{
231 0         0 return $self->_error('-where hashref/arrayref must be specified');
232             }
233              
234 1 50       22 my $query = DBR::Query::Delete->new(
    50          
235             instance => $self->{instance},
236             session => $self->{session},
237             tables => $Qtable,
238             where => $where,
239             quiet_error => $params{-quiet} ? 1:0
240             ) or return $self->_error('failed to create query object');
241              
242 1         6 return $query->run();
243              
244             }
245              
246             sub _tables{
247 498     498   932 my $self = shift;
248 498         957 my $tables = shift;
249              
250 498 50 33     2332 if(ref($tables) eq 'ARRAY' and @{$tables} == 1){
  498         3307  
251 498         1243 $tables = $tables->[0]
252             }
253              
254 498         1414 my @Qtables;
255 498 50       2741 if(ref($tables) eq 'ARRAY'){
    50          
256 0         0 my $ct = 0;
257 0         0 foreach my $table (@{$tables}){
  0         0  
258 0 0       0 return $self->_error("Invalid table name specified ($table)") unless
259             $table =~ /^[A-Za-z][A-Za-z0-9_-]*$/;
260              
261 0 0       0 return $self->_error('No more than 26 tables allowed in a join') if $ct > 25;
262 0         0 my $alias = chr(97 + $ct++); # a-z
263              
264 0 0       0 my $Qtable = DBR::Config::Table::Anon->new(
265             session => $self->{session},
266             name => $table,
267             alias => $alias,
268             ) or return $self->_error('Failed to create table object');
269 0         0 push @Qtables, $Qtable;
270             }
271             }elsif(ref($tables) eq 'HASH'){
272 0         0 foreach my $alias (keys %{$tables}){
  0         0  
273              
274 0 0       0 return $self->_error("invalid table alias '$alias' in -table[s]") unless $alias =~ /^[A-Za-z][A-Za-z0-9_-]*$/;
275 0         0 my $table = $tables->{ $alias };
276 0 0       0 return $self->_error("Invalid table name specified ($table)") unless $table =~ /^[A-Za-z][A-Za-z0-9_-]*$/;
277              
278 0 0       0 my $Qtable = DBR::Config::Table::Anon->new(
279             session => $self->{session},
280             name => $table,
281             alias => $alias,
282             ) or return $self->_error('Failed to create table object');
283 0         0 push @Qtables, $Qtable;
284             }
285             }else{
286 498 50       3837 return $self->_error("Invalid table name specified ($tables)") unless $tables =~ /^[A-Za-z][A-Za-z0-9_-]*$/;
287              
288 498 50       4506 my $Qtable = DBR::Config::Table::Anon->new(
289             session => $self->{session},
290             name => $tables,
291             ) or return $self->_error('Failed to create table object');
292 498         1958 push @Qtables, $Qtable;
293             }
294              
295 498         1990 return \@Qtables;
296              
297             }
298              
299             sub _where {
300 527     527   1110 my $self = shift;
301 527         1018 my $param = shift;
302              
303 527 100       1963 $param = [%{$param}] if (ref($param) eq 'HASH');
  526         2907  
304 527 50       2077 $param = [] unless (ref($param) eq 'ARRAY');
305              
306              
307 527 50       1805 return 0 unless scalar(@$param); # No where parameters
308              
309 527         973 my $where;
310              
311             my @out;
312 527         911 while (@{$param}) {
  1227         4354  
313 700         1147 my $val1 = shift @{$param};
  700         1359  
314              
315             # is it an OR? (single element)
316 700 50       2043 if (ref($val1) eq 'ARRAY') {
317 0         0 my @or;
318 0         0 foreach my $element (@{ $val1 }){
  0         0  
319 0 0       0 push @or, $self->_where($element) or $self->_error('convertvals failed');
320             }
321              
322 0         0 push @out, DBR::Query::Part::Or->new( @or );
323              
324             } else {
325 700         1280 my $key = $val1;
326 700         905 my $value = shift @{$param};
  700         1397  
327              
328 700 100       1986 if (ref($value) eq 'HASH') {
329 1 50 33     19 if($value->{-table} && ($value->{-field} || $value->{-fields})){ #does it smell like a subquery?
      33        
330              
331 1 50       7 my $field = DBR::Config::Field::Anon->new(
332             session => $self->{session},
333             name => $key,
334             ) or return $self->_error('Failed to create field object');
335              
336 1 50       7 my $compat = DBR::Interface::DBRv1->new(
337             session => $self->{session},
338             instance => $self->{instance},
339             ) or return $self->_error('failed to create Query object');
340              
341 1 50       3 my $query = $compat->select(%{$value}, -query => 1) or return $self->_error('failed to create query object');
  1         18  
342 1 50       8 return $self->_error('invalid subquery') unless $query->can_be_subquery;
343              
344 1         14 push @out, DBR::Query::Part::Subquery->new($field, $query);
345              
346             }else{
347 0         0 my $alias = $key;
348              
349 0 0       0 if(%{$value}){
  0         0  
350 0         0 foreach my $k (keys %{$value}) {
  0         0  
351 0         0 print STDERR "FOO: '$alias.$k'\n";
352 0 0       0 my $ret = $self->_processfield("$alias.$k", $value->{$k}) or return $self->_error('failed to process field object');
353 0         0 push @out, $ret
354             }
355             }
356              
357             }
358              
359             } else {
360              
361 699 50       2710 my $ret = $self->_processfield($key,$value) or return $self->_error('failed to process field object');
362              
363 699         1827 push @out, $ret
364             }
365              
366             }
367             }
368              
369 527 100       1613 if(@out > 1){
370 173         1793 return DBR::Query::Part::And->new(@out);
371             }else{
372 354         1225 return $out[0];
373             }
374              
375             }
376              
377             sub _processfield{
378 699     699   2311 my $self = shift;
379 699         1379 my $fieldname = shift;
380 699         1314 my $value = shift;
381              
382 699 50       3306 my $field = DBR::Config::Field::Anon->new(
383             session => $self->{session},
384             name => $fieldname
385             ) or return $self->_error('Failed to create fromfield object');
386 699         1218 my $flags;
387              
388 699 100       2233 if (ref($value) eq 'ARRAY'){
389 476         1181 $flags = $value->[0];
390             }
391              
392 699 50 66     13604 if ($flags && $flags =~ /j/) { # join
393              
394 0 0       0 my $tofield = DBR::Config::Field::Anon->new(
395             session => $self->{session},
396             name => $value->[1]
397             ) or return $self->_error('Failed to create tofield object');
398              
399 0 0       0 my $join = DBR::Query::Part::Join->new($field,$tofield)
400             or return $self->_error('failed to create join object');
401              
402 0         0 return $join;
403              
404             } else {
405 699         1227 my $is_number = 0;
406 699         1010 my $operator;
407              
408 699 100       1919 if ($flags) {
409 476 100       7638 if ( $flags =~ /like/ ) {
    50          
    50          
    50          
    50          
    50          
    50          
410 1         4 $operator = 'like';# like
411             #return $self->_error('LIKE flag disabled without the allowquery flag') unless $self->{config}->{allowquery};
412 0         0 } elsif ( $flags =~ /!/ ) { $operator = 'not'; # Not
413 0         0 } elsif ( $flags =~ /\<\>/ ) { $operator = 'not'; $is_number = 1; # greater than less than
  0         0  
414 0         0 } elsif ( $flags =~ /\>=/ ) { $operator = 'ge'; $is_number = 1; # greater than eq
  0         0  
415 0         0 } elsif ( $flags =~ /\<=/ ) { $operator = 'le'; $is_number = 1; # less than eq
  0         0  
416 0         0 } elsif ( $flags =~ /\>/ ) { $operator = 'gt'; $is_number = 1; # greater than
  0         0  
417 0         0 } elsif ( $flags =~ /\</ ) { $operator = 'lt'; $is_number = 1; # less than
  0         0  
418             }
419             }
420              
421 699   100     3375 $operator ||= 'eq';
422              
423 699 50       2633 my $valobj = $self->_value($value,$is_number) or return $self->_error('_value failed');
424              
425 699 50       5433 my $compobj = DBR::Query::Part::Compare->new(
426             field => $field,
427             operator => $operator,
428             value => $valobj
429             ) or return $self->_error('failed to create compare object');
430              
431 699         4431 return $compobj;
432              
433             }
434              
435             }
436              
437             sub _value {
438 2770     2770   5099 my $self = shift;
439 2770         4602 my $value = shift;
440 2770   50     31304 my $is_number = shift || 0;
441              
442 2770         3790 my $flags;
443 2770 100       9091 if (ref($value) eq 'ARRAY'){
444 2012         16631 $value = [ @$value ]; # shallow clone
445 2012         4119 $flags = shift @$value;
446             }
447              
448 2770 100 100     16074 if($flags && $flags =~ /d/){ $is_number = 1 }
  2011         3001  
449              
450 2770 50       17692 my $valobj = DBR::Query::Part::Value->new(
451             is_number => $is_number,
452             value => $value,
453             session => $self->{session}
454             ) or return $self->_error('failed to create value object');
455 2770         10328 return $valobj;
456              
457             }
458              
459             1;