File Coverage

blib/lib/DBIx/DBO.pm
Criterion Covered Total %
statement 164 172 95.3
branch 92 108 85.1
condition 36 44 81.8
subroutine 36 38 94.7
pod 21 23 91.3
total 349 385 90.6


line stmt bran cond sub pod time code
1 14     14   537829 use 5.014;
  14         53  
2 14     14   107 use warnings;
  14         36  
  14         1199  
3              
4             package DBIx::DBO 0.50;
5              
6 14     14   27112 use DBI;
  14         350708  
  14         1574  
7 14     14   140 use Carp qw(carp croak);
  14         67  
  14         1534  
8              
9             our %Config = (
10             AutoReconnect => 0,
11             CacheQuery => 0,
12             DebugSQL => 0,
13             OnRowUpdate => 'simple',
14             QuoteIdentifier => 1,
15             );
16             my @ConnectArgs;
17              
18 14     14   11912 use DBIx::DBO::DBD;
  14         51  
  14         619  
19 14     14   10204 use DBIx::DBO::Table;
  14         47  
  14         569  
20 14     14   11640 use DBIx::DBO::Query;
  14         67  
  14         652  
21 14     14   10171 use DBIx::DBO::Row;
  14         67  
  14         43595  
22              
23 51     51 1 615 sub dbd_class { 'DBIx::DBO::DBD' }
24 23     23 1 178 sub table_class { 'DBIx::DBO::Table' }
25 24     24 1 152 sub query_class { 'DBIx::DBO::Query' }
26 26     26 1 208 sub row_class { 'DBIx::DBO::Row' }
27              
28             *_isa = \&DBIx::DBO::DBD::_isa;
29              
30             =head1 NAME
31              
32             DBIx::DBO - An OO interface to SQL queries and results. Easily constructs SQL queries, and simplifies processing of the returned data.
33              
34             =head1 SYNOPSIS
35              
36             use DBIx::DBO;
37            
38             # Create the DBO
39             my $dbo = DBIx::DBO->connect('DBI:mysql:my_db', 'me', 'mypasswd') or die $DBI::errstr;
40            
41             # Create a "read-only" connection (useful for a replicated database)
42             $dbo->connect_readonly('DBI:mysql:my_db', 'me', 'mypasswd') or die $DBI::errstr;
43            
44             # Start with a Query object
45             my $query = $dbo->query('my_table');
46            
47             # Find records with an 'o' in the name
48             $query->where('name', 'LIKE', '%o%');
49            
50             # And with an id that is less than 500
51             $query->where('id', '<', 500);
52            
53             # Exluding those with an age range from 20 to 29
54             $query->where('age', 'NOT BETWEEN', [20, 29]);
55            
56             # Return only the first 10 rows
57             $query->limit(10);
58            
59             # Fetch the rows
60             while (my $row = $query->fetch) {
61            
62             # Use the row as an array reference
63             printf "id=%d name=%s status=%s\n", $row->[0], $row->[1], $row->[4];
64            
65             # Or as a hash reference
66             print 'id=', $row->{id}, "\n", 'name=', $row->{name};
67            
68             # Update/delete rows
69             $row->update(status => 'Fired!') if $row->{name} eq 'Harry';
70             $row->delete if $row->{id} == 27;
71             }
72              
73             =head1 DESCRIPTION
74              
75             This module provides a convenient and efficient way to access a database. It can construct queries for you and returns the results in easy to use methods.
76              
77             Once you've created a C object using one or both of C or C, you can begin creating L objects. These are the "workhorse" objects, they encapsulate an entire query with JOINs, WHERE clauses, etc. You need not have to know about what created the C to be able to use or modify it. This makes it valuable in environments like mod_perl or large projects that prefer an object oriented approach to data.
78              
79             The query is only automatically executed when the data is requested. This is to make it possible to minimise lookups that may not be needed or to delay them as late as possible.
80              
81             The L object returned can be treated as both an arrayref or a hashref. The data is aliased for efficient use of memory. C objects can be updated or deleted, even when created by JOINs (If the DB supports it).
82              
83             =head1 METHODS
84              
85             =cut
86              
87             sub import {
88 16     16   276915 my $class = shift;
89 16 100       96 if (@_ & 1) {
90 1         4 my $opt = pop;
91 1         436 carp "Import option '$opt' passed without a value";
92             }
93 16         5141 while (my($opt, $val) = splice @_, 0, 2) {
94 6 100       20 if (exists $Config{$opt}) {
95 5         42 DBIx::DBO::DBD->_set_config(\%Config, $opt, $val);
96             } else {
97 1         198 carp "Unknown import option '$opt'";
98             }
99             }
100             }
101              
102             =head3 C
103              
104             DBIx::DBO->new($dbh);
105             DBIx::DBO->new(undef, $readonly_dbh);
106              
107             Create a new C object from existsing C handles. You must provide one or both of the I and I C handles.
108              
109             =head3 C
110              
111             $dbo = DBIx::DBO->connect($data_source, $username, $password, \%attr)
112             or die $DBI::errstr;
113              
114             Takes the same arguments as Lconnect|DBI/"connect"> for a I connection to a database. It returns the C object if the connection succeeds or undefined on failure.
115              
116             =head3 C
117              
118             Takes the same arguments as C for a I connection to a database. It returns the C object if the connection succeeds or undefined on failure.
119              
120             Both C & C can be called on a C object to add that respective connection to create a C with both I and I connections.
121              
122             my $dbo = DBIx::DBO->connect($master_dsn, $username, $password, \%attr)
123             or die $DBI::errstr;
124             $dbo->connect_readonly($slave_dsn, $username, $password, \%attr)
125             or die $DBI::errstr;
126              
127             =cut
128              
129             sub new {
130 20     20 1 7639 my $me = shift;
131 20 100       85 croak 'Too many arguments for '.(caller(0))[3] if @_ > 3;
132 19         46 my($dbh, $rdbh, $new) = @_;
133              
134 19 100 100     133 if (defined $new and not UNIVERSAL::isa($new, 'HASH')) {
135 1         8 croak '3rd argument to '.(caller(0))[3].' is not a HASH reference';
136             }
137 18 100       44 if (defined $dbh) {
138 12 100       63 croak 'Invalid read-write database handle' unless _isa($dbh, 'DBI::db');
139 11         38 $new->{dbh} = $dbh;
140 11   66     159 $new->{dbd} //= $dbh->{Driver}{Name};
141             }
142 17 100       194 if (defined $rdbh) {
143 6 100       16 croak 'Invalid read-only database handle' unless _isa($rdbh, 'DBI::db');
144             croak 'The read-write and read-only connections must use the same DBI driver'
145 5 100 100     44 if $dbh and $dbh->{Driver}{Name} ne $rdbh->{Driver}{Name};
146 4         32 $new->{rdbh} = $rdbh;
147 4   66     39 $new->{dbd} //= $rdbh->{Driver}{Name};
148             }
149 15 100       106 croak "Can't create the DBO, unknown database driver" unless $new->{dbd};
150 14         62 $new->{dbd_class} = $me->dbd_class->_require_dbd_class($new->{dbd});
151 14         78 $me->_init($new);
152             }
153              
154             sub _init {
155 14     14   43 my($class, $me) = @_;
156 14         32 bless $me, $class;
157 14         162 $me->{dbd_class}->_init_dbo($me);
158             }
159              
160             sub connect {
161 11     11 1 239292 my $me = shift;
162 11         23 my $conn;
163 11 100       40 if (ref $me) {
164 4 100       18 croak 'DBO is already connected' if $me->{dbh};
165 3 100       18 $me->_check_driver($_[0]) if @_;
166 2 100       5 if ($me->config('AutoReconnect')) {
167 1   50     5 $conn = $me->{ConnectArgs} //= scalar @ConnectArgs;
168             } else {
169 1 50       10 undef $ConnectArgs[$me->{ConnectArgs}] if defined $me->{ConnectArgs};
170 1         3 delete $me->{ConnectArgs};
171             }
172 2 50       8 $me->{dbh} = $me->_connect($conn, @_) or return;
173 2         630 return $me;
174             }
175 7         16 my %new;
176 7 100       40 $conn = $new{ConnectArgs} = scalar @ConnectArgs if $me->config('AutoReconnect');
177 7 50       42 my $dbh = $me->_connect($conn, @_) or return;
178 7         3645 $me->new($dbh, undef, \%new);
179             }
180              
181             sub connect_readonly {
182 12     12 1 1177 my $me = shift;
183 12         20 my $conn;
184 12 100       36 if (ref $me) {
185 11         145 undef $me->{rdbh};
186 11 100       56 $me->_check_driver($_[0]) if @_;
187 9 100       36 if ($me->config('AutoReconnect')) {
188 4   100     22 $conn = $me->{ConnectReadOnlyArgs} //= scalar @ConnectArgs;
189             } else {
190 5 100       23 undef $ConnectArgs[$me->{ConnectReadOnlyArgs}] if defined $me->{ConnectReadOnlyArgs};
191 5         11 delete $me->{ConnectReadOnlyArgs};
192             }
193 9 50       32 $me->{rdbh} = $me->_connect($conn, @_) or return;
194 7         2193 return $me;
195             }
196 1         2 my %new;
197 1 50       6 $conn = $new{ConnectReadOnlyArgs} = scalar @ConnectArgs if $me->config('AutoReconnect');
198 1 50       5 my $dbh = $me->_connect($conn, @_) or return;
199 1         297 $me->new(undef, $dbh, \%new);
200             }
201              
202             sub _check_driver {
203 9     9   23 my($me, $dsn) = @_;
204              
205 9 100       44 my $driver = (DBI->parse_dsn($dsn))[1] or
206             croak "Can't connect to data source '$dsn' because I can't work out what driver to use " .
207             "(it doesn't seem to contain a 'dbi:driver:' prefix and the DBI_DRIVER env var is not set)";
208              
209             ref($me) =~ /::DBD::\Q$driver\E$/ or
210             $driver eq $me->{dbd} or
211 8 100 66     381 croak "Can't connect to the data source '$dsn'\n" .
212             "The read-write and read-only connections must use the same DBI driver";
213             }
214              
215             # Our HandleError adds a stack trace to PrintError & RaiseError
216             sub _handle_error {
217 0 0   0   0 if ($Config{DebugSQL} > 1) {
218 0         0 $_[0] = Carp::longmess($_[0]);
219 0         0 return 0;
220             }
221 0 0       0 carp $_[1]->errstr if $_[1]->{PrintError};
222 0 0       0 croak $_[1]->errstr if $_[1]->{RaiseError};
223 0         0 return 1;
224             }
225              
226             sub _connect {
227 20     20   123 my($me, $conn_idx, @conn) = @_;
228              
229 20 100 66     119 if (@conn) {
    100          
230             # If a conn index is given then store the connection args
231 14 100       44 $ConnectArgs[$conn_idx] = \@conn if defined $conn_idx;
232             } elsif (defined $conn_idx and $ConnectArgs[$conn_idx]) {
233             # Retrieve the connection args
234 4         7 @conn = @{$ConnectArgs[$conn_idx]};
  4         15  
235             } else {
236 2         10 croak "Can't auto-connect as AutoReconnect was not set";
237             }
238              
239 18         31 my %attr;
240 18 100       69 %attr = %{$conn[3]} if ref $conn[3] eq 'HASH';
  4         19  
241             # AutoCommit is always on
242 18         105 %attr = (HandleError => \&_handle_error, PrintError => 0, RaiseError => 1, %attr, AutoCommit => 1);
243              
244 18         68 local @DBIx::DBO::CARP_NOT = qw(DBI);
245 18         131 DBI->connect(@conn);
246             }
247              
248             =head3 C
249              
250             $dbo->table($table);
251             $dbo->table([$schema, $table]);
252             $dbo->table($table_object);
253              
254             Create and return a new L object.
255             Tables can be specified by their name or an arrayref of schema and table name or another L object.
256              
257             =cut
258              
259             sub table {
260 15     15 1 4869 $_[0]->table_class->new(@_);
261             }
262              
263             =head3 C
264              
265             $dbo->query($table, ...);
266             $dbo->query([$schema, $table], ...);
267             $dbo->query($table_object, ...);
268              
269             Create a new L object from the tables specified.
270             In scalar context, just the C object will be returned.
271             In list context, the C object and L objects will be returned for each table specified.
272              
273             my($query, $table1, $table2) = $dbo->query(['my_schema', 'my_table'], 'my_other_table');
274              
275             =cut
276              
277             sub query {
278 17     17 1 2620 $_[0]->query_class->new(@_);
279             }
280              
281             =head3 C
282              
283             $dbo->row($table || $table_object || $query_object);
284              
285             Create and return a new L object.
286              
287             =cut
288              
289             sub row {
290 6     6 1 1882 $_[0]->row_class->new(@_);
291             }
292              
293             =head3 C, C, C, C
294              
295             $dbo->selectrow_array($statement, \%attr, @bind_values);
296             $dbo->selectrow_arrayref($statement, \%attr, @bind_values);
297             $dbo->selectrow_hashref($statement, \%attr, @bind_values);
298             $dbo->selectall_arrayref($statement, \%attr, @bind_values);
299              
300             These convenience methods provide access to Lselectrow_array|DBI/"selectrow_array">, Lselectrow_arrayref|DBI/"selectrow_arrayref">, Lselectrow_hashref|DBI/"selectrow_hashref">, Lselectall_arrayref|DBI/"selectall_arrayref"> methods.
301             They default to using the I C handle.
302              
303             =cut
304              
305             sub selectrow_array {
306 1     1 1 3 my $me = shift;
307 1         13 $me->{dbd_class}->_selectrow_array($me, @_);
308             }
309              
310             sub selectrow_arrayref {
311 2     2 1 6 my $me = shift;
312 2         20 $me->{dbd_class}->_selectrow_arrayref($me, @_);
313             }
314              
315             sub selectrow_hashref {
316 0     0 1 0 my $me = shift;
317 0         0 $me->{dbd_class}->_selectrow_hashref($me, @_);
318             }
319              
320             sub selectall_arrayref {
321 6     6 1 15 my $me = shift;
322 6         45 $me->{dbd_class}->_selectall_arrayref($me, @_);
323             }
324              
325             =head3 C
326              
327             $dbo->do($statement) or die $dbo->dbh->errstr;
328             $dbo->do($statement, \%attr) or die $dbo->dbh->errstr;
329             $dbo->do($statement, \%attr, @bind_values) or die ...
330              
331             This provides access to the Ldo|DBI/"do"> method. It defaults to using the I C handle.
332              
333             =cut
334              
335             sub do {
336 6     6 1 625 my $me = shift;
337 6         47 $me->{dbd_class}->_do($me, @_);
338             }
339              
340             =head3 C
341              
342             $dbo->table_info($table);
343             $dbo->table_info([$schema, $table]);
344             $dbo->table_info($table_object);
345              
346             Returns a hashref containing C, C and C for the table.
347             Mainly for internal use.
348              
349             =cut
350              
351             sub table_info {
352 33     33 1 83 my($me, $table) = @_;
353 33 100       96 croak 'No table name supplied' unless length $table;
354              
355 31         49 my $schema;
356 31 100       90 if (_isa($table, 'DBIx::DBO::Table')) {
357 2 100       12 croak 'This table is from a different DBO connection' if $table->{DBO} != $me;
358 1         5 ($schema, $table) = @$table{qw(Schema Name)};
359             } else {
360 29 100       197 ($schema, $table) = ref $table eq 'ARRAY' ? @$table : $me->{dbd_class}->_unquote_table($me, $table);
361 29   100     207 $schema //= $me->{dbd_class}->_get_table_schema($me, $table);
362              
363             $me->{dbd_class}->_get_table_info($me, $schema, $table)
364 29 100 100     237 unless exists $me->{TableInfo}{$schema // ''}{$table};
365             }
366 28   100     187 return ($schema, $table, $me->{TableInfo}{$schema // ''}{$table});
367             }
368              
369             =head3 C
370              
371             Disconnect both the I & I connections to the database.
372              
373             =cut
374              
375             sub disconnect {
376 4     4 1 561 my $me = shift;
377 4 100       19 if ($me->{dbh}) {
378 3         71 $me->{dbh}->disconnect;
379 3         73 undef $me->{dbh};
380             }
381 4 100       18 if ($me->{rdbh}) {
382 3         79 $me->{rdbh}->disconnect;
383 3         46 undef $me->{rdbh};
384             }
385 4         19 delete $me->{TableInfo};
386 4         14 return;
387             }
388              
389             =head2 Common Methods
390              
391             These methods are accessible from all DBIx::DBO* objects.
392              
393             =head3 C
394              
395             This C object.
396              
397             =head3 C
398              
399             The I C handle.
400              
401             =head3 C
402              
403             The I C handle, or if there is no I connection, the I C handle.
404              
405             =cut
406              
407 2     2 1 187483 sub dbo { $_[0] }
408              
409             sub _handle {
410 497     497   1126 my($me, $type) = @_;
411             # $type can be 'read-only', 'read-write' or false (which means try read-only then read-write)
412 497 100 66     2699 $type ||= defined $me->{rdbh} ? 'read-only' : 'read-write';
413 497 100       1342 my($d, $c) = $type ne 'read-only' ? qw(dbh ConnectArgs) : qw(rdbh ConnectReadOnlyArgs);
414 497 100       1343 croak "No $type handle connected" unless defined $me->{$d};
415             # Automatically reconnect, but only if possible and needed
416 495 100 100     1494 $me->{$d} = $me->_connect($me->{$c}) if exists $me->{$c} and not $me->{$d}->ping;
417 495         4516 $me->{$d};
418             }
419              
420             sub dbh {
421 34     34 1 66 my $me = shift;
422 34   50     111 $me->_handle($me->config('UseHandle') || 'read-write');
423             }
424              
425             sub rdbh {
426 463     463 1 809 my $me = shift;
427 463         1278 $me->_handle($me->config('UseHandle'));
428             }
429              
430             =head3 C
431              
432             $global_setting = DBIx::DBO->config($option);
433             DBIx::DBO->config($option => $global_setting);
434             $dbo_setting = $dbo->config($option);
435             $dbo->config($option => $dbo_setting);
436              
437             Get or set the global or this C config settings. When setting an option, the previous value is returned. When getting an option's value, if the value is undefined, the global value is returned.
438              
439             =head2 Available C options
440              
441             =over
442              
443             =item C
444              
445             Boolean setting to store the connection details for re-use.
446             Before every operation the connection will be tested via ping() and reconnected automatically if needed.
447             Changing this has no effect after the connection has been made.
448             Defaults to C.
449              
450             =item C
451              
452             Boolean setting to cause C objects to cache their entire result for re-use.
453             The query will only be executed automatically once.
454             To rerun the query, either explicitly call L or alter the query.
455             Defaults to C.
456              
457             =item C
458              
459             Set to C<1> or C<2> to warn about each SQL command executed. C<2> adds a full stack trace.
460             Defaults to C<0> (silent).
461              
462             =item C
463              
464             Set to C<'empty'>, C<'simple'> or C<'reload'> to define the behaviour of a C after an L.
465             C<'empty'> will simply leave the C empty after every update.
466             C<'simple'> will set the values in the C if they are not complex expressions, otherwise the C will be empty.
467             C<'reload'> is the same as C<'simple'> except it also tries to reload the C if possible.
468             Defaults to C<'simple'>.
469              
470             =item C
471              
472             Boolean setting to control quoting of SQL identifiers (schema, table and column names).
473              
474             =item C
475              
476             Set to C<'read-write'> or C<'read-only'> to force using only that handle for all operations.
477             Defaults to C which chooses the I handle for reads and the I handle otherwise.
478              
479             =back
480              
481             Global options can also be set when C'ing the module:
482              
483             use DBIx::DBO QuoteIdentifier => 0, DebugSQL => 1;
484              
485             =cut
486              
487             sub config {
488 609     609 1 145226 my($me, $opt) = @_;
489 609 100       1599 if (@_ > 2) {
490             return ref $me
491 46 100 100     563 ? $me->{dbd_class}->_set_config($me->{Config} //= {}, $opt, $_[2])
492             : $me->dbd_class->_set_config(\%Config, $opt, $_[2]);
493             }
494             return ref $me
495 563 100 100     2914 ? $me->{dbd_class}->_get_config($opt, $me->{Config} //= {}, \%Config)
496             : $me->dbd_class->_get_config($opt, \%Config);
497             }
498              
499             sub STORABLE_freeze {
500 16     16 0 377 my $me = $_[0];
501 16 100 66     535 return unless ref $me->{dbh} or ref $me->{rdbh};
502              
503             # Stash the unfreezable bits
504 8         14 my %stash = map { $_ => delete $me->{$_} } qw(dbh rdbh ConnectArgs ConnectReadOnlyArgs);
  32         62  
505 8 50       32 $me->{dbh} = "$stash{dbh}" if defined $stash{dbh};
506 8 50       14 $me->{rdbh} = "$stash{rdbh}" if defined $stash{rdbh};
507 8         13 for (qw(ConnectArgs ConnectReadOnlyArgs)) {
508 16 50       32 $me->{$_} = $ConnectArgs[$stash{$_}] if defined $stash{$_};
509             }
510              
511 8         12 my $frozen = Storable::nfreeze($me);
512              
513             # Restore the stashed bits
514 8         84 for (qw(dbh rdbh ConnectArgs ConnectReadOnlyArgs)) {
515 32 100       51 $me->{$_} = $stash{$_} if defined $stash{$_};
516             }
517              
518 8         258 return $frozen;
519             }
520              
521             sub STORABLE_thaw {
522 8     8 0 980 my($me, $cloning, $frozen) = @_;
523              
524 8         9 %$me = %{ Storable::thaw($frozen) };
  8         17  
525 8         206 for (qw(ConnectArgs ConnectReadOnlyArgs)) {
526 16 50       189 $me->{$_} = push(@ConnectArgs, $me->{$_}) - 1 if exists $me->{$_};
527             }
528             }
529              
530             sub DESTROY {
531 17     17   457 undef %{$_[0]};
  17         339  
532             }
533              
534             1;
535              
536             __END__