← Index
NYTProf Performance Profile   « block view • line view • sub view »
For 05.Domain_and_Item.t
  Run on Tue May 4 17:21:41 2010
Reported on Tue May 4 17:22:50 2010

File /data/SimpleDB-Class/author.t/../lib/SimpleDB/Class/SQL.pm
Statements Executed 854
Statement Execution Time 3.81ms
Subroutines — ordered by exclusive time
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
11110.8ms89.3msSimpleDB::Class::SQL::::BEGIN@19SimpleDB::Class::SQL::BEGIN@19
1115.04ms5.37msSimpleDB::Class::SQL::::BEGIN@20SimpleDB::Class::SQL::BEGIN@20
1111.66ms6.34msSimpleDB::Class::SQL::::BEGIN@18SimpleDB::Class::SQL::BEGIN@18
19721.16ms7.90msSimpleDB::Class::SQL::::to_sqlSimpleDB::Class::SQL::to_sql
2321813µs5.63msSimpleDB::Class::SQL::::recurse_whereSimpleDB::Class::SQL::recurse_where
5241295µs328µsSimpleDB::Class::SQL::::quote_attributeSimpleDB::Class::SQL::quote_attribute
111261µs841µsSimpleDB::Class::SQL::::BEGIN@21SimpleDB::Class::SQL::BEGIN@21
2231198µs226µsSimpleDB::Class::SQL::::quote_valueSimpleDB::Class::SQL::quote_value
913262µs62µsSimpleDB::Class::SQL::::CORE:substSimpleDB::Class::SQL::CORE:subst (opcode)
11133µs2.02msSimpleDB::Class::SQL::::BEGIN@17SimpleDB::Class::SQL::BEGIN@17
11113µs141µsSimpleDB::Class::SQL::::BEGIN@403SimpleDB::Class::SQL::BEGIN@403
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package SimpleDB::Class::SQL;
2
3=head1 NAME
4
5SimpleDB::Class::SQL - SQL generation tools for SimpleDB.
6
7=head1 DESCRIPTION
8
9This class is used to generate the SQL needed for the Select operation on SimpleDB's web service.
10
11=head1 METHODS
12
13The following methods are available from this class.
14
15=cut
16
17327µs24.02ms
# spent 2.02ms (33µs+1.99) within SimpleDB::Class::SQL::BEGIN@17 which was called # once (33µs+1.99ms) by SimpleDB::Class::Domain::BEGIN@18 at line 17
use Moose;
# spent 2.02ms making 1 call to SimpleDB::Class::SQL::BEGIN@17 # spent 1.99ms making 1 call to Moose::Exporter::__ANON__[Moose/Exporter.pm:389]
183119µs26.49ms
# spent 6.34ms (1.66+4.69) within SimpleDB::Class::SQL::BEGIN@18 which was called # once (1.66ms+4.69ms) by SimpleDB::Class::Domain::BEGIN@18 at line 18
use JSON;
# spent 6.34ms making 1 call to SimpleDB::Class::SQL::BEGIN@18 # spent 141µs making 1 call to JSON::import
193135µs189.3ms
# spent 89.3ms (10.8+78.5) within SimpleDB::Class::SQL::BEGIN@19 which was called # once (10.8ms+78.5ms) by SimpleDB::Class::Domain::BEGIN@18 at line 19
use DateTime;
# spent 89.3ms making 1 call to SimpleDB::Class::SQL::BEGIN@19
203132µs25.41ms
# spent 5.37ms (5.04+336µs) within SimpleDB::Class::SQL::BEGIN@20 which was called # once (5.04ms+336µs) by SimpleDB::Class::Domain::BEGIN@18 at line 20
use DateTime::Format::Strptime;
# spent 5.37ms making 1 call to SimpleDB::Class::SQL::BEGIN@20 # spent 36µs making 1 call to Exporter::import
213848µs2883µs
# spent 841µs (261+580) within SimpleDB::Class::SQL::BEGIN@21 which was called # once (261µs+580µs) by SimpleDB::Class::Domain::BEGIN@18 at line 21
use Clone qw(clone);
# spent 841µs making 1 call to SimpleDB::Class::SQL::BEGIN@21 # spent 42µs making 1 call to Exporter::import
22
23#--------------------------------------------------------
24
25=head2 new ( params )
26
27Constructor.
28
29=head3 params
30
31A hash of options you can pass in to the constructor.
32
33=head4 item_class
34
35A L<SimpleDB::Class::Item> subclass name. This is required.
36
37=head4 simpledb
38
39A reference to the L<SimpleDB::Class> object. This is required.
40
41=head4 output
42
43Defaults to '*'. Alternatively you can pass a string of 'count(*)' or an attribute. Or you can pass an array ref of attributes.
44
45=head4 where
46
47A hash reference containing a series of clauses. Here are some examples and what the resulting queries would be. You can of course combine all these options to create your own queries.
48
49B<NOTE:> If you want to search on an item's id (or ItemName) then you should use the C<itemName()> function as the id doesn't actually exist in the item's data.
50
51Direct comparison.
52
53 { foo => 1 }
54
55 select * from domain where foo=1
56
57 { foo => 1, bar => 2 }
58
59 select * from domain where foo=1 and bar=2
60
61 { foo => [ '>', 5 ] } # '=', '!=', '>', '<', '<=', '>='
62
63 select * from domain where foo > 5
64
65Direct comparison with an or clause.
66
67 { -or => { foo => 1, bar => 2 } }
68
69 select * from domain where (foo=1 or bar=2)
70
71Find all items where these attributes intersect.
72
73 { -intersection => { foo => 1, bar => 2 } }
74
75 select * from domain where (foo=1 intersection bar=2)
76
77Combining OR and AND.
78
79 { -or => { foo => 1, -and => { this => 'that', bar => 2 } }
80
81 select * from domain where (foo=1 or ( this='that' and bar=2 ))
82
83Finding within a range.
84
85 { foo=>['between', 5, 10] }
86
87 select * from domain where foo between 5 and 10
88
89Finding within a set.
90
91 { foo => ['in', 1, 3, 5, 7 ] }
92
93 select * from domain where foo in (1, 3, 5, 7)
94
95Finding in a set where every item returned matches all members of the set.
96
97 { foo => ['every', 1, 3, 5, 7 ] }
98
99 select * from domain where every(foo) in (1, 3, 5, 7)
100
101String comparisons. You can match on either side of the string ('%this', 'that%') or both ('%this%'). Note that matching at the beginning or both sides of the string is a slow operation.
102
103 { foo => [ 'like', 'this%' ] } # 'not like'
104
105 select * from domain where foo like 'this%'
106
107Null comparisons. These are very slow. Try inserting 'Null' or 'None' into a field and do string comparisons rather than null comparisons.
108
109 { foo => 'is null' } # 'is not null'
110
111 select * from domain where foo is null
112
113=head4 order_by
114
115An attribute to order the result set by, defaults to ascending order. Can also pass in an array ref containing an attribute and 'desc' or 'asc'. If an array ref is passed in containing only an attribute name it is an implied descending order.
116
117 "foo"
118
119 ["foo","desc"]
120
121 ["foo"]
122
123=head4 limit
124
125An integer of a number of items to limit the result set to.
126
127=cut
128
129#--------------------------------------------------------
130
131=head2 output ()
132
133Returns what was passed into the constructor for the output field.
134
135=cut
136
13713µs11.67mshas output => (
# spent 1.67ms making 1 call to Moose::has
138 is => 'ro',
139 default => '*',
140);
141
142#--------------------------------------------------------
143
144=head2 simpledb ()
145
146Returns the reference passed into the constructor.
147
148=cut
149
15012µs1881µshas simpledb => (
# spent 881µs making 1 call to Moose::has
151 is => 'ro',
152 required => 1,
153);
154
155#--------------------------------------------------------
156
157=head2 item_class ()
158
159Returns what was passed into the constructor for the item_class field.
160
161=cut
162
16312µs1882µshas item_class => (
# spent 882µs making 1 call to Moose::has
164 is => 'ro',
165 required => 1,
166);
167
168#--------------------------------------------------------
169
170=head2 where ()
171
172Returns what was passed into the constructor for the where field.
173
174=head2 has_where()
175
176Returns a boolean indicating whether a where clause has been set.
177
178=cut
179
18012µs11.16mshas where => (
# spent 1.16ms making 1 call to Moose::has
181 is => 'ro',
182 predicate => 'has_where',
183);
184
185#--------------------------------------------------------
186
187=head2 order_by ()
188
189Returns what was passed into the constructor for the output field.
190
191=head2 has_order_by ()
192
193Returns a boolean indicating whether an order by clause has been set.
194
195=cut
196
19712µs11.19mshas order_by => (
# spent 1.19ms making 1 call to Moose::has
198 is => 'ro',
199 predicate => 'has_order_by',
200);
201
202#--------------------------------------------------------
203
204=head2 limit ()
205
206Returns what was passed into the constructor for the output field.
207
208=head2 has_limit ()
209
210=cut
211
21211µs11.14mshas limit => (
# spent 1.14ms making 1 call to Moose::has
213 is => 'ro',
214 predicate => 'has_limit',
215);
216
217#--------------------------------------------------------
218
219=head2 quote_value ( string )
220
221Escapes ' and " in values. If C<itemName()> is what's passed in, it will not be quoted.
222
223
224=head3 string
225
226The value to escape.
227
228=cut
229
230
# spent 226µs (198+29) within SimpleDB::Class::SQL::quote_value which was called 22 times, avg 10µs/call: # 13 times (105µs+17µs) by SimpleDB::Class::SQL::recurse_where at line 337, avg 9µs/call # 7 times (77µs+9µs) by SimpleDB::Class::SQL::recurse_where at line 294, avg 12µs/call # 2 times (16µs+2µs) by SimpleDB::Class::SQL::recurse_where at line 316, avg 9µs/call
sub quote_value {
23188237µs my ($self, $string) = @_;
232 $string =~ s/'/''/g;
# spent 19µs making 22 calls to SimpleDB::Class::SQL::CORE:subst, avg 864ns/call
233 $string =~ s/"/""/g;
# spent 10µs making 22 calls to SimpleDB::Class::SQL::CORE:subst, avg 445ns/call
234 return "'".$string."'";
235}
236
237#--------------------------------------------------------
238
239=head2 quote_attribute ( string )
240
241Escapes an attribute with so that it can contain spaces and other special characters by wrapping it in backticks `. If C<itemName()> is what's passed in, it will not be quoted.
242
243=head3 string
244
245The attribute name to escape.
246
247=cut
248
249
# spent 328µs (295+33) within SimpleDB::Class::SQL::quote_attribute which was called 52 times, avg 6µs/call: # 21 times (137µs+17µs) by SimpleDB::Class::SQL::recurse_where at line 291, avg 7µs/call # 19 times (88µs+10µs) by SimpleDB::Class::SQL::to_sql at line 393, avg 5µs/call # 7 times (25µs+2µs) by SimpleDB::Class::SQL::to_sql at line 384, avg 4µs/call # 5 times (44µs+4µs) by SimpleDB::Class::SQL::to_sql at line 358, avg 10µs/call
sub quote_attribute {
250198373µs my ($self, $string) = @_;
251 if ($string eq 'itemName()') {
252 return $string;
253 }
254 $string =~ s/`/``/g;
# spent 34µs making 47 calls to SimpleDB::Class::SQL::CORE:subst, avg 713ns/call
255 return "`".$string."`";
256}
257
258#--------------------------------------------------------
259
260=head2 recurese_where ( constraints, [ op ] )
261
262Traverses a where() hierarchy and returns a stringified SQL version of the where clause.
263
264=head3 constraints
265
266A portion of a where hierarchy, perhaps broken off from the main for detailed analysis.
267
268=head3 op
269
270If it's a chunk broken off, -and, -or, -intersection then the operator will be passed through here.
271
272=cut
273
274
# spent 5.63ms (813µs+4.82) within SimpleDB::Class::SQL::recurse_where which was called 23 times, avg 245µs/call: # 19 times (714µs+4.92ms) by SimpleDB::Class::SQL::to_sql at line 369, avg 296µs/call # 4 times (98µs+-98µs) by SimpleDB::Class::SQL::recurse_where at line 279, avg 0s/call
sub recurse_where {
275115188µs my ($self, $constraints, $op) = @_;
276 $op ||= ' and ';
277 my @sets;
278 foreach my $key (keys %{$constraints}) {
279109249µs40s if ($key eq '-and') {
# spent 747µs making 4 calls to SimpleDB::Class::SQL::recurse_where, avg 187µs/call, recursion: max depth 1, time 747µs
280 push @sets, '('.$self->recurse_where($constraints->{$key}, ' and ').')';
281 }
282 elsif ($key eq '-or') {
283 push @sets, '('.$self->recurse_where($constraints->{$key}, ' or ').')';
284 }
285 elsif ($key eq '-intersection') {
286 push @sets, '('.$self->recurse_where($constraints->{$key}, ' intersection ').')';
287 }
288 else {
289 my $value = $constraints->{$key};
290 my $item_class = $self->item_class;
# spent 69µs making 21 calls to SimpleDB::Class::SQL::item_class, avg 3µs/call
291 my $attribute = $self->quote_attribute($key);
# spent 155µs making 21 calls to SimpleDB::Class::SQL::quote_attribute, avg 7µs/call
29242134µs if (ref $value eq 'ARRAY') {
293 my $cmp = shift @{$value};
29429µs142.17ms if ($cmp eq '>') {
# spent 2.09ms making 7 calls to SimpleDB::Class::Item::stringify_value, avg 298µs/call # spent 86µs making 7 calls to SimpleDB::Class::SQL::quote_value, avg 12µs/call
295 push @sets, $attribute.' > '.$self->quote_value($item_class->stringify_value($key, $value->[0]));
296 }
297 elsif ($cmp eq '<') {
298 push @sets, $attribute.' < '.$self->quote_value($item_class->stringify_value($key, $value->[0]));
299 }
300 elsif ($cmp eq '<=') {
301 push @sets, $attribute.' <= '.$self->quote_value($item_class->stringify_value($key, $value->[0]));
302 }
303 elsif ($cmp eq '>=') {
304 push @sets, $attribute.' >= '.$self->quote_value($item_class->stringify_value($key, $value->[0]));
305 }
306 elsif ($cmp eq '!=') {
307 push @sets, $attribute.' != '.$self->quote_value($item_class->stringify_value($key, $value->[0]));
308 }
309 elsif ($cmp eq 'like') {
310 push @sets, $attribute.' like '.$self->quote_value($item_class->stringify_value($key, $value->[0]));
311 }
312 elsif ($cmp eq 'not like') {
313 push @sets, $attribute.' not like '.$self->quote_value($item_class->stringify_value($key, $value->[0]));
314 }
315 elsif ($cmp eq 'in') {
31628µs426µs my @values = map {$self->quote_value($item_class->stringify_value($key, $_))} @{$value};
# spent 18µs making 2 calls to SimpleDB::Class::SQL::quote_value, avg 9µs/call # spent 7µs making 2 calls to SimpleDB::Class::Item::stringify_value, avg 4µs/call
317 push @sets, $attribute.' in ('.join(', ', @values).')';
318 }
319 elsif ($cmp eq 'every') {
320 my @values = map {$self->quote_value($item_class->stringify_value($key, $_))} @{$value};
321 push @sets, 'every('.$attribute.') in ('.join(', ', @values).')';
322 }
323 elsif ($cmp eq 'between') {
324 push @sets, $attribute.' between '.$self->quote_value($item_class->stringify_value($key, $value->[0]))
325 .' and '.$self->quote_value($item_class->stringify_value($key, $value->[1]));
326 }
327 }
328 else {
329 my $value = $constraints->{$key};
3301388µs if ($value eq 'is null') {
331 push @sets, $attribute.' is null';
332 }
333 elsif ($value eq 'is not null') {
334 push @sets, $attribute.' is not null';
335 }
336 else {
337 push @sets, $attribute.' = '.$self->quote_value($item_class->stringify_value($key, $value));
# spent 2.27ms making 13 calls to SimpleDB::Class::Item::stringify_value, avg 175µs/call # spent 122µs making 13 calls to SimpleDB::Class::SQL::quote_value, avg 9µs/call
338 }
339 }
340 }
341 }
342 return join($op, @sets);
343}
344
345#--------------------------------------------------------
346
347=head2 to_sql ( )
348
349Returns the entire query as a stringified SQL version.
350
351=cut
352
353
# spent 7.90ms (1.16+6.74) within SimpleDB::Class::SQL::to_sql which was called 19 times, avg 416µs/call: # 10 times (525µs+3.17ms) by SimpleDB::Class::ResultSet::fetch_result at line 240 of ../lib/SimpleDB/Class/ResultSet.pm, avg 369µs/call # 2 times (173µs+1.22ms) by SimpleDB::Class::Domain::max at line 351 of ../lib/SimpleDB/Class/Domain.pm, avg 697µs/call # 2 times (142µs+1.04ms) by SimpleDB::Class::Domain::min at line 402 of ../lib/SimpleDB/Class/Domain.pm, avg 593µs/call # 2 times (151µs+157µs) by SimpleDB::Class::Domain::count at line 258 of ../lib/SimpleDB/Class/Domain.pm, avg 154µs/call # once (63µs+475µs) by SimpleDB::Class::ResultSet::paginate at line 405 of ../lib/SimpleDB/Class/ResultSet.pm # once (51µs+377µs) by SimpleDB::Class::ResultSet::count at line 288 of ../lib/SimpleDB/Class/ResultSet.pm # once (52µs+301µs) by SimpleDB::Class::Domain::fetch_ids at line 296 of ../lib/SimpleDB/Class/Domain.pm
sub to_sql {
354190686µs my ($self) = @_;
355
356 # output
357 my $output = $self->output;
# spent 76µs making 19 calls to SimpleDB::Class::SQL::output, avg 4µs/call
358 if (ref $output eq 'ARRAY') {
# spent 48µs making 5 calls to SimpleDB::Class::SQL::quote_attribute, avg 10µs/call
359 my @fields = map {$self->quote_attribute($_)} @{$output};
360 $output = join ', ', @fields;
361 }
362 elsif ($output ne '*' && $output ne 'count(*)') {
363 $output = $self->quote_attribute($output);
364 }
365
366 # where
367 my $where='';
36838417µs1961µs if ($self->has_where) {
# spent 61µs making 19 calls to SimpleDB::Class::SQL::has_where, avg 3µs/call
369 $where = $self->recurse_where(clone($self->where));
# spent 5.63ms making 19 calls to SimpleDB::Class::SQL::recurse_where, avg 296µs/call # spent 207µs making 19 calls to Clone::clone, avg 11µs/call # spent 70µs making 19 calls to SimpleDB::Class::SQL::where, avg 4µs/call
370 if ($where ne '') {
371 $where = ' where '.$where;
372 }
373 }
374
375 # sort
376 my $sort='';
3772853µs1971µs if ($self->has_order_by) {
# spent 71µs making 19 calls to SimpleDB::Class::SQL::has_order_by, avg 4µs/call
378 my $by = $self->order_by;
# spent 26µs making 7 calls to SimpleDB::Class::SQL::order_by, avg 4µs/call
379 my $direction = 'asc';
38044µs if (ref $by eq 'ARRAY') {
381 ($by, $direction) = @{$by};
382 $direction ||= 'desc';
383 }
384 $sort = ' order by '.$self->quote_attribute($by).' '.$direction;
# spent 27µs making 7 calls to SimpleDB::Class::SQL::quote_attribute, avg 4µs/call
385 }
386
387 # limit
388 my $limit='';
389 if ($self->has_limit) {
# spent 51µs making 19 calls to SimpleDB::Class::SQL::has_limit, avg 3µs/call # spent 24µs making 7 calls to SimpleDB::Class::SQL::limit, avg 3µs/call
390 $limit = ' limit '.$self->limit;
391 }
392
393 return 'select '.$output.' from '.$self->quote_attribute($self->simpledb->add_domain_prefix($self->item_class->domain_name)).$where.$sort.$limit;
# spent 204µs making 19 calls to SimpleDB::Class::add_domain_prefix, avg 11µs/call # spent 98µs making 19 calls to SimpleDB::Class::SQL::quote_attribute, avg 5µs/call # spent 69µs making 19 calls to SimpleDB::Class::SQL::simpledb, avg 4µs/call # spent 34µs making 16 calls to Foo::Domain::domain_name, avg 2µs/call # spent 33µs making 19 calls to SimpleDB::Class::SQL::item_class, avg 2µs/call # spent 10µs making 2 calls to Foo::Parent::domain_name, avg 5µs/call # spent 1µs making 1 call to Foo::Child::domain_name
394}
395
396
397=head1 LEGAL
398
399SimpleDB::Class is Copyright 2009-2010 Plain Black Corporation (L<http://www.plainblack.com/>) and is licensed under the same terms as Perl itself.
400
401=cut
402
403346µs2268µs
# spent 141µs (13+128) within SimpleDB::Class::SQL::BEGIN@403 which was called # once (13µs+128µs) by SimpleDB::Class::Domain::BEGIN@18 at line 403
no Moose;
# spent 141µs making 1 call to SimpleDB::Class::SQL::BEGIN@403 # spent 128µs making 1 call to Moose::Exporter::__ANON__[Moose/Exporter.pm:478]
404148µs22.81ms__PACKAGE__->meta->make_immutable;
# spent 2.77ms making 1 call to Class::MOP::Class::make_immutable # spent 36µs making 1 call to SimpleDB::Class::SQL::meta
# spent 62µs within SimpleDB::Class::SQL::CORE:subst which was called 91 times, avg 685ns/call: # 47 times (34µs+0s) by SimpleDB::Class::SQL::quote_attribute at line 254 of ../lib/SimpleDB/Class/SQL.pm, avg 713ns/call # 22 times (19µs+0s) by SimpleDB::Class::SQL::quote_value at line 232 of ../lib/SimpleDB/Class/SQL.pm, avg 864ns/call # 22 times (10µs+0s) by SimpleDB::Class::SQL::quote_value at line 233 of ../lib/SimpleDB/Class/SQL.pm, avg 445ns/call
sub SimpleDB::Class::SQL::CORE:subst; # xsub