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