File Coverage

blib/lib/DBIx/ProcedureCall.pm
Criterion Covered Total %
statement 80 148 54.0
branch 19 80 23.7
condition n/a
subroutine 11 17 64.7
pod 0 1 0.0
total 110 246 44.7


line stmt bran cond sub pod time code
1             package DBIx::ProcedureCall;
2              
3 3     3   29557 use strict;
  3         7  
  3         108  
4 3     3   19 use warnings;
  3         5  
  3         117  
5              
6 3     3   18 use Carp qw(croak);
  3         10  
  3         4624  
7              
8              
9             our $VERSION = '0.11';
10              
11             our %__loaded_drivers;
12              
13             our %__known_attributes = qw~
14             procedure 1
15             function 1
16             cached 1
17             package 1
18             packaged 1
19             cursor 1
20             fetch() 1
21             fetch[] 1
22             fetch{} 1
23             fetch[[]] 1
24             fetch[{}] 1
25             table 1
26             boolean 1
27             ~;
28            
29             sub __run_procedure{
30 1     1   3 my $dbh =$_[0];
31 1 50       4 croak "expected a database handle as first parameter, but got nothing" unless $dbh;
32            
33             # determine database type
34 1         2 my $dbtype = eval { $dbh->get_info(17); }; # 17 : SQL_DBMS_NAME
  1         36  
35 1 50       259 croak "could not determine the database type from $dbh: $@. Is that really a DBI database handle? " unless $dbtype;
36            
37 0         0 my $name = $_[1];
38 0 0       0 croak "expected a procedure name to run against the database, but got nothing" unless $name;
39            
40             # delegate to the driver
41 0 0       0 unless ($__loaded_drivers{$dbtype}){
42 0 0       0 eval "require DBIx::ProcedureCall::$dbtype; \$__loaded_drivers{$dbtype} = 1;"
43             or croak "failed to load driver for $dbtype database: $@";
44             }
45            
46 0         0 "DBIx::ProcedureCall::$dbtype"->__run_procedure(@_);
47             }
48              
49             sub __run_function{
50 0     0   0 my $dbh = $_[0];
51 0 0       0 croak "expected a database handle as first parameter, but got nothing" unless $dbh;
52            
53             # determine database type
54 0         0 my $dbtype = eval { $dbh->get_info(17); }; # 17 : SQL_DBMS_NAME
  0         0  
55 0 0       0 croak "could not determine the database type from $dbh: $@. Is that really a DBI database handle? " unless $dbtype;
56            
57 0         0 my $name = $_[1];
58 0 0       0 croak "expected a function name to run against the database, but got nothing" unless $name;
59            
60 0         0 my $attr = $_[2];
61            
62             # delegate to the driver
63 0 0       0 unless ($__loaded_drivers{$dbtype}){
64 0 0       0 eval "require DBIx::ProcedureCall::$dbtype; \$__loaded_drivers{$dbtype} = 1;"
65             or croak "failed to load driver for $dbtype database: $@";
66             }
67 0         0 my $r = "DBIx::ProcedureCall::$dbtype"->__run_function(@_);
68 0 0       0 return $r unless $attr->{fetch};
69            
70             #fetch cursor
71 0         0 return __fetch($r, $attr, $dbtype);
72            
73             }
74              
75             sub __fetch{
76 0     0   0 my ($sth, $attr, $dbtype) = @_;
77 0         0 my $data;
78 0 0       0 if ($attr->{'fetch[[]]'} ) { $data = $sth->fetchall_arrayref; }
  0 0       0  
    0          
    0          
    0          
79             elsif ($attr->{'fetch()'} ) {
80 0         0 my @data = $sth->fetchrow_array;
81 0 0       0 "DBIx::ProcedureCall::$dbtype"->__close($sth) if $attr->{cursor};
82 0         0 return @data;
83             }
84 0         0 elsif ($attr->{'fetch[{}]'} ) { $data = $sth->fetchall_arrayref({ }); }
85 0         0 elsif ($attr->{'fetch{}'} ) { $data = $sth->fetchrow_hashref; }
86 0         0 elsif ($attr->{'fetch[]'} ) { $data = $sth->fetchrow_arrayref; }
87            
88 0 0       0 "DBIx::ProcedureCall::$dbtype"->__close($sth)
89             if $attr->{cursor};
90            
91 0         0 return $data;
92             }
93              
94             sub __bind_params{
95 0     0   0 my ($sql, $start_index, $params) = @_;
96 0         0 my @binder;
97 0 0       0 if (ref $params eq 'ARRAY'){
98 0         0 my $i = $start_index;
99 0         0 foreach (@$params){
100             # special bind options
101 0 0       0 if (ref $_ eq 'ARRAY'){
102 0         0 @binder = @$_;
103             }
104             else
105             {
106 0         0 @binder = ( $_ );
107             }
108             # INOUT parameters
109 0 0       0 if (ref $binder[0]){
110             # default MAXLEN 100
111 0 0       0 $binder[1] = 100 unless exists $binder[1];
112 0         0 $sql->bind_param_inout($i++, @binder);
113             }
114             else{
115 0         0 $sql->bind_param($i++, @binder);
116             }
117             }
118             }
119             else{
120 0         0 foreach (keys %$params){
121             # special bind options
122 0         0 my $p = $params->{$_};
123 0 0       0 if (ref $p eq 'ARRAY'){
124 0         0 @binder = @$p;
125             }
126             else
127             {
128 0         0 @binder = ( $p );
129             }
130             # INOUT parameters
131 0 0       0 if (ref $binder[0]){
132             # default MAXLEN 100
133 0 0       0 $binder[1] = 100 unless exists $binder[1];
134 0         0 $sql->bind_param_inout(":$_", @binder);
135             }
136             else{
137 0         0 $sql->bind_param(":$_", @binder);
138             }
139             }
140             }
141             }
142              
143             sub __run{
144 1     1   2 my $w = shift;
145 1         3 my $name = shift;
146 1         2 my $attr = shift;
147 1         2 my $dbh = shift;
148             # check function/procedure attribute
149 1 50       7 $w = 0 if $attr->{function};
150 1 50       4 $w = undef if $attr->{procedure};
151             # in void context run a procedure
152 1 50       7 return __run_procedure($dbh, $name, $attr, @_) unless defined $w;
153             # in non-void context run a function
154 0         0 return __run_function($dbh, $name, $attr, @_);
155             }
156              
157             sub run{
158 0     0 0 0 my $dbh = shift;
159 0         0 my $n = shift;
160 0         0 my ($name, @attr) = split ':', $n;
161 0         0 my @err = grep { not exists $__known_attributes{lc $_} } @attr;
  0         0  
162 0 0       0 croak "tried to set unknown attributes (@err) for stored procedure '$name' " if @err;
163            
164 0         0 my %attr = map { (lc($_) => 1) } @attr;
  0         0  
165            
166             # any fetch implies function
167 0 0       0 if ( grep /^fetch/, keys %attr ) {
168 0         0 $attr{'function'} = 1;
169 0         0 $attr{'fetch'} = 1;
170             }
171            
172             # cursor implies function
173 0 0       0 $attr{'function'} = 1 if $attr{'cursor'};
174            
175             # table implies function
176 0 0       0 $attr{'function'} = 1 if $attr{'table'};
177            
178            
179 0         0 return __run(wantarray, $name, \%attr, $dbh, @_);
180             }
181              
182              
183             sub import {
184 19     19   2979 my $class = shift;
185 19         71 my $caller = (caller)[0];
186 3     3   29 no strict 'refs';
  3         12  
  3         2657  
187 19         55 foreach (@_) {
188 38         121 my ($name, @attr) = split ':';
189            
190 38         67 my @err = grep { not exists $__known_attributes{lc $_} } @attr;
  40         145  
191 38 50       92 croak "tried to set unknown attributes (@err) for stored procedure '$name' " if @err;
192            
193 38         54 my %attr = map { (lc($_) => 1) } @attr;
  40         138  
194            
195            
196             # any fetch implies function
197 38 100       165 if ( grep /^fetch/, keys %attr ) {
198 7         13 $attr{'function'} = 1;
199 7         12 $attr{'fetch'} = 1;
200             }
201            
202             # cursor implies function
203 38 100       102 $attr{'function'} = 1 if $attr{'cursor'};
204            
205             # table implies function
206 38 100       80 $attr{'function'} = 1 if $attr{'table'};
207            
208             # boolean implies function
209 38 100       87 $attr{'function'} = 1 if $attr{'boolean'};
210            
211 38 100       77 if ($attr{'package'}){
212 3         8 delete $attr{'package'};
213 3         611 my $pkgname = $name;
214 3         10 $pkgname =~ s/\./::/g;
215 3         10 $pkgname =~ s/[^:\w]/_/g;
216 3     1   22 *{"${pkgname}::AUTOLOAD"} = sub {__pkg_autoload($name, \%attr, @_) };
  3         30  
  1         12  
217 3         52 next;
218             }
219 35 100       70 if ($attr{'packaged'}){
220 6         569 delete $attr{'packaged'};
221 6         49 my @p = split '\.', $name;
222 6 50       21 die "cannot create a package for unpackaged procedure $name (name contains no dots)"
223             unless @p>1;
224 6         10 my $subname = pop @p;
225 6         14 my $pkgname = join '::', @p;
226 6         12 $pkgname =~ s/[^:\w]/_/g;
227 6         14 $subname =~ s/[^:\w]/_/g;
228 6     0   22 *{"${pkgname}::$subname"} = sub {__run(wantarray,$name,\%attr, @_) };
  6         29  
  0         0  
229 6         63 next;
230             }
231            
232 29         39 my $subname = $name;
233 29         80 $subname =~ s/\W/_/g;
234 29         327 *{"${caller}::$subname"} = sub {
235 0     0   0 __run(wantarray,$name,\%attr, @_)
236 29         112 };
237             }
238             }
239              
240             sub __pkg_autoload{
241 1     1   3 my $name = shift;
242 1         2 my $attr = shift;
243 1         2 my $pkgname = $name;
244 1         5 $pkgname =~ s/\./::/g;
245 1         3 $pkgname =~ s/[^:\w]/_/g;
246 1         2 our $AUTOLOAD;
247 1         20 my @p = split '::', $AUTOLOAD;
248 1         3 my $subname = $p[-1];
249 1         5 $name = "$name.$subname";
250             my $sub = sub {
251 1     1   6 __run(wantarray,$name,$attr, @_);
252 1         6 };
253 3     3   25 no strict 'refs';
  3         5  
  3         220  
254 1         3 *{"${pkgname}::$subname"} = $sub;
  1         6  
255 1         4 $sub->(@_);
256             }
257              
258              
259             1;
260             __END__