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