File Coverage

blib/lib/MPMinus/Store/DBI.pm
Criterion Covered Total %
statement 54 88 61.3
branch 18 76 23.6
condition 14 47 29.7
subroutine 8 13 61.5
pod 5 6 83.3
total 99 230 43.0


line stmt bran cond sub pod time code
1             package MPMinus::Store::DBI; # $Id$
2 1     1   16908 use strict;
  1         2  
  1         105  
3              
4             =head1 NAME
5              
6             MPMinus::Store::DBI - Database independent interface for MPMinus on CTK::DBI based
7              
8             =head1 VERSION
9              
10             Version 1.00
11              
12             =head1 SYNOPSIS
13              
14             use MPMinus::Store::DBI;
15              
16             # MySQL connect
17             my $mysql = new MPMinus::Store::DBI (
18             -m => $m, # OPTIONAL
19             -dsn => 'DBI:mysql:database=TEST;host=192.168.1.1',
20             -user => 'login',
21             -pass => 'password',
22             -connect_to => 5,
23             -request_to => 60
24             -attr => {
25             mysql_enable_utf8 => 1,
26             RaiseError => 0,
27             PrintError => 0,
28             },
29             ); # See CTK::DBI
30            
31             # MySQL connect (old style, without DSN)
32             my $mysql = new MPMinus::Store::DBI (
33             -m => $m, # OPTIONAL
34            
35             -driver => 'mysql', # Driver name. See DBI module
36             # Available drivers:
37             # CSV, DBM, ExampleP, File, Gofer, ODBC, Oracle,
38             # Pg, Proxy, SQLite, Sponge, mysql
39             -host => '192.168.1.1',
40             -port => '3306', # default
41             -database => 'TEST',
42            
43             -user => 'login',
44             -pass => 'password',
45             -attr => {
46             mysql_enable_utf8 => 1,
47             RaiseError => 0,
48             PrintError => 0,
49             },
50             );
51              
52             my $dbh = $mysql->connect;
53            
54             my $pingstat = $mysql->ping if $mysql;
55            
56             $mysql->reconnect() unless $pingstat;
57            
58             # Table select (as array)
59             my @result = $mysql->table($sql, @inargs);
60              
61             # Table select (as hash)
62             my %result = $mysql->tableh($key, $sql, @inargs); # $key - primary index field name
63              
64             # Record (as array)
65             my @result = $mysql->record($sql, @inargs);
66              
67             # Record (as hash)
68             my %result = $mysql->recordh($sql, @inargs);
69              
70             # Fiels (as scalar)
71             my $result = $mysql->field($sql, @inargs);
72              
73             # SQL/PL-SQL
74             my $sth = $mysql->execute($sql, @inargs);
75             ...
76             $sth->finish;
77              
78             =head1 DESCRIPTION
79              
80             Database independent interface for MPMinus on CTK::DBI based.
81              
82             =head2 DEBUG
83              
84             Set $MPMinus::Store::DBI::DEBUG_FORCE = 1 for enable debugging in STDERR where object $m undefined
85              
86             Coming soon
87              
88             =head1 METHODS
89              
90             =over 8
91              
92             =item B<ping>
93              
94             my $status = $mysql->ping();
95              
96             Returns connection's life status
97              
98             =item B<reconnect>
99              
100             $mysql->reconnect unless $mysql->ping();
101              
102             =item B<err, errstr, state>
103              
104             my $err = $mysql->err;
105             my $errstr = $mysql->errstr;
106             my $state = $mysql->state;
107              
108             Methods returns DBI values: err, errstr and state.
109              
110             See L<DBI/"METHODS_COMMON_TO_ALL_HANDLES">
111              
112             =back
113              
114             =head1 EXAMPLES
115              
116             =over 8
117              
118             =item B<Handler example>
119              
120             package MPM::foo::Handlers;
121             use strict;
122            
123             use MPMinus::Store::DBI;
124            
125             sub handler {
126             my $r = shift;
127             my $m = MPMinus->m;
128            
129             ...
130            
131             # MySQL connect
132             $m->set_node(
133             mysql => new MPMinus::Store::DBI (
134             -m => $m,
135             -dsn => 'DBI:mysql:database=NAME;host=HOST',
136             -user => 'USER',
137             -pass => 'PASSWORD',
138             -attr => {
139             mysql_enable_utf8 => 1,
140             RaiseError => 0,
141             PrintError => 0,
142             HandleError => sub { $m->log_error(shift || '') },
143             },
144             )
145             ) unless $m->mysql;
146            
147             ...
148            
149             }
150            
151             package MPM::foo::Test;
152             use strict;
153              
154             sub response {
155             my $m = shift;
156            
157             my @data = $m->mysql->table('select * from table');
158            
159             ...
160            
161             return Apache2::Const::OK;
162             }
163              
164             =item B<Handler example with reconnection>
165              
166             package MPM::foo::Handlers;
167             use strict;
168            
169             use MPMinus::Store::DBI;
170            
171             sub handler {
172             my $r = shift;
173             my $m = MPMinus->m;
174            
175             ...
176            
177             # MySQL connect/reconnect
178             if ($m->mysql) {
179             $m->mysql->reconnect unless $m->mysql->ping;
180             } else {
181             # eval 'sub CTK::DBI::_error {1}'; # For supressing CTK::DBI errors
182             $m->set_node(
183             mysql => new MPMinus::Store::DBI (
184             -m => $m,
185             -dsn => 'DBI:mysql:database=NAME;host=HOST',
186             -user => 'USER',
187             -pass => 'PASSWORD',
188             -attr => {
189             mysql_enable_utf8 => 1,
190             RaiseError => 0,
191             PrintError => 0,
192             HandleError => sub { $m->log_error(shift || '') },
193             },
194             )
195             );
196             }
197            
198             ...
199            
200             }
201            
202             package MPM::foo::Test;
203             use strict;
204              
205             sub response {
206             my $m = shift;
207            
208             my @data = $m->mysql->table('select * from table');
209            
210             ...
211            
212             return Apache2::Const::OK;
213             }
214              
215             =item B<Simple example>
216              
217             use MPMinus::Store::DBI;
218              
219             $MPMinus::Store::DBI::DEBUG_FORCE = 1;
220             my $dbi = new MPMinus::Store::DBI (
221             -driver => 'mysql',
222             -name => 'mylocaldb',
223             -user => 'user',
224             -password => 'password'
225             );
226             ...
227             my @table = $dbi->table("select * from tablename where date = ?", "01.01.2000");
228              
229             =item B<Sponge example>
230              
231             use MPMinus::Store::DBI;
232              
233             $MPMinus::Store::DBI::DEBUG_FORCE = 1;
234             my $o = new MPMinus::Store::DBI(
235             -driver => 'Sponge',
236             -attr => { RaiseError => 1 },
237             );
238             my $dbh = $o->connect();
239             my $sth = $dbh->prepare("select * from table", {
240             rows => [
241             [qw/foo bar baz/],
242             [qw/qux quux corge/],
243             [qw/grault garply waldo/],
244             ],
245             NAME => [qw/h1 h2 h3/],
246             });
247              
248             $sth->execute();
249             my $result = $sth->fetchall_arrayref;
250             $sth->finish;
251             print Dumper($result);
252              
253             =back
254              
255             =head1 HISTORY
256              
257             =over 8
258              
259             =item B<1.00 / Mon Apr 29 11:04:52 2013 MSK>
260              
261             Init version
262              
263             =back
264              
265             =head1 SEE ALSO
266              
267             L<CTK::DBI>, L<Apache::DBI>, L<DBI>
268              
269             =head1 AUTHOR
270              
271             Serz Minus (Lepenkov Sergey) L<http://serzik.ru> E<lt>minus@mail333.comE<gt>
272              
273             =head1 COPYRIGHT
274              
275             Copyright (C) 1998-2013 D&D Corporation. All Rights Reserved
276              
277             =head1 LICENSE
278              
279             This program is free software: you can redistribute it and/or modify
280             it under the terms of the GNU General Public License as published by
281             the Free Software Foundation, either version 3 of the License, or
282             (at your option) any later version.
283              
284             This program is distributed in the hope that it will be useful,
285             but WITHOUT ANY WARRANTY; without even the implied warranty of
286             MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
287             GNU General Public License for more details.
288              
289             See C<LICENSE> file
290              
291             =cut
292              
293 1     1   7 use vars qw($VERSION $DEBUG_FORCE);
  1         2  
  1         182  
