fix and regression test for RT #62642
[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
1a58752c 9use DBIx::Class::Exception;
6298a324 10use Scalar::Util 'weaken';
942cd0c1 11use IO::File;
1bc193ac 12use DBIx::Class::Storage::TxnScopeGuard;
f43ea814 13use Try::Tiny;
fd323bf1 14use namespace::clean;
046ad905 15
046ad905 16__PACKAGE__->mk_group_accessors('simple' => qw/debug debugobj schema/);
e4eb8ee1 17__PACKAGE__->mk_group_accessors('inherited' => 'cursor_class');
18
19__PACKAGE__->cursor_class('DBIx::Class::Cursor');
20
21sub cursor { shift->cursor_class(@_); }
046ad905 22
4012acd8 23package # Hide from PAUSE
24 DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION;
25
26use overload '"' => sub {
27 'DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION'
28};
29
30sub new {
31 my $class = shift;
32 my $self = {};
33 return bless $self, $class;
34}
35
36package DBIx::Class::Storage;
37
046ad905 38=head1 NAME
39
40DBIx::Class::Storage - Generic Storage Handler
41
42=head1 DESCRIPTION
43
44A base implementation of common Storage methods. For specific
45information about L<DBI>-based storage, see L<DBIx::Class::Storage::DBI>.
46
47=head1 METHODS
48
49=head2 new
50
51Arguments: $schema
52
53Instantiates the Storage object.
54
55=cut
56
57sub new {
58 my ($self, $schema) = @_;
59
60 $self = ref $self if ref $self;
61
62 my $new = {};
63 bless $new, $self;
64
65 $new->set_schema($schema);
b6cd6478 66 my $debugobj;
67 if (my $profile = $ENV{DBIC_TRACE_PROFILE}) {
68 require DBIx::Class::Storage::Debug::PrettyPrint;
69 if ($profile =~ /^\.?\//) {
70 require Config::Any;
2a2a7b23 71
72 my $cfg = try {
73 Config::Any->load_files({ files => [$profile], use_ext => 1 });
74 } catch {
75 # sanitize the error message a bit
76 $_ =~ s/at \s+ .+ Storage\.pm \s line \s \d+ $//x;
77 $self->throw_exception("Failure processing \$ENV{DBIC_TRACE_PROFILE}: $_");
78 };
b6cd6478 79
80 my ($filename, $config) = %{$cfg->[0]};
81 $debugobj = DBIx::Class::Storage::Debug::PrettyPrint->new($config)
82 } else {
83 $debugobj = DBIx::Class::Storage::Debug::PrettyPrint->new({ profile => $profile })
84 }
85 } else {
86 $debugobj = DBIx::Class::Storage::Statistics->new
87 }
88 $new->debugobj($debugobj);
046ad905 89
90 my $debug_env = $ENV{DBIX_CLASS_STORAGE_DBI_DEBUG}
91 || $ENV{DBIC_TRACE};
92
046ad905 93 $new->debug(1) if $debug_env;
94
95 $new;
96}
97
98=head2 set_schema
99
100Used to reset the schema class or object which owns this
101storage object, such as during L<DBIx::Class::Schema/clone>.
102
103=cut
104
105sub set_schema {
106 my ($self, $schema) = @_;
107 $self->schema($schema);
6298a324 108 weaken $self->{schema} if ref $self->{schema};
046ad905 109}
110
111=head2 connected
112
113Returns true if we have an open storage connection, false
114if it is not (yet) open.
115
116=cut
117
a62cf8d4 118sub connected { die "Virtual method!" }
046ad905 119
120=head2 disconnect
121
122Closes any open storage connection unconditionally.
123
124=cut
125
126sub disconnect { die "Virtual method!" }
127
128=head2 ensure_connected
129
130Initiate a connection to the storage if one isn't already open.
131
132=cut
133
a62cf8d4 134sub ensure_connected { die "Virtual method!" }
046ad905 135
136=head2 throw_exception
137
138Throws an exception - croaks.
139
140=cut
141
142sub throw_exception {
143 my $self = shift;
144
2a2a7b23 145 if (ref $self and $self->schema) {
1a58752c 146 $self->schema->throw_exception(@_);
147 }
148 else {
149 DBIx::Class::Exception->throw(@_);
150 }
046ad905 151}
a62cf8d4 152
4012acd8 153=head2 txn_do
a62cf8d4 154
4012acd8 155=over 4
a62cf8d4 156
4012acd8 157=item Arguments: C<$coderef>, @coderef_args?
a62cf8d4 158
4012acd8 159=item Return Value: The return value of $coderef
160
161=back
162
163Executes C<$coderef> with (optional) arguments C<@coderef_args> atomically,
164returning its result (if any). If an exception is caught, a rollback is issued
165and the exception is rethrown. If the rollback fails, (i.e. throws an
166exception) an exception is thrown that includes a "Rollback failed" message.
167
168For example,
169
170 my $author_rs = $schema->resultset('Author')->find(1);
171 my @titles = qw/Night Day It/;
172
173 my $coderef = sub {
174 # If any one of these fails, the entire transaction fails
175 $author_rs->create_related('books', {
176 title => $_
177 }) foreach (@titles);
178
179 return $author->books;
180 };
181
182 my $rs;
20674fcd 183 try {
4012acd8 184 $rs = $schema->txn_do($coderef);
20674fcd 185 } catch {
6b89ee0b 186 my $error = shift;
20674fcd 187 # Transaction failed
4012acd8 188 die "something terrible has happened!" #
6b89ee0b 189 if ($error =~ /Rollback failed/); # Rollback failed
4012acd8 190
191 deal_with_failed_transaction();
20674fcd 192 };
4012acd8 193
194In a nested transaction (calling txn_do() from within a txn_do() coderef) only
195the outermost transaction will issue a L</txn_commit>, and txn_do() can be
196called in void, scalar and list context and it will behave as expected.
197
05075aee 198Please note that all of the code in your coderef, including non-DBIx::Class
199code, is part of a transaction. This transaction may fail out halfway, or
200it may get partially double-executed (in the case that our DB connection
201failed halfway through the transaction, in which case we reconnect and
202restart the txn). Therefore it is best that any side-effects in your coderef
203are idempotent (that is, can be re-executed multiple times and get the
204same result), and that you check up on your side-effects in the case of
205transaction failure.
6500d50f 206
4012acd8 207=cut
208
209sub txn_do {
38ed54cd 210 my $self = shift;
211 my $coderef = shift;
4012acd8 212
213 ref $coderef eq 'CODE' or $self->throw_exception
214 ('$coderef must be a CODE reference');
215
216 my (@return_values, $return_value);
217
218 $self->txn_begin; # If this throws an exception, no rollback is needed
219
220 my $wantarray = wantarray; # Need to save this since the context
9780718f 221 # inside the try{} block is independent
4012acd8 222 # of the context that called txn_do()
38ed54cd 223 my $args = \@_;
224
20674fcd 225 try {
4012acd8 226
227 # Need to differentiate between scalar/list context to allow for
228 # returning a list in scalar context to get the size of the list
229 if ($wantarray) {
230 # list context
38ed54cd 231 @return_values = $coderef->(@$args);
4012acd8 232 } elsif (defined $wantarray) {
233 # scalar context
38ed54cd 234 $return_value = $coderef->(@$args);
4012acd8 235 } else {
236 # void context
38ed54cd 237 $coderef->(@$args);
4012acd8 238 }
239 $self->txn_commit;
52b420dd 240 }
241 catch {
6b89ee0b 242 my $error = shift;
4012acd8 243
20674fcd 244 try {
4012acd8 245 $self->txn_rollback;
20674fcd 246 } catch {
4012acd8 247 my $exception_class = "DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION";
248 $self->throw_exception($error) # propagate nested rollback
52b420dd 249 if $_ =~ /$exception_class/;
4012acd8 250
251 $self->throw_exception(
52b420dd 252 "Transaction aborted: $error. Rollback failed: $_"
4012acd8 253 );
4012acd8 254 }
20674fcd 255 $self->throw_exception($error); # txn failed but rollback succeeded
52b420dd 256 };
4012acd8 257
258 return $wantarray ? @return_values : $return_value;
a62cf8d4 259}
260
046ad905 261=head2 txn_begin
262
263Starts a transaction.
264
265See the preferred L</txn_do> method, which allows for
266an entire code block to be executed transactionally.
267
268=cut
269
270sub txn_begin { die "Virtual method!" }
271
272=head2 txn_commit
273
274Issues a commit of the current transaction.
275
be01f1be 276It does I<not> perform an actual storage commit unless there's a DBIx::Class
277transaction currently in effect (i.e. you called L</txn_begin>).
278
046ad905 279=cut
280
281sub txn_commit { die "Virtual method!" }
282
283=head2 txn_rollback
284
285Issues a rollback of the current transaction. A nested rollback will
286throw a L<DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION> exception,
287which allows the rollback to propagate to the outermost transaction.
288
289=cut
290
291sub txn_rollback { die "Virtual method!" }
292
adb3554a 293=head2 svp_begin
294
360dc8a5 295Arguments: $savepoint_name?
adb3554a 296
360dc8a5 297Created a new savepoint using the name provided as argument. If no name
298is provided, a random name will be used.
adb3554a 299
300=cut
301
302sub svp_begin { die "Virtual method!" }
303
304=head2 svp_release
305
360dc8a5 306Arguments: $savepoint_name?
adb3554a 307
360dc8a5 308Release the savepoint provided as argument. If none is provided,
309release the savepoint created most recently. This will implicitly
310release all savepoints created after the one explicitly released as well.
adb3554a 311
312=cut
313
314sub svp_release { die "Virtual method!" }
315
316=head2 svp_rollback
317
360dc8a5 318Arguments: $savepoint_name?
adb3554a 319
360dc8a5 320Rollback to the savepoint provided as argument. If none is provided,
321rollback to the savepoint created most recently. This will implicitly
322release all savepoints created after the savepoint we rollback to.
adb3554a 323
324=cut
325
326sub svp_rollback { die "Virtual method!" }
327
dd018f09 328=for comment
3b7f3eac 329
6936e902 330=head2 txn_scope_guard
1bc193ac 331
6936e902 332An alternative way of transaction handling based on
333L<DBIx::Class::Storage::TxnScopeGuard>:
89028f42 334
6936e902 335 my $txn_guard = $storage->txn_scope_guard;
89028f42 336
337 $row->col1("val1");
338 $row->update;
339
6936e902 340 $txn_guard->commit;
89028f42 341
6936e902 342If an exception occurs, or the guard object otherwise leaves the scope
343before C<< $txn_guard->commit >> is called, the transaction will be rolled
344back by an explicit L</txn_rollback> call. In essence this is akin to
345using a L</txn_begin>/L</txn_commit> pair, without having to worry
346about calling L</txn_rollback> at the right places. Note that since there
347is no defined code closure, there will be no retries and other magic upon
348database disconnection. If you need such functionality see L</txn_do>.
1bc193ac 349
350=cut
351
352sub txn_scope_guard {
353 return DBIx::Class::Storage::TxnScopeGuard->new($_[0]);
354}
355
046ad905 356=head2 sql_maker
357
358Returns a C<sql_maker> object - normally an object of class
d5dedbd6 359C<DBIx::Class::SQLMaker>.
046ad905 360
361=cut
362
363sub sql_maker { die "Virtual method!" }
364
365=head2 debug
366
367Causes trace information to be emitted on the C<debugobj> object.
368(or C<STDERR> if C<debugobj> has not specifically been set).
369
370This is the equivalent to setting L</DBIC_TRACE> in your
371shell environment.
372
373=head2 debugfh
374
375Set or retrieve the filehandle used for trace/debug output. This should be
48580715 376an IO::Handle compatible object (only the C<print> method is used. Initially
046ad905 377set to be STDERR - although see information on the
378L<DBIC_TRACE> environment variable.
379
380=cut
381
382sub debugfh {
383 my $self = shift;
384
385 if ($self->debugobj->can('debugfh')) {
386 return $self->debugobj->debugfh(@_);
387 }
388}
389
390=head2 debugobj
391
392Sets or retrieves the object used for metric collection. Defaults to an instance
393of L<DBIx::Class::Storage::Statistics> that is compatible with the original
394method of using a coderef as a callback. See the aforementioned Statistics
395class for more information.
396
397=head2 debugcb
398
399Sets a callback to be executed each time a statement is run; takes a sub
400reference. Callback is executed as $sub->($op, $info) where $op is
401SELECT/INSERT/UPDATE/DELETE and $info is what would normally be printed.
402
403See L<debugobj> for a better way.
404
405=cut
406
407sub debugcb {
408 my $self = shift;
409
410 if ($self->debugobj->can('callback')) {
411 return $self->debugobj->callback(@_);
412 }
413}
414
e4eb8ee1 415=head2 cursor_class
046ad905 416
417The cursor class for this Storage object.
418
419=cut
420
046ad905 421=head2 deploy
422
423Deploy the tables to storage (CREATE TABLE and friends in a SQL-based
424Storage class). This would normally be called through
425L<DBIx::Class::Schema/deploy>.
426
427=cut
428
429sub deploy { die "Virtual method!" }
430
a3eaff0e 431=head2 connect_info
432
433The arguments of C<connect_info> are always a single array reference,
434and are Storage-handler specific.
435
436This is normally accessed via L<DBIx::Class::Schema/connection>, which
437encapsulates its argument list in an arrayref before calling
438C<connect_info> here.
439
440=cut
441
046ad905 442sub connect_info { die "Virtual method!" }
a3eaff0e 443
444=head2 select
445
446Handle a select statement.
447
448=cut
449
450sub select { die "Virtual method!" }
451
452=head2 insert
453
454Handle an insert statement.
455
456=cut
457
046ad905 458sub insert { die "Virtual method!" }
a3eaff0e 459
460=head2 update
461
462Handle an update statement.
463
464=cut
465
046ad905 466sub update { die "Virtual method!" }
a3eaff0e 467
468=head2 delete
469
470Handle a delete statement.
471
472=cut
473
046ad905 474sub delete { die "Virtual method!" }
a3eaff0e 475
476=head2 select_single
477
478Performs a select, fetch and return of data - handles a single row
479only.
480
481=cut
482
046ad905 483sub select_single { die "Virtual method!" }
a3eaff0e 484
485=head2 columns_info_for
486
c22c7625 487Returns metadata for the given source's columns. This
488is *deprecated*, and will be removed before 1.0. You should
489be specifying the metadata yourself if you need it.
a3eaff0e 490
491=cut
492
046ad905 493sub columns_info_for { die "Virtual method!" }
494
495=head1 ENVIRONMENT VARIABLES
496
497=head2 DBIC_TRACE
498
499If C<DBIC_TRACE> is set then trace information
500is produced (as when the L<debug> method is set).
501
502If the value is of the form C<1=/path/name> then the trace output is
503written to the file C</path/name>.
504
505This environment variable is checked when the storage object is first
fd323bf1 506created (when you call connect on your schema). So, run-time changes
507to this environment variable will not take effect unless you also
046ad905 508re-connect on your schema.
509
b6cd6478 510=head2 DBIC_TRACE_PROFILE
511
512If C<DBIC_TRACE_PROFILE> is set, L<DBIx::Class::Storage::PrettyPrint>
513will be used to format the output from C<DBIC_TRACE>. The value it
514is set to is the C<profile> that it will be used. If the value is a
515filename the file is read with L<Config::Any> and the results are
516used as the configuration for tracing. See L<SQL::Abstract::Tree/new>
517for what that structure should look like.
518
519
046ad905 520=head2 DBIX_CLASS_STORAGE_DBI_DEBUG
521
522Old name for DBIC_TRACE
523
ace385bd 524=head1 SEE ALSO
525
2f0790c4 526L<DBIx::Class::Storage::DBI> - reference storage implementation using
527SQL::Abstract and DBI.
ace385bd 528
046ad905 529=head1 AUTHORS
530
531Matt S. Trout <mst@shadowcatsystems.co.uk>
532
533Andy Grundman <andy@hybridized.org>
534
535=head1 LICENSE
536
537You may distribute this code under the same terms as Perl itself.
538
539=cut
540
a62cf8d4 5411;