1 package DBIx::Class::Storage;
6 use base qw/DBIx::Class/;
11 @DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION::ISA
12 = '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 dbic_internal_catch fail_on_internal_call );
22 __PACKAGE__->mk_group_accessors(simple => qw/debug schema transaction_depth auto_savepoint savepoints/);
23 __PACKAGE__->mk_group_accessors(component_class => 'cursor_class');
25 __PACKAGE__->cursor_class('DBIx::Class::Cursor');
27 sub cursor :DBIC_method_is_indirect_sugar {
28 DBIx::Class::_ENV_::ASSERT_NO_INTERNAL_INDIRECT_CALLS and fail_on_internal_call;
29 shift->cursor_class(@_);
34 DBIx::Class::Storage - Generic Storage Handler
38 A base implementation of common Storage methods. For specific
39 information about L<DBI>-based storage, see L<DBIx::Class::Storage::DBI>.
47 Instantiates the Storage object.
52 my ($self, $schema) = @_;
54 $self = ref $self if ref $self;
60 $new->set_schema($schema);
62 if $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG} || $ENV{DBIC_TRACE};
69 Used to reset the schema class or object which owns this
70 storage object, such as during L<DBIx::Class::Schema/clone>.
75 my ($self, $schema) = @_;
76 $self->schema($schema);
77 weaken $self->{schema} if ref $self->{schema};
82 Returns true if we have an open storage connection, false
83 if it is not (yet) open.
87 sub connected { die "Virtual method!" }
91 Closes any open storage connection unconditionally.
95 sub disconnect { die "Virtual method!" }
97 =head2 ensure_connected
99 Initiate a connection to the storage if one isn't already open.
103 sub ensure_connected { die "Virtual method!" }
105 =head2 throw_exception
107 Throws an exception - croaks.
111 sub throw_exception {
114 if (ref $self and $self->schema) {
115 $self->schema->throw_exception(@_);
118 DBIx::Class::Exception->throw(@_);
126 =item Arguments: C<$coderef>, @coderef_args?
128 =item Return Value: The return value of $coderef
132 Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
133 returning its result (if any). If an exception is caught, a rollback is issued
134 and the exception is rethrown. If the rollback fails, (i.e. throws an
135 exception) an exception is thrown that includes a "Rollback failed" message.
139 my $author_rs = $schema->resultset('Author')->find(1);
140 my @titles = qw/Night Day It/;
143 # If any one of these fails, the entire transaction fails
144 $author_rs->create_related('books', {
146 }) foreach (@titles);
148 return $author->books;
153 $rs = $schema->txn_do($coderef);
154 } dbic_internal_catch {
157 die "something terrible has happened!"
158 if ($error =~ /Rollback failed/); # Rollback failed
160 deal_with_failed_transaction();
163 In a nested transaction (calling txn_do() from within a txn_do() coderef) only
164 the outermost transaction will issue a L</txn_commit>, and txn_do() can be
165 called in void, scalar and list context and it will behave as expected.
167 Please note that all of the code in your coderef, including non-DBIx::Class
168 code, is part of a transaction. This transaction may fail out halfway, or
169 it may get partially double-executed (in the case that our DB connection
170 failed halfway through the transaction, in which case we reconnect and
171 restart the txn). Therefore it is best that any side-effects in your coderef
172 are idempotent (that is, can be re-executed multiple times and get the
173 same result), and that you check up on your side-effects in the case of
181 DBIx::Class::Storage::BlockRunner->new(
184 retry_handler => sub {
185 $_[0]->failed_attempt_count == 1
187 ! $_[0]->storage->connected
194 Starts a transaction.
196 See the preferred L</txn_do> method, which allows for
197 an entire code block to be executed transactionally.
204 if($self->transaction_depth == 0) {
205 $self->debugobj->txn_begin()
207 $self->_exec_txn_begin;
209 elsif ($self->auto_savepoint) {
212 $self->{transaction_depth}++;
218 Issues a commit of the current transaction.
220 It does I<not> perform an actual storage commit unless there's a DBIx::Class
221 transaction currently in effect (i.e. you called L</txn_begin>).
228 if ($self->transaction_depth == 1) {
229 $self->debugobj->txn_commit() if $self->debug;
230 $self->_exec_txn_commit;
231 $self->{transaction_depth}--;
232 $self->savepoints([]);
234 elsif($self->transaction_depth > 1) {
235 $self->{transaction_depth}--;
236 $self->svp_release if $self->auto_savepoint;
239 $self->throw_exception( 'Refusing to commit without a started transaction' );
245 Issues a rollback of the current transaction. A nested rollback will
246 throw a L<DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION> exception,
247 which allows the rollback to propagate to the outermost transaction.
254 if ($self->transaction_depth == 1) {
255 $self->debugobj->txn_rollback() if $self->debug;
256 $self->{transaction_depth}--;
258 # in case things get really hairy - just disconnect
259 dbic_internal_try { $self->_exec_txn_rollback; 1 } or do {
260 my $rollback_error = $@;
262 # whatever happens, too low down the stack to care
263 # FIXME - revisit if stackable exceptions become a thing
264 dbic_internal_try { $self->disconnect };
269 $self->savepoints([]);
271 elsif ($self->transaction_depth > 1) {
272 $self->{transaction_depth}--;
274 if ($self->auto_savepoint) {
279 DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->throw(
280 "A txn_rollback in nested transaction is ineffective! (depth $self->{transaction_depth})"
285 $self->throw_exception( 'Refusing to roll back without a started transaction' );
289 # to be called by several internal stacked transaction handler codepaths
290 # not for external consumption
291 # *DOES NOT* throw exceptions, instead:
292 # - returns false on success
293 # - returns the exception on failed rollback
294 sub __delicate_rollback {
298 ( $self->transaction_depth || 0 ) > 1
300 # FIXME - the autosvp check here shouldn't be happening, it should be a role-ish thing
301 # The entire concept needs to be rethought with the storage layer... or something
302 ! $self->auto_savepoint
304 # the handle seems healthy, and there is nothing for us to do with it
305 # just go ahead and bow out, without triggering the txn_rollback() "nested exception"
306 # the unwind will eventually fail somewhere higher up if at all
307 # FIXME: a ::Storage::DBI-specific method, not a generic ::Storage one
308 $self->_seems_connected
310 # all above checks out - there is nothing to do on the $dbh itself
311 # just a plain soft-decrease of depth
312 $self->{transaction_depth}--;
320 $self->txn_rollback; 1
322 dbic_internal_catch {
326 # we were passed an existing exception to augment (think DESTROY stacks etc)
328 my ($exception) = @args;
330 # append our text - THIS IS A TEMPORARY FIXUP!
332 # If the passed in exception is a reference, or an object we don't know
333 # how to augment - flattening it is just damn rude
335 # FIXME - a better way, not liable to destroy an existing exception needs
336 # to be created. For the time being perpetuating the sin below in order
337 # to break the deadlock of which yak is being shaved first
340 length ref $$exception
343 ! defined blessed $$exception
345 ! $$exception->isa( 'DBIx::Class::Exception' )
356 # SUCH HIDEOUS, MUCH AUGH! (and double WOW on the s/// at the end below)
357 $rbe =~ s/ at .+? line \d+$//;
361 defined blessed $$exception
363 $$exception->isa( 'DBIx::Class::Exception' )
367 "Transaction aborted: $$exception->{msg}. Rollback failed: $rbe"
371 "Transaction aborted: $$exception. Rollback failed: $rbe"
373 ) =~ s/Transaction aborted: (?=Transaction aborted:)//;
383 Arguments: $savepoint_name?
385 Created a new savepoint using the name provided as argument. If no name
386 is provided, a random name will be used.
391 my ($self, $name) = @_;
393 $self->throw_exception ("You can't use savepoints outside a transaction")
394 unless $self->transaction_depth;
396 my $exec = $self->can('_exec_svp_begin')
397 or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
399 $name = $self->_svp_generate_name
400 unless defined $name;
402 push @{ $self->{savepoints} }, $name;
404 $self->debugobj->svp_begin($name) if $self->debug;
406 $exec->($self, $name);
409 sub _svp_generate_name {
411 return 'savepoint_'.scalar(@{ $self->{'savepoints'} });
417 Arguments: $savepoint_name?
419 Release the savepoint provided as argument. If none is provided,
420 release the savepoint created most recently. This will implicitly
421 release all savepoints created after the one explicitly released as well.
426 my ($self, $name) = @_;
428 $self->throw_exception ("You can't use savepoints outside a transaction")
429 unless $self->transaction_depth;
431 my $exec = $self->can('_exec_svp_release')
432 or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
435 my @stack = @{ $self->savepoints };
438 while( $svp ne $name ) {
440 $self->throw_exception ("Savepoint '$name' does not exist")
446 $self->savepoints(\@stack); # put back what's left
449 $name = pop @{ $self->savepoints }
450 or $self->throw_exception('No savepoints to release');;
453 $self->debugobj->svp_release($name) if $self->debug;
455 $exec->($self, $name);
460 Arguments: $savepoint_name?
462 Rollback to the savepoint provided as argument. If none is provided,
463 rollback to the savepoint created most recently. This will implicitly
464 release all savepoints created after the savepoint we rollback to.
469 my ($self, $name) = @_;
471 $self->throw_exception ("You can't use savepoints outside a transaction")
472 unless $self->transaction_depth;
474 my $exec = $self->can('_exec_svp_rollback')
475 or $self->throw_exception ("Your Storage implementation doesn't support savepoints");
478 my @stack = @{ $self->savepoints };
481 # a rollback doesn't remove the named savepoint,
482 # only everything after it
483 while (@stack and $stack[-1] ne $name) {
487 $self->throw_exception ("Savepoint '$name' does not exist")
490 $self->savepoints(\@stack); # put back what's left
493 $name = $self->savepoints->[-1]
494 or $self->throw_exception('No savepoints to rollback');;
497 $self->debugobj->svp_rollback($name) if $self->debug;
499 $exec->($self, $name);
502 =head2 txn_scope_guard
504 An alternative way of transaction handling based on
505 L<DBIx::Class::Storage::TxnScopeGuard>:
507 my $txn_guard = $storage->txn_scope_guard;
509 $result->col1("val1");
514 If an exception occurs, or the guard object otherwise leaves the scope
515 before C<< $txn_guard->commit >> is called, the transaction will be rolled
516 back by an explicit L</txn_rollback> call. In essence this is akin to
517 using a L</txn_begin>/L</txn_commit> pair, without having to worry
518 about calling L</txn_rollback> at the right places. Note that since there
519 is no defined code closure, there will be no retries and other magic upon
520 database disconnection. If you need such functionality see L</txn_do>.
524 sub txn_scope_guard {
525 return DBIx::Class::Storage::TxnScopeGuard->new($_[0]);
530 Returns a C<sql_maker> object - normally an object of class
531 C<DBIx::Class::SQLMaker>.
535 sub sql_maker { die "Virtual method!" }
539 Causes trace information to be emitted on the L</debugobj> object.
540 (or C<STDERR> if L</debugobj> has not specifically been set).
542 This is the equivalent to setting L</DBIC_TRACE> in your
547 An opportunistic proxy to L<< ->debugobj->debugfh(@_)
548 |DBIx::Class::Storage::Statistics/debugfh >>
549 If the currently set L</debugobj> does not have a L</debugfh> method, caling
557 if ($self->debugobj->can('debugfh')) {
558 return $self->debugobj->debugfh(@_);
564 Sets or retrieves the object used for metric collection. Defaults to an instance
565 of L<DBIx::Class::Storage::Statistics> that is compatible with the original
566 method of using a coderef as a callback. See the aforementioned Statistics
567 class for more information.
575 return $self->{debugobj} = $_[0];
578 $self->{debugobj} ||= do {
579 if (my $profile = $ENV{DBIC_TRACE_PROFILE}) {
580 require DBIx::Class::Storage::Debug::PrettyPrint;
583 if ($profile =~ /^\.?\//) {
585 require DBIx::Class::Optional::Dependencies;
586 if ( my $missing = DBIx::Class::Optional::Dependencies->req_missing_for ('config_file_reader') ) {
587 $self->throw_exception("Unable to parse TRACE_PROFILE config file '$profile' without $missing");
590 my $cfg = dbic_internal_try {
591 Config::Any->load_files({ files => [$profile], use_ext => 1 });
592 } dbic_internal_catch {
593 # sanitize the error message a bit
594 $_ =~ s/at \s+ .+ Storage\.pm \s line \s \d+ $//x;
595 $self->throw_exception("Failure processing \$ENV{DBIC_TRACE_PROFILE}: $_");
598 @pp_args = values %{$cfg->[0]};
601 @pp_args = { profile => $profile };
605 # Hash::Merge is a sorry piece of shit and tramples all over $@
606 # *without* throwing an exception
607 # This is a rather serious problem in the debug codepath
608 # Insulate the condition here with a try{} until a review of
609 # DBIx::Class::Storage::Debug::PrettyPrint takes place
610 # we do rethrow the error unconditionally, the only reason
611 # to try{} is to preserve the precise state of $@ (down
612 # to the scalar (if there is one) address level)
614 # Yes I am aware this is fragile and TxnScopeGuard needs
615 # a better fix. This is another yak to shave... :(
617 DBIx::Class::Storage::Debug::PrettyPrint->new(@pp_args);
618 } dbic_internal_catch {
619 $self->throw_exception($_);
623 require DBIx::Class::Storage::Statistics;
624 DBIx::Class::Storage::Statistics->new
631 Sets a callback to be executed each time a statement is run; takes a sub
632 reference. Callback is executed as $sub->($op, $info) where $op is
633 SELECT/INSERT/UPDATE/DELETE and $info is what would normally be printed.
635 See L</debugobj> for a better way.
642 if ($self->debugobj->can('callback')) {
643 return $self->debugobj->callback(@_);
649 The cursor class for this Storage object.
655 Deploy the tables to storage (CREATE TABLE and friends in a SQL-based
656 Storage class). This would normally be called through
657 L<DBIx::Class::Schema/deploy>.
661 sub deploy { die "Virtual method!" }
665 The arguments of C<connect_info> are always a single array reference,
666 and are Storage-handler specific.
668 This is normally accessed via L<DBIx::Class::Schema/connection>, which
669 encapsulates its argument list in an arrayref before calling
670 C<connect_info> here.
674 sub connect_info { die "Virtual method!" }
678 Handle a select statement.
682 sub select { die "Virtual method!" }
686 Handle an insert statement.
690 sub insert { die "Virtual method!" }
694 Handle an update statement.
698 sub update { die "Virtual method!" }
702 Handle a delete statement.
706 sub delete { die "Virtual method!" }
710 Performs a select, fetch and return of data - handles a single row
715 sub select_single { die "Virtual method!" }
717 =head2 columns_info_for
719 Returns metadata for the given source's columns. This
720 is *deprecated*, and will be removed before 1.0. You should
721 be specifying the metadata yourself if you need it.
725 sub columns_info_for { die "Virtual method!" }
727 =head1 ENVIRONMENT VARIABLES
731 If C<DBIC_TRACE> is set then trace information
732 is produced (as when the L</debug> method is set).
734 If the value is of the form C<1=/path/name> then the trace output is
735 written to the file C</path/name>.
737 This environment variable is checked when the storage object is first
738 created (when you call connect on your schema). So, run-time changes
739 to this environment variable will not take effect unless you also
740 re-connect on your schema.
742 =head2 DBIC_TRACE_PROFILE
744 If C<DBIC_TRACE_PROFILE> is set, L<DBIx::Class::Storage::Debug::PrettyPrint>
745 will be used to format the output from C<DBIC_TRACE>. The value it
746 is set to is the C<profile> that it will be used. If the value is a
747 filename the file is read with L<Config::Any> and the results are
748 used as the configuration for tracing. See L<SQL::Abstract::Tree/new>
749 for what that structure should look like.
751 =head2 DBIX_CLASS_STORAGE_DBI_DEBUG
753 Old name for DBIC_TRACE
757 L<DBIx::Class::Storage::DBI> - reference storage implementation using
758 SQL::Abstract and DBI.
760 =head1 FURTHER QUESTIONS?
762 Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>.
764 =head1 COPYRIGHT AND LICENSE
766 This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE>
767 by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can
768 redistribute it and/or modify it under the same terms as the
769 L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>.