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