File Coverage

blib/lib/DBIx/DBO.pm
Criterion Covered Total %
statement 175 186 94.0
branch 101 122 82.7
condition 29 39 74.3
subroutine 38 40 95.0
pod 17 19 89.4
total 360 406 88.6


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