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 qw( dbic_internal_try fail_on_internal_call );
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');
29 DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS and fail_on_internal_call;
30 shift->cursor_class(@_);
35 DBIx::Class::Storage - Generic Storage Handler
39 A base implementation of common Storage methods. For specific
40 information about L<DBI>-based storage, see L<DBIx::Class::Storage::DBI>.
48 Instantiates the Storage object.
53 my ($self, $schema) = @_;
55 $self = ref $self if ref $self;
61 $new->set_schema($schema);
63 if $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG} || $ENV{DBIC_TRACE};
70 Used to reset the schema class or object which owns this
71 storage object, such as during L<DBIx::Class::Schema/clone>.
76 my ($self, $schema) = @_;
77 $self->schema($schema);
78 weaken $self->{schema} if ref $self->{schema};
83 Returns true if we have an open storage connection, false
84 if it is not (yet) open.
88 sub connected { die "Virtual method!" }
92 Closes any open storage connection unconditionally.
96 sub disconnect { die "Virtual method!" }
98 =head2 ensure_connected
100 Initiate a connection to the storage if one isn't already open.
104 sub ensure_connected { die "Virtual method!" }
106 =head2 throw_exception
108 Throws an exception - croaks.
112 sub throw_exception {
115 if (ref $self and $self->schema) {
116 $self->schema->throw_exception(@_);
119 DBIx::Class::Exception->throw(@_);
127 =item Arguments: C<$coderef>, @coderef_args?
129 =item Return Value: The return value of $coderef
133 Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
134 returning its result (if any). If an exception is caught, a rollback is issued
135 and the exception is rethrown. If the rollback fails, (i.e. throws an
136 exception) an exception is thrown that includes a "Rollback failed" message.
140 my $author_rs = $schema->resultset('Author')->find(1);
141 my @titles = qw/Night Day It/;
144 # If any one of these fails, the entire transaction fails
145 $author_rs->create_related('books', {
147 }) foreach (@titles);
149 return $author->books;
154 $rs = $schema->txn_do($coderef);
158 die "something terrible has happened!"
159 if ($error =~ /Rollback failed/); # Rollback failed
161 deal_with_failed_transaction();
164 In a nested transaction (calling txn_do() from within a txn_do() coderef) only
165 the outermost transaction will issue a L</txn_commit>, and txn_do() can be
166 called in void, scalar and list context and it will behave as expected.
168 Please note that all of the code in your coderef, including non-DBIx::Class
169 code, is part of a transaction. This transaction may fail out halfway, or
170 it may get partially double-executed (in the case that our DB connection
171 failed halfway through the transaction, in which case we reconnect and
172 restart the txn). Therefore it is best that any side-effects in your coderef
173 are idempotent (that is, can be re-executed multiple times and get the
174 same result), and that you check up on your side-effects in the case of
182 DBIx::Class::Storage::BlockRunner->new(
185 retry_handler => sub {
186 $_[0]->failed_attempt_count == 1
188 ! $_[0]->storage->connected
195 Starts a transaction.
197 See the preferred L</txn_do> method, which allows for
198 an entire code block to be executed transactionally.
205 if($self->transaction_depth == 0) {
206 $self->debugobj->txn_begin()
208 $self->_exec_txn_begin;
210 elsif ($self->auto_savepoint) {
213 $self->{transaction_depth}++;
219 Issues a commit of the current transaction.
221 It does I<not> perform an actual storage commit unless there's a DBIx::Class
222 transaction currently in effect (i.e. you called L</txn_begin>).
229 if ($self->transaction_depth == 1) {
230 $self->debugobj->txn_commit() if $self->debug;
231 $self->_exec_txn_commit;
232 $self->{transaction_depth}--;
233 $self->savepoints([]);
235 elsif($self->transaction_depth > 1) {
236 $self->{transaction_depth}--;
237 $self->svp_release if $self->auto_savepoint;
240 $self->throw_exception( 'Refusing to commit without a started transaction' );
246 Issues a rollback of the current transaction. A nested rollback will
247 throw a L<DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION> exception,
248 which allows the rollback to propagate to the outermost transaction.
255 if ($self->transaction_depth == 1) {
256 $self->debugobj->txn_rollback() if $self->debug;
257 $self->{transaction_depth}--;
259 # in case things get really hairy - just disconnect
260 dbic_internal_try { $self->_exec_txn_rollback; 1 } or do {
261 my $rollback_error = $@;
263 # whatever happens, too low down the stack to care
264 # FIXME - revisit if stackable exceptions become a thing
265 dbic_internal_try { $self->disconnect };
270 $self->savepoints([]);
272 elsif ($self->transaction_depth > 1) {
273 $self->{transaction_depth}--;
275 if ($self->auto_savepoint) {
280 DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->throw(
281 "A txn_rollback in nested transaction is ineffective! (depth $self->{transaction_depth})"
286 $self->throw_exception( 'Refusing to roll back without a started transaction' );
290 # to be called by several internal stacked transaction handler codepaths
291 # not for external consumption
292 # *DOES NOT* throw exceptions, instead:
293 # - returns false on success
294 # - returns the exception on failed rollback
295 sub __delicate_rollback {
299 ( $self->transaction_depth || 0 ) > 1
301 # FIXME - the autosvp check here shouldn't be happening, it should be a role-ish thing
302 # The entire concept needs to be rethought with the storage layer... or something
303 ! $self->auto_savepoint
305 # the handle seems healthy, and there is nothing for us to do with it
306 # just go ahead and bow out, without triggering the txn_rollback() "nested exception"
307 # the unwind will eventually fail somewhere higher up if at all
308 # FIXME: a ::Storage::DBI-specific method, not a generic ::Storage one
309 $self->_seems_connected
311 # all above checks out - there is nothing to do on the $dbh itself
312 # just a plain soft-decrease of depth
313 $self->{transaction_depth}--;
321 $self->txn_rollback; 1
327 # we were passed an existing exception to augment (think DESTROY stacks etc)
329 my ($exception) = @args;
331 # append our text - THIS IS A TEMPORARY FIXUP!
333 # If the passed in exception is a reference, or an object we don't know
334 # how to augment - flattening it is just damn rude
336 # FIXME - a better way, not liable to destroy an existing exception needs
337 # to be created. For the time being perpetuating the sin below in order
338 # to break the deadlock of which yak is being shaved first
341 length ref $$exception
344 ! defined blessed $$exception
346 ! $$exception->isa( 'DBIx::Class::Exception' )
357 # SUCH HIDEOUS, MUCH AUGH! (and double WOW on the s/// at the end below)
358 $rbe =~ s/ at .+? line \d+$//;
362 defined blessed $$exception
364 $$exception->isa( 'DBIx::Class::Exception' )
368 "Transaction aborted: $$exception->{msg}. Rollback failed: $rbe"
372 "Transaction aborted: $$exception. Rollback failed: $rbe"
374 ) =~ s/Transaction aborted: (?=Transaction aborted:)//;
384 Arguments: $savepoint_name?
386 Created a new savepoint using the name provided as argument. If no name
387 is provided, a random name will be used.
392 my ($self, $name) = @_;
394 $self->throw_exception ("You can't use savepoints outside a transaction")
395 unless $self->transaction_depth;
397 my $exec = $self->can('_exec_svp_begin')
398 or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
400 $name = $self->_svp_generate_name
401 unless defined $name;
403 push @{ $self->{savepoints} }, $name;
405 $self->debugobj->svp_begin($name) if $self->debug;
407 $exec->($self, $name);
410 sub _svp_generate_name {
412 return 'savepoint_'.scalar(@{ $self->{'savepoints'} });
418 Arguments: $savepoint_name?
420 Release the savepoint provided as argument. If none is provided,
421 release the savepoint created most recently. This will implicitly
422 release all savepoints created after the one explicitly released as well.
427 my ($self, $name) = @_;
429 $self->throw_exception ("You can't use savepoints outside a transaction")
430 unless $self->transaction_depth;
432 my $exec = $self->can('_exec_svp_release')
433 or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
436 my @stack = @{ $self->savepoints };
439 while( $svp ne $name ) {
441 $self->throw_exception ("Savepoint '$name' does not exist")
447 $self->savepoints(\@stack); # put back what's left
450 $name = pop @{ $self->savepoints }
451 or $self->throw_exception('No savepoints to release');;
454 $self->debugobj->svp_release($name) if $self->debug;
456 $exec->($self, $name);
461 Arguments: $savepoint_name?
463 Rollback to the savepoint provided as argument. If none is provided,
464 rollback to the savepoint created most recently. This will implicitly
465 release all savepoints created after the savepoint we rollback to.
470 my ($self, $name) = @_;
472 $self->throw_exception ("You can't use savepoints outside a transaction")
473 unless $self->transaction_depth;
475 my $exec = $self->can('_exec_svp_rollback')
476 or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
479 my @stack = @{ $self->savepoints };
482 # a rollback doesn't remove the named savepoint,
483 # only everything after it
484 while (@stack and $stack[-1] ne $name) {
488 $self->throw_exception ("Savepoint '$name' does not exist")
491 $self->savepoints(\@stack); # put back what's left
494 $name = $self->savepoints->[-1]
495 or $self->throw_exception('No savepoints to rollback');;
498 $self->debugobj->svp_rollback($name) if $self->debug;
500 $exec->($self, $name);
503 =head2 txn_scope_guard
505 An alternative way of transaction handling based on
506 L<DBIx::Class::Storage::TxnScopeGuard>:
508 my $txn_guard = $storage->txn_scope_guard;
510 $result->col1("val1");
515 If an exception occurs, or the guard object otherwise leaves the scope
516 before C<< $txn_guard->commit >> is called, the transaction will be rolled
517 back by an explicit L</txn_rollback> call. In essence this is akin to
518 using a L</txn_begin>/L</txn_commit> pair, without having to worry
519 about calling L</txn_rollback> at the right places. Note that since there
520 is no defined code closure, there will be no retries and other magic upon
521 database disconnection. If you need such functionality see L</txn_do>.
525 sub txn_scope_guard {
526 return DBIx::Class::Storage::TxnScopeGuard->new($_[0]);
531 Returns a C<sql_maker> object - normally an object of class
532 C<DBIx::Class::SQLMaker>.
536 sub sql_maker { die "Virtual method!" }
540 Causes trace information to be emitted on the L</debugobj> object.
541 (or C<STDERR> if L</debugobj> has not specifically been set).
543 This is the equivalent to setting L</DBIC_TRACE> in your
548 An opportunistic proxy to L<< ->debugobj->debugfh(@_)
549 |DBIx::Class::Storage::Statistics/debugfh >>
550 If the currently set L</debugobj> does not have a L</debugfh> method, caling
558 if ($self->debugobj->can('debugfh')) {
559 return $self->debugobj->debugfh(@_);
565 Sets or retrieves the object used for metric collection. Defaults to an instance
566 of L<DBIx::Class::Storage::Statistics> that is compatible with the original
567 method of using a coderef as a callback. See the aforementioned Statistics
568 class for more information.
576 return $self->{debugobj} = $_[0];
579 $self->{debugobj} ||= do {
580 if (my $profile = $ENV{DBIC_TRACE_PROFILE}) {
581 require DBIx::Class::Storage::Debug::PrettyPrint;
584 if ($profile =~ /^\.?\//) {
586 require DBIx::Class::Optional::Dependencies;
587 if ( my $missing = DBIx::Class::Optional::Dependencies->req_missing_for ('config_file_reader') ) {
588 $self->throw_exception("Unable to parse TRACE_PROFILE config file '$profile' without $missing");
591 my $cfg = dbic_internal_try {
592 Config::Any->load_files({ files => [$profile], use_ext => 1 });
594 # sanitize the error message a bit
595 $_ =~ s/at \s+ .+ Storage\.pm \s line \s \d+ $//x;
596 $self->throw_exception("Failure processing \$ENV{DBIC_TRACE_PROFILE}: $_");
599 @pp_args = values %{$cfg->[0]};
602 @pp_args = { profile => $profile };
606 # Hash::Merge is a sorry piece of shit and tramples all over $@
607 # *without* throwing an exception
608 # This is a rather serious problem in the debug codepath
609 # Insulate the condition here with a try{} until a review of
610 # DBIx::Class::Storage::Debug::PrettyPrint takes place
611 # we do rethrow the error unconditionally, the only reason
612 # to try{} is to preserve the precise state of $@ (down
613 # to the scalar (if there is one) address level)
615 # Yes I am aware this is fragile and TxnScopeGuard needs
616 # a better fix. This is another yak to shave... :(
618 DBIx::Class::Storage::Debug::PrettyPrint->new(@pp_args);
620 $self->throw_exception($_);
624 require DBIx::Class::Storage::Statistics;
625 DBIx::Class::Storage::Statistics->new
632 Sets a callback to be executed each time a statement is run; takes a sub
633 reference. Callback is executed as $sub->($op, $info) where $op is
634 SELECT/INSERT/UPDATE/DELETE and $info is what would normally be printed.
636 See L</debugobj> for a better way.
643 if ($self->debugobj->can('callback')) {
644 return $self->debugobj->callback(@_);
650 The cursor class for this Storage object.
656 Deploy the tables to storage (CREATE TABLE and friends in a SQL-based
657 Storage class). This would normally be called through
658 L<DBIx::Class::Schema/deploy>.
662 sub deploy { die "Virtual method!" }
666 The arguments of C<connect_info> are always a single array reference,
667 and are Storage-handler specific.
669 This is normally accessed via L<DBIx::Class::Schema/connection>, which
670 encapsulates its argument list in an arrayref before calling
671 C<connect_info> here.
675 sub connect_info { die "Virtual method!" }
679 Handle a select statement.
683 sub select { die "Virtual method!" }
687 Handle an insert statement.
691 sub insert { die "Virtual method!" }
695 Handle an update statement.
699 sub update { die "Virtual method!" }
703 Handle a delete statement.
707 sub delete { die "Virtual method!" }
711 Performs a select, fetch and return of data - handles a single row
716 sub select_single { die "Virtual method!" }
718 =head2 columns_info_for
720 Returns metadata for the given source's columns. This
721 is *deprecated*, and will be removed before 1.0. You should
722 be specifying the metadata yourself if you need it.
726 sub columns_info_for { die "Virtual method!" }
728 =head1 ENVIRONMENT VARIABLES
732 If C<DBIC_TRACE> is set then trace information
733 is produced (as when the L</debug> method is set).
735 If the value is of the form C<1=/path/name> then the trace output is
736 written to the file C</path/name>.
738 This environment variable is checked when the storage object is first
739 created (when you call connect on your schema). So, run-time changes
740 to this environment variable will not take effect unless you also
741 re-connect on your schema.
743 =head2 DBIC_TRACE_PROFILE
745 If C<DBIC_TRACE_PROFILE> is set, L<DBIx::Class::Storage::Debug::PrettyPrint>
746 will be used to format the output from C<DBIC_TRACE>. The value it
747 is set to is the C<profile> that it will be used. If the value is a
748 filename the file is read with L<Config::Any> and the results are
749 used as the configuration for tracing. See L<SQL::Abstract::Tree/new>
750 for what that structure should look like.
752 =head2 DBIX_CLASS_STORAGE_DBI_DEBUG
754 Old name for DBIC_TRACE
758 L<DBIx::Class::Storage::DBI> - reference storage implementation using
759 SQL::Abstract and DBI.
761 =head1 FURTHER QUESTIONS?
763 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
765 =head1 COPYRIGHT AND LICENSE
767 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
768 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
769 redistribute it and/or modify it under the same terms as the
770 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.