1 package DBIx::Class::Storage;
6 use base qw/DBIx::Class/;
10 package # Hide from PAUSE
11 DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION;
12 use base 'DBIx::Class::Exception';
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';
23 __PACKAGE__->mk_group_accessors(simple => qw/debug schema transaction_depth auto_savepoint savepoints/);
24 __PACKAGE__->mk_group_accessors(component_class => 'cursor_class');
26 __PACKAGE__->cursor_class('DBIx::Class::Cursor');
28 sub cursor { shift->cursor_class(@_); }
32 DBIx::Class::Storage - Generic Storage Handler
36 A base implementation of common Storage methods. For specific
37 information about L<DBI>-based storage, see L<DBIx::Class::Storage::DBI>.
45 Instantiates the Storage object.
50 my ($self, $schema) = @_;
52 $self = ref $self if ref $self;
58 $new->set_schema($schema);
60 if $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG} || $ENV{DBIC_TRACE};
67 Used to reset the schema class or object which owns this
68 storage object, such as during L<DBIx::Class::Schema/clone>.
73 my ($self, $schema) = @_;
74 $self->schema($schema);
75 weaken $self->{schema} if ref $self->{schema};
80 Returns true if we have an open storage connection, false
81 if it is not (yet) open.
85 sub connected { die "Virtual method!" }
89 Closes any open storage connection unconditionally.
93 sub disconnect { die "Virtual method!" }
95 =head2 ensure_connected
97 Initiate a connection to the storage if one isn't already open.
101 sub ensure_connected { die "Virtual method!" }
103 =head2 throw_exception
105 Throws an exception - croaks.
109 sub throw_exception {
112 if (ref $self and $self->schema) {
113 $self->schema->throw_exception(@_);
116 DBIx::Class::Exception->throw(@_);
124 =item Arguments: C<$coderef>, @coderef_args?
126 =item Return Value: The return value of $coderef
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.
137 my $author_rs = $schema->resultset('Author')->find(1);
138 my @titles = qw/Night Day It/;
141 # If any one of these fails, the entire transaction fails
142 $author_rs->create_related('books', {
144 }) foreach (@titles);
146 return $author->books;
151 $rs = $schema->txn_do($coderef);
155 die "something terrible has happened!"
156 if ($error =~ /Rollback failed/); # Rollback failed
158 deal_with_failed_transaction();
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.
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
179 DBIx::Class::Storage::BlockRunner->new(
182 retry_handler => sub {
183 $_[0]->failed_attempt_count == 1
185 ! $_[0]->storage->connected
192 Starts a transaction.
194 See the preferred L</txn_do> method, which allows for
195 an entire code block to be executed transactionally.
202 if($self->transaction_depth == 0) {
203 $self->debugobj->txn_begin()
205 $self->_exec_txn_begin;
207 elsif ($self->auto_savepoint) {
210 $self->{transaction_depth}++;
216 Issues a commit of the current transaction.
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>).
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([]);
232 elsif($self->transaction_depth > 1) {
233 $self->{transaction_depth}--;
234 $self->svp_release if $self->auto_savepoint;
237 $self->throw_exception( 'Refusing to commit without a started transaction' );
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.
252 if ($self->transaction_depth == 1) {
253 $self->debugobj->txn_rollback() if $self->debug;
254 $self->{transaction_depth}--;
256 # in case things get really hairy - just disconnect
257 dbic_internal_try { $self->_exec_txn_rollback; 1 } or do {
258 my $rollback_error = $@;
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 };
267 $self->savepoints([]);
269 elsif ($self->transaction_depth > 1) {
270 $self->{transaction_depth}--;
272 if ($self->auto_savepoint) {
277 DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->throw(
278 "A txn_rollback in nested transaction is ineffective! (depth $self->{transaction_depth})"
283 $self->throw_exception( 'Refusing to roll back without a started transaction' );
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 {
296 ( $self->transaction_depth || 0 ) > 1
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
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
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}--;
318 $self->txn_rollback; 1
324 # we were passed an existing exception to augment (think DESTROY stacks etc)
326 my ($exception) = @args;
328 # append our text - THIS IS A TEMPORARY FIXUP!
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
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
338 length ref $$exception
341 ! defined blessed $$exception
343 ! $$exception->isa( 'DBIx::Class::Exception' )
354 # SUCH HIDEOUS, MUCH AUGH! (and double WOW on the s/// at the end below)
355 $rbe =~ s/ at .+? line \d+$//;
359 defined blessed $$exception
361 $$exception->isa( 'DBIx::Class::Exception' )
365 "Transaction aborted: $$exception->{msg}. Rollback failed: $rbe"
369 "Transaction aborted: $$exception. Rollback failed: $rbe"
371 ) =~ s/Transaction aborted: (?=Transaction aborted:)//;
381 Arguments: $savepoint_name?
383 Created a new savepoint using the name provided as argument. If no name
384 is provided, a random name will be used.
389 my ($self, $name) = @_;
391 $self->throw_exception ("You can't use savepoints outside a transaction")
392 unless $self->transaction_depth;
394 my $exec = $self->can('_exec_svp_begin')
395 or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
397 $name = $self->_svp_generate_name
398 unless defined $name;
400 push @{ $self->{savepoints} }, $name;
402 $self->debugobj->svp_begin($name) if $self->debug;
404 $exec->($self, $name);
407 sub _svp_generate_name {
409 return 'savepoint_'.scalar(@{ $self->{'savepoints'} });
415 Arguments: $savepoint_name?
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.
424 my ($self, $name) = @_;
426 $self->throw_exception ("You can't use savepoints outside a transaction")
427 unless $self->transaction_depth;
429 my $exec = $self->can('_exec_svp_release')
430 or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
433 my @stack = @{ $self->savepoints };
436 do { $svp = pop @stack } until $svp eq $name;
438 $self->throw_exception ("Savepoint '$name' does not exist")
441 $self->savepoints(\@stack); # put back what's left
444 $name = pop @{ $self->savepoints }
445 or $self->throw_exception('No savepoints to release');;
448 $self->debugobj->svp_release($name) if $self->debug;
450 $exec->($self, $name);
455 Arguments: $savepoint_name?
457 Rollback to the savepoint provided as argument. If none is provided,
458 rollback to the savepoint created most recently. This will implicitly
459 release all savepoints created after the savepoint we rollback to.
464 my ($self, $name) = @_;
466 $self->throw_exception ("You can't use savepoints outside a transaction")
467 unless $self->transaction_depth;
469 my $exec = $self->can('_exec_svp_rollback')
470 or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
473 my @stack = @{ $self->savepoints };
476 # a rollback doesn't remove the named savepoint,
477 # only everything after it
478 while (@stack and $stack[-1] ne $name) {
482 $self->throw_exception ("Savepoint '$name' does not exist")
485 $self->savepoints(\@stack); # put back what's left
488 $name = $self->savepoints->[-1]
489 or $self->throw_exception('No savepoints to rollback');;
492 $self->debugobj->svp_rollback($name) if $self->debug;
494 $exec->($self, $name);
497 =head2 txn_scope_guard
499 An alternative way of transaction handling based on
500 L<DBIx::Class::Storage::TxnScopeGuard>:
502 my $txn_guard = $storage->txn_scope_guard;
504 $result->col1("val1");
509 If an exception occurs, or the guard object otherwise leaves the scope
510 before C<< $txn_guard->commit >> is called, the transaction will be rolled
511 back by an explicit L</txn_rollback> call. In essence this is akin to
512 using a L</txn_begin>/L</txn_commit> pair, without having to worry
513 about calling L</txn_rollback> at the right places. Note that since there
514 is no defined code closure, there will be no retries and other magic upon
515 database disconnection. If you need such functionality see L</txn_do>.
519 sub txn_scope_guard {
520 return DBIx::Class::Storage::TxnScopeGuard->new($_[0]);
525 Returns a C<sql_maker> object - normally an object of class
526 C<DBIx::Class::SQLMaker>.
530 sub sql_maker { die "Virtual method!" }
534 Causes trace information to be emitted on the L</debugobj> object.
535 (or C<STDERR> if L</debugobj> has not specifically been set).
537 This is the equivalent to setting L</DBIC_TRACE> in your
542 An opportunistic proxy to L<< ->debugobj->debugfh(@_)
543 |DBIx::Class::Storage::Statistics/debugfh >>
544 If the currently set L</debugobj> does not have a L</debugfh> method, caling
552 if ($self->debugobj->can('debugfh')) {
553 return $self->debugobj->debugfh(@_);
559 Sets or retrieves the object used for metric collection. Defaults to an instance
560 of L<DBIx::Class::Storage::Statistics> that is compatible with the original
561 method of using a coderef as a callback. See the aforementioned Statistics
562 class for more information.
570 return $self->{debugobj} = $_[0];
573 $self->{debugobj} ||= do {
574 if (my $profile = $ENV{DBIC_TRACE_PROFILE}) {
575 require DBIx::Class::Storage::Debug::PrettyPrint;
578 if ($profile =~ /^\.?\//) {
580 if ( my $missing = DBIx::Class::Optional::Dependencies->req_missing_for ('config_file_reader') ) {
581 $self->throw_exception("Unable to parse TRACE_PROFILE config file '$profile' without $missing");
584 my $cfg = dbic_internal_try {
585 Config::Any->load_files({ files => [$profile], use_ext => 1 });
587 # sanitize the error message a bit
588 $_ =~ s/at \s+ .+ Storage\.pm \s line \s \d+ $//x;
589 $self->throw_exception("Failure processing \$ENV{DBIC_TRACE_PROFILE}: $_");
592 @pp_args = values %{$cfg->[0]};
595 @pp_args = { profile => $profile };
599 # Hash::Merge is a sorry piece of shit and tramples all over $@
600 # *without* throwing an exception
601 # This is a rather serious problem in the debug codepath
602 # Insulate the condition here with a try{} until a review of
603 # DBIx::Class::Storage::Debug::PrettyPrint takes place
604 # we do rethrow the error unconditionally, the only reason
605 # to try{} is to preserve the precise state of $@ (down
606 # to the scalar (if there is one) address level)
608 # Yes I am aware this is fragile and TxnScopeGuard needs
609 # a better fix. This is another yak to shave... :(
611 DBIx::Class::Storage::Debug::PrettyPrint->new(@pp_args);
613 $self->throw_exception($_);
617 require DBIx::Class::Storage::Statistics;
618 DBIx::Class::Storage::Statistics->new
625 Sets a callback to be executed each time a statement is run; takes a sub
626 reference. Callback is executed as $sub->($op, $info) where $op is
627 SELECT/INSERT/UPDATE/DELETE and $info is what would normally be printed.
629 See L</debugobj> for a better way.
636 if ($self->debugobj->can('callback')) {
637 return $self->debugobj->callback(@_);
643 The cursor class for this Storage object.
649 Deploy the tables to storage (CREATE TABLE and friends in a SQL-based
650 Storage class). This would normally be called through
651 L<DBIx::Class::Schema/deploy>.
655 sub deploy { die "Virtual method!" }
659 The arguments of C<connect_info> are always a single array reference,
660 and are Storage-handler specific.
662 This is normally accessed via L<DBIx::Class::Schema/connection>, which
663 encapsulates its argument list in an arrayref before calling
664 C<connect_info> here.
668 sub connect_info { die "Virtual method!" }
672 Handle a select statement.
676 sub select { die "Virtual method!" }
680 Handle an insert statement.
684 sub insert { die "Virtual method!" }
688 Handle an update statement.
692 sub update { die "Virtual method!" }
696 Handle a delete statement.
700 sub delete { die "Virtual method!" }
704 Performs a select, fetch and return of data - handles a single row
709 sub select_single { die "Virtual method!" }
711 =head2 columns_info_for
713 Returns metadata for the given source's columns. This
714 is *deprecated*, and will be removed before 1.0. You should
715 be specifying the metadata yourself if you need it.
719 sub columns_info_for { die "Virtual method!" }
721 =head1 ENVIRONMENT VARIABLES
725 If C<DBIC_TRACE> is set then trace information
726 is produced (as when the L</debug> method is set).
728 If the value is of the form C<1=/path/name> then the trace output is
729 written to the file C</path/name>.
731 This environment variable is checked when the storage object is first
732 created (when you call connect on your schema). So, run-time changes
733 to this environment variable will not take effect unless you also
734 re-connect on your schema.
736 =head2 DBIC_TRACE_PROFILE
738 If C<DBIC_TRACE_PROFILE> is set, L<DBIx::Class::Storage::Debug::PrettyPrint>
739 will be used to format the output from C<DBIC_TRACE>. The value it
740 is set to is the C<profile> that it will be used. If the value is a
741 filename the file is read with L<Config::Any> and the results are
742 used as the configuration for tracing. See L<SQL::Abstract::Tree/new>
743 for what that structure should look like.
745 =head2 DBIX_CLASS_STORAGE_DBI_DEBUG
747 Old name for DBIC_TRACE
751 L<DBIx::Class::Storage::DBI> - reference storage implementation using
752 SQL::Abstract and DBI.
754 =head1 FURTHER QUESTIONS?
756 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
758 =head1 COPYRIGHT AND LICENSE
760 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
761 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
762 redistribute it and/or modify it under the same terms as the
763 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.