294             $VERSION = 1.00;
295              
296             use constant {
297 1         115 ATTR_NAMES => [
298             ['M', 'GLOBAL', 'GLOB', 'MPMINUS', 'MPM'], # 0
299             ['DSN','STRING','STR'], # 1
300             ['HOST','HOSTNAME','SERVER','SERVERNAME','ADDRESS','ADDR','SERVERADDR'], # 2
301             ['DB','BD','DBNAME','DATABASE','NAME','DATABASENAME'], # 3
302             ['PORT',], # 4
303             ['USER','USERNAME','LOGIN'], # 5
304             ['PASSWORD','PASS'], # 6
305             ['DRIVER','DRIVERNAME'], # 7
306             ['TIMEOUT_CONNECT','CONNECT_TIMEOUT','CNT_TIMEOUT','TIMEOUT_CNT','TO_CONNECT','CONNECT_TO'],# 8
307             ['TIMEOUT_REQUEST','REQUEST_TIMEOUT','REQ_TIMEOUT','TIMEOUT_REQ','TO_REQUEST','REQUEST_TO'],# 9
308             ['ATTRIBUTES','ATTR','ATTRHASH','PARAMS'], # 10
309             ],
310 1     1   7 };
  1         1  
311              
312 1     1   1565 use DBI;
  1         23181  
  1         86  
