Filename | /2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/Storage/DBIHacks.pm |
Statements | Executed 949077 statements in 2.25s |
Calls | P | F | Exclusive Time |
Inclusive Time |
Subroutine |
---|---|---|---|---|---|
7779 | 3 | 2 | 1.50s | 2.20s | _resolve_column_info | DBIx::Class::Storage::DBIHacks::
111955 | 5 | 1 | 269ms | 269ms | CORE:match (opcode) | DBIx::Class::Storage::DBIHacks::
14485 | 2 | 2 | 222ms | 240ms | _resolve_ident_sources | DBIx::Class::Storage::DBIHacks::
6706 | 1 | 1 | 90.0ms | 571ms | _prune_unused_joins | DBIx::Class::Storage::DBIHacks::
2102 | 3 | 2 | 58.5ms | 284ms | _extract_order_criteria | DBIx::Class::Storage::DBIHacks::
2102 | 2 | 1 | 46.6ms | 188ms | __ANON__[:667] | DBIx::Class::Storage::DBIHacks::
147 | 1 | 1 | 42.9ms | 157ms | _resolve_aliastypes_from_select_args | DBIx::Class::Storage::DBIHacks::
6615 | 4 | 1 | 10.8ms | 10.8ms | CORE:regcomp (opcode) | DBIx::Class::Storage::DBIHacks::
147 | 1 | 1 | 4.91ms | 4.91ms | _inner_join_to_node | DBIx::Class::Storage::DBIHacks::
1323 | 2 | 1 | 1.52ms | 1.52ms | CORE:qr (opcode) | DBIx::Class::Storage::DBIHacks::
152 | 1 | 1 | 400µs | 400µs | CORE:subst (opcode) | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 29µs | 353µs | _group_over_selection | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 13µs | 33µs | BEGIN@609 | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 13µs | 15µs | BEGIN@10 | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 12µs | 49µs | BEGIN@16 | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 11µs | 28µs | BEGIN@18 | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 11µs | 20µs | BEGIN@14 | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 9µs | 192µs | BEGIN@19 | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 9µs | 5.52ms | BEGIN@13 | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 8µs | 30µs | BEGIN@17 | DBIx::Class::Storage::DBIHacks::
1 | 1 | 1 | 7µs | 15µs | BEGIN@11 | DBIx::Class::Storage::DBIHacks::
0 | 0 | 0 | 0s | 0s | __ANON__[:139] | DBIx::Class::Storage::DBIHacks::
0 | 0 | 0 | 0s | 0s | __ANON__[:632] | DBIx::Class::Storage::DBIHacks::
0 | 0 | 0 | 0s | 0s | __ANON__[:636] | DBIx::Class::Storage::DBIHacks::
0 | 0 | 0 | 0s | 0s | _adjust_select_args_for_complex_prefetch | DBIx::Class::Storage::DBIHacks::
0 | 0 | 0 | 0s | 0s | _extract_condition_columns | DBIx::Class::Storage::DBIHacks::
Line | State ments |
Time on line |
Calls | Time in subs |
Code |
---|---|---|---|---|---|
1 | package #hide from PAUSE | ||||
2 | DBIx::Class::Storage::DBIHacks; | ||||
3 | |||||
4 | # | ||||
5 | # This module contains code that should never have seen the light of day, | ||||
6 | # does not belong in the Storage, or is otherwise unfit for public | ||||
7 | # display. The arrival of SQLA2 should immediately obsolete 90% of this | ||||
8 | # | ||||
9 | |||||
10 | 3 | 18µs | 2 | 17µs | # spent 15µs (13+2) within DBIx::Class::Storage::DBIHacks::BEGIN@10 which was called:
# once (13µs+2µs) by base::import at line 10 # spent 15µs making 1 call to DBIx::Class::Storage::DBIHacks::BEGIN@10
# spent 2µs making 1 call to strict::import |
11 | 3 | 20µs | 2 | 22µs | # spent 15µs (7+8) within DBIx::Class::Storage::DBIHacks::BEGIN@11 which was called:
# once (7µs+8µs) by base::import at line 11 # spent 15µs making 1 call to DBIx::Class::Storage::DBIHacks::BEGIN@11
# spent 8µs making 1 call to warnings::import |
12 | |||||
13 | 3 | 34µs | 2 | 5.52ms | # spent 5.52ms (9µs+5.51) within DBIx::Class::Storage::DBIHacks::BEGIN@13 which was called:
# once (9µs+5.51ms) by base::import at line 13 # spent 5.52ms making 1 call to DBIx::Class::Storage::DBIHacks::BEGIN@13
# spent 5.51ms making 1 call to base::import, recursion: max depth 1, sum of overlapping time 5.51ms |
14 | 3 | 23µs | 2 | 30µs | # spent 20µs (11+10) within DBIx::Class::Storage::DBIHacks::BEGIN@14 which was called:
# once (11µs+10µs) by base::import at line 14 # spent 20µs making 1 call to DBIx::Class::Storage::DBIHacks::BEGIN@14
# spent 10µs making 1 call to mro::import |
15 | |||||
16 | 3 | 25µs | 2 | 86µs | # spent 49µs (12+37) within DBIx::Class::Storage::DBIHacks::BEGIN@16 which was called:
# once (12µs+37µs) by base::import at line 16 # spent 49µs making 1 call to DBIx::Class::Storage::DBIHacks::BEGIN@16
# spent 37µs making 1 call to Exporter::import |
17 | 3 | 19µs | 2 | 52µs | # spent 30µs (8+22) within DBIx::Class::Storage::DBIHacks::BEGIN@17 which was called:
# once (8µs+22µs) by base::import at line 17 # spent 30µs making 1 call to DBIx::Class::Storage::DBIHacks::BEGIN@17
# spent 22µs making 1 call to Exporter::import |
18 | 3 | 21µs | 2 | 46µs | # spent 28µs (11+18) within DBIx::Class::Storage::DBIHacks::BEGIN@18 which was called:
# once (11µs+18µs) by base::import at line 18 # spent 28µs making 1 call to DBIx::Class::Storage::DBIHacks::BEGIN@18
# spent 18µs making 1 call to Exporter::import |
19 | 3 | 1.97ms | 2 | 375µs | # spent 192µs (9+183) within DBIx::Class::Storage::DBIHacks::BEGIN@19 which was called:
# once (9µs+183µs) by base::import at line 19 # spent 192µs making 1 call to DBIx::Class::Storage::DBIHacks::BEGIN@19
# spent 183µs making 1 call to namespace::clean::import |
20 | |||||
21 | # | ||||
22 | # This code will remove non-selecting/non-restricting joins from | ||||
23 | # {from} specs, aiding the RDBMS query optimizer | ||||
24 | # | ||||
25 | # spent 571ms (90.0+481) within DBIx::Class::Storage::DBIHacks::_prune_unused_joins which was called 6706 times, avg 85µs/call:
# 6706 times (90.0ms+481ms) by DBIx::Class::Storage::DBI::_select_args at line 2165 of DBIx/Class/Storage/DBI.pm, avg 85µs/call | ||||
26 | 6706 | 5.92ms | my $self = shift; | ||
27 | 6706 | 11.6ms | my ($from, $select, $where, $attrs) = @_; | ||
28 | |||||
29 | 6706 | 20.8ms | 6706 | 324ms | return $from unless $self->_use_join_optimizer; # spent 324ms making 6706 calls to DBIx::Class::Storage::DBI::_use_join_optimizer, avg 48µs/call |
30 | |||||
31 | 6706 | 44.9ms | if (ref $from ne 'ARRAY' || ref $from->[0] ne 'HASH' || ref $from->[1] ne 'ARRAY') { | ||
32 | return $from; # only standard {from} specs are supported | ||||
33 | } | ||||
34 | |||||
35 | 147 | 454µs | 147 | 157ms | my $aliastypes = $self->_resolve_aliastypes_from_select_args(@_); # spent 157ms making 147 calls to DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args, avg 1.07ms/call |
36 | |||||
37 | # a grouped set will not be affected by amount of rows. Thus any | ||||
38 | # {multiplying} joins can go | ||||
39 | 147 | 114µs | delete $aliastypes->{multiplying} if $attrs->{group_by}; | ||
40 | |||||
41 | 147 | 185µs | my @newfrom = $from->[0]; # FROM head is always present | ||
42 | |||||
43 | 147 | 60µs | my %need_joins; | ||
44 | 147 | 229µs | for (values %$aliastypes) { | ||
45 | # add all requested aliases | ||||
46 | 882 | 803µs | $need_joins{$_} = 1 for keys %$_; | ||
47 | |||||
48 | # add all their parents (as per joinpath which is an AoH { table => alias }) | ||||
49 | 882 | 1.10ms | $need_joins{$_} = 1 for map { values %$_ } map { @$_ } values %$_; | ||
50 | } | ||||
51 | 147 | 292µs | for my $j (@{$from}[1..$#$from]) { | ||
52 | 147 | 352µs | push @newfrom, $j if ( | ||
53 | (! $j->[0]{-alias}) # legacy crap | ||||
54 | || | ||||
55 | $need_joins{$j->[0]{-alias}} | ||||
56 | ); | ||||
57 | } | ||||
58 | |||||
59 | 147 | 821µs | return \@newfrom; | ||
60 | } | ||||
61 | |||||
62 | # | ||||
63 | # This is the code producing joined subqueries like: | ||||
64 | # SELECT me.*, other.* FROM ( SELECT me.* FROM ... ) JOIN other ON ... | ||||
65 | # | ||||
66 | sub _adjust_select_args_for_complex_prefetch { | ||||
67 | my ($self, $from, $select, $where, $attrs) = @_; | ||||
68 | |||||
69 | $self->throw_exception ('Nothing to prefetch... how did we get here?!') | ||||
70 | if not @{$attrs->{_prefetch_selector_range}}; | ||||
71 | |||||
72 | $self->throw_exception ('Complex prefetches are not supported on resultsets with a custom from attribute') | ||||
73 | if (ref $from ne 'ARRAY' || ref $from->[0] ne 'HASH' || ref $from->[1] ne 'ARRAY'); | ||||
74 | |||||
75 | |||||
76 | # generate inner/outer attribute lists, remove stuff that doesn't apply | ||||
77 | my $outer_attrs = { %$attrs }; | ||||
78 | delete $outer_attrs->{$_} for qw/where bind rows offset group_by having/; | ||||
79 | |||||
80 | my $inner_attrs = { %$attrs }; | ||||
81 | delete $inner_attrs->{$_} for qw/for collapse _prefetch_selector_range _collapse_order_by select as/; | ||||
82 | |||||
83 | |||||
84 | # bring over all non-collapse-induced order_by into the inner query (if any) | ||||
85 | # the outer one will have to keep them all | ||||
86 | delete $inner_attrs->{order_by}; | ||||
87 | if (my $ord_cnt = @{$outer_attrs->{order_by}} - @{$outer_attrs->{_collapse_order_by}} ) { | ||||
88 | $inner_attrs->{order_by} = [ | ||||
89 | @{$outer_attrs->{order_by}}[ 0 .. $ord_cnt - 1] | ||||
90 | ]; | ||||
91 | } | ||||
92 | |||||
93 | # generate the inner/outer select lists | ||||
94 | # for inside we consider only stuff *not* brought in by the prefetch | ||||
95 | # on the outside we substitute any function for its alias | ||||
96 | my $outer_select = [ @$select ]; | ||||
97 | my $inner_select = []; | ||||
98 | |||||
99 | my ($p_start, $p_end) = @{$outer_attrs->{_prefetch_selector_range}}; | ||||
100 | for my $i (0 .. $p_start - 1, $p_end + 1 .. $#$outer_select) { | ||||
101 | my $sel = $outer_select->[$i]; | ||||
102 | |||||
103 | if (ref $sel eq 'HASH' ) { | ||||
104 | $sel->{-as} ||= $attrs->{as}[$i]; | ||||
105 | $outer_select->[$i] = join ('.', $attrs->{alias}, ($sel->{-as} || "inner_column_$i") ); | ||||
106 | } | ||||
107 | |||||
108 | push @$inner_select, $sel; | ||||
109 | |||||
110 | push @{$inner_attrs->{as}}, $attrs->{as}[$i]; | ||||
111 | } | ||||
112 | |||||
113 | # construct the inner $from and lock it in a subquery | ||||
114 | # we need to prune first, because this will determine if we need a group_by below | ||||
115 | # the fake group_by is so that the pruner throws away all non-selecting, non-restricting | ||||
116 | # multijoins (since we def. do not care about those inside the subquery) | ||||
117 | |||||
118 | my $inner_subq = do { | ||||
119 | |||||
120 | # must use it here regardless of user requests | ||||
121 | local $self->{_use_join_optimizer} = 1; | ||||
122 | |||||
123 | my $inner_from = $self->_prune_unused_joins ($from, $inner_select, $where, { | ||||
124 | group_by => ['dummy'], %$inner_attrs, | ||||
125 | }); | ||||
126 | |||||
127 | my $inner_aliastypes = | ||||
128 | $self->_resolve_aliastypes_from_select_args( $inner_from, $inner_select, $where, $inner_attrs ); | ||||
129 | |||||
130 | # we need to simulate collapse in the subq if a multiplying join is pulled | ||||
131 | # by being a non-selecting restrictor | ||||
132 | if ( | ||||
133 | ! $inner_attrs->{group_by} | ||||
134 | and | ||||
135 | first { | ||||
136 | $inner_aliastypes->{restricting}{$_} | ||||
137 | and | ||||
138 | ! $inner_aliastypes->{selecting}{$_} | ||||
139 | } ( keys %{$inner_aliastypes->{multiplying}||{}} ) | ||||
140 | ) { | ||||
141 | my $unprocessed_order_chunks; | ||||
142 | ($inner_attrs->{group_by}, $unprocessed_order_chunks) = $self->_group_over_selection ( | ||||
143 | $inner_from, $inner_select, $inner_attrs->{order_by} | ||||
144 | ); | ||||
145 | |||||
146 | $self->throw_exception ( | ||||
147 | 'A required group_by clause could not be constructed automatically due to a complex ' | ||||
148 | . 'order_by criteria. Either order_by columns only (no functions) or construct a suitable ' | ||||
149 | . 'group_by by hand' | ||||
150 | ) if $unprocessed_order_chunks; | ||||
151 | } | ||||
152 | |||||
153 | # we already optimized $inner_from above | ||||
154 | local $self->{_use_join_optimizer} = 0; | ||||
155 | |||||
156 | # generate the subquery | ||||
157 | $self->_select_args_to_query ( | ||||
158 | $inner_from, | ||||
159 | $inner_select, | ||||
160 | $where, | ||||
161 | $inner_attrs, | ||||
162 | ); | ||||
163 | }; | ||||
164 | |||||
165 | # Generate the outer from - this is relatively easy (really just replace | ||||
166 | # the join slot with the subquery), with a major caveat - we can not | ||||
167 | # join anything that is non-selecting (not part of the prefetch), but at | ||||
168 | # the same time is a multi-type relationship, as it will explode the result. | ||||
169 | # | ||||
170 | # There are two possibilities here | ||||
171 | # - either the join is non-restricting, in which case we simply throw it away | ||||
172 | # - it is part of the restrictions, in which case we need to collapse the outer | ||||
173 | # result by tackling yet another group_by to the outside of the query | ||||
174 | |||||
175 | $from = [ @$from ]; | ||||
176 | |||||
177 | # so first generate the outer_from, up to the substitution point | ||||
178 | my @outer_from; | ||||
179 | while (my $j = shift @$from) { | ||||
180 | $j = [ $j ] unless ref $j eq 'ARRAY'; # promote the head-from to an AoH | ||||
181 | |||||
182 | if ($j->[0]{-alias} eq $attrs->{alias}) { # time to swap | ||||
183 | |||||
184 | push @outer_from, [ | ||||
185 | { | ||||
186 | -alias => $attrs->{alias}, | ||||
187 | -rsrc => $j->[0]{-rsrc}, | ||||
188 | $attrs->{alias} => $inner_subq, | ||||
189 | }, | ||||
190 | @{$j}[1 .. $#$j], | ||||
191 | ]; | ||||
192 | last; # we'll take care of what's left in $from below | ||||
193 | } | ||||
194 | else { | ||||
195 | push @outer_from, $j; | ||||
196 | } | ||||
197 | } | ||||
198 | |||||
199 | # scan the *remaining* from spec against different attributes, and see which joins are needed | ||||
200 | # in what role | ||||
201 | my $outer_aliastypes = | ||||
202 | $self->_resolve_aliastypes_from_select_args( $from, $outer_select, $where, $outer_attrs ); | ||||
203 | |||||
204 | # unroll parents | ||||
205 | my ($outer_select_chain, $outer_restrict_chain) = map { +{ | ||||
206 | map { $_ => 1 } map { values %$_} map { @$_ } values %{ $outer_aliastypes->{$_} || {} } | ||||
207 | } } qw/selecting restricting/; | ||||
208 | |||||
209 | # see what's left - throw away if not selecting/restricting | ||||
210 | # also throw in a group_by if a non-selecting multiplier, | ||||
211 | # to guard against cross-join explosions | ||||
212 | my $need_outer_group_by; | ||||
213 | while (my $j = shift @$from) { | ||||
214 | my $alias = $j->[0]{-alias}; | ||||
215 | |||||
216 | if ( | ||||
217 | $outer_select_chain->{$alias} | ||||
218 | ) { | ||||
219 | push @outer_from, $j | ||||
220 | } | ||||
221 | elsif ($outer_restrict_chain->{$alias}) { | ||||
222 | push @outer_from, $j; | ||||
223 | $need_outer_group_by ||= $outer_aliastypes->{multiplying}{$alias} ? 1 : 0; | ||||
224 | } | ||||
225 | } | ||||
226 | |||||
227 | # demote the outer_from head | ||||
228 | $outer_from[0] = $outer_from[0][0]; | ||||
229 | |||||
230 | if ($need_outer_group_by and ! $outer_attrs->{group_by}) { | ||||
231 | |||||
232 | my $unprocessed_order_chunks; | ||||
233 | ($outer_attrs->{group_by}, $unprocessed_order_chunks) = $self->_group_over_selection ( | ||||
234 | \@outer_from, $outer_select, $outer_attrs->{order_by} | ||||
235 | ); | ||||
236 | |||||
237 | $self->throw_exception ( | ||||
238 | 'A required group_by clause could not be constructed automatically due to a complex ' | ||||
239 | . 'order_by criteria. Either order_by columns only (no functions) or construct a suitable ' | ||||
240 | . 'group_by by hand' | ||||
241 | ) if $unprocessed_order_chunks; | ||||
242 | |||||
243 | } | ||||
244 | |||||
245 | # This is totally horrific - the $where ends up in both the inner and outer query | ||||
246 | # Unfortunately not much can be done until SQLA2 introspection arrives, and even | ||||
247 | # then if where conditions apply to the *right* side of the prefetch, you may have | ||||
248 | # to both filter the inner select (e.g. to apply a limit) and then have to re-filter | ||||
249 | # the outer select to exclude joins you didin't want in the first place | ||||
250 | # | ||||
251 | # OTOH it can be seen as a plus: <ash> (notes that this query would make a DBA cry ;) | ||||
252 | return (\@outer_from, $outer_select, $where, $outer_attrs); | ||||
253 | } | ||||
254 | |||||
255 | # | ||||
256 | # I KNOW THIS SUCKS! GET SQLA2 OUT THE DOOR SO THIS CAN DIE! | ||||
257 | # | ||||
258 | # Due to a lack of SQLA2 we fall back to crude scans of all the | ||||
259 | # select/where/order/group attributes, in order to determine what | ||||
260 | # aliases are neded to fulfill the query. This information is used | ||||
261 | # throughout the code to prune unnecessary JOINs from the queries | ||||
262 | # in an attempt to reduce the execution time. | ||||
263 | # Although the method is pretty horrific, the worst thing that can | ||||
264 | # happen is for it to fail due to some scalar SQL, which in turn will | ||||
265 | # result in a vocal exception. | ||||
266 | # spent 157ms (42.9+114) within DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args which was called 147 times, avg 1.07ms/call:
# 147 times (42.9ms+114ms) by DBIx::Class::Storage::DBIHacks::_prune_unused_joins at line 35, avg 1.07ms/call | ||||
267 | 147 | 155µs | my ( $self, $from, $select, $where, $attrs ) = @_; | ||
268 | |||||
269 | 147 | 145µs | $self->throw_exception ('Unable to analyze custom {from}') | ||
270 | if ref $from ne 'ARRAY'; | ||||
271 | |||||
272 | # what we will return | ||||
273 | 147 | 44µs | my $aliases_by_type; | ||
274 | |||||
275 | # see what aliases are there to work with | ||||
276 | 147 | 36µs | my $alias_list; | ||
277 | 147 | 128µs | for (@$from) { | ||
278 | 294 | 89µs | my $j = $_; | ||
279 | 294 | 176µs | $j = $j->[0] if ref $j eq 'ARRAY'; | ||
280 | 294 | 231µs | my $al = $j->{-alias} | ||
281 | or next; | ||||
282 | |||||
283 | 294 | 180µs | $alias_list->{$al} = $j; | ||
284 | $aliases_by_type->{multiplying}{$al} ||= $j->{-join_path}||[] if ( | ||||
285 | # not array == {from} head == can't be multiplying | ||||
286 | ( ref($_) eq 'ARRAY' and ! $j->{-is_single} ) | ||||
287 | or | ||||
288 | # a parent of ours is already a multiplier | ||||
289 | 294 | 1.03ms | ( grep { $aliases_by_type->{multiplying}{$_} } @{ $j->{-join_path}||[] } ) | ||
290 | ); | ||||
291 | } | ||||
292 | |||||
293 | # get a column to source/alias map (including unqualified ones) | ||||
294 | 147 | 404µs | 147 | 35.4ms | my $colinfo = $self->_resolve_column_info ($from); # spent 35.4ms making 147 calls to DBIx::Class::Storage::DBIHacks::_resolve_column_info, avg 241µs/call |
295 | |||||
296 | # set up a botched SQLA | ||||
297 | 147 | 241µs | 147 | 305µs | my $sql_maker = $self->sql_maker; # spent 305µs making 147 calls to DBIx::Class::Storage::DBI::sql_maker, avg 2µs/call |
298 | |||||
299 | # these are throw away results, do not pollute the bind stack | ||||
300 | 147 | 219µs | local $sql_maker->{select_bind}; | ||
301 | 147 | 90µs | local $sql_maker->{where_bind}; | ||
302 | 147 | 177µs | local $sql_maker->{group_bind}; | ||
303 | 147 | 121µs | local $sql_maker->{having_bind}; | ||
304 | |||||
305 | # we can't scan properly without any quoting (\b doesn't cut it | ||||
306 | # everywhere), so unless there is proper quoting set - use our | ||||
307 | # own weird impossible character. | ||||
308 | # Also in the case of no quoting, we need to explicitly disable | ||||
309 | # name_sep, otherwise sorry nasty legacy syntax like | ||||
310 | # { 'count(foo.id)' => { '>' => 3 } } will stop working >:( | ||||
311 | 147 | 223µs | local $sql_maker->{quote_char} = $sql_maker->{quote_char}; | ||
312 | 147 | 263µs | local $sql_maker->{name_sep} = $sql_maker->{name_sep}; | ||
313 | |||||
314 | 147 | 136µs | unless (defined $sql_maker->{quote_char} and length $sql_maker->{quote_char}) { | ||
315 | 147 | 181µs | $sql_maker->{quote_char} = ["\x00", "\xFF"]; | ||
316 | # if we don't unset it we screw up retarded but unfortunately working | ||||
317 | # 'MAX(foo.bar)' => { '>', 3 } | ||||
318 | 147 | 74µs | $sql_maker->{name_sep} = ''; | ||
319 | } | ||||
320 | |||||
321 | 147 | 1.01ms | 149 | 1.28ms | my ($lquote, $rquote, $sep) = map { quotemeta $_ } ($sql_maker->_quote_chars, $sql_maker->name_sep); # spent 1.13ms making 147 calls to DBIx::Class::SQLMaker::_quote_chars, avg 8µs/call
# spent 153µs making 1 call to DBIx::Class::SQLMaker::name_sep
# spent 2µs making 1 call to DBIx::Class::SQLMaker::SQLite::name_sep |
322 | |||||
323 | # generate sql chunks | ||||
324 | my $to_scan = { | ||||
325 | restricting => [ | ||||
326 | $sql_maker->_recurse_where ($where), | ||||
327 | $sql_maker->_parse_rs_attrs ({ | ||||
328 | map { $_ => $attrs->{$_} } (qw/group_by having/) | ||||
329 | }), | ||||
330 | ], | ||||
331 | selecting => [ | ||||
332 | $sql_maker->_recurse_fields ($select), | ||||
333 | 147 | 2.82ms | 588 | 59.0ms | ( map { $_->[0] } $self->_extract_order_criteria ($attrs->{order_by}, $sql_maker) ), # spent 24.7ms making 147 calls to SQL::Abstract::_recurse_where, avg 168µs/call
# spent 21.6ms making 147 calls to DBIx::Class::Storage::DBIHacks::_extract_order_criteria, avg 147µs/call
# spent 12.0ms making 147 calls to DBIx::Class::SQLMaker::_recurse_fields, avg 81µs/call
# spent 814µs making 147 calls to DBIx::Class::SQLMaker::_parse_rs_attrs, avg 6µs/call |
334 | ], | ||||
335 | }; | ||||
336 | |||||
337 | # throw away empty chunks | ||||
338 | 294 | 861µs | $_ = [ map { $_ || () } @$_ ] for values %$to_scan; | ||
339 | |||||
340 | # first loop through all fully qualified columns and get the corresponding | ||||
341 | # alias (should work even if they are in scalarrefs) | ||||
342 | 147 | 257µs | for my $alias (keys %$alias_list) { | ||
343 | 294 | 4.96ms | 588 | 3.75ms | my $al_re = qr/ # spent 3.08ms making 294 calls to DBIx::Class::Storage::DBIHacks::CORE:regcomp, avg 10µs/call
# spent 668µs making 294 calls to DBIx::Class::Storage::DBIHacks::CORE:qr, avg 2µs/call |
344 | $lquote $alias $rquote $sep | ||||
345 | | | ||||
346 | \b $alias \. | ||||
347 | /x; | ||||
348 | |||||
349 | 294 | 484µs | for my $type (keys %$to_scan) { | ||
350 | 588 | 562µs | for my $piece (@{$to_scan->{$type}}) { | ||
351 | 1176 | 8.46ms | 2352 | 4.31ms | $aliases_by_type->{$type}{$alias} ||= $alias_list->{$alias}{-join_path}||[] # spent 3.36ms making 1176 calls to DBIx::Class::Storage::DBIHacks::CORE:match, avg 3µs/call
# spent 954µs making 1176 calls to DBIx::Class::Storage::DBIHacks::CORE:regcomp, avg 811ns/call |
352 | if ($piece =~ $al_re); | ||||
353 | } | ||||
354 | } | ||||
355 | } | ||||
356 | |||||
357 | # now loop through unqualified column names, and try to locate them within | ||||
358 | # the chunks | ||||
359 | 147 | 684µs | for my $col (keys %$colinfo) { | ||
360 | 2058 | 3.74ms | 2058 | 703µs | next if $col =~ / \. /x; # if column is qualified it was caught by the above # spent 703µs making 2058 calls to DBIx::Class::Storage::DBIHacks::CORE:match, avg 342ns/call |
361 | |||||
362 | 1029 | 8.04ms | 2058 | 4.86ms | my $col_re = qr/ $lquote $col $rquote /x; # spent 4.01ms making 1029 calls to DBIx::Class::Storage::DBIHacks::CORE:regcomp, avg 4µs/call
# spent 853µs making 1029 calls to DBIx::Class::Storage::DBIHacks::CORE:qr, avg 829ns/call |
363 | |||||
364 | 1029 | 1.31ms | for my $type (keys %$to_scan) { | ||
365 | 2058 | 1.79ms | for my $piece (@{$to_scan->{$type}}) { | ||
366 | 4116 | 16.5ms | 8232 | 4.31ms | if ($piece =~ $col_re) { # spent 2.73ms making 4116 calls to DBIx::Class::Storage::DBIHacks::CORE:regcomp, avg 664ns/call
# spent 1.57ms making 4116 calls to DBIx::Class::Storage::DBIHacks::CORE:match, avg 382ns/call |
367 | 147 | 230µs | my $alias = $colinfo->{$col}{-source_alias}; | ||
368 | 147 | 272µs | $aliases_by_type->{$type}{$alias} ||= $alias_list->{$alias}{-join_path}||[]; | ||
369 | } | ||||
370 | } | ||||
371 | } | ||||
372 | } | ||||
373 | |||||
374 | # Add any non-left joins to the restriction list (such joins are indeed restrictions) | ||||
375 | 147 | 167µs | for my $j (values %$alias_list) { | ||
376 | 294 | 253µs | my $alias = $j->{-alias} or next; | ||
377 | 294 | 467µs | $aliases_by_type->{restricting}{$alias} ||= $j->{-join_path}||[] if ( | ||
378 | (not $j->{-join_type}) | ||||
379 | or | ||||
380 | ($j->{-join_type} !~ /^left (?: \s+ outer)? $/xi) | ||||
381 | ); | ||||
382 | } | ||||
383 | |||||
384 | 147 | 2.65ms | return $aliases_by_type; | ||
385 | } | ||||
386 | |||||
387 | # This is the engine behind { distinct => 1 } | ||||
388 | # spent 353µs (29+324) within DBIx::Class::Storage::DBIHacks::_group_over_selection which was called:
# once (29µs+324µs) by DBIx::Class::ResultSet::_resolved_attrs at line 3280 of DBIx/Class/ResultSet.pm | ||||
389 | 1 | 1µs | my ($self, $from, $select, $order_by) = @_; | ||
390 | |||||
391 | 1 | 3µs | 1 | 208µs | my $rs_column_list = $self->_resolve_column_info ($from); # spent 208µs making 1 call to DBIx::Class::Storage::DBIHacks::_resolve_column_info |
392 | |||||
393 | 1 | 400ns | my (@group_by, %group_index); | ||
394 | |||||
395 | # the logic is: if it is a { func => val } we assume an aggregate, | ||||
396 | # otherwise if \'...' or \[...] we assume the user knows what is | ||||
397 | # going on thus group over it | ||||
398 | 1 | 1µs | for (@$select) { | ||
399 | 1 | 1µs | if (! ref($_) or ref ($_) ne 'HASH' ) { | ||
400 | 1 | 800ns | push @group_by, $_; | ||
401 | 1 | 500ns | $group_index{$_}++; | ||
402 | 1 | 4µs | 1 | 1µs | if ($rs_column_list->{$_} and $_ !~ /\./ ) { # spent 1µs making 1 call to DBIx::Class::Storage::DBIHacks::CORE:match |
403 | # add a fully qualified version as well | ||||
404 | $group_index{"$rs_column_list->{$_}{-source_alias}.$_"}++; | ||||
405 | } | ||||
406 | } | ||||
407 | } | ||||
408 | |||||
409 | # add any order_by parts that are not already present in the group_by | ||||
410 | # we need to be careful not to add any named functions/aggregates | ||||
411 | # i.e. order_by => [ ... { count => 'foo' } ... ] | ||||
412 | 1 | 400ns | my @leftovers; | ||
413 | 1 | 4µs | 1 | 115µs | for ($self->_extract_order_criteria($order_by)) { # spent 115µs making 1 call to DBIx::Class::Storage::DBIHacks::_extract_order_criteria |
414 | # only consider real columns (for functions the user got to do an explicit group_by) | ||||
415 | if (@$_ != 1) { | ||||
416 | push @leftovers, $_; | ||||
417 | next; | ||||
418 | } | ||||
419 | my $chunk = $_->[0]; | ||||
420 | my $colinfo = $rs_column_list->{$chunk} or do { | ||||
421 | push @leftovers, $_; | ||||
422 | next; | ||||
423 | }; | ||||
424 | |||||
425 | $chunk = "$colinfo->{-source_alias}.$chunk" if $chunk !~ /\./; | ||||
426 | push @group_by, $chunk unless $group_index{$chunk}++; | ||||
427 | } | ||||
428 | |||||
429 | return wantarray | ||||
430 | 1 | 10µs | ? (\@group_by, (@leftovers ? \@leftovers : undef) ) | ||
431 | : \@group_by | ||||
432 | ; | ||||
433 | } | ||||
434 | |||||
435 | # spent 240ms (222+17.7) within DBIx::Class::Storage::DBIHacks::_resolve_ident_sources which was called 14485 times, avg 17µs/call:
# 7779 times (105ms+11.4ms) by DBIx::Class::Storage::DBIHacks::_resolve_column_info at line 477, avg 15µs/call
# 6706 times (118ms+6.34ms) by DBIx::Class::Storage::DBI::_select_args at line 2109 of DBIx/Class/Storage/DBI.pm, avg 19µs/call | ||||
436 | 14485 | 8.76ms | my ($self, $ident) = @_; | ||
437 | |||||
438 | 14485 | 9.12ms | my $alias2source = {}; | ||
439 | 14485 | 4.76ms | my $rs_alias; | ||
440 | |||||
441 | # the reason this is so contrived is that $ident may be a {from} | ||||
442 | # structure, specifying multiple tables to join | ||||
443 | 14485 | 83.5ms | 15779 | 17.7ms | if ( blessed $ident && $ident->isa("DBIx::Class::ResultSource") ) { # spent 14.0ms making 14485 calls to Scalar::Util::blessed, avg 967ns/call
# spent 3.68ms making 1294 calls to UNIVERSAL::isa, avg 3µs/call |
444 | # this is compat mode for insert/update/delete which do not deal with aliases | ||||
445 | 1294 | 2.55ms | $alias2source->{me} = $ident; | ||
446 | 1294 | 1.20ms | $rs_alias = 'me'; | ||
447 | } | ||||
448 | elsif (ref $ident eq 'ARRAY') { | ||||
449 | |||||
450 | 13191 | 10.9ms | for (@$ident) { | ||
451 | 13632 | 3.14ms | my $tabinfo; | ||
452 | 13632 | 12.9ms | if (ref $_ eq 'HASH') { | ||
453 | 13191 | 3.81ms | $tabinfo = $_; | ||
454 | 13191 | 17.1ms | $rs_alias = $tabinfo->{-alias}; | ||
455 | } | ||||
456 | 13632 | 8.21ms | if (ref $_ eq 'ARRAY' and ref $_->[0] eq 'HASH') { | ||
457 | $tabinfo = $_->[0]; | ||||
458 | } | ||||
459 | |||||
460 | 13632 | 40.0ms | $alias2source->{$tabinfo->{-alias}} = $tabinfo->{-rsrc} | ||
461 | if ($tabinfo->{-rsrc}); | ||||
462 | } | ||||
463 | } | ||||
464 | |||||
465 | 14485 | 57.6ms | return ($alias2source, $rs_alias); | ||
466 | } | ||||
467 | |||||
468 | # Takes $ident, \@column_names | ||||
469 | # | ||||
470 | # returns { $column_name => \%column_info, ... } | ||||
471 | # also note: this adds -result_source => $rsrc to the column info | ||||
472 | # | ||||
473 | # If no columns_names are supplied returns info about *all* columns | ||||
474 | # for all sources | ||||
475 | # spent 2.20s (1.50+701ms) within DBIx::Class::Storage::DBIHacks::_resolve_column_info which was called 7779 times, avg 283µs/call:
# 7631 times (1.48s+689ms) by DBIx::Class::Storage::DBI::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/Storage/DBI.pm:1443] at line 1435 of DBIx/Class/Storage/DBI.pm, avg 284µs/call
# 147 times (23.2ms+12.2ms) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 294, avg 241µs/call
# once (134µs+75µs) by DBIx::Class::Storage::DBIHacks::_group_over_selection at line 391 | ||||
476 | 7779 | 8.57ms | my ($self, $ident, $colnames) = @_; | ||
477 | 7779 | 21.6ms | 7779 | 116ms | my ($alias2src, $root_alias) = $self->_resolve_ident_sources($ident); # spent 116ms making 7779 calls to DBIx::Class::Storage::DBIHacks::_resolve_ident_sources, avg 15µs/call |
478 | |||||
479 | 7779 | 4.55ms | my (%seen_cols, @auto_colnames); | ||
480 | |||||
481 | # compile a global list of column names, to be able to properly | ||||
482 | # disambiguate unqualified column names (if at all possible) | ||||
483 | 7779 | 15.4ms | for my $alias (keys %$alias2src) { | ||
484 | 8073 | 6.18ms | my $rsrc = $alias2src->{$alias}; | ||
485 | 8073 | 38.7ms | 8073 | 49.9ms | for my $colname ($rsrc->columns) { # spent 49.9ms making 8073 calls to DBIx::Class::ResultSource::columns, avg 6µs/call |
486 | 52302 | 67.0ms | push @{$seen_cols{$colname}}, $alias; | ||
487 | 52302 | 57.5ms | push @auto_colnames, "$alias.$colname" unless $colnames; | ||
488 | } | ||||
489 | } | ||||
490 | |||||
491 | $colnames ||= [ | ||||
492 | @auto_colnames, | ||||
493 | 7779 | 57.4ms | grep { @{$seen_cols{$_}} == 1 } (keys %seen_cols), | ||
494 | ]; | ||||
495 | |||||
496 | 7779 | 4.00ms | my (%return, $colinfos); | ||
497 | 7779 | 9.28ms | foreach my $col (@$colnames) { | ||
498 | 104604 | 566ms | 104604 | 263ms | my ($source_alias, $colname) = $col =~ m/^ (?: ([^\.]+) \. )? (.+) $/x; # spent 263ms making 104604 calls to DBIx::Class::Storage::DBIHacks::CORE:match, avg 3µs/call |
499 | |||||
500 | # if the column was seen exactly once - we know which rsrc it came from | ||||
501 | $source_alias ||= $seen_cols{$colname}[0] | ||||
502 | 104604 | 103ms | if ($seen_cols{$colname} and @{$seen_cols{$colname}} == 1); | ||
503 | |||||
504 | 104604 | 17.0ms | next unless $source_alias; | ||
505 | |||||
506 | 104604 | 43.1ms | my $rsrc = $alias2src->{$source_alias} | ||
507 | or next; | ||||
508 | |||||
509 | $return{$col} = { | ||||
510 | %{ | ||||
511 | 104604 | 644ms | 8073 | 272ms | ( $colinfos->{$source_alias} ||= $rsrc->columns_info )->{$colname} # spent 272ms making 8073 calls to DBIx::Class::ResultSource::columns_info, avg 34µs/call |
512 | || | ||||
513 | $self->throw_exception( | ||||
514 | "No such column '$colname' on source " . $rsrc->source_name | ||||
515 | ); | ||||
516 | }, | ||||
517 | -result_source => $rsrc, | ||||
518 | -source_alias => $source_alias, | ||||
519 | }; | ||||
520 | } | ||||
521 | |||||
522 | 7779 | 77.8ms | return \%return; | ||
523 | } | ||||
524 | |||||
525 | # The DBIC relationship chaining implementation is pretty simple - every | ||||
526 | # new related_relationship is pushed onto the {from} stack, and the {select} | ||||
527 | # window simply slides further in. This means that when we count somewhere | ||||
528 | # in the middle, we got to make sure that everything in the join chain is an | ||||
529 | # actual inner join, otherwise the count will come back with unpredictable | ||||
530 | # results (a resultset may be generated with _some_ rows regardless of if | ||||
531 | # the relation which the $rs currently selects has rows or not). E.g. | ||||
532 | # $artist_rs->cds->count - normally generates: | ||||
533 | # SELECT COUNT( * ) FROM artist me LEFT JOIN cd cds ON cds.artist = me.artistid | ||||
534 | # which actually returns the number of artists * (number of cds || 1) | ||||
535 | # | ||||
536 | # So what we do here is crawl {from}, determine if the current alias is at | ||||
537 | # the top of the stack, and if not - make sure the chain is inner-joined down | ||||
538 | # to the root. | ||||
539 | # | ||||
540 | # spent 4.91ms within DBIx::Class::Storage::DBIHacks::_inner_join_to_node which was called 147 times, avg 33µs/call:
# 147 times (4.91ms+0s) by DBIx::Class::ResultSet::related_resultset at line 2881 of DBIx/Class/ResultSet.pm, avg 33µs/call | ||||
541 | 147 | 135µs | my ($self, $from, $alias) = @_; | ||
542 | |||||
543 | # subqueries and other oddness are naturally not supported | ||||
544 | 147 | 555µs | return $from if ( | ||
545 | ref $from ne 'ARRAY' | ||||
546 | || | ||||
547 | @$from <= 1 | ||||
548 | || | ||||
549 | ref $from->[0] ne 'HASH' | ||||
550 | || | ||||
551 | ! $from->[0]{-alias} | ||||
552 | || | ||||
553 | $from->[0]{-alias} eq $alias # this last bit means $alias is the head of $from - nothing to do | ||||
554 | ); | ||||
555 | |||||
556 | # find the current $alias in the $from structure | ||||
557 | 147 | 57µs | my $switch_branch; | ||
558 | JOINSCAN: | ||||
559 | 147 | 468µs | for my $j (@{$from}[1 .. $#$from]) { | ||
560 | 147 | 157µs | if ($j->[0]{-alias} eq $alias) { | ||
561 | 147 | 108µs | $switch_branch = $j->[0]{-join_path}; | ||
562 | 147 | 255µs | last JOINSCAN; | ||
563 | } | ||||
564 | } | ||||
565 | |||||
566 | # something else went quite wrong | ||||
567 | 147 | 33µs | return $from unless $switch_branch; | ||
568 | |||||
569 | # So it looks like we will have to switch some stuff around. | ||||
570 | # local() is useless here as we will be leaving the scope | ||||
571 | # anyway, and deep cloning is just too fucking expensive | ||||
572 | # So replace the first hashref in the node arrayref manually | ||||
573 | 147 | 167µs | my @new_from = ($from->[0]); | ||
574 | 147 | 533µs | my $sw_idx = { map { (values %$_), 1 } @$switch_branch }; #there's one k/v per join-path | ||
575 | |||||
576 | 147 | 256µs | for my $j (@{$from}[1 .. $#$from]) { | ||
577 | 147 | 152µs | my $jalias = $j->[0]{-alias}; | ||
578 | |||||
579 | 147 | 221µs | if ($sw_idx->{$jalias}) { | ||
580 | 147 | 915µs | my %attrs = %{$j->[0]}; | ||
581 | 147 | 136µs | delete $attrs{-join_type}; | ||
582 | push @new_from, [ | ||||
583 | \%attrs, | ||||
584 | 147 | 275µs | @{$j}[ 1 .. $#$j ], | ||
585 | ]; | ||||
586 | } | ||||
587 | else { | ||||
588 | push @new_from, $j; | ||||
589 | } | ||||
590 | } | ||||
591 | |||||
592 | 147 | 498µs | return \@new_from; | ||
593 | } | ||||
594 | |||||
595 | # yet another atrocity: attempt to extract all columns from a | ||||
596 | # where condition by hooking _quote | ||||
597 | sub _extract_condition_columns { | ||||
598 | my ($self, $cond, $sql_maker) = @_; | ||||
599 | |||||
600 | return [] unless $cond; | ||||
601 | |||||
602 | $sql_maker ||= $self->{_sql_ident_capturer} ||= do { | ||||
603 | # FIXME - replace with a Moo trait | ||||
604 | my $orig_sm_class = ref $self->sql_maker; | ||||
605 | my $smic_class = "${orig_sm_class}::_IdentCapture_"; | ||||
606 | |||||
607 | unless ($smic_class->isa('SQL::Abstract')) { | ||||
608 | |||||
609 | 3 | 332µs | 2 | 52µs | # spent 33µs (13+20) within DBIx::Class::Storage::DBIHacks::BEGIN@609 which was called:
# once (13µs+20µs) by base::import at line 609 # spent 33µs making 1 call to DBIx::Class::Storage::DBIHacks::BEGIN@609
# spent 20µs making 1 call to strict::unimport |
610 | *{"${smic_class}::_quote"} = subname "${smic_class}::_quote" => sub { | ||||
611 | my ($self, $ident) = @_; | ||||
612 | if (ref $ident eq 'SCALAR') { | ||||
613 | $ident = $$ident; | ||||
614 | my $storage_quotes = $self->sql_quote_char || '"'; | ||||
615 | my ($ql, $qr) = map | ||||
616 | { quotemeta $_ } | ||||
617 | (ref $storage_quotes eq 'ARRAY' ? @$storage_quotes : ($storage_quotes) x 2 ) | ||||
618 | ; | ||||
619 | |||||
620 | while ($ident =~ / | ||||
621 | $ql (\w+) $qr | ||||
622 | | | ||||
623 | ([\w\.]+) | ||||
624 | /xg) { | ||||
625 | $self->{_captured_idents}{$1||$2}++; | ||||
626 | } | ||||
627 | } | ||||
628 | else { | ||||
629 | $self->{_captured_idents}{$ident}++; | ||||
630 | } | ||||
631 | return $ident; | ||||
632 | }; | ||||
633 | |||||
634 | *{"${smic_class}::_get_captured_idents"} = subname "${smic_class}::_get_captures" => sub { | ||||
635 | (delete shift->{_captured_idents}) || {}; | ||||
636 | }; | ||||
637 | |||||
638 | $self->inject_base ($smic_class, $orig_sm_class); | ||||
639 | |||||
640 | } | ||||
641 | |||||
642 | $smic_class->new(); | ||||
643 | }; | ||||
644 | |||||
645 | $sql_maker->_recurse_where($cond); | ||||
646 | |||||
647 | return [ sort keys %{$sql_maker->_get_captured_idents} ]; | ||||
648 | } | ||||
649 | |||||
650 | # spent 284ms (58.5+225) within DBIx::Class::Storage::DBIHacks::_extract_order_criteria which was called 2102 times, avg 135µs/call:
# 1954 times (56.6ms+206ms) by DBIx::Class::ResultSetColumn::new at line 68 of DBIx/Class/ResultSetColumn.pm, avg 134µs/call
# 147 times (1.84ms+19.7ms) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 333, avg 147µs/call
# once (25µs+90µs) by DBIx::Class::Storage::DBIHacks::_group_over_selection at line 413 | ||||
651 | 2102 | 3.14ms | my ($self, $order_by, $sql_maker) = @_; | ||
652 | |||||
653 | # spent 188ms (46.6+142) within DBIx::Class::Storage::DBIHacks::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/Storage/DBIHacks.pm:667] which was called 2102 times, avg 90µs/call:
# 1955 times (42.4ms+126ms) by DBIx::Class::Storage::DBIHacks::_extract_order_criteria at line 675, avg 86µs/call
# 147 times (4.14ms+15.6ms) by DBIx::Class::Storage::DBIHacks::_extract_order_criteria at line 669, avg 134µs/call | ||||
654 | 2102 | 1.62ms | my ($sql_maker, $order_by) = @_; | ||
655 | |||||
656 | 2102 | 679µs | return scalar $sql_maker->_order_by_chunks ($order_by) | ||
657 | unless wantarray; | ||||
658 | |||||
659 | 2102 | 670µs | my @chunks; | ||
660 | 2102 | 37.3ms | 2102 | 141ms | for ($sql_maker->_order_by_chunks ($order_by) ) { # spent 141ms making 2102 calls to SQL::Abstract::_order_by_chunks, avg 67µs/call |
661 | 152 | 159µs | my $chunk = ref $_ ? $_ : [ $_ ]; | ||
662 | 152 | 914µs | 152 | 400µs | $chunk->[0] =~ s/\s+ (?: ASC|DESC ) \s* $//ix; # spent 400µs making 152 calls to DBIx::Class::Storage::DBIHacks::CORE:subst, avg 3µs/call |
663 | 152 | 200µs | push @chunks, $chunk; | ||
664 | } | ||||
665 | |||||
666 | 2102 | 11.0ms | return @chunks; | ||
667 | 2102 | 7.74ms | }; | ||
668 | |||||
669 | 2102 | 1.71ms | 147 | 19.7ms | if ($sql_maker) { # spent 19.7ms making 147 calls to DBIx::Class::Storage::DBIHacks::__ANON__[DBIx/Class/Storage/DBIHacks.pm:667], avg 134µs/call |
670 | return $parser->($sql_maker, $order_by); | ||||
671 | } | ||||
672 | else { | ||||
673 | 1955 | 6.75ms | 1955 | 13.3ms | $sql_maker = $self->sql_maker; # spent 13.3ms making 1955 calls to DBIx::Class::Storage::DBI::sql_maker, avg 7µs/call |
674 | 1955 | 4.32ms | local $sql_maker->{quote_char}; | ||
675 | 1955 | 16.2ms | 1955 | 168ms | return $parser->($sql_maker, $order_by); # spent 168ms making 1955 calls to DBIx::Class::Storage::DBIHacks::__ANON__[DBIx/Class/Storage/DBIHacks.pm:667], avg 86µs/call |
676 | } | ||||
677 | } | ||||
678 | |||||
679 | 1 | 12µs | 1 | 234µs | 1; # spent 234µs making 1 call to B::Hooks::EndOfScope::__ANON__[B/Hooks/EndOfScope.pm:26] |
# spent 269ms within DBIx::Class::Storage::DBIHacks::CORE:match which was called 111955 times, avg 2µs/call:
# 104604 times (263ms+0s) by DBIx::Class::Storage::DBIHacks::_resolve_column_info at line 498, avg 3µs/call
# 4116 times (1.57ms+0s) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 366, avg 382ns/call
# 2058 times (703µs+0s) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 360, avg 342ns/call
# 1176 times (3.36ms+0s) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 351, avg 3µs/call
# once (1µs+0s) by DBIx::Class::Storage::DBIHacks::_group_over_selection at line 402 | |||||
# spent 1.52ms within DBIx::Class::Storage::DBIHacks::CORE:qr which was called 1323 times, avg 1µs/call:
# 1029 times (853µs+0s) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 362, avg 829ns/call
# 294 times (668µs+0s) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 343, avg 2µs/call | |||||
# spent 10.8ms within DBIx::Class::Storage::DBIHacks::CORE:regcomp which was called 6615 times, avg 2µs/call:
# 4116 times (2.73ms+0s) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 366, avg 664ns/call
# 1176 times (954µs+0s) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 351, avg 811ns/call
# 1029 times (4.01ms+0s) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 362, avg 4µs/call
# 294 times (3.08ms+0s) by DBIx::Class::Storage::DBIHacks::_resolve_aliastypes_from_select_args at line 343, avg 10µs/call | |||||
# spent 400µs within DBIx::Class::Storage::DBIHacks::CORE:subst which was called 152 times, avg 3µs/call:
# 152 times (400µs+0s) by DBIx::Class::Storage::DBIHacks::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/Storage/DBIHacks.pm:667] at line 662, avg 3µs/call |