cleanup cursor class handling
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage.pm
1 package DBIx::Class::Storage;
2
3 use strict;
4 use warnings;
5
6 use base qw/DBIx::Class/;
7
8 use Scalar::Util qw/weaken/;
9 use Carp::Clan qw/^DBIx::Class/;
10 use IO::File;
11
12 __PACKAGE__->mk_group_accessors('simple' => qw/debug debugobj schema/);
13 __PACKAGE__->mk_group_accessors('inherited' => 'cursor_class');
14
15 __PACKAGE__->cursor_class('DBIx::Class::Cursor');
16
17 sub cursor { shift->cursor_class(@_); }
18
19 package # Hide from PAUSE
20     DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION;
21
22 use overload '"' => sub {
23   'DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION'
24 };
25
26 sub new {
27   my $class = shift;
28   my $self = {};
29   return bless $self, $class;
30 }
31
32 package DBIx::Class::Storage;
33
34 =head1 NAME
35
36 DBIx::Class::Storage - Generic Storage Handler
37
38 =head1 DESCRIPTION
39
40 A base implementation of common Storage methods.  For specific
41 information about L<DBI>-based storage, see L<DBIx::Class::Storage::DBI>.
42
43 =head1 METHODS
44
45 =head2 new
46
47 Arguments: $schema
48
49 Instantiates the Storage object.
50
51 =cut
52
53 sub new {
54   my ($self, $schema) = @_;
55
56   $self = ref $self if ref $self;
57
58   my $new = {};
59   bless $new, $self;
60
61   $new->set_schema($schema);
62   $new->debugobj(new DBIx::Class::Storage::Statistics());
63
64   my $fh;
65
66   my $debug_env = $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG}
67                   || $ENV{DBIC_TRACE};
68
69   if (defined($debug_env) && ($debug_env =~ /=(.+)$/)) {
70     $fh = IO::File->new($1, 'w')
71       or $new->throw_exception("Cannot open trace file $1");
72   } else {
73     $fh = IO::File->new('>&STDERR');
74   }
75
76   $fh->autoflush(1);
77   $new->debugfh($fh);
78   $new->debug(1) if $debug_env;
79
80   $new;
81 }
82
83 =head2 set_schema
84
85 Used to reset the schema class or object which owns this
86 storage object, such as during L<DBIx::Class::Schema/clone>.
87
88 =cut
89
90 sub set_schema {
91   my ($self, $schema) = @_;
92   $self->schema($schema);
93   weaken($self->{schema}) if ref $self->{schema};
94 }
95
96 =head2 connected
97
98 Returns true if we have an open storage connection, false
99 if it is not (yet) open.
100
101 =cut
102
103 sub connected { die "Virtual method!" }
104
105 =head2 disconnect
106
107 Closes any open storage connection unconditionally.
108
109 =cut
110
111 sub disconnect { die "Virtual method!" }
112
113 =head2 ensure_connected
114
115 Initiate a connection to the storage if one isn't already open.
116
117 =cut
118
119 sub ensure_connected { die "Virtual method!" }
120
121 =head2 throw_exception
122
123 Throws an exception - croaks.
124
125 =cut
126
127 sub throw_exception {
128   my $self = shift;
129
130   $self->schema->throw_exception(@_) if $self->schema;
131   croak @_;
132 }
133
134 =head2 txn_do
135
136 =over 4
137
138 =item Arguments: C<$coderef>, @coderef_args?
139
140 =item Return Value: The return value of $coderef
141
142 =back
143
144 Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
145 returning its result (if any). If an exception is caught, a rollback is issued
146 and the exception is rethrown. If the rollback fails, (i.e. throws an
147 exception) an exception is thrown that includes a "Rollback failed" message.
148
149 For example,
150
151   my $author_rs = $schema->resultset('Author')->find(1);
152   my @titles = qw/Night Day It/;
153
154   my $coderef = sub {
155     # If any one of these fails, the entire transaction fails
156     $author_rs->create_related('books', {
157       title => $_
158     }) foreach (@titles);
159
160     return $author->books;
161   };
162
163   my $rs;
164   eval {
165     $rs = $schema->txn_do($coderef);
166   };
167
168   if ($@) {                                  # Transaction failed
169     die "something terrible has happened!"   #
170       if ($@ =~ /Rollback failed/);          # Rollback failed
171
172     deal_with_failed_transaction();
173   }
174
175 In a nested transaction (calling txn_do() from within a txn_do() coderef) only
176 the outermost transaction will issue a L</txn_commit>, and txn_do() can be
177 called in void, scalar and list context and it will behave as expected.
178
179 Please note that all of the code in your coderef, including non-DBIx::Class
180 code, is part of a transaction.  This transaction may fail out halfway, or
181 it may get partially double-executed (in the case that our DB connection
182 failed halfway through the transaction, in which case we reconnect and
183 restart the txn).  Therefore it is best that any side-effects in your coderef
184 are idempotent (that is, can be re-executed multiple times and get the
185 same result), and that you check up on your side-effects in the case of
186 transaction failure.
187
188 =cut
189
190 sub txn_do {
191   my ($self, $coderef, @args) = @_;
192
193   ref $coderef eq 'CODE' or $self->throw_exception
194     ('$coderef must be a CODE reference');
195
196   my (@return_values, $return_value);
197
198   $self->txn_begin; # If this throws an exception, no rollback is needed
199
200   my $wantarray = wantarray; # Need to save this since the context
201                              # inside the eval{} block is independent
202                              # of the context that called txn_do()
203   eval {
204
205     # Need to differentiate between scalar/list context to allow for
206     # returning a list in scalar context to get the size of the list
207     if ($wantarray) {
208       # list context
209       @return_values = $coderef->(@args);
210     } elsif (defined $wantarray) {
211       # scalar context
212       $return_value = $coderef->(@args);
213     } else {
214       # void context
215       $coderef->(@args);
216     }
217     $self->txn_commit;
218   };
219
220   if ($@) {
221     my $error = $@;
222
223     eval {
224       $self->txn_rollback;
225     };
226
227     if ($@) {
228       my $rollback_error = $@;
229       my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
230       $self->throw_exception($error)  # propagate nested rollback
231         if $rollback_error =~ /$exception_class/;
232
233       $self->throw_exception(
234         "Transaction aborted: $error. Rollback failed: ${rollback_error}"
235       );
236     } else {
237       $self->throw_exception($error); # txn failed but rollback succeeded
238     }
239   }
240
241   return $wantarray ? @return_values : $return_value;
242 }
243
244 =head2 txn_begin
245
246 Starts a transaction.
247
248 See the preferred L</txn_do> method, which allows for
249 an entire code block to be executed transactionally.
250
251 =cut
252
253 sub txn_begin { die "Virtual method!" }
254
255 =head2 txn_commit
256
257 Issues a commit of the current transaction.
258
259 =cut
260
261 sub txn_commit { die "Virtual method!" }
262
263 =head2 txn_rollback
264
265 Issues a rollback of the current transaction. A nested rollback will
266 throw a L<DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION> exception,
267 which allows the rollback to propagate to the outermost transaction.
268
269 =cut
270
271 sub txn_rollback { die "Virtual method!" }
272
273 =head2 sql_maker
274
275 Returns a C<sql_maker> object - normally an object of class
276 C<DBIC::SQL::Abstract>.
277
278 =cut
279
280 sub sql_maker { die "Virtual method!" }
281
282 =head2 debug
283
284 Causes trace information to be emitted on the C<debugobj> object.
285 (or C<STDERR> if C<debugobj> has not specifically been set).
286
287 This is the equivalent to setting L</DBIC_TRACE> in your
288 shell environment.
289
290 =head2 debugfh
291
292 Set or retrieve the filehandle used for trace/debug output.  This should be
293 an IO::Handle compatible ojbect (only the C<print> method is used.  Initially
294 set to be STDERR - although see information on the
295 L<DBIC_TRACE> environment variable.
296
297 =cut
298
299 sub debugfh {
300     my $self = shift;
301
302     if ($self->debugobj->can('debugfh')) {
303         return $self->debugobj->debugfh(@_);
304     }
305 }
306
307 =head2 debugobj
308
309 Sets or retrieves the object used for metric collection. Defaults to an instance
310 of L<DBIx::Class::Storage::Statistics> that is compatible with the original
311 method of using a coderef as a callback.  See the aforementioned Statistics
312 class for more information.
313
314 =head2 debugcb
315
316 Sets a callback to be executed each time a statement is run; takes a sub
317 reference.  Callback is executed as $sub->($op, $info) where $op is
318 SELECT/INSERT/UPDATE/DELETE and $info is what would normally be printed.
319
320 See L<debugobj> for a better way.
321
322 =cut
323
324 sub debugcb {
325     my $self = shift;
326
327     if ($self->debugobj->can('callback')) {
328         return $self->debugobj->callback(@_);
329     }
330 }
331
332 =head2 cursor_class
333
334 The cursor class for this Storage object.
335
336 =cut
337
338 =head2 deploy
339
340 Deploy the tables to storage (CREATE TABLE and friends in a SQL-based
341 Storage class). This would normally be called through
342 L<DBIx::Class::Schema/deploy>.
343
344 =cut
345
346 sub deploy { die "Virtual method!" }
347
348 =head2 connect_info
349
350 The arguments of C<connect_info> are always a single array reference,
351 and are Storage-handler specific.
352
353 This is normally accessed via L<DBIx::Class::Schema/connection>, which
354 encapsulates its argument list in an arrayref before calling
355 C<connect_info> here.
356
357 =cut
358
359 sub connect_info { die "Virtual method!" }
360
361 =head2 select
362
363 Handle a select statement.
364
365 =cut
366
367 sub select { die "Virtual method!" }
368
369 =head2 insert
370
371 Handle an insert statement.
372
373 =cut
374
375 sub insert { die "Virtual method!" }
376
377 =head2 update
378
379 Handle an update statement.
380
381 =cut
382
383 sub update { die "Virtual method!" }
384
385 =head2 delete
386
387 Handle a delete statement.
388
389 =cut
390
391 sub delete { die "Virtual method!" }
392
393 =head2 select_single
394
395 Performs a select, fetch and return of data - handles a single row
396 only.
397
398 =cut
399
400 sub select_single { die "Virtual method!" }
401
402 =head2 columns_info_for
403
404 Returns metadata for the given source's columns.  This
405 is *deprecated*, and will be removed before 1.0.  You should
406 be specifying the metadata yourself if you need it.
407
408 =cut
409
410 sub columns_info_for { die "Virtual method!" }
411
412 =head1 ENVIRONMENT VARIABLES
413
414 =head2 DBIC_TRACE
415
416 If C<DBIC_TRACE> is set then trace information
417 is produced (as when the L<debug> method is set).
418
419 If the value is of the form C<1=/path/name> then the trace output is
420 written to the file C</path/name>.
421
422 This environment variable is checked when the storage object is first
423 created (when you call connect on your schema).  So, run-time changes 
424 to this environment variable will not take effect unless you also 
425 re-connect on your schema.
426
427 =head2 DBIX_CLASS_STORAGE_DBI_DEBUG
428
429 Old name for DBIC_TRACE
430
431 =head1 AUTHORS
432
433 Matt S. Trout <mst@shadowcatsystems.co.uk>
434
435 Andy Grundman <andy@hybridized.org>
436
437 =head1 LICENSE
438
439 You may distribute this code under the same terms as Perl itself.
440
441 =cut
442
443 1;