313 1     1   14 use base qw/CTK::DBI/;
  1         1  
  1         706  
314 1     1   136217 use CTK::Util qw/ :API /;
  1         2  
  1         878  
315              
316             sub new {
317 1     1 0 71 my $class = shift;
318 1         6 my @in = read_attributes(ATTR_NAMES,@_);
319            
320             # Îñíîâíûå àòðèáóòû ñîåäèíåíèÿ MySQL
321 1         121 my $m = $in[0];
322 1   50     7 my $dsn = $in[1] || '';
323 1   50     4 my $host = $in[2] || '';
324 1   50     6 my $db = $in[3] || '';
325 1   50     5 my $port = $in[4] || '';
326 1   50     4 my $user = $in[5] || '';
327 1   50     6 my $pass = $in[6] || '';
328 1   50     3 my $driver = $in[7] || '';
329 1   50     4 my $toc = $in[8] || 0;
330 1   50     3 my $tor = $in[9] || 0;
331 1   50     4 my $attr = $in[10] || undef;
332            
333 1 50       2 unless ($dsn) {
334 1         9 my @adrivers = DBI->available_drivers();
335 1 50       387 if (grep {$driver eq $_} @adrivers) {
  6         9  
336 1 50       6 if ($driver =~ /mysql/i) {
    50          
337 0 0       0 $dsn = "DBI:mysql:database=$db".($host?";host=$host":'').($port?";port=$port":'');
    0          
338             } elsif ($driver =~ /Oracle/i) {
339 0 0       0 if ($host) {
340 0 0       0 $dsn = "DBI:Oracle:host=$host".($db?";service_name=$db":'').($port?";port=$port":'');
    0          
341             } else {
342 0 0       0 $dsn = "DBI:Oracle:".($db?"$db":'').($port?";port=$port":'');
    0          
343             }
344             } else {
345             # dbi:DriverName:database=database_name;host=hostname;port=port
346 1 50       8 $dsn = "DBI:".$driver.":"
    50          
    50          
347             .($db?"database=$db":'')
348             .($host?";host=$host":'')
349             .($port?";port=$port":'');
350             }
351             } else {
352 0         0 carp("Driver \"$driver\" not availebled. Available drivers: ",join(", ",@adrivers));
353             }
354             }
355 1         7 my %args = (
356             -dsn => $dsn,
357             -user => $user,
358             -pass => $pass,
359             -timeout_connect => $toc,
360             -timeout_request => $tor,
361             -attr => $attr,
362             );
363              
364 1 50       3 if ($dsn) {
365 1         19 my $obj = $class->SUPER::new(%args);
366 1 50 33     2593 $obj = bless({}, $class) unless $obj && ref($obj) eq __PACKAGE__;
367 1         3 $obj->{m} = $m;
368 1 50       3 return $obj unless $obj->{dbh};
369 1 50 33     4 if ($m && ref($m) eq 'MPMinus') {
370 0         0 $m->debug("--- CONNECT {$dsn} AS $obj ---");
371             } else {
372 1 50       2 carp("--- CONNECT {$dsn} AS $obj ---") if $DEBUG_FORCE;
373             }
374 1 50       7 return $obj if $obj;
375             } else {
376 0         0 return bless({
377             m=>$m,
378             }, $class);
379             }
380 0         0 return undef;
381             }
382             sub ping {
383 0     0 1 0 my $self = shift;
384 0 0 0     0 return 0 unless $self && ref($self) eq __PACKAGE__;
385 0 0       0 return 0 unless $self->{dsn};
386 0 0       0 return 0 unless $self->{dbh};
387 0 0       0 return 0 unless $self->{dbh}->can('ping');
388 0         0 return $self->{dbh}->ping();
389             }
390             sub reconnect {
391 0     0 1 0 my $self = shift;
392              
393 0         0 my $m = $self->{m};
394 0         0 my $dsn = $self->{dsn};
395            
396             # See CTK::DBI::DBI_CONNECT
397             $self->{dbh} = CTK::DBI::DBI_CONNECT(
398             $dsn,
399             $self->{user},
400             $self->{password},
401             $self->{attr},
402             $self->{connect_to},
403 0         0 );
404 0 0       0 if ($self->{dbh}) {
405 0 0 0     0 if ($m && ref($m) eq 'MPMinus') {
406 0         0 $m->debug("--- RECONNECT {$dsn} AS $self ---");
407             } else {
408 0 0       0 carp("--- RECONNECT {$dsn} AS $self ---") if $DEBUG_FORCE;
409             }
410 0         0 return 1;
411             }
412 0         0 return undef;
413             }
414             sub err {
415 0     0 1 0 my $self = shift;
416 0 0 0     0 return $self->{dbh}->err if $self->{dbh} && $self->{dbh}->can('err');
417 0 0       0 return defined $DBI::err ? $DBI::err : 0;
418             }
419             sub errstr {
420 0     0 1 0 my $self = shift;
421 0 0 0     0 return $self->{dbh}->errstr if $self->{dbh} && $self->{dbh}->can('errstr');
422 0 0       0 return defined $DBI::errstr ? $DBI::errstr : '';
423             }
424             sub state {
425 0     0 1 0 my $self = shift;
426 0 0 0     0 return $self->{dbh}->state if $self->{dbh} && $self->{dbh}->can('state');
427 0 0       0 return defined $DBI::state ? $DBI::state : '';
428             }
429             sub DESTROY {
430 1     1   2605 my $self = shift;
431 1         3 my $dsn = '';
432 1 50       7 $dsn = $self->{dsn} if $self->{dsn};
433 1         4 my $m = '';
434 1 50       7 $m = $self->{m} if $self->{m};
435            
436 1 50 33     8 if ($dsn && $self->{dbh}) {
437 1 50 33     6 if($m && ref($m) eq 'MPMinus') {
438 0         0 $m->debug("--- DISCONNECT {$dsn} ---");
439             } else {
440 1 50       84 carp("--- DISCONNECT {$dsn} ---") if $DEBUG_FORCE;
441             }
442             }
443             }
444              
445             1;