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