Filename | /usr/share/perl5/DBIx/Class/Storage/DBI/Cursor.pm |
Statements | Executed 34 statements in 178µs |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
2 | 2 | 2 | 203µs | 33.5ms | next | DBIx::Class::Storage::DBI::Cursor::
2 | 1 | 1 | 38µs | 43µs | new | DBIx::Class::Storage::DBI::Cursor::
2 | 1 | 1 | 36µs | 155µs | __finish_sth | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 35µs | 50µs | BEGIN@10 | DBIx::Class::Storage::DBI::Cursor::
4 | 2 | 1 | 25µs | 25µs | sth | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 21µs | 62µs | BEGIN@8 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 20µs | 31µs | BEGIN@3 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 19µs | 619µs | BEGIN@6 | DBIx::Class::Storage::DBI::Cursor::
2 | 2 | 2 | 18µs | 172µs | DESTROY | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 15µs | 42µs | BEGIN@9 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 14µs | 199µs | BEGIN@11 | DBIx::Class::Storage::DBI::Cursor::
1 | 1 | 1 | 12µs | 19µs | BEGIN@4 | 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 | 43µs | # spent 31µs (20+12) within DBIx::Class::Storage::DBI::Cursor::BEGIN@3 which was called:
# once (20µs+12µs) by Class::C3::Componentised::ensure_class_loaded at line 3 # spent 31µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@3
# spent 12µs making 1 call to strict::import | ||
4 | 2 | 26µs | # spent 19µs (12+7) within DBIx::Class::Storage::DBI::Cursor::BEGIN@4 which was called:
# once (12µs+7µs) by Class::C3::Componentised::ensure_class_loaded at line 4 # spent 19µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@4
# spent 7µs making 1 call to warnings::import | ||
5 | |||||
6 | 2 | 1.22ms | # spent 619µs (19+601) within DBIx::Class::Storage::DBI::Cursor::BEGIN@6 which was called:
# once (19µs+601µs) by Class::C3::Componentised::ensure_class_loaded at line 6 # spent 619µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@6
# spent 601µs making 1 call to base::import | ||
7 | |||||
8 | 2 | 104µs | # spent 62µs (21+42) within DBIx::Class::Storage::DBI::Cursor::BEGIN@8 which was called:
# once (21µs+42µs) by Class::C3::Componentised::ensure_class_loaded at line 8 # spent 62µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@8
# spent 42µs making 1 call to Exporter::import | ||
9 | 2 | 68µs | # spent 42µs (15+27) within DBIx::Class::Storage::DBI::Cursor::BEGIN@9 which was called:
# once (15µs+27µs) by Class::C3::Componentised::ensure_class_loaded at line 9 # spent 42µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@9
# spent 27µs making 1 call to Exporter::import | ||
10 | 2 | 65µs | # spent 50µs (35+15) within DBIx::Class::Storage::DBI::Cursor::BEGIN@10 which was called:
# once (35µs+15µs) by Class::C3::Componentised::ensure_class_loaded at line 10 # spent 50µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@10
# spent 15µs making 1 call to List::Util::import | ||
11 | 2 | 383µs | # spent 199µs (14+185) within DBIx::Class::Storage::DBI::Cursor::BEGIN@11 which was called:
# once (14µs+185µs) by Class::C3::Componentised::ensure_class_loaded at line 11 # spent 199µs making 1 call to DBIx::Class::Storage::DBI::Cursor::BEGIN@11
# spent 185µs making 1 call to namespace::clean::import | ||
12 | |||||
13 | 1 | 242µs | __PACKAGE__->mk_group_accessors('simple' => # spent 242µ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 | my %cursor_registry; | ||||
53 | |||||
54 | # spent 43µs (38+5) within DBIx::Class::Storage::DBI::Cursor::new which was called 2 times, avg 22µs/call:
# 2 times (38µs+5µs) by DBIx::Class::Storage::DBI::select at line 2559 of DBIx/Class/Storage/DBI.pm, avg 22µs/call | ||||
55 | 1 | 700ns | my ($class, $storage, $args, $attrs) = @_; | ||
56 | |||||
57 | 1 | 4µs | my $self = bless { | ||
58 | storage => $storage, | ||||
59 | args => $args, | ||||
60 | attrs => $attrs, | ||||
61 | }, ref $class || $class; | ||||
62 | |||||
63 | 1 | 600ns | 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 | 5µs | for keys %cursor_registry; | ||
69 | |||||
70 | 1 | 11µs | 4 | 5µs | weaken( $cursor_registry{ refaddr($self) } = $self ) # spent 2µs making 2 calls to Scalar::Util::refaddr, avg 1µs/call
# spent 2µs making 2 calls to Scalar::Util::weaken, avg 1µs/call |
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 33.5ms (203µs+33.3) within DBIx::Class::Storage::DBI::Cursor::next which was called 2 times, avg 16.7ms/call:
# once (140µs+32.0ms) by DBIx::Class::ResultSet::_construct_results at line 1329 of DBIx/Class/ResultSet.pm
# once (63µs+1.22ms) by DBIx::Class::ResultSetColumn::next at line 160 of DBIx/Class/ResultSetColumn.pm | ||||
105 | 1 | 500ns | my $self = shift; | ||
106 | |||||
107 | 1 | 1µs | return if $self->{_done}; | ||
108 | |||||
109 | 1 | 100ns | my $sth; | ||
110 | |||||
111 | 1 | 900ns | 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 | 5µs | 2 | 7µs | unless ($sth = $self->sth) { # spent 7µs making 2 calls to DBIx::Class::Storage::DBI::Cursor::sth, avg 3µs/call |
125 | 1 | 27µs | 4 | 32.3ms | (undef, $sth, undef) = $self->storage->_select( @{$self->{args}} ); # spent 32.1ms making 2 calls to DBIx::Class::Storage::DBI::_select, avg 16.0ms/call
# spent 179µs making 2 calls to DBIx::Class::Storage::DBI::Cursor::storage, avg 90µs/call |
126 | |||||
127 | 1 | 14µs | 2 | 22µs | $self->{_results} = [ (undef) x $sth->FETCH('NUM_OF_FIELDS') ]; # spent 22µs making 2 calls to DBI::common::FETCH, avg 11µs/call |
128 | 1 | 7µs | 4 | 1.83ms | $sth->bind_columns( \( @{$self->{_results}} ) ); # spent 919µs making 2 calls to DBI::st::bind_columns, avg 459µs/call
# spent 908µs making 2 calls to DBD::mysql::st::__ANON__[DBD/mysql.pm:810], avg 454µs/call |
129 | |||||
130 | 1 | 1µs | if ( $self->{attrs}{software_limit} and $self->{attrs}{offset} ) { | ||
131 | $sth->fetch for 1 .. $self->{attrs}{offset}; | ||||
132 | } | ||||
133 | |||||
134 | 1 | 2µs | 2 | 18µs | $self->sth($sth); # spent 18µs making 2 calls to DBIx::Class::Storage::DBI::Cursor::sth, avg 9µs/call |
135 | } | ||||
136 | |||||
137 | 1 | 8µs | 2 | 14µs | if ($sth->fetch) { # spent 14µs making 2 calls to DBI::st::fetch, avg 7µs/call |
138 | 1 | 1µs | $self->{_pos}++; | ||
139 | 1 | 5µ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 | 600ns | my $self = shift; | ||
193 | |||||
194 | 2 | 2µs | if (@_) { | ||
195 | 1 | 2µs | delete @{$self}{qw/_pos _done _pid _intra_thread/}; | ||
196 | |||||
197 | 1 | 1µs | $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 | 9µ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 172µs (18+155) within DBIx::Class::Storage::DBI::Cursor::DESTROY which was called 2 times, avg 86µs/call:
# once (10µs+103µs) by DBIx::Class::ResultSet::count at line 32 of Koha/Borrower/Discharge.pm
# once (8µs+52µs) by CGI::Compile::ROOT::home_vagrant_kohaclone_circ_ysearch_2epl::__ANON__[/home/vagrant/kohaclone/circ/ysearch.pl:115] at line 2 of circ/ysearch.pl | ||||
236 | 1 | 10µs | 2 | 155µs | $_[0]->__finish_sth if $_[0]->{sth}; # spent 155µs making 2 calls to DBIx::Class::Storage::DBI::Cursor::__finish_sth, avg 78µs/call |
237 | } | ||||
238 | |||||
239 | # spent 155µs (36+119) within DBIx::Class::Storage::DBI::Cursor::__finish_sth which was called 2 times, avg 78µs/call:
# 2 times (36µs+119µs) by DBIx::Class::Storage::DBI::Cursor::DESTROY at line 236, avg 78µs/call | ||||
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 | 500ns | my $self = shift; | ||
249 | |||||
250 | # No need to care about failures here | ||||
251 | 2 | 20µ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 | 8µs | 2 | 7µs | $self->{sth} and ! try { ! $self->{sth}->FETCH('Active') } # spent 7µs making 2 calls to DBI::common::FETCH, avg 4µs/call |
253 | 1 | 26µs | 3 | 119µs | ); # spent 119µs making 3 calls to Try::Tiny::try, avg 40µ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 | 179µs | 1; # spent 179µs making 1 call to B::Hooks::EndOfScope::XS::__ANON__ |