Another overhaul of transaction/savepoint 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 use mro 'c3';
8
9 {
10   package # Hide from PAUSE
11     DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION;
12   use base 'DBIx::Class::Exception';
13 }
14
15 use DBIx::Class::Carp;
16 use Scalar::Util qw/blessed weaken/;
17 use DBIx::Class::Storage::TxnScopeGuard;
18 use Try::Tiny;
19 use namespace::clean;
20
21 __PACKAGE__->mk_group_accessors(simple => qw/debug schema transaction_depth auto_savepoint savepoints/);
22 __PACKAGE__->mk_group_accessors(component_class => 'cursor_class');
23
24 __PACKAGE__->cursor_class('DBIx::Class::Cursor');
25
26 sub cursor { shift->cursor_class(@_); }
27
28 =head1 NAME
29
30 DBIx::Class::Storage - Generic Storage Handler
31
32 =head1 DESCRIPTION
33
34 A base implementation of common Storage methods.  For specific
35 information about L<DBI>-based storage, see L<DBIx::Class::Storage::DBI>.
36
37 =head1 METHODS
38
39 =head2 new
40
41 Arguments: $schema
42
43 Instantiates the Storage object.
44
45 =cut
46
47 sub new {
48   my ($self, $schema) = @_;
49
50   $self = ref $self if ref $self;
51
52   my $new = bless( {
53     transaction_depth => 0,
54     savepoints => [],
55   }, $self);
56
57   $new->set_schema($schema);
58   $new->debug(1)
59     if $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG} || $ENV{DBIC_TRACE};
60
61   $new;
62 }
63
64 =head2 set_schema
65
66 Used to reset the schema class or object which owns this
67 storage object, such as during L<DBIx::Class::Schema/clone>.
68
69 =cut
70
71 sub set_schema {
72   my ($self, $schema) = @_;
73   $self->schema($schema);
74   weaken $self->{schema} if ref $self->{schema};
75 }
76
77 =head2 connected
78
79 Returns true if we have an open storage connection, false
80 if it is not (yet) open.
81
82 =cut
83
84 sub connected { die "Virtual method!" }
85
86 =head2 disconnect
87
88 Closes any open storage connection unconditionally.
89
90 =cut
91
92 sub disconnect { die "Virtual method!" }
93
94 =head2 ensure_connected
95
96 Initiate a connection to the storage if one isn't already open.
97
98 =cut
99
100 sub ensure_connected { die "Virtual method!" }
101
102 =head2 throw_exception
103
104 Throws an exception - croaks.
105
106 =cut
107
108 sub throw_exception {
109   my $self = shift;
110
111   if (ref $self and $self->schema) {
112     $self->schema->throw_exception(@_);
113   }
114   else {
115     DBIx::Class::Exception->throw(@_);
116   }
117 }
118
119 =head2 txn_do
120
121 =over 4
122
123 =item Arguments: C<$coderef>, @coderef_args?
124
125 =item Return Value: The return value of $coderef
126
127 =back
128
129 Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
130 returning its result (if any). If an exception is caught, a rollback is issued
131 and the exception is rethrown. If the rollback fails, (i.e. throws an
132 exception) an exception is thrown that includes a "Rollback failed" message.
133
134 For example,
135
136   my $author_rs = $schema->resultset('Author')->find(1);
137   my @titles = qw/Night Day It/;
138
139   my $coderef = sub {
140     # If any one of these fails, the entire transaction fails
141     $author_rs->create_related('books', {
142       title => $_
143     }) foreach (@titles);
144
145     return $author->books;
146   };
147
148   my $rs;
149   try {
150     $rs = $schema->txn_do($coderef);
151   } catch {
152     my $error = shift;
153     # Transaction failed
154     die "something terrible has happened!"
155       if ($error =~ /Rollback failed/);          # Rollback failed
156
157     deal_with_failed_transaction();
158   };
159
160 In a nested transaction (calling txn_do() from within a txn_do() coderef) only
161 the outermost transaction will issue a L</txn_commit>, and txn_do() can be
162 called in void, scalar and list context and it will behave as expected.
163
164 Please note that all of the code in your coderef, including non-DBIx::Class
165 code, is part of a transaction.  This transaction may fail out halfway, or
166 it may get partially double-executed (in the case that our DB connection
167 failed halfway through the transaction, in which case we reconnect and
168 restart the txn).  Therefore it is best that any side-effects in your coderef
169 are idempotent (that is, can be re-executed multiple times and get the
170 same result), and that you check up on your side-effects in the case of
171 transaction failure.
172
173 =cut
174
175 sub txn_do {
176   my $self = shift;
177   my $coderef = shift;
178
179   ref $coderef eq 'CODE' or $self->throw_exception
180     ('$coderef must be a CODE reference');
181
182   my $abort_txn = sub {
183     my ($self, $exception) = @_;
184
185     my $rollback_exception = try { $self->txn_rollback; undef } catch { shift };
186
187     if ( $rollback_exception and (
188       ! defined blessed $rollback_exception
189           or
190       ! $rollback_exception->isa('DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION')
191     ) ) {
192       $self->throw_exception(
193         "Transaction aborted: ${exception}. "
194         . "Rollback failed: ${rollback_exception}"
195       );
196     }
197     $self->throw_exception($exception);
198   };
199
200   # take a ref instead of a copy, to preserve coderef @_ aliasing semantics
201   my $args = \@_;
202
203   # do not turn on until a succesful txn_begin
204   my $attempt_commit = 0;
205
206   my $txn_init_depth = $self->transaction_depth;
207
208   try {
209     $self->txn_begin;
210     $attempt_commit = 1;
211     $coderef->(@$args)
212   }
213   catch {
214     $attempt_commit = 0;
215
216     # init depth of > 0 implies nesting or non-autocommit (either way no retry)
217     if($txn_init_depth or $self->connected ) {
218       $abort_txn->($self, $_);
219     }
220     else {
221       carp "Retrying txn_do($coderef) after catching disconnected exception: $_"
222         if $ENV{DBIC_STORAGE_RETRY_DEBUG};
223
224       $self->_populate_dbh;
225
226       # if txn_depth is > 1 this means something was done to the
227       # original $dbh, otherwise we would not get past the if() above
228       $self->throw_exception(sprintf
229         'Unexpected transaction depth of %d on freshly connected handle',
230         $self->transaction_depth,
231       ) if $self->transaction_depth;
232
233       $self->txn_begin;
234       $attempt_commit = 1;
235
236       try {
237         $coderef->(@$args)
238       }
239       catch {
240         $attempt_commit = 0;
241         $abort_txn->($self, $_)
242       };
243     };
244   }
245   finally {
246     if ($attempt_commit) {
247       my $delta_txn = (1 + $txn_init_depth) - $self->transaction_depth;
248
249       if ($delta_txn) {
250         # a rollback in a top-level txn_do is valid-ish (seen in the wild and our own tests)
251         carp "Unexpected reduction of transaction depth by $delta_txn after execution of $coderef, skipping txn_do's commit"
252           unless $delta_txn == 1 and $self->transaction_depth == 0;
253       }
254       else {
255         $self->txn_commit;
256       }
257     }
258   };
259 }
260
261 =head2 txn_begin
262
263 Starts a transaction.
264
265 See the preferred L</txn_do> method, which allows for
266 an entire code block to be executed transactionally.
267
268 =cut
269
270 sub txn_begin {
271   my $self = shift;
272
273   if($self->transaction_depth == 0) {
274     $self->debugobj->txn_begin()
275       if $self->debug;
276     $self->_exec_txn_begin;
277   }
278   elsif ($self->auto_savepoint) {
279     $self->svp_begin;
280   }
281   $self->{transaction_depth}++;
282
283 }
284
285 =head2 txn_commit
286
287 Issues a commit of the current transaction.
288
289 It does I<not> perform an actual storage commit unless there's a DBIx::Class
290 transaction currently in effect (i.e. you called L</txn_begin>).
291
292 =cut
293
294 sub txn_commit {
295   my $self = shift;
296
297   if ($self->transaction_depth == 1) {
298     $self->debugobj->txn_commit() if $self->debug;
299     $self->_exec_txn_commit;
300     $self->{transaction_depth}--;
301   }
302   elsif($self->transaction_depth > 1) {
303     $self->{transaction_depth}--;
304     $self->svp_release if $self->auto_savepoint;
305   }
306   else {
307     $self->throw_exception( 'Refusing to commit without a started transaction' );
308   }
309 }
310
311 =head2 txn_rollback
312
313 Issues a rollback of the current transaction. A nested rollback will
314 throw a L<DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION> exception,
315 which allows the rollback to propagate to the outermost transaction.
316
317 =cut
318
319 sub txn_rollback {
320   my $self = shift;
321
322   if ($self->transaction_depth == 1) {
323     $self->debugobj->txn_rollback() if $self->debug;
324     $self->_exec_txn_rollback;
325     $self->{transaction_depth}--;
326   }
327   elsif ($self->transaction_depth > 1) {
328     $self->{transaction_depth}--;
329
330     if ($self->auto_savepoint) {
331       $self->svp_rollback;
332       $self->svp_release;
333     }
334     else {
335       DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->throw(
336         "A txn_rollback in nested transaction is ineffective! (depth $self->{transaction_depth})"
337       );
338     }
339   }
340   else {
341     $self->throw_exception( 'Refusing to roll back without a started transaction' );
342   }
343 }
344
345 =head2 svp_begin
346
347 Arguments: $savepoint_name?
348
349 Created a new savepoint using the name provided as argument. If no name
350 is provided, a random name will be used.
351
352 =cut
353
354 sub svp_begin {
355   my ($self, $name) = @_;
356
357   $self->throw_exception ("You can't use savepoints outside a transaction")
358     unless $self->transaction_depth;
359
360   my $exec = $self->can('_exec_svp_begin')
361     or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
362
363   $name = $self->_svp_generate_name
364     unless defined $name;
365
366   push @{ $self->{savepoints} }, $name;
367
368   $self->debugobj->svp_begin($name) if $self->debug;
369
370   $exec->($self, $name);
371 }
372
373 sub _svp_generate_name {
374   my ($self) = @_;
375   return 'savepoint_'.scalar(@{ $self->{'savepoints'} });
376 }
377
378
379 =head2 svp_release
380
381 Arguments: $savepoint_name?
382
383 Release the savepoint provided as argument. If none is provided,
384 release the savepoint created most recently. This will implicitly
385 release all savepoints created after the one explicitly released as well.
386
387 =cut
388
389 sub svp_release {
390   my ($self, $name) = @_;
391
392   $self->throw_exception ("You can't use savepoints outside a transaction")
393     unless $self->transaction_depth;
394
395   my $exec = $self->can('_exec_svp_release')
396     or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
397
398   if (defined $name) {
399     my @stack = @{ $self->savepoints };
400     my $svp;
401
402     do { $svp = pop @stack } until $svp eq $name;
403
404     $self->throw_exception ("Savepoint '$name' does not exist")
405       unless $svp;
406
407     $self->savepoints(\@stack); # put back what's left
408   }
409   else {
410     $name = pop @{ $self->savepoints }
411       or $self->throw_exception('No savepoints to release');;
412   }
413
414   $self->debugobj->svp_release($name) if $self->debug;
415
416   $exec->($self, $name);
417 }
418
419 =head2 svp_rollback
420
421 Arguments: $savepoint_name?
422
423 Rollback to the savepoint provided as argument. If none is provided,
424 rollback to the savepoint created most recently. This will implicitly
425 release all savepoints created after the savepoint we rollback to.
426
427 =cut
428
429 sub svp_rollback {
430   my ($self, $name) = @_;
431
432   $self->throw_exception ("You can't use savepoints outside a transaction")
433     unless $self->transaction_depth;
434
435   my $exec = $self->can('_exec_svp_rollback')
436     or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
437
438   if (defined $name) {
439     my @stack = @{ $self->savepoints };
440     my $svp;
441
442     # a rollback doesn't remove the named savepoint,
443     # only everything after it
444     while (@stack and $stack[-1] ne $name) {
445       pop @stack
446     };
447
448     $self->throw_exception ("Savepoint '$name' does not exist")
449       unless @stack;
450
451     $self->savepoints(\@stack); # put back what's left
452   }
453   else {
454     $name = $self->savepoints->[-1]
455       or $self->throw_exception('No savepoints to rollback');;
456   }
457
458   $self->debugobj->svp_rollback($name) if $self->debug;
459
460   $exec->($self, $name);
461 }
462
463 =for comment
464
465 =head2 txn_scope_guard
466
467 An alternative way of transaction handling based on
468 L<DBIx::Class::Storage::TxnScopeGuard>:
469
470  my $txn_guard = $storage->txn_scope_guard;
471
472  $row->col1("val1");
473  $row->update;
474
475  $txn_guard->commit;
476
477 If an exception occurs, or the guard object otherwise leaves the scope
478 before C<< $txn_guard->commit >> is called, the transaction will be rolled
479 back by an explicit L</txn_rollback> call. In essence this is akin to
480 using a L</txn_begin>/L</txn_commit> pair, without having to worry
481 about calling L</txn_rollback> at the right places. Note that since there
482 is no defined code closure, there will be no retries and other magic upon
483 database disconnection. If you need such functionality see L</txn_do>.
484
485 =cut
486
487 sub txn_scope_guard {
488   return DBIx::Class::Storage::TxnScopeGuard->new($_[0]);
489 }
490
491 =head2 sql_maker
492
493 Returns a C<sql_maker> object - normally an object of class
494 C<DBIx::Class::SQLMaker>.
495
496 =cut
497
498 sub sql_maker { die "Virtual method!" }
499
500 =head2 debug
501
502 Causes trace information to be emitted on the L</debugobj> object.
503 (or C<STDERR> if L</debugobj> has not specifically been set).
504
505 This is the equivalent to setting L</DBIC_TRACE> in your
506 shell environment.
507
508 =head2 debugfh
509
510 Set or retrieve the filehandle used for trace/debug output.  This should be
511 an IO::Handle compatible object (only the C<print> method is used.  Initially
512 set to be STDERR - although see information on the
513 L<DBIC_TRACE> environment variable.
514
515 =cut
516
517 sub debugfh {
518     my $self = shift;
519
520     if ($self->debugobj->can('debugfh')) {
521         return $self->debugobj->debugfh(@_);
522     }
523 }
524
525 =head2 debugobj
526
527 Sets or retrieves the object used for metric collection. Defaults to an instance
528 of L<DBIx::Class::Storage::Statistics> that is compatible with the original
529 method of using a coderef as a callback.  See the aforementioned Statistics
530 class for more information.
531
532 =cut
533
534 sub debugobj {
535   my $self = shift;
536
537   if (@_) {
538     return $self->{debugobj} = $_[0];
539   }
540
541   $self->{debugobj} ||= do {
542     if (my $profile = $ENV{DBIC_TRACE_PROFILE}) {
543       require DBIx::Class::Storage::Debug::PrettyPrint;
544       if ($profile =~ /^\.?\//) {
545         require Config::Any;
546
547         my $cfg = try {
548           Config::Any->load_files({ files => [$profile], use_ext => 1 });
549         } catch {
550           # sanitize the error message a bit
551           $_ =~ s/at \s+ .+ Storage\.pm \s line \s \d+ $//x;
552           $self->throw_exception("Failure processing \$ENV{DBIC_TRACE_PROFILE}: $_");
553         };
554
555         DBIx::Class::Storage::Debug::PrettyPrint->new(values %{$cfg->[0]});
556       }
557       else {
558         DBIx::Class::Storage::Debug::PrettyPrint->new({ profile => $profile });
559       }
560     }
561     else {
562       require DBIx::Class::Storage::Statistics;
563       DBIx::Class::Storage::Statistics->new
564     }
565   };
566 }
567
568 =head2 debugcb
569
570 Sets a callback to be executed each time a statement is run; takes a sub
571 reference.  Callback is executed as $sub->($op, $info) where $op is
572 SELECT/INSERT/UPDATE/DELETE and $info is what would normally be printed.
573
574 See L</debugobj> for a better way.
575
576 =cut
577
578 sub debugcb {
579     my $self = shift;
580
581     if ($self->debugobj->can('callback')) {
582         return $self->debugobj->callback(@_);
583     }
584 }
585
586 =head2 cursor_class
587
588 The cursor class for this Storage object.
589
590 =cut
591
592 =head2 deploy
593
594 Deploy the tables to storage (CREATE TABLE and friends in a SQL-based
595 Storage class). This would normally be called through
596 L<DBIx::Class::Schema/deploy>.
597
598 =cut
599
600 sub deploy { die "Virtual method!" }
601
602 =head2 connect_info
603
604 The arguments of C<connect_info> are always a single array reference,
605 and are Storage-handler specific.
606
607 This is normally accessed via L<DBIx::Class::Schema/connection>, which
608 encapsulates its argument list in an arrayref before calling
609 C<connect_info> here.
610
611 =cut
612
613 sub connect_info { die "Virtual method!" }
614
615 =head2 select
616
617 Handle a select statement.
618
619 =cut
620
621 sub select { die "Virtual method!" }
622
623 =head2 insert
624
625 Handle an insert statement.
626
627 =cut
628
629 sub insert { die "Virtual method!" }
630
631 =head2 update
632
633 Handle an update statement.
634
635 =cut
636
637 sub update { die "Virtual method!" }
638
639 =head2 delete
640
641 Handle a delete statement.
642
643 =cut
644
645 sub delete { die "Virtual method!" }
646
647 =head2 select_single
648
649 Performs a select, fetch and return of data - handles a single row
650 only.
651
652 =cut
653
654 sub select_single { die "Virtual method!" }
655
656 =head2 columns_info_for
657
658 Returns metadata for the given source's columns.  This
659 is *deprecated*, and will be removed before 1.0.  You should
660 be specifying the metadata yourself if you need it.
661
662 =cut
663
664 sub columns_info_for { die "Virtual method!" }
665
666 =head1 ENVIRONMENT VARIABLES
667
668 =head2 DBIC_TRACE
669
670 If C<DBIC_TRACE> is set then trace information
671 is produced (as when the L</debug> method is set).
672
673 If the value is of the form C<1=/path/name> then the trace output is
674 written to the file C</path/name>.
675
676 This environment variable is checked when the storage object is first
677 created (when you call connect on your schema).  So, run-time changes
678 to this environment variable will not take effect unless you also
679 re-connect on your schema.
680
681 =head2 DBIC_TRACE_PROFILE
682
683 If C<DBIC_TRACE_PROFILE> is set, L<DBIx::Class::Storage::PrettyPrint>
684 will be used to format the output from C<DBIC_TRACE>.  The value it
685 is set to is the C<profile> that it will be used.  If the value is a
686 filename the file is read with L<Config::Any> and the results are
687 used as the configuration for tracing.  See L<SQL::Abstract::Tree/new>
688 for what that structure should look like.
689
690
691 =head2 DBIX_CLASS_STORAGE_DBI_DEBUG
692
693 Old name for DBIC_TRACE
694
695 =head1 SEE ALSO
696
697 L<DBIx::Class::Storage::DBI> - reference storage implementation using
698 SQL::Abstract and DBI.
699
700 =head1 AUTHORS
701
702 Matt S. Trout <mst@shadowcatsystems.co.uk>
703
704 Andy Grundman <andy@hybridized.org>
705
706 =head1 LICENSE
707
708 You may distribute this code under the same terms as Perl itself.
709
710 =cut
711
712 1;