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