Filename | /usr/share/perl5/DBIx/Class/Storage/DBI/Cursor.pm |
Statements | Executed 52 statements in 2.24ms |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
1 | 1 | 1 | 91µs | 1.54ms | next | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 26µs | 37µs | BEGIN@10 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 20µs | 33µs | BEGIN@3 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 14µs | 50µs | BEGIN@8 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 14µs | 15µs | new | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 12µs | 544µs | BEGIN@6 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 12µs | 55µs | __finish_sth | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 11µs | 34µs | BEGIN@9 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 10µs | 161µs | BEGIN@11 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 9µs | 17µs | BEGIN@4 | DBIx::Class::Storage::DBI::Cursor::
2 | 2 | 1 | 8µs | 8µs | sth | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 6µs | 62µs | DESTROY | DBIx::Class::Storage::DBI::Cursor::
0 | 0 | 0 | 0s | 0s | CLONE | DBIx::Class::Storage::DBI::Cursor::
0 | 0 | 0 | 0s | 0s | __ANON__[:251] | DBIx::Class::Storage::DBI::Cursor::
0 | 0 | 0 | 0s | 0s | __ANON__[:252] | DBIx::Class::Storage::DBI::Cursor::
0 | 0 | 0 | 0s | 0s | all | DBIx::Class::Storage::DBI::Cursor::
0 | 0 | 0 | 0s | 0s | reset | DBIx::Class::Storage::DBI::Cursor::
0 | 0 | 0 | 0s | 0s | try {...} | DBIx::Class::Storage::DBI::Cursor::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package DBIx::Class::Storage::DBI::Cursor; | ||||
2 | |||||
3 | 2 | 49µs | 2 | 46µs | # spent 33µs (20+13) within DBIx::Class::Storage::DBI::Cursor::BEGIN@3 which was called:
# once (20µs+13µs) by Class::C3::Componentised::ensure_class_loaded at line 3 # spent 33µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@3
# spent 13µs making 1 call to strict::import |
4 | 2 | 38µs | 2 | 24µs | # spent 17µs (9+8) within DBIx::Class::Storage::DBI::Cursor::BEGIN@4 which was called:
# once (9µs+8µs) by Class::C3::Componentised::ensure_class_loaded at line 4 # spent 17µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@4
# spent 8µs making 1 call to warnings::import |
5 | |||||
6 | 2 | 222µs | 2 | 1.08ms | # spent 544µs (12+532) within DBIx::Class::Storage::DBI::Cursor::BEGIN@6 which was called:
# once (12µs+532µs) by Class::C3::Componentised::ensure_class_loaded at line 6 # spent 544µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@6
# spent 532µs making 1 call to base::import |
7 | |||||
8 | 2 | 73µs | 2 | 86µs | # spent 50µs (14+36) within DBIx::Class::Storage::DBI::Cursor::BEGIN@8 which was called:
# once (14µs+36µs) by Class::C3::Componentised::ensure_class_loaded at line 8 # spent 50µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@8
# spent 36µs making 1 call to Exporter::import |
9 | 2 | 56µs | 2 | 56µs | # spent 34µs (11+22) within DBIx::Class::Storage::DBI::Cursor::BEGIN@9 which was called:
# once (11µs+22µs) by Class::C3::Componentised::ensure_class_loaded at line 9 # spent 34µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@9
# spent 22µs making 1 call to Exporter::import |
10 | 2 | 58µs | 2 | 49µs | # spent 37µs (26+11) within DBIx::Class::Storage::DBI::Cursor::BEGIN@10 which was called:
# once (26µs+11µs) by Class::C3::Componentised::ensure_class_loaded at line 10 # spent 37µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@10
# spent 11µs making 1 call to List::Util::import |
11 | 2 | 1.58ms | 2 | 312µs | # spent 161µs (10+151) within DBIx::Class::Storage::DBI::Cursor::BEGIN@11 which was called:
# once (10µs+151µs) by Class::C3::Componentised::ensure_class_loaded at line 11 # spent 161µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@11
# spent 151µs making 1 call to namespace::clean::import |
12 | |||||
13 | 1 | 14µs | 1 | 207µs | __PACKAGE__->mk_group_accessors('simple' => # spent 207µs making 1 call to Class::Accessor::Grouped::mk_group_accessors |
14 | qw/storage args attrs/ | ||||
15 | ); | ||||
16 | |||||
17 | =head1 NAME | ||||
18 | |||||
19 | DBIx::Class::Storage::DBI::Cursor - Object representing a query cursor on a | ||||
20 | resultset. | ||||
21 | |||||
22 | =head1 SYNOPSIS | ||||
23 | |||||
24 | my $cursor = $schema->resultset('CD')->cursor(); | ||||
25 | |||||
26 | # raw values off the database handle in resultset columns/select order | ||||
27 | my @next_cd_column_values = $cursor->next; | ||||
28 | |||||
29 | # list of all raw values as arrayrefs | ||||
30 | my @all_cds_column_values = $cursor->all; | ||||
31 | |||||
32 | =head1 DESCRIPTION | ||||
33 | |||||
34 | A Cursor represents a query cursor on a L<DBIx::Class::ResultSet> object. It | ||||
35 | allows for traversing the result set with L</next>, retrieving all results with | ||||
36 | L</all> and resetting the cursor with L</reset>. | ||||
37 | |||||
38 | Usually, you would use the cursor methods built into L<DBIx::Class::ResultSet> | ||||
39 | to traverse it. See L<DBIx::Class::ResultSet/next>, | ||||
40 | L<DBIx::Class::ResultSet/reset> and L<DBIx::Class::ResultSet/all> for more | ||||
41 | information. | ||||
42 | |||||
43 | =head1 METHODS | ||||
44 | |||||
45 | =head2 new | ||||
46 | |||||
47 | Returns a new L<DBIx::Class::Storage::DBI::Cursor> object. | ||||
48 | |||||
49 | =cut | ||||
50 | |||||
51 | { | ||||
52 | 2 | 500ns | my %cursor_registry; | ||
53 | |||||
54 | # spent 15µs (14+1) within DBIx::Class::Storage::DBI::Cursor::new which was called:
# once (14µs+1µs) by DBIx::Class::Storage::DBI::select at line 2559 of DBIx/Class/Storage/DBI.pm | ||||
55 | 1 | 600ns | my ($class, $storage, $args, $attrs) = @_; | ||
56 | |||||
57 | 1 | 3µs | my $self = bless { | ||
58 | storage => $storage, | ||||
59 | args => $args, | ||||
60 | attrs => $attrs, | ||||
61 | }, ref $class || $class; | ||||
62 | |||||
63 | 1 | 200ns | if (DBIx::Class::_ENV_::HAS_ITHREADS) { | ||
64 | |||||
65 | # quick "garbage collection" pass - prevents the registry | ||||
66 | # from slowly growing with a bunch of undef-valued keys | ||||
67 | defined $cursor_registry{$_} or delete $cursor_registry{$_} | ||||
68 | 1 | 1µs | for keys %cursor_registry; | ||
69 | |||||
70 | 1 | 9µs | 2 | 1µs | weaken( $cursor_registry{ refaddr($self) } = $self ) # spent 700ns making 1 call to Scalar::Util::refaddr
# spent 700ns making 1 call to Scalar::Util::weaken |
71 | } | ||||
72 | |||||
73 | 1 | 3µs | return $self; | ||
74 | } | ||||
75 | |||||
76 | sub CLONE { | ||||
77 | for (keys %cursor_registry) { | ||||
78 | # once marked we no longer care about them, hence no | ||||
79 | # need to keep in the registry, left alone renumber the | ||||
80 | # keys (all addresses are now different) | ||||
81 | my $self = delete $cursor_registry{$_} | ||||
82 | or next; | ||||
83 | |||||
84 | $self->{_intra_thread} = 1; | ||||
85 | } | ||||
86 | } | ||||
87 | } | ||||
88 | |||||
89 | =head2 next | ||||
90 | |||||
91 | =over 4 | ||||
92 | |||||
93 | =item Arguments: none | ||||
94 | |||||
95 | =item Return Value: \@row_columns | ||||
96 | |||||
97 | =back | ||||
98 | |||||
99 | Advances the cursor to the next row and returns an array of column | ||||
100 | values (the result of L<DBI/fetchrow_array> method). | ||||
101 | |||||
102 | =cut | ||||
103 | |||||
104 | # spent 1.54ms (91µs+1.45) within DBIx::Class::Storage::DBI::Cursor::next which was called:
# once (91µs+1.45ms) by DBIx::Class::ResultSetColumn::next at line 160 of DBIx/Class/ResultSetColumn.pm | ||||
105 | 1 | 300ns | my $self = shift; | ||
106 | |||||
107 | 1 | 11µs | return if $self->{_done}; | ||
108 | |||||
109 | 1 | 100ns | my $sth; | ||
110 | |||||
111 | 1 | 800ns | if ( | ||
112 | $self->{attrs}{software_limit} | ||||
113 | && $self->{attrs}{rows} | ||||
114 | && ($self->{_pos}||0) >= $self->{attrs}{rows} | ||||
115 | ) { | ||||
116 | if ($sth = $self->sth) { | ||||
117 | # explicit finish will issue warnings, unlike the DESTROY below | ||||
118 | $sth->finish if $sth->FETCH('Active'); | ||||
119 | } | ||||
120 | $self->{_done} = 1; | ||||
121 | return; | ||||
122 | } | ||||
123 | |||||
124 | 1 | 2µs | 1 | 2µs | unless ($sth = $self->sth) { # spent 2µs making 1 call to DBIx::Class::Storage::DBI::Cursor::sth |
125 | 1 | 20µs | 2 | 1.39ms | (undef, $sth, undef) = $self->storage->_select( @{$self->{args}} ); # spent 1.24ms making 1 call to DBIx::Class::Storage::DBI::_select
# spent 149µs making 1 call to DBIx::Class::Storage::DBI::Cursor::storage |
126 | |||||
127 | 1 | 13µs | 1 | 6µs | $self->{_results} = [ (undef) x $sth->FETCH('NUM_OF_FIELDS') ]; # spent 6µs making 1 call to DBI::common::FETCH |
128 | 1 | 9µs | 2 | 65µs | $sth->bind_columns( \( @{$self->{_results}} ) ); # spent 35µs making 1 call to DBI::st::bind_columns
# spent 30µs making 1 call to DBD::mysql::st::__ANON__[DBD/mysql.pm:810] |
129 | |||||
130 | 1 | 700ns | if ( $self->{attrs}{software_limit} and $self->{attrs}{offset} ) { | ||
131 | $sth->fetch for 1 .. $self->{attrs}{offset}; | ||||
132 | } | ||||
133 | |||||
134 | 1 | 2µs | 1 | 6µs | $self->sth($sth); # spent 6µs making 1 call to DBIx::Class::Storage::DBI::Cursor::sth |
135 | } | ||||
136 | |||||
137 | 1 | 7µs | 1 | 3µs | if ($sth->fetch) { # spent 3µs making 1 call to DBI::st::fetch |
138 | 1 | 1µs | $self->{_pos}++; | ||
139 | 1 | 4µs | return @{$self->{_results}}; | ||
140 | } else { | ||||
141 | $self->{_done} = 1; | ||||
142 | return (); | ||||
143 | } | ||||
144 | } | ||||
145 | |||||
146 | |||||
147 | =head2 all | ||||
148 | |||||
149 | =over 4 | ||||
150 | |||||
151 | =item Arguments: none | ||||
152 | |||||
153 | =item Return Value: \@row_columns+ | ||||
154 | |||||
155 | =back | ||||
156 | |||||
157 | Returns a list of arrayrefs of column values for all rows in the | ||||
158 | L<DBIx::Class::ResultSet>. | ||||
159 | |||||
160 | =cut | ||||
161 | |||||
162 | sub all { | ||||
163 | my $self = shift; | ||||
164 | |||||
165 | # delegate to DBIC::Cursor which will delegate back to next() | ||||
166 | if ($self->{attrs}{software_limit} | ||||
167 | && ($self->{attrs}{offset} || $self->{attrs}{rows})) { | ||||
168 | return $self->next::method(@_); | ||||
169 | } | ||||
170 | |||||
171 | my $sth; | ||||
172 | |||||
173 | if ($sth = $self->sth) { | ||||
174 | # explicit finish will issue warnings, unlike the DESTROY below | ||||
175 | $sth->finish if ( ! $self->{_done} and $sth->FETCH('Active') ); | ||||
176 | $self->sth(undef); | ||||
177 | } | ||||
178 | |||||
179 | (undef, $sth) = $self->storage->_select( @{$self->{args}} ); | ||||
180 | |||||
181 | return ( | ||||
182 | DBIx::Class::_ENV_::SHUFFLE_UNORDERED_RESULTSETS | ||||
183 | and | ||||
184 | ! $self->{attrs}{order_by} | ||||
185 | ) | ||||
186 | ? shuffle @{$sth->fetchall_arrayref} | ||||
187 | : @{$sth->fetchall_arrayref} | ||||
188 | ; | ||||
189 | } | ||||
190 | |||||
191 | sub sth { | ||||
192 | 2 | 500ns | my $self = shift; | ||
193 | |||||
194 | 2 | 1µs | if (@_) { | ||
195 | 1 | 1µs | delete @{$self}{qw/_pos _done _pid _intra_thread/}; | ||
196 | |||||
197 | 1 | 500ns | $self->{sth} = $_[0]; | ||
198 | 1 | 2µs | $self->{_pid} = $$ if ! DBIx::Class::_ENV_::BROKEN_FORK and $_[0]; | ||
199 | } | ||||
200 | elsif ($self->{sth} and ! $self->{_done}) { | ||||
201 | |||||
202 | my $invalidate_handle_reason; | ||||
203 | |||||
204 | if (DBIx::Class::_ENV_::HAS_ITHREADS and $self->{_intra_thread} ) { | ||||
205 | $invalidate_handle_reason = 'Multi-thread'; | ||||
206 | } | ||||
207 | elsif (!DBIx::Class::_ENV_::BROKEN_FORK and $self->{_pid} != $$ ) { | ||||
208 | $invalidate_handle_reason = 'Multi-process'; | ||||
209 | } | ||||
210 | |||||
211 | if ($invalidate_handle_reason) { | ||||
212 | $self->storage->throw_exception("$invalidate_handle_reason access attempted while cursor in progress (position $self->{_pos})") | ||||
213 | if $self->{_pos}; | ||||
214 | |||||
215 | # reinvokes the reset logic above | ||||
216 | $self->sth(undef); | ||||
217 | } | ||||
218 | } | ||||
219 | |||||
220 | 2 | 8µs | return $self->{sth}; | ||
221 | } | ||||
222 | |||||
223 | =head2 reset | ||||
224 | |||||
225 | Resets the cursor to the beginning of the L<DBIx::Class::ResultSet>. | ||||
226 | |||||
227 | =cut | ||||
228 | |||||
229 | sub reset { | ||||
230 | $_[0]->__finish_sth if $_[0]->{sth}; | ||||
231 | $_[0]->sth(undef); | ||||
232 | } | ||||
233 | |||||
234 | |||||
235 | # spent 62µs (6+55) within DBIx::Class::Storage::DBI::Cursor::DESTROY which was called:
# once (6µs+55µs) by DBIx::Class::ResultSet::count at line 32 of Koha/Borrower/Discharge.pm | ||||
236 | 1 | 11µs | 1 | 55µs | $_[0]->__finish_sth if $_[0]->{sth}; # spent 55µs making 1 call to DBIx::Class::Storage::DBI::Cursor::__finish_sth |
237 | } | ||||
238 | |||||
239 | # spent 55µs (12+44) within DBIx::Class::Storage::DBI::Cursor::__finish_sth which was called:
# once (12µs+44µs) by DBIx::Class::Storage::DBI::Cursor::DESTROY at line 236 | ||||
240 | # It is (sadly) extremely important to finish() handles we are about | ||||
241 | # to lose (due to reset() or a DESTROY() ). $rs->reset is the closest | ||||
242 | # thing the user has to getting to the underlying finish() API and some | ||||
243 | # DBDs mandate this (e.g. DBD::InterBase will segfault, DBD::Sybase | ||||
244 | # won't start a transaction sanely, etc) | ||||
245 | # We also can't use the accessor here, as it will trigger a fork/thread | ||||
246 | # check, and resetting a cursor in a child is perfectly valid | ||||
247 | |||||
248 | 1 | 600ns | my $self = shift; | ||
249 | |||||
250 | # No need to care about failures here | ||||
251 | 2 | 15µs | 1 | 3µs | try { local $SIG{__WARN__} = sub {}; $self->{sth}->finish } if ( # spent 3µs making 1 call to DBI::st::finish |
252 | 1 | 7µs | 1 | 2µs | $self->{sth} and ! try { ! $self->{sth}->FETCH('Active') } # spent 2µs making 1 call to DBI::common::FETCH |
253 | 1 | 13µs | 2 | 44µs | ); # spent 44µs making 2 calls to Try::Tiny::try, avg 22µs/call |
254 | } | ||||
255 | |||||
256 | =head1 FURTHER QUESTIONS? | ||||
257 | |||||
258 | Check the list of L<additional DBIC resources|DBIx::Class/GETTING HELP/SUPPORT>. | ||||
259 | |||||
260 | =head1 COPYRIGHT AND LICENSE | ||||
261 | |||||
262 | This module is free software L<copyright|DBIx::Class/COPYRIGHT AND LICENSE> | ||||
263 | by the L<DBIx::Class (DBIC) authors|DBIx::Class/AUTHORS>. You can | ||||
264 | redistribute it and/or modify it under the same terms as the | ||||
265 | L<DBIx::Class library|DBIx::Class/COPYRIGHT AND LICENSE>. | ||||
266 | |||||
267 | =cut | ||||
268 | |||||
269 | 1 | 4µs | 1 | 167µs | 1; # spent 167µs making 1 call to B::Hooks::EndOfScope::XS::__ANON__ |