← Index
NYTProf Performance Profile   « block view • line view • sub view »
For xt/tapper-mcp-scheduler-with-db-longrun.t
  Run on Tue May 22 17:18:39 2012
Reported on Tue May 22 17:23:02 2012

Filename/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/ResultSet.pm
StatementsExecuted 3369599 statements in 5.75s
Subroutines
Calls P F Exclusive
Time
Inclusive
Time
Subroutine
17692521.17s1.75sDBIx::Class::ResultSet::::_resolved_attrsDBIx::Class::ResultSet::_resolved_attrs
16979321.07s2.88sDBIx::Class::ResultSet::::search_rsDBIx::Class::ResultSet::search_rs
3385921611ms866msDBIx::Class::ResultSet::::_normalize_selectionDBIx::Class::ResultSet::_normalize_selection
2506184604ms2.34sDBIx::Class::ResultSet::::newDBIx::Class::ResultSet::new
471711322ms399msDBIx::Class::ResultSet::::_collapse_resultDBIx::Class::ResultSet::_collapse_result
3180941215ms351msDBIx::Class::ResultSet::::result_classDBIx::Class::ResultSet::result_class
1762311205ms205msDBIx::Class::ResultSet::::_stack_condDBIx::Class::ResultSet::_stack_cond
3419941149ms696msDBIx::Class::ResultSet::::_merge_attrDBIx::Class::ResultSet::_merge_attr
12686651119ms119msDBIx::Class::ResultSet::::CORE:matchDBIx::Class::ResultSet::CORE:match (opcode)
194974117ms5.59sDBIx::Class::ResultSet::::countDBIx::Class::ResultSet::count
471731107ms676msDBIx::Class::ResultSet::::_construct_objectDBIx::Class::ResultSet::_construct_object
200733104ms4.94sDBIx::Class::ResultSet::::findDBIx::Class::ResultSet::find
998731104ms845msDBIx::Class::ResultSet::::_resolved_attrs_copyDBIx::Class::ResultSet::_resolved_attrs_copy
603153104ms1.02sDBIx::Class::ResultSet::::cursorDBIx::Class::ResultSet::cursor
1487813995.9ms3.15sDBIx::Class::ResultSet::::searchDBIx::Class::ResultSet::search
19491175.0ms1.40sDBIx::Class::ResultSet::::_count_rsDBIx::Class::ResultSet::_count_rs
20071174.2ms3.93sDBIx::Class::ResultSet::::singleDBIx::Class::ResultSet::single
16105563.7ms3.22sDBIx::Class::ResultSet::::allDBIx::Class::ResultSet::all
23186656.3ms2.89sDBIx::Class::ResultSet::::nextDBIx::Class::ResultSet::next
21344137.2ms70.3msDBIx::Class::ResultSet::::_has_resolved_attrDBIx::Class::ResultSet::_has_resolved_attr
462971136.7ms36.7msDBIx::Class::ResultSet::::CORE:regcompDBIx::Class::ResultSet::CORE:regcomp (opcode)
146781134.4ms34.4msDBIx::Class::ResultSet::::__ANON__[:3506]DBIx::Class::ResultSet::__ANON__[:3506]
8061128.9ms32.5msDBIx::Class::ResultSet::::_remove_aliasDBIx::Class::ResultSet::_remove_alias
195211128.6ms28.6msDBIx::Class::ResultSet::::__ANON__[:3493]DBIx::Class::ResultSet::__ANON__[:3493]
135655126.3ms26.3msDBIx::Class::ResultSet::::get_cacheDBIx::Class::ResultSet::get_cache
4492119.5ms285msDBIx::Class::ResultSet::::new_resultDBIx::Class::ResultSet::new_result
8062118.4ms50.8msDBIx::Class::ResultSet::::_merge_with_rscondDBIx::Class::ResultSet::_merge_with_rscond
19542215.9ms1.01sDBIx::Class::ResultSet::::get_columnDBIx::Class::ResultSet::get_column
3572113.4ms42.6msDBIx::Class::ResultSet::::_build_unique_condDBIx::Class::ResultSet::_build_unique_cond
147119.13ms124msDBIx::Class::ResultSet::::related_resultsetDBIx::Class::ResultSet::related_resultset
147117.75ms58.1msDBIx::Class::ResultSet::::_chain_relationshipDBIx::Class::ResultSet::_chain_relationship
2101227.74ms7.74msDBIx::Class::ResultSet::::_merge_joinpref_attrDBIx::Class::ResultSet::_merge_joinpref_attr
1954116.79ms6.79msDBIx::Class::ResultSet::::current_source_aliasDBIx::Class::ResultSet::current_source_alias
357215.62ms5.91msDBIx::Class::ResultSet::::_qualify_cond_columnsDBIx::Class::ResultSet::_qualify_cond_columns
1909115.01ms5.01msDBIx::Class::ResultSet::::_boolDBIx::Class::ResultSet::_bool
4743215.01ms5.01msDBIx::Class::ResultSet::::CORE:sortDBIx::Class::ResultSet::CORE:sort (opcode)
357112.57ms16.2msDBIx::Class::ResultSet::::__ANON__[:858]DBIx::Class::ResultSet::__ANON__[:858]
148111.51ms49.7msDBIx::Class::ResultSet::::resetDBIx::Class::ResultSet::reset
1111.40ms4.82msDBIx::Class::ResultSet::::BEGIN@11DBIx::Class::ResultSet::BEGIN@11
148221.32ms289msDBIx::Class::ResultSet::::firstDBIx::Class::ResultSet::first
147111.28ms146msDBIx::Class::ResultSet::::search_relatedDBIx::Class::ResultSet::search_related
19111.10ms2.16sDBIx::Class::ResultSet::::_rs_update_deleteDBIx::Class::ResultSet::_rs_update_delete
1111.02ms1.40msDBIx::Class::ResultSet::::BEGIN@8DBIx::Class::ResultSet::BEGIN@8
2422858µs2.78sDBIx::Class::ResultSet::::createDBIx::Class::ResultSet::create
1911373µs2.16sDBIx::Class::ResultSet::::deleteDBIx::Class::ResultSet::delete
2611339µs6.23msDBIx::Class::ResultSet::::__ANON__[:793]DBIx::Class::ResultSet::__ANON__[:793]
11111µs255µsDBIx::Class::ResultSet::::BEGIN@22DBIx::Class::ResultSet::BEGIN@22
11111µs13µsDBIx::Class::ResultSet::::BEGIN@3DBIx::Class::ResultSet::BEGIN@3
1119µs64µsDBIx::Class::ResultSet::::BEGIN@25DBIx::Class::ResultSet::BEGIN@25
1118µs51µsDBIx::Class::ResultSet::::BEGIN@9DBIx::Class::ResultSet::BEGIN@9
1118µs92µsDBIx::Class::ResultSet::::BEGIN@6DBIx::Class::ResultSet::BEGIN@6
1118µs40µsDBIx::Class::ResultSet::::BEGIN@10DBIx::Class::ResultSet::BEGIN@10
1117µs14µsDBIx::Class::ResultSet::::BEGIN@4DBIx::Class::ResultSet::BEGIN@4
1116µs65µsDBIx::Class::ResultSet::::BEGIN@5DBIx::Class::ResultSet::BEGIN@5
1116µs6µsDBIx::Class::ResultSet::::BEGIN@14DBIx::Class::ResultSet::BEGIN@14
1115µs5µsDBIx::Class::ResultSet::::BEGIN@7DBIx::Class::ResultSet::BEGIN@7
1115µs5µsDBIx::Class::ResultSet::::BEGIN@16DBIx::Class::ResultSet::BEGIN@16
0000s0sDBIx::Class::ResultSet::::STORABLE_freezeDBIx::Class::ResultSet::STORABLE_freeze
0000s0sDBIx::Class::ResultSet::::STORABLE_thawDBIx::Class::ResultSet::STORABLE_thaw
0000s0sDBIx::Class::ResultSet::::__ANON__[:2152]DBIx::Class::ResultSet::__ANON__[:2152]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3159]DBIx::Class::ResultSet::__ANON__[:3159]
0000s0sDBIx::Class::ResultSet::::__ANON__[:332]DBIx::Class::ResultSet::__ANON__[:332]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3488]DBIx::Class::ResultSet::__ANON__[:3488]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3491]DBIx::Class::ResultSet::__ANON__[:3491]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3499]DBIx::Class::ResultSet::__ANON__[:3499]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3504]DBIx::Class::ResultSet::__ANON__[:3504]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3513]DBIx::Class::ResultSet::__ANON__[:3513]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3517]DBIx::Class::ResultSet::__ANON__[:3517]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3519]DBIx::Class::ResultSet::__ANON__[:3519]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3527]DBIx::Class::ResultSet::__ANON__[:3527]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3532]DBIx::Class::ResultSet::__ANON__[:3532]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3534]DBIx::Class::ResultSet::__ANON__[:3534]
0000s0sDBIx::Class::ResultSet::::__ANON__[:3541]DBIx::Class::ResultSet::__ANON__[:3541]
0000s0sDBIx::Class::ResultSet::::__ANON__[:356]DBIx::Class::ResultSet::__ANON__[:356]
0000s0sDBIx::Class::ResultSet::::__ANON__[:860]DBIx::Class::ResultSet::__ANON__[:860]
0000s0sDBIx::Class::ResultSet::::_calculate_scoreDBIx::Class::ResultSet::_calculate_score
0000s0sDBIx::Class::ResultSet::::_collapse_condDBIx::Class::ResultSet::_collapse_cond
0000s0sDBIx::Class::ResultSet::::_collapse_queryDBIx::Class::ResultSet::_collapse_query
0000s0sDBIx::Class::ResultSet::::_count_subq_rsDBIx::Class::ResultSet::_count_subq_rs
0000s0sDBIx::Class::ResultSet::::_non_unique_find_fallbackDBIx::Class::ResultSet::_non_unique_find_fallback
0000s0sDBIx::Class::ResultSet::::_normalize_populate_argsDBIx::Class::ResultSet::_normalize_populate_args
0000s0sDBIx::Class::ResultSet::::_rollout_arrayDBIx::Class::ResultSet::_rollout_array
0000s0sDBIx::Class::ResultSet::::_rollout_attrDBIx::Class::ResultSet::_rollout_attr
0000s0sDBIx::Class::ResultSet::::_rollout_hashDBIx::Class::ResultSet::_rollout_hash
0000s0sDBIx::Class::ResultSet::::as_queryDBIx::Class::ResultSet::as_query
0000s0sDBIx::Class::ResultSet::::as_subselect_rsDBIx::Class::ResultSet::as_subselect_rs
0000s0sDBIx::Class::ResultSet::::clear_cacheDBIx::Class::ResultSet::clear_cache
0000s0sDBIx::Class::ResultSet::::count_literalDBIx::Class::ResultSet::count_literal
0000s0sDBIx::Class::ResultSet::::count_rsDBIx::Class::ResultSet::count_rs
0000s0sDBIx::Class::ResultSet::::delete_allDBIx::Class::ResultSet::delete_all
0000s0sDBIx::Class::ResultSet::::find_or_createDBIx::Class::ResultSet::find_or_create
0000s0sDBIx::Class::ResultSet::::find_or_newDBIx::Class::ResultSet::find_or_new
0000s0sDBIx::Class::ResultSet::::is_orderedDBIx::Class::ResultSet::is_ordered
0000s0sDBIx::Class::ResultSet::::is_pagedDBIx::Class::ResultSet::is_paged
0000s0sDBIx::Class::ResultSet::::pageDBIx::Class::ResultSet::page
0000s0sDBIx::Class::ResultSet::::pagerDBIx::Class::ResultSet::pager
0000s0sDBIx::Class::ResultSet::::populateDBIx::Class::ResultSet::populate
0000s0sDBIx::Class::ResultSet::::search_likeDBIx::Class::ResultSet::search_like
0000s0sDBIx::Class::ResultSet::::search_literalDBIx::Class::ResultSet::search_literal
0000s0sDBIx::Class::ResultSet::::search_related_rsDBIx::Class::ResultSet::search_related_rs
0000s0sDBIx::Class::ResultSet::::set_cacheDBIx::Class::ResultSet::set_cache
0000s0sDBIx::Class::ResultSet::::sliceDBIx::Class::ResultSet::slice
0000s0sDBIx::Class::ResultSet::::throw_exceptionDBIx::Class::ResultSet::throw_exception
0000s0sDBIx::Class::ResultSet::::updateDBIx::Class::ResultSet::update
0000s0sDBIx::Class::ResultSet::::update_allDBIx::Class::ResultSet::update_all
0000s0sDBIx::Class::ResultSet::::update_or_createDBIx::Class::ResultSet::update_or_create
0000s0sDBIx::Class::ResultSet::::update_or_newDBIx::Class::ResultSet::update_or_new
Call graph for these subroutines as a Graphviz dot language file.
Line State
ments
Time
on line
Calls Time
in subs
Code
1package DBIx::Class::ResultSet;
2
3317µs215µs
# spent 13µs (11+2) within DBIx::Class::ResultSet::BEGIN@3 which was called: # once (11µs+2µs) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 3
use strict;
# spent 13µs making 1 call to DBIx::Class::ResultSet::BEGIN@3 # spent 2µs making 1 call to strict::import
4319µs221µs
# spent 14µs (7+7) within DBIx::Class::ResultSet::BEGIN@4 which was called: # once (7µs+7µs) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 4
use warnings;
# spent 14µs making 1 call to DBIx::Class::ResultSet::BEGIN@4 # spent 7µs making 1 call to warnings::import
5319µs2124µs
# spent 65µs (6+59) within DBIx::Class::ResultSet::BEGIN@5 which was called: # once (6µs+59µs) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 5
use base qw/DBIx::Class/;
# spent 65µs making 1 call to DBIx::Class::ResultSet::BEGIN@5 # spent 59µs making 1 call to base::import
6320µs2176µs
# spent 92µs (8+84) within DBIx::Class::ResultSet::BEGIN@6 which was called: # once (8µs+84µs) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 6
use DBIx::Class::Carp;
# spent 92µs making 1 call to DBIx::Class::ResultSet::BEGIN@6 # spent 84µs making 1 call to DBIx::Class::Carp::import
7318µs15µs
# spent 5µs within DBIx::Class::ResultSet::BEGIN@7 which was called: # once (5µs+0s) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 7
use DBIx::Class::Exception;
# spent 5µs making 1 call to DBIx::Class::ResultSet::BEGIN@7
83101µs11.40ms
# spent 1.40ms (1.02+386µs) within DBIx::Class::ResultSet::BEGIN@8 which was called: # once (1.02ms+386µs) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 8
use DBIx::Class::ResultSetColumn;
# spent 1.40ms making 1 call to DBIx::Class::ResultSet::BEGIN@8
9320µs294µs
# spent 51µs (8+43) within DBIx::Class::ResultSet::BEGIN@9 which was called: # once (8µs+43µs) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 9
use Scalar::Util qw/blessed weaken/;
# spent 51µs making 1 call to DBIx::Class::ResultSet::BEGIN@9 # spent 43µs making 1 call to Exporter::import
10319µs273µs
# spent 40µs (8+32) within DBIx::Class::ResultSet::BEGIN@10 which was called: # once (8µs+32µs) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 10
use Try::Tiny;
# spent 40µs making 1 call to DBIx::Class::ResultSet::BEGIN@10 # spent 33µs making 1 call to Exporter::import
113102µs14.82ms
# spent 4.82ms (1.40+3.42) within DBIx::Class::ResultSet::BEGIN@11 which was called: # once (1.40ms+3.42ms) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 11
use Data::Compare (); # no imports!!! guard against insane architecture
# spent 4.82ms making 1 call to DBIx::Class::ResultSet::BEGIN@11
12
13# not importing first() as it will clash with our own method
14338µs16µs
# spent 6µs within DBIx::Class::ResultSet::BEGIN@14 which was called: # once (6µs+0s) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 14
use List::Util ();
# spent 6µs making 1 call to DBIx::Class::ResultSet::BEGIN@14
15
16
# spent 5µs within DBIx::Class::ResultSet::BEGIN@16 which was called: # once (5µs+0s) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 20
BEGIN {
17 # De-duplication in _merge_attr() is disabled, but left in for reference
18 # (the merger is used for other things that ought not to be de-duped)
1915µs *__HM_DEDUP = sub () { 0 };
20114µs15µs}
# spent 5µs making 1 call to DBIx::Class::ResultSet::BEGIN@16
21
22330µs2499µs
# spent 255µs (11+244) within DBIx::Class::ResultSet::BEGIN@22 which was called: # once (11µs+244µs) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 22
use namespace::clean;
# spent 255µs making 1 call to DBIx::Class::ResultSet::BEGIN@22 # spent 244µs making 1 call to namespace::clean::import
23
24use overload
25156µs
# spent 64µs (9+56) within DBIx::Class::ResultSet::BEGIN@25 which was called: # once (9µs+56µs) by DBIx::Class::ResultSource::Table::BEGIN@6 at line 27
'0+' => "count",
# spent 56µs making 1 call to overload::import
26 'bool' => "_bool",
2739.27ms164µs fallback => 1;
# spent 64µs making 1 call to DBIx::Class::ResultSet::BEGIN@25
28
29116µs1173µs__PACKAGE__->mk_group_accessors('simple' => qw/_result_class result_source/);
# spent 173µs making 1 call to Class::Accessor::Grouped::mk_group_accessors
30
31=head1 NAME
32
33DBIx::Class::ResultSet - Represents a query used for fetching a set of results.
34
35=head1 SYNOPSIS
36
37 my $users_rs = $schema->resultset('User');
38 while( $user = $users_rs->next) {
39 print $user->username;
40 }
41
42 my $registered_users_rs = $schema->resultset('User')->search({ registered => 1 });
43 my @cds_in_2005 = $schema->resultset('CD')->search({ year => 2005 })->all();
44
45=head1 DESCRIPTION
46
47A ResultSet is an object which stores a set of conditions representing
48a query. It is the backbone of DBIx::Class (i.e. the really
49important/useful bit).
50
51No SQL is executed on the database when a ResultSet is created, it
52just stores all the conditions needed to create the query.
53
54A basic ResultSet representing the data of an entire table is returned
55by calling C<resultset> on a L<DBIx::Class::Schema> and passing in a
56L<Source|DBIx::Class::Manual::Glossary/Source> name.
57
58 my $users_rs = $schema->resultset('User');
59
60A new ResultSet is returned from calling L</search> on an existing
61ResultSet. The new one will contain all the conditions of the
62original, plus any new conditions added in the C<search> call.
63
64A ResultSet also incorporates an implicit iterator. L</next> and L</reset>
65can be used to walk through all the L<DBIx::Class::Row>s the ResultSet
66represents.
67
68The query that the ResultSet represents is B<only> executed against
69the database when these methods are called:
70L</find>, L</next>, L</all>, L</first>, L</single>, L</count>.
71
72If a resultset is used in a numeric context it returns the L</count>.
73However, if it is used in a boolean context it is B<always> true. So if
74you want to check if a resultset has any results, you must use C<if $rs
75!= 0>.
76
77=head1 EXAMPLES
78
79=head2 Chaining resultsets
80
81Let's say you've got a query that needs to be run to return some data
82to the user. But, you have an authorization system in place that
83prevents certain users from seeing certain information. So, you want
84to construct the basic query in one method, but add constraints to it in
85another.
86
87 sub get_data {
88 my $self = shift;
89 my $request = $self->get_request; # Get a request object somehow.
90 my $schema = $self->result_source->schema;
91
92 my $cd_rs = $schema->resultset('CD')->search({
93 title => $request->param('title'),
94 year => $request->param('year'),
95 });
96
97 $cd_rs = $self->apply_security_policy( $cd_rs );
98
99 return $cd_rs->all();
100 }
101
102 sub apply_security_policy {
103 my $self = shift;
104 my ($rs) = @_;
105
106 return $rs->search({
107 subversive => 0,
108 });
109 }
110
111=head3 Resolving conditions and attributes
112
113When a resultset is chained from another resultset, conditions and
114attributes with the same keys need resolving.
115
116L</join>, L</prefetch>, L</+select>, L</+as> attributes are merged
117into the existing ones from the original resultset.
118
119The L</where> and L</having> attributes, and any search conditions, are
120merged with an SQL C<AND> to the existing condition from the original
121resultset.
122
123All other attributes are overridden by any new ones supplied in the
124search attributes.
125
126=head2 Multiple queries
127
128Since a resultset just defines a query, you can do all sorts of
129things with it with the same object.
130
131 # Don't hit the DB yet.
132 my $cd_rs = $schema->resultset('CD')->search({
133 title => 'something',
134 year => 2009,
135 });
136
137 # Each of these hits the DB individually.
138 my $count = $cd_rs->count;
139 my $most_recent = $cd_rs->get_column('date_released')->max();
140 my @records = $cd_rs->all;
141
142And it's not just limited to SELECT statements.
143
144 $cd_rs->delete();
145
146This is even cooler:
147
148 $cd_rs->create({ artist => 'Fred' });
149
150Which is the same as:
151
152 $schema->resultset('CD')->create({
153 title => 'something',
154 year => 2009,
155 artist => 'Fred'
156 });
157
158See: L</search>, L</count>, L</get_column>, L</all>, L</create>.
159
160=head1 METHODS
161
162=head2 new
163
164=over 4
165
166=item Arguments: $source, \%$attrs
167
168=item Return Value: $rs
169
170=back
171
172The resultset constructor. Takes a source object (usually a
173L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see
174L</ATTRIBUTES> below). Does not perform any queries -- these are
175executed as needed by the other methods.
176
177Generally you won't need to construct a resultset manually. You'll
178automatically get one from e.g. a L</search> called in scalar context:
179
180 my $rs = $schema->resultset('CD')->search({ title => '100th Window' });
181
182IMPORTANT: If called on an object, proxies to new_result instead so
183
184 my $cd = $schema->resultset('CD')->new({ title => 'Spoon' });
185
186will return a CD object, not a ResultSet.
187
188=cut
189
190
# spent 2.34s (604ms+1.73) within DBIx::Class::ResultSet::new which was called 25061 times, avg 93µs/call: # 16979 times (352ms+909ms) by DBIx::Class::ResultSet::search_rs at line 434, avg 74µs/call # 5708 times (203ms+372ms) by DBIx::Class::ResultSource::resultset at line 1039 of DBIx/Class/ResultSource.pm, avg 101µs/call # 1949 times (44.0ms+187ms) by DBIx::Class::ResultSet::_count_rs at line 1498, avg 118µs/call # 147 times (2.11ms+131ms) by Tapper::Schema::TestrunDB::Result::Testrun::rerun at line 151 of Tapper/Schema/TestrunDB/Result/Testrun.pm, avg 908µs/call # 147 times (940µs+58.9ms) by Tapper::Schema::TestrunDB::Result::Testrun::rerun at line 122 of Tapper/Schema/TestrunDB/Result/Testrun.pm, avg 407µs/call # 129 times (1.59ms+75.8ms) by Tapper::Schema::TestrunDB::Result::Testrun::assign_preconditions at line 193 of Tapper/Schema/TestrunDB/Result/Testrun.pm, avg 600µs/call # once (14µs+468µs) by main::RUNTIME at line 40 of xt/tapper-mcp-scheduler-with-db-longrun.t # once (6µs+182µs) by main::RUNTIME at line 39 of xt/tapper-mcp-scheduler-with-db-longrun.t
sub new {
191271846634ms my $class = shift;
192425267ms return $class->new_result(@_) if ref $class;
# spent 267ms making 425 calls to DBIx::Class::ResultSet::new_result, avg 628µs/call
193
194 my ($source, $attrs) = @_;
1952463667.6ms $source = $source->resolve
# spent 67.6ms making 24636 calls to UNIVERSAL::isa, avg 3µs/call
196 if $source->isa('DBIx::Class::ResultSourceHandle');
197 $attrs = { %{$attrs||{}} };
198
199 if ($attrs->{page}) {
200 $attrs->{rows} ||= 10;
201 }
202
203 $attrs->{alias} ||= 'me';
204
205 my $self = bless {
206 result_source => $source,
207 cond => $attrs->{where},
208 pager => undef,
209 attrs => $attrs,
210 }, $class;
211
212 # if there is a dark selector, this means we are already in a
213 # chain and the cleanup/sanification was taken care of by
214 # _search_rs already
21524636664ms $self->_normalize_selection($attrs)
# spent 664ms making 24636 calls to DBIx::Class::ResultSet::_normalize_selection, avg 27µs/call
216 unless $attrs->{_dark_selector};
217
21847265737ms $self->result_class(
# spent 416ms making 22629 calls to DBIx::Class::ResultSource::result_class, avg 18µs/call # spent 321ms making 24636 calls to DBIx::Class::ResultSet::result_class, avg 13µs/call
219 $attrs->{result_class} || $source->result_class
220 );
221
222 $self;
223}
224
225=head2 search
226
227=over 4
228
229=item Arguments: $cond, \%attrs?
230
231=item Return Value: $resultset (scalar context) || @row_objs (list context)
232
233=back
234
235 my @cds = $cd_rs->search({ year => 2001 }); # "... WHERE year = 2001"
236 my $new_rs = $cd_rs->search({ year => 2005 });
237
238 my $new_rs = $cd_rs->search([ { year => 2005 }, { year => 2004 } ]);
239 # year = 2005 OR year = 2004
240
241In list context, C<< ->all() >> is called implicitly on the resultset, thus
242returning a list of row objects instead. To avoid that, use L</search_rs>.
243
244If you need to pass in additional attributes but no additional condition,
245call it as C<search(undef, \%attrs)>.
246
247 # "SELECT name, artistid FROM $artist_table"
248 my @all_artists = $schema->resultset('Artist')->search(undef, {
249 columns => [qw/name artistid/],
250 });
251
252For a list of attributes that can be passed to C<search>, see
253L</ATTRIBUTES>. For more examples of using this function, see
254L<Searching|DBIx::Class::Manual::Cookbook/Searching>. For a complete
255documentation for the first argument, see L<SQL::Abstract>
256and its extension L<DBIx::Class::SQLMaker>.
257
258For more help on using joins with search, see L<DBIx::Class::Manual::Joining>.
259
260=head3 CAVEAT
261
262Note that L</search> does not process/deflate any of the values passed in the
263L<SQL::Abstract>-compatible search condition structure. This is unlike other
264condition-bound methods L</new>, L</create> and L</find>. The user must ensure
265manually that any value passed to this method will stringify to something the
266RDBMS knows how to deal with. A notable example is the handling of L<DateTime>
267objects, for more info see:
268L<DBIx::Class::Manual::Cookbook/Formatting_DateTime_objects_in_queries>.
269
270=cut
271
272
# spent 3.15s (95.9ms+3.05) within DBIx::Class::ResultSet::search which was called 14878 times, avg 211µs/call: # 5440 times (38.9ms+1.28s) by DBIx::Class::Relationship::Base::search_related at line 512 of DBIx/Class/Relationship/Base.pm, avg 242µs/call # 3531 times (25.6ms+602ms) by DBIx::Class::Relationship::Base::related_resultset at line 493 of DBIx/Class/Relationship/Base.pm, avg 178µs/call # 2007 times (11.3ms+342ms) by DBIx::Class::ResultSet::find at line 803, avg 176µs/call # 1954 times (9.08ms+540ms) by DBIx::Class::ResultSetColumn::_resultset at line 471 of DBIx/Class/ResultSetColumn.pm, avg 281µs/call # 807 times (2.63ms+113ms) by Tapper::Schema::TestrunDB::Result::Queue::queued_testruns at line 42 of Tapper/Schema/TestrunDB/Result/Queue.pm, avg 143µs/call # 477 times (3.29ms+69.3ms) by Tapper::MCP::Scheduler::PrioQueue::get_testrequests at line 38 of lib/Tapper/MCP/Scheduler/PrioQueue.pm, avg 152µs/call # 214 times (2.86ms+50.5ms) by Tapper::Schema::TestrunDB::ResultSet::Host::free_hosts at line 17 of Tapper/Schema/TestrunDB/ResultSet/Host.pm, avg 249µs/call # 147 times (658µs+19.6ms) by DBIx::Class::ResultSet::search_related at line 923, avg 138µs/call # 147 times (495µs+17.9ms) by Tapper::Schema::TestrunDB::Result::Testrun::rerun at line 176 of Tapper/Schema/TestrunDB/Result/Testrun.pm, avg 125µs/call # 147 times (999µs+15.1ms) by Tapper::Schema::TestrunDB::Result::Testrun::rerun at line 132 of Tapper/Schema/TestrunDB/Result/Testrun.pm, avg 110µs/call # 5 times (70µs+2.69ms) by DBIx::Class::Schema::Versioned::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/Schema/Versioned.pm:533] at line 530 of DBIx/Class/Schema/Versioned.pm, avg 552µs/call # once (7µs+168µs) by Tapper::Schema::TestrunDB::Result::TestrunScheduling::gen_schema_functions at line 93 of Tapper/Schema/TestrunDB/Result/TestrunScheduling.pm # once (6µs+101µs) by DBIx::Class::Schema::Versioned::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/Schema/Versioned.pm:752] at line 750 of DBIx/Class/Schema/Versioned.pm
sub search {
2734463488.7ms my $self = shift;
274148782.52s my $rs = $self->search_rs( @_ );
# spent 2.52s making 14878 calls to DBIx::Class::ResultSet::search_rs, avg 169µs/call
275
276331527ms if (wantarray) {
# spent 527ms making 331 calls to DBIx::Class::ResultSet::all, avg 1.59ms/call
277 return $rs->all;
278 }
279 elsif (defined wantarray) {
280 return $rs;
281 }
282 else {
283 # we can be called by a relationship helper, which in
284 # turn may be called in void context due to some braindead
285 # overload or whatever else the user decided to be clever
286 # at this particular day. Thus limit the exception to
287 # external code calls only
288 $self->throw_exception ('->search is *not* a mutator, calling it in void context makes no sense')
289 if (caller)[0] !~ /^\QDBIx::Class::/;
290
291 return ();
292 }
293}
294
295=head2 search_rs
296
297=over 4
298
299=item Arguments: $cond, \%attrs?
300
301=item Return Value: $resultset
302
303=back
304
305This method does the same exact thing as search() except it will
306always return a resultset, even in list context.
307
308=cut
309
310
# spent 2.88s (1.07+1.81) within DBIx::Class::ResultSet::search_rs which was called 16979 times, avg 169µs/call: # 14878 times (979ms+1.54s) by DBIx::Class::ResultSet::search at line 274, avg 169µs/call # 1954 times (82.7ms+256ms) by DBIx::Class::ResultSetColumn::new at line 79 of DBIx/Class/ResultSetColumn.pm, avg 173µs/call # 147 times (8.58ms+10.2ms) by DBIx::Class::ResultSet::related_resultset at line 2909, avg 128µs/call
sub search_rs {
311339580565ms my $self = shift;
312
313 # Special-case handling for (undef, undef).
314 if ( @_ == 2 && !defined $_[1] && !defined $_[0] ) {
315 @_ = ();
316 }
317
318 my $call_attrs = {};
319922328.8ms if (@_ > 1) {
320 if (ref $_[-1] eq 'HASH') {
321 # copy for _normalize_selection
322 $call_attrs = { %{ pop @_ } };
323 }
324 elsif (! defined $_[-1] ) {
325 pop @_; # search({}, undef)
326 }
327 }
328
329 # see if we can keep the cache (no $rs changes)
330 my $cache;
331 my %safe = (alias => 1, cache => 1);
332922345.9ms2452053.4ms if ( ! List::Util::first { !$safe{$_} } keys %$call_attrs and (
# spent 36.2ms making 16979 calls to List::Util::first, avg 2µs/call # spent 17.2ms making 7541 calls to DBIx::Class::ResultSet::get_cache, avg 2µs/call
333 ! defined $_[0]
334 or
335 ref $_[0] eq 'HASH' && ! keys %{$_[0]}
336 or
337 ref $_[0] eq 'ARRAY' && ! @{$_[0]}
338 )) {
339 $cache = $self->get_cache;
340 }
341
3422434µs my $rsrc = $self->result_source;
# spent 434µs making 2 calls to DBIx::Class::ResultSet::result_source, avg 217µs/call
343
344 my $old_attrs = { %{$self->{attrs}} };
345 my $old_having = delete $old_attrs->{having};
346 my $old_where = delete $old_attrs->{where};
347
348 my $new_attrs = { %$old_attrs };
349
350 # take care of call attrs (only if anything is changing)
35192230181ms if (keys %$call_attrs) {
352
353 my @selector_attrs = qw/select as columns cols +select +as +columns include_columns/;
354
355 # reset the current selector list if new selectors are supplied
3563493558.1ms922329.8ms if (List::Util::first { exists $call_attrs->{$_} } qw/columns cols select as/) {
# spent 29.8ms making 9223 calls to List::Util::first, avg 3µs/call
357 delete @{$old_attrs}{(@selector_attrs, '_dark_selector')};
358 }
359
360 # Normalize the new selector list (operates on the passed-in attr structure)
361 # Need to do it on every chain instead of only once on _resolved_attrs, in
362 # order to allow detection of empty vs partial 'as'
363 $call_attrs->{_dark_selector} = $old_attrs->{_dark_selector}
364 if $old_attrs->{_dark_selector};
3659223203ms $self->_normalize_selection ($call_attrs);
# spent 203ms making 9223 calls to DBIx::Class::ResultSet::_normalize_selection, avg 22µs/call
366
367 # start with blind overwriting merge, exclude selector attrs
368 $new_attrs = { %{$old_attrs}, %{$call_attrs} };
369 delete @{$new_attrs}{@selector_attrs};
370
371 for (@selector_attrs) {
3727378480.6ms390955.0ms $new_attrs->{$_} = $self->_merge_attr($old_attrs->{$_}, $call_attrs->{$_})
# spent 55.0ms making 3909 calls to DBIx::Class::ResultSet::_merge_attr, avg 14µs/call
373 if ( exists $old_attrs->{$_} or exists $call_attrs->{$_} );
374 }
375
376 # older deprecated name, use only if {columns} is not there
377 if (my $c = delete $new_attrs->{cols}) {
378 if ($new_attrs->{columns}) {
379 carp "Resultset specifies both the 'columns' and the legacy 'cols' attributes - ignoring 'cols'";
380 }
381 else {
382 $new_attrs->{columns} = $c;
383 }
384 }
385
386
387 # join/prefetch use their own crazy merging heuristics
388 foreach my $key (qw/join prefetch/) {
3891844619.9ms $new_attrs->{$key} = $self->_merge_joinpref_attr($old_attrs->{$key}, $call_attrs->{$key})
390 if exists $call_attrs->{$key};
391 }
392
393 # stack binds together
394 $new_attrs->{bind} = [ @{ $old_attrs->{bind} || [] }, @{ $call_attrs->{bind} || [] } ];
395 }
396
397
398 # rip apart the rest of @_, parse a condition
399958513.7ms my $call_cond = do {
400
401 if (ref $_[0] eq 'HASH') {
402 (keys %{$_[0]}) ? $_[0] : undef
403 }
404 elsif (@_ == 1) {
405 $_[0]
406 }
407 elsif (@_ % 2) {
408 $self->throw_exception('Odd number of arguments to search')
409 }
410 else {
411 +{ @_ }
412 }
413
414 } if @_;
415
416 if( @_ > 1 and ! $rsrc->result_class->isa('DBIx::Class::CDBICompat') ) {
417 carp_unique 'search( %condition ) is deprecated, use search( \%condition ) instead';
418 }
419
420 for ($old_where, $call_cond) {
4215158194.1ms if (defined $_) {
42217623205ms $new_attrs->{where} = $self->_stack_cond (
# spent 205ms making 17623 calls to DBIx::Class::ResultSet::_stack_cond, avg 12µs/call
423 $_, $new_attrs->{where}
424 );
425 }
426 }
427
428 if (defined $old_having) {
429 $new_attrs->{having} = $self->_stack_cond (
430 $old_having, $new_attrs->{having}
431 )
432 }
433
434169791.26s my $rs = (ref $self)->new($rsrc, $new_attrs);
# spent 1.26s making 16979 calls to DBIx::Class::ResultSet::new, avg 74µs/call
435
436 $rs->set_cache($cache) if ($cache);
437
438 return $rs;
439}
440
4411300nsmy $dark_sel_dumper;
442
# spent 866ms (611+256) within DBIx::Class::ResultSet::_normalize_selection which was called 33859 times, avg 26µs/call: # 24636 times (467ms+197ms) by DBIx::Class::ResultSet::new at line 215, avg 27µs/call # 9223 times (144ms+58.9ms) by DBIx::Class::ResultSet::search_rs at line 365, avg 22µs/call
sub _normalize_selection {
443101577140ms my ($self, $attrs) = @_;
444
445 # legacy syntax
446 $attrs->{'+columns'} = $self->_merge_attr($attrs->{'+columns'}, delete $attrs->{include_columns})
447 if exists $attrs->{include_columns};
448
449 # columns are always placed first, however
450
451 # Keep the X vs +X separation until _resolved_attrs time - this allows to
452 # delay the decision on whether to use a default select list ($rsrc->columns)
453 # allowing stuff like the remove_columns helper to work
454 #
455 # select/as +select/+as pairs need special handling - the amount of select/as
456 # elements in each pair does *not* have to be equal (think multicolumn
457 # selectors like distinct(foo, bar) ). If the selector is bare (no 'as'
458 # supplied at all) - try to infer the alias, either from the -as parameter
459 # of the selector spec, or use the parameter whole if it looks like a column
460 # name (ugly legacy heuristic). If all fails - leave the selector bare (which
461 # is ok as well), but make sure no more additions to the 'as' chain take place
462 for my $pref ('', '+') {
463
464 my ($sel, $as) = map {
465692792461ms my $key = "${pref}${_}";
466
467 my $val = [ ref $attrs->{$key} eq 'ARRAY'
468 ? @{$attrs->{$key}}
469 : $attrs->{$key} || ()
470 ];
471 delete $attrs->{$key};
472 $val;
473 } qw/select as/;
474
4755991233.7ms if (! @$as and ! @$sel ) {
476 next;
477 }
478 elsif (@$as and ! @$sel) {
479 $self->throw_exception(
480 "Unable to handle ${pref}as specification (@$as) without a corresponding ${pref}select"
481 );
482 }
483 elsif( ! @$as ) {
484 # no as part supplied at all - try to deduce (unless explicit end of named selection is declared)
485 # if any @$as has been supplied we assume the user knows what (s)he is doing
486 # and blindly keep stacking up pieces
487 unless ($attrs->{_dark_selector}) {
488 SELECTOR:
489 for (@$sel) {
490 if ( ref $_ eq 'HASH' and exists $_->{-as} ) {
491 push @$as, $_->{-as};
492 }
493 # assume any plain no-space, no-parenthesis string to be a column spec
494 # FIXME - this is retarded but is necessary to support shit like 'count(foo)'
495 elsif ( ! ref $_ and $_ =~ /^ [^\s\(\)]+ $/x) {
496 push @$as, $_;
497 }
498 # if all else fails - raise a flag that no more aliasing will be allowed
499 else {
500 $attrs->{_dark_selector} = {
501 plus_stage => $pref,
502 string => ($dark_sel_dumper ||= do {
503 require Data::Dumper::Concise;
504 Data::Dumper::Concise::DumperObject()->Indent(0);
505 })->Values([$_])->Dump
506 ,
507 };
508 last SELECTOR;
509 }
510 }
511 }
512 }
513 elsif (@$as < @$sel) {
514 $self->throw_exception(
515 "Unable to handle an ${pref}as specification (@$as) with less elements than the corresponding ${pref}select"
516 );
517 }
518 elsif ($pref and $attrs->{_dark_selector}) {
519 $self->throw_exception(
520 "Unable to process named '+select', resultset contains an unnamed selector $attrs->{_dark_selector}{string}"
521 );
522 }
523
524
525 # merge result
5267806139ms $attrs->{"${pref}select"} = $self->_merge_attr($attrs->{"${pref}select"}, $sel);
# spent 139ms making 7806 calls to DBIx::Class::ResultSet::_merge_attr, avg 18µs/call
5277806117ms $attrs->{"${pref}as"} = $self->_merge_attr($attrs->{"${pref}as"}, $as);
# spent 117ms making 7806 calls to DBIx::Class::ResultSet::_merge_attr, avg 15µs/call
528 }
529}
530
531
# spent 205ms within DBIx::Class::ResultSet::_stack_cond which was called 17623 times, avg 12µs/call: # 17623 times (205ms+0s) by DBIx::Class::ResultSet::search_rs at line 422, avg 12µs/call
sub _stack_cond {
53270492118ms my ($self, $left, $right) = @_;
533
534 # collapse single element top-level conditions
535 # (single pass only, unlikely to need recursion)
536 for ($left, $right) {
5377208295.1ms if (ref $_ eq 'ARRAY') {
5381831µs if (@$_ == 0) {
539 $_ = undef;
540 }
541 elsif (@$_ == 1) {
542 $_ = $_->[0];
543 }
544 }
545 elsif (ref $_ eq 'HASH') {
546 my ($first, $more) = keys %$_;
547
548 # empty hash
5491812513.3ms if (! defined $first) {
550 $_ = undef;
551 }
552 # one element hash
553 elsif (! defined $more) {
554 if ($first eq '-and' and ref $_->{'-and'} eq 'HASH') {
555 $_ = $_->{'-and'};
556 }
557 elsif ($first eq '-or' and ref $_->{'-or'} eq 'ARRAY') {
558 $_ = $_->{'-or'};
559 }
560 }
561 }
562 }
563
564 # merge hashes with weeding out of duplicates (simple cases only)
56524213.09ms if (ref $left eq 'HASH' and ref $right eq 'HASH') {
566
567 # shallow copy to destroy
568 $right = { %$right };
569 for (grep { exists $right->{$_} } keys %$left) {
570 # the use of eq_deeply here is justified - the rhs of an
571 # expression can contain a lot of twisted weird stuff
572 delete $right->{$_} if Data::Compare::Compare( $left->{$_}, $right->{$_} );
573 }
574
575 $right = undef unless keys %$right;
576 }
577
578
5798073.25ms if (defined $left xor defined $right) {
580 return defined $left ? $left : $right;
581 }
582 elsif (! defined $left) {
583 return undef;
584 }
585 else {
586 return { -and => [ $left, $right ] };
587 }
588}
589
590=head2 search_literal
591
592=over 4
593
594=item Arguments: $sql_fragment, @bind_values
595
596=item Return Value: $resultset (scalar context) || @row_objs (list context)
597
598=back
599
600 my @cds = $cd_rs->search_literal('year = ? AND title = ?', qw/2001 Reload/);
601 my $newrs = $artist_rs->search_literal('name = ?', 'Metallica');
602
603Pass a literal chunk of SQL to be added to the conditional part of the
604resultset query.
605
606CAVEAT: C<search_literal> is provided for Class::DBI compatibility and should
607only be used in that context. C<search_literal> is a convenience method.
608It is equivalent to calling $schema->search(\[]), but if you want to ensure
609columns are bound correctly, use C<search>.
610
611Example of how to use C<search> instead of C<search_literal>
612
613 my @cds = $cd_rs->search_literal('cdid = ? AND (artist = ? OR artist = ?)', (2, 1, 2));
614 my @cds = $cd_rs->search(\[ 'cdid = ? AND (artist = ? OR artist = ?)', [ 'cdid', 2 ], [ 'artist', 1 ], [ 'artist', 2 ] ]);
615
616
617See L<DBIx::Class::Manual::Cookbook/Searching> and
618L<DBIx::Class::Manual::FAQ/Searching> for searching techniques that do not
619require C<search_literal>.
620
621=cut
622
623sub search_literal {
624 my ($self, $sql, @bind) = @_;
625 my $attr;
626 if ( @bind && ref($bind[-1]) eq 'HASH' ) {
627 $attr = pop @bind;
628 }
629 return $self->search(\[ $sql, map [ __DUMMY__ => $_ ], @bind ], ($attr || () ));
630}
631
632=head2 find
633
634=over 4
635
636=item Arguments: \%columns_values | @pk_values, \%attrs?
637
638=item Return Value: $row_object | undef
639
640=back
641
642Finds and returns a single row based on supplied criteria. Takes either a
643hashref with the same format as L</create> (including inference of foreign
644keys from related objects), or a list of primary key values in the same
645order as the L<primary columns|DBIx::Class::ResultSource/primary_columns>
646declaration on the L</result_source>.
647
648In either case an attempt is made to combine conditions already existing on
649the resultset with the condition passed to this method.
650
651To aid with preparing the correct query for the storage you may supply the
652C<key> attribute, which is the name of a
653L<unique constraint|DBIx::Class::ResultSource/add_unique_constraint> (the
654unique constraint corresponding to the
655L<primary columns|DBIx::Class::ResultSource/primary_columns> is always named
656C<primary>). If the C<key> attribute has been supplied, and DBIC is unable
657to construct a query that satisfies the named unique constraint fully (
658non-NULL values for each column member of the constraint) an exception is
659thrown.
660
661If no C<key> is specified, the search is carried over all unique constraints
662which are fully defined by the available condition.
663
664If no such constraint is found, C<find> currently defaults to a simple
665C<< search->(\%column_values) >> which may or may not do what you expect.
666Note that this fallback behavior may be deprecated in further versions. If
667you need to search with arbitrary conditions - use L</search>. If the query
668resulting from this fallback produces more than one row, a warning to the
669effect is issued, though only the first row is constructed and returned as
670C<$row_object>.
671
672In addition to C<key>, L</find> recognizes and applies standard
673L<resultset attributes|/ATTRIBUTES> in the same way as L</search> does.
674
675Note that if you have extra concerns about the correctness of the resulting
676query you need to specify the C<key> attribute and supply the entire condition
677as an argument to find (since it is not always possible to perform the
678combination of the resultset condition with the supplied one, especially if
679the resultset condition contains literal sql).
680
681For example, to find a row by its primary key:
682
683 my $cd = $schema->resultset('CD')->find(5);
684
685You can also find a row by a specific unique constraint:
686
687 my $cd = $schema->resultset('CD')->find(
688 {
689 artist => 'Massive Attack',
690 title => 'Mezzanine',
691 },
692 { key => 'cd_artist_title' }
693 );
694
695See also L</find_or_create> and L</update_or_create>.
696
697=cut
698
699
# spent 4.94s (104ms+4.84) within DBIx::Class::ResultSet::find which was called 2007 times, avg 2.46ms/call: # 1654 times (78.9ms+3.89s) by DBIx::Class::Relationship::Base::find_related at line 621 of DBIx/Class/Relationship/Base.pm, avg 2.40ms/call # 331 times (21.9ms+836ms) by Tapper::Model::get_hardware_overview at line 96 of Tapper/Model.pm, avg 2.59ms/call # 22 times (3.67ms+111ms) by Test::Fixture::DBIC::Schema::_insert at line 77 of Test/Fixture/DBIC/Schema.pm, avg 5.21ms/call
sub find {
7003010557.3ms my $self = shift;
701 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
702
70312µs my $rsrc = $self->result_source;
# spent 2µs making 1 call to DBIx::Class::ResultSet::result_source
704
705 my $constraint_name;
706 if (exists $attrs->{key}) {
707 $constraint_name = defined $attrs->{key}
708 ? $attrs->{key}
709 : $self->throw_exception("An undefined 'key' resultset attribute makes no sense")
710 ;
711 }
712
713 # Parse out the condition from input
714 my $call_cond;
715
71619863.61ms if (ref $_[0] eq 'HASH') {
717 $call_cond = { %{$_[0]} };
718 }
719 else {
720 # if only values are supplied we need to default to 'primary'
721 $constraint_name = 'primary' unless defined $constraint_name;
722
7233316.50ms my @c_cols = $rsrc->unique_constraint_columns($constraint_name);
# spent 6.50ms making 331 calls to DBIx::Class::ResultSource::unique_constraint_columns, avg 20µs/call
724
725 $self->throw_exception(
726 "No constraint columns, maybe a malformed '$constraint_name' constraint?"
727 ) unless @c_cols;
728
729 $self->throw_exception (
730 'find() expects either a column/value hashref, or a list of values '
731 . "corresponding to the columns of the specified unique constraint '$constraint_name'"
732 ) unless @c_cols == @_;
733
734 $call_cond = {};
735 @{$call_cond}{@c_cols} = @_;
736 }
737
738 my %related;
739 for my $key (keys %$call_cond) {
740418838µs if (
741 my $keyref = ref($call_cond->{$key})
742 and
743 my $relinfo = $rsrc->relationship_info($key)
744 ) {
745 my $val = delete $call_cond->{$key};
746
747 next if $keyref eq 'ARRAY'; # has_many for multi_create
748
749 my $rel_q = $rsrc->_resolve_condition(
750 $relinfo->{cond}, $val, $key, $key
751 );
752 die "Can't handle complex relationship conditions in find" if ref($rel_q) ne 'HASH';
753 @related{keys %$rel_q} = values %$rel_q;
754 }
755 }
756
757 # relationship conditions take precedence (?)
758 @{$call_cond}{keys %related} = values %related;
759
760 my $alias = exists $attrs->{alias} ? $attrs->{alias} : $self->{attrs}{alias};
761 my $final_cond;
76266326µs66241.9ms if (defined $constraint_name) {
# spent 36.7ms making 331 calls to DBIx::Class::ResultSet::_build_unique_cond, avg 111µs/call # spent 5.20ms making 331 calls to DBIx::Class::ResultSet::_qualify_cond_columns, avg 16µs/call
763 $final_cond = $self->_qualify_cond_columns (
764
765 $self->_build_unique_cond (
766 $constraint_name,
767 $call_cond,
768 ),
769
770 $alias,
771 );
772 }
773 elsif ($self->{attrs}{accessor} and $self->{attrs}{accessor} eq 'single') {
774 # This means that we got here after a merger of relationship conditions
775 # in ::Relationship::Base::search_related (the row method), and furthermore
776 # the relationship is of the 'single' type. This means that the condition
777 # provided by the relationship (already attached to $self) is sufficient,
778 # as there can be only one row in the database that would satisfy the
779 # relationship
780 }
781 else {
782 # no key was specified - fall down to heuristics mode:
783 # run through all unique queries registered on the resultset, and
784 # 'OR' all qualifying queries together
785 my (@unique_queries, %seen_column_combinations);
78622688µs for my $c_name ($rsrc->unique_constraint_names) {
# spent 688µs making 22 calls to DBIx::Class::ResultSource::unique_constraint_names, avg 31µs/call
787 next if $seen_column_combinations{
78852870µs52664µs join "\x00", sort $rsrc->unique_constraint_columns($c_name)
# spent 572µs making 26 calls to DBIx::Class::ResultSource::unique_constraint_columns, avg 22µs/call # spent 92µs making 26 calls to DBIx::Class::ResultSet::CORE:sort, avg 4µs/call
789 }++;
790
791
# spent 6.23ms (339µs+5.89) within DBIx::Class::ResultSet::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/ResultSet.pm:793] which was called 26 times, avg 240µs/call: # 26 times (339µs+5.89ms) by Try::Tiny::try at line 71 of Try/Tiny.pm, avg 240µs/call
push @unique_queries, try {
79226315µs265.89ms $self->_build_unique_cond ($c_name, $call_cond, 'croak_on_nulls')
# spent 5.89ms making 26 calls to DBIx::Class::ResultSet::_build_unique_cond, avg 227µs/call
793266.87ms } || ();
# spent 6.87ms making 26 calls to Try::Tiny::try, avg 264µs/call
794 }
795
796 $final_cond = @unique_queries
79726164µs26707µs ? [ map { $self->_qualify_cond_columns($_, $alias) } @unique_queries ]
# spent 707µs making 26 calls to DBIx::Class::ResultSet::_qualify_cond_columns, avg 27µs/call
798 : $self->_non_unique_find_fallback ($call_cond, $attrs)
799 ;
800 }
801
802 # Run the query, passing the result_class since it should propagate for find
8034014359ms my $rs = $self->search ($final_cond, {result_class => $self->result_class, %$attrs});
# spent 353ms making 2007 calls to DBIx::Class::ResultSet::search, avg 176µs/call # spent 5.78ms making 2007 calls to DBIx::Class::ResultSet::result_class, avg 3µs/call
804200730.4ms2007494ms if (keys %{$rs->_resolved_attrs->{collapse}}) {
# spent 494ms making 2007 calls to DBIx::Class::ResultSet::_resolved_attrs, avg 246µs/call
805 my $row = $rs->next;
806 carp "Query returned more than one row" if $rs->next;
807 return $row;
808 }
809 else {
81020073.93s return $rs->single;
# spent 3.93s making 2007 calls to DBIx::Class::ResultSet::single, avg 1.96ms/call
811 }
812}
813
814# This is a stop-gap method as agreed during the discussion on find() cleanup:
815# http://lists.scsys.co.uk/pipermail/dbix-class/2010-October/009535.html
816#
817# It is invoked when find() is called in legacy-mode with insufficiently-unique
818# condition. It is provided for overrides until a saner way forward is devised
819#
820# *NOTE* This is not a public method, and it's *GUARANTEED* to disappear down
821# the road. Please adjust your tests accordingly to catch this situation early
822# DBIx::Class::ResultSet->can('_non_unique_find_fallback') is reasonable
823#
824# The method will not be removed without an adequately complete replacement
825# for strict-mode enforcement
826sub _non_unique_find_fallback {
827 my ($self, $cond, $attrs) = @_;
828
829 return $self->_qualify_cond_columns(
830 $cond,
831 exists $attrs->{alias}
832 ? $attrs->{alias}
833 : $self->{attrs}{alias}
834 );
835}
836
837
838
# spent 5.91ms (5.62+289µs) within DBIx::Class::ResultSet::_qualify_cond_columns which was called 357 times, avg 17µs/call: # 331 times (4.95ms+255µs) by DBIx::Class::ResultSet::find at line 762, avg 16µs/call # 26 times (674µs+34µs) by DBIx::Class::ResultSet::find at line 797, avg 27µs/call
sub _qualify_cond_columns {
83914283.28ms my ($self, $cond, $alias) = @_;
840
841 my %aliased = %$cond;
842 for (keys %aliased) {
8433593.00ms359289µs $aliased{"$alias.$_"} = delete $aliased{$_}
# spent 289µs making 359 calls to DBIx::Class::ResultSet::CORE:match, avg 804ns/call
844 if $_ !~ /\./;
845 }
846
847 return \%aliased;
848}
849
850
# spent 42.6ms (13.4+29.1) within DBIx::Class::ResultSet::_build_unique_cond which was called 357 times, avg 119µs/call: # 331 times (12.0ms+24.7ms) by DBIx::Class::ResultSet::find at line 762, avg 111µs/call # 26 times (1.48ms+4.41ms) by DBIx::Class::ResultSet::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/ResultSet.pm:793] at line 792, avg 227µs/call
sub _build_unique_cond {
851249912.0ms my ($self, $constraint_name, $extra_cond, $croak_on_null) = @_;
852
8533583.68ms my @c_cols = $self->result_source->unique_constraint_columns($constraint_name);
# spent 3.68ms making 357 calls to DBIx::Class::ResultSource::unique_constraint_columns, avg 10µs/call # spent 700ns making 1 call to DBIx::Class::ResultSet::result_source
854
855 # combination may fail if $self->{cond} is non-trivial
856
# spent 16.2ms (2.57+13.7) within DBIx::Class::ResultSet::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/ResultSet.pm:858] which was called 357 times, avg 45µs/call: # 357 times (2.57ms+13.7ms) by Try::Tiny::try at line 71 of Try/Tiny.pm, avg 45µs/call
my ($final_cond) = try {
8573572.37ms35713.7ms $self->_merge_with_rscond ($extra_cond)
# spent 13.7ms making 357 calls to DBIx::Class::ResultSet::_merge_with_rscond, avg 38µs/call
858 } catch {
859 +{ %$extra_cond }
86071421.8ms };
# spent 23.2ms making 357 calls to Try::Tiny::try, avg 65µs/call, recursion: max depth 1, sum of overlapping time 3.69ms # spent 2.29ms making 357 calls to Try::Tiny::catch, avg 6µs/call
861
862 # trim out everything not in $columns
863 $final_cond = { map {
864 exists $final_cond->{$_}
865 ? ( $_ => $final_cond->{$_} )
866 : ()
867 } @c_cols };
868
869 if (my @missing = grep
870 { ! ($croak_on_null ? defined $final_cond->{$_} : exists $final_cond->{$_}) }
871 (@c_cols)
872 ) {
873 $self->throw_exception( sprintf ( "Unable to satisfy requested constraint '%s', no values for column(s): %s",
874 $constraint_name,
875 join (', ', map { "'$_'" } @missing),
876 ) );
877 }
878
879 if (
880 !$croak_on_null
881 and
882 !$ENV{DBIC_NULLABLE_KEY_NOWARN}
883 and
884 my @undefs = grep { ! defined $final_cond->{$_} } (keys %$final_cond)
885 ) {
886 carp_unique ( sprintf (
887 "NULL/undef values supplied for requested unique constraint '%s' (NULL "
888 . 'values in column(s): %s). This is almost certainly not what you wanted, '
889 . 'though you can set DBIC_NULLABLE_KEY_NOWARN to disable this warning.',
890 $constraint_name,
891 join (', ', map { "'$_'" } @undefs),
892 ));
893 }
894
895 return $final_cond;
896}
897
898=head2 search_related
899
900=over 4
901
902=item Arguments: $rel, $cond, \%attrs?
903
904=item Return Value: $new_resultset (scalar context) || @row_objs (list context)
905
906=back
907
908 $new_rs = $cd_rs->search_related('artist', {
909 name => 'Emo-R-Us',
910 });
911
912Searches the specified relationship, optionally specifying a condition and
913attributes for matching records. See L</ATTRIBUTES> for more information.
914
915In list context, C<< ->all() >> is called implicitly on the resultset, thus
916returning a list of row objects instead. To avoid that, use L</search_related_rs>.
917
918See also L</search_related_rs>.
919
920=cut
921
922
# spent 146ms (1.28+145) within DBIx::Class::ResultSet::search_related which was called 147 times, avg 992µs/call: # 147 times (1.28ms+145ms) by Tapper::Schema::TestrunDB::Result::Testrun::preconditions_rs at line 68 of DBIx/Class/Relationship/ManyToMany.pm, avg 992µs/call
sub search_related {
9231471.12ms294145ms return shift->related_resultset(shift)->search(@_);
# spent 124ms making 147 calls to DBIx::Class::ResultSet::related_resultset, avg 846µs/call # spent 20.3ms making 147 calls to DBIx::Class::ResultSet::search, avg 138µs/call
924}
925
926=head2 search_related_rs
927
928This method works exactly the same as search_related, except that
929it guarantees a resultset, even in list context.
930
931=cut
932
933sub search_related_rs {
934 return shift->related_resultset(shift)->search_rs(@_);
935}
936
937=head2 cursor
938
939=over 4
940
941=item Arguments: none
942
943=item Return Value: $cursor
944
945=back
946
947Returns a storage-driven cursor to the given resultset. See
948L<DBIx::Class::Cursor> for more information.
949
950=cut
951
952
# spent 1.02s (104ms+911ms) within DBIx::Class::ResultSet::cursor which was called 6031 times, avg 168µs/call: # 2318 times (28.4ms+340ms) by DBIx::Class::ResultSet::next at line 1209, avg 159µs/call # 1954 times (38.1ms+350ms) by DBIx::Class::ResultSetColumn::next at line 161 of DBIx/Class/ResultSetColumn.pm, avg 198µs/call # 1610 times (34.8ms+178ms) by DBIx::Class::ResultSet::all at line 1651, avg 132µs/call # 148 times (2.89ms+43.5ms) by DBIx::Class::ResultSet::reset at line 1679, avg 313µs/call # once (21µs+308µs) by DBIx::Class::Schema::Versioned::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/Schema/Versioned.pm:752] at line 750 of DBIx/Class/Schema/Versioned.pm
sub cursor {
9531809372.8ms my ($self) = @_;
954
9556031454ms my $attrs = $self->_resolved_attrs_copy;
# spent 454ms making 6031 calls to DBIx::Class::ResultSet::_resolved_attrs_copy, avg 75µs/call
956
9579399137ms return $self->{cursor}
# spent 111ms making 4699 calls to DBIx::Class::ResultSource::storage, avg 24µs/call # spent 26.7ms making 4699 calls to DBIx::Class::Storage::DBI::select, avg 6µs/call # spent 800ns making 1 call to DBIx::Class::ResultSet::result_source
958 ||= $self->result_source->storage->select($attrs->{from}, $attrs->{select},
959 $attrs->{where},$attrs);
960}
961
962=head2 single
963
964=over 4
965
966=item Arguments: $cond?
967
968=item Return Value: $row_object | undef
969
970=back
971
972 my $cd = $schema->resultset('CD')->single({ year => 2001 });
973
974Inflates the first result without creating a cursor if the resultset has
975any records in it; if not returns C<undef>. Used by L</find> as a lean version
976of L</search>.
977
978While this method can take an optional search condition (just like L</search>)
979being a fast-code-path it does not recognize search attributes. If you need to
980add extra joins or similar, call L</search> and then chain-call L</single> on the
981L<DBIx::Class::ResultSet> returned.
982
983=over
984
985=item B<Note>
986
987As of 0.08100, this method enforces the assumption that the preceding
988query returns only one row. If more than one row is returned, you will receive
989a warning:
990
991 Query returned more than one row
992
993In this case, you should be using L</next> or L</find> instead, or if you really
994know what you are doing, use the L</rows> attribute to explicitly limit the size
995of the resultset.
996
997This method will also throw an exception if it is called on a resultset prefetching
998has_many, as such a prefetch implies fetching multiple rows from the database in
999order to assemble the resulting object.
1000
1001=back
1002
1003=cut
1004
1005
# spent 3.93s (74.2ms+3.85) within DBIx::Class::ResultSet::single which was called 2007 times, avg 1.96ms/call: # 2007 times (74.2ms+3.85s) by DBIx::Class::ResultSet::find at line 810, avg 1.96ms/call
sub single {
10061404960.1ms my ($self, $where) = @_;
1007 if(@_ > 2) {
1008 $self->throw_exception('single() only takes search conditions, no attributes. You want ->search( $cond, $attrs )->single()');
1009 }
1010
1011200729.8ms my $attrs = $self->_resolved_attrs_copy;
# spent 29.8ms making 2007 calls to DBIx::Class::ResultSet::_resolved_attrs_copy, avg 15µs/call
1012
1013 if (keys %{$attrs->{collapse}}) {
1014 $self->throw_exception(
1015 'single() can not be used on resultsets prefetching has_many. Use find( \%cond ) or next() instead'
1016 );
1017 }
1018
1019 if ($where) {
1020 if (defined $attrs->{where}) {
1021 $attrs->{where} = {
1022 '-and' =>
1023 [ map { ref $_ eq 'ARRAY' ? [ -or => $_ ] : $_ }
1024 $where, delete $attrs->{where} ]
1025 };
1026 } else {
1027 $attrs->{where} = $where;
1028 }
1029 }
1030
1031401579.6ms my @data = $self->result_source->storage->select_single(
# spent 63.5ms making 2007 calls to DBIx::Class::ResultSource::storage, avg 32µs/call # spent 16.2ms making 2007 calls to DBIx::Class::Storage::DBI::select_single, avg 8µs/call # spent 700ns making 1 call to DBIx::Class::ResultSet::result_source
1032 $attrs->{from}, $attrs->{select},
1033 $attrs->{where}, $attrs
1034 );
1035
10361566227ms return (@data ? ($self->_construct_object(@data))[0] : undef);
# spent 227ms making 1566 calls to DBIx::Class::ResultSet::_construct_object, avg 145µs/call
1037}
1038
1039
1040# _collapse_query
1041#
1042# Recursively collapse the query, accumulating values for each column.
1043
1044sub _collapse_query {
1045 my ($self, $query, $collapsed) = @_;
1046
1047 $collapsed ||= {};
1048
1049 if (ref $query eq 'ARRAY') {
1050 foreach my $subquery (@$query) {
1051 next unless ref $subquery; # -or
1052 $collapsed = $self->_collapse_query($subquery, $collapsed);
1053 }
1054 }
1055 elsif (ref $query eq 'HASH') {
1056 if (keys %$query and (keys %$query)[0] eq '-and') {
1057 foreach my $subquery (@{$query->{-and}}) {
1058 $collapsed = $self->_collapse_query($subquery, $collapsed);
1059 }
1060 }
1061 else {
1062 foreach my $col (keys %$query) {
1063 my $value = $query->{$col};
1064 $collapsed->{$col}{$value}++;
1065 }
1066 }
1067 }
1068
1069 return $collapsed;
1070}
1071
1072=head2 get_column
1073
1074=over 4
1075
1076=item Arguments: $cond?
1077
1078=item Return Value: $resultsetcolumn
1079
1080=back
1081
1082 my $max_length = $rs->get_column('length')->max;
1083
1084Returns a L<DBIx::Class::ResultSetColumn> instance for a column of the ResultSet.
1085
1086=cut
1087
1088
# spent 1.01s (15.9ms+998ms) within DBIx::Class::ResultSet::get_column which was called 1954 times, avg 519µs/call: # 1949 times (15.8ms+970ms) by DBIx::Class::ResultSet::_count_rs at line 1498, avg 506µs/call # 5 times (80µs+28.0ms) by DBIx::Class::Schema::Versioned::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/Schema/Versioned.pm:533] at line 530 of DBIx/Class/Schema/Versioned.pm, avg 5.62ms/call
sub get_column {
1089586215.0ms my ($self, $column) = @_;
10901954998ms my $new = DBIx::Class::ResultSetColumn->new($self, $column);
# spent 998ms making 1954 calls to DBIx::Class::ResultSetColumn::new, avg 511µs/call
1091 return $new;
1092}
1093
1094=head2 search_like
1095
1096=over 4
1097
1098=item Arguments: $cond, \%attrs?
1099
1100=item Return Value: $resultset (scalar context) || @row_objs (list context)
1101
1102=back
1103
1104 # WHERE title LIKE '%blue%'
1105 $cd_rs = $rs->search_like({ title => '%blue%'});
1106
1107Performs a search, but uses C<LIKE> instead of C<=> as the condition. Note
1108that this is simply a convenience method retained for ex Class::DBI users.
1109You most likely want to use L</search> with specific operators.
1110
1111For more information, see L<DBIx::Class::Manual::Cookbook>.
1112
1113This method is deprecated and will be removed in 0.09. Use L</search()>
1114instead. An example conversion is:
1115
1116 ->search_like({ foo => 'bar' });
1117
1118 # Becomes
1119
1120 ->search({ foo => { like => 'bar' } });
1121
1122=cut
1123
1124sub search_like {
1125 my $class = shift;
1126 carp_unique (
1127 'search_like() is deprecated and will be removed in DBIC version 0.09.'
1128 .' Instead use ->search({ x => { -like => "y%" } })'
1129 .' (note the outer pair of {}s - they are important!)'
1130 );
1131 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
1132 my $query = ref $_[0] eq 'HASH' ? { %{shift()} }: {@_};
1133 $query->{$_} = { 'like' => $query->{$_} } for keys %$query;
1134 return $class->search($query, { %$attrs });
1135}
1136
1137=head2 slice
1138
1139=over 4
1140
1141=item Arguments: $first, $last
1142
1143=item Return Value: $resultset (scalar context) || @row_objs (list context)
1144
1145=back
1146
1147Returns a resultset or object list representing a subset of elements from the
1148resultset slice is called on. Indexes are from 0, i.e., to get the first
1149three records, call:
1150
1151 my ($one, $two, $three) = $rs->slice(0, 2);
1152
1153=cut
1154
1155sub slice {
1156 my ($self, $min, $max) = @_;
1157 my $attrs = {}; # = { %{ $self->{attrs} || {} } };
1158 $attrs->{offset} = $self->{attrs}{offset} || 0;
1159 $attrs->{offset} += $min;
1160 $attrs->{rows} = ($max ? ($max - $min + 1) : 1);
1161 return $self->search(undef, $attrs);
1162 #my $slice = (ref $self)->new($self->result_source, $attrs);
1163 #return (wantarray ? $slice->all : $slice);
1164}
1165
1166=head2 next
1167
1168=over 4
1169
1170=item Arguments: none
1171
1172=item Return Value: $result | undef
1173
1174=back
1175
1176Returns the next element in the resultset (C<undef> is there is none).
1177
1178Can be used to efficiently iterate over records in the resultset:
1179
1180 my $rs = $schema->resultset('CD')->search;
1181 while (my $cd = $rs->next) {
1182 print $cd->title;
1183 }
1184
1185Note that you need to store the resultset object, and call C<next> on it.
1186Calling C<< resultset('Table')->next >> repeatedly will always return the
1187first record from the resultset.
1188
1189=cut
1190
1191
# spent 2.89s (56.3ms+2.83) within DBIx::Class::ResultSet::next which was called 2318 times, avg 1.24ms/call: # 905 times (14.9ms+326ms) by Tapper::Schema::TestrunDB::ResultSet::Queue::official_queuelist at line 21 of Tapper/Schema/TestrunDB/ResultSet/Queue.pm, avg 377µs/call # 511 times (18.4ms+772ms) by Tapper::Model::free_hosts_with_features at line 78 of Tapper/Model.pm, avg 1.55ms/call # 477 times (11.6ms+1.02s) by Tapper::MCP::Scheduler::PrioQueue::get_first_fitting at line 53 of lib/Tapper/MCP/Scheduler/PrioQueue.pm, avg 2.17ms/call # 276 times (6.80ms+473ms) by Tapper::Schema::TestrunDB::Result::Testrun::rerun at line 178 of Tapper/Schema/TestrunDB/Result/Testrun.pm, avg 1.74ms/call # 148 times (4.58ms+234ms) by DBIx::Class::ResultSet::first at line 1699, avg 1.61ms/call # once (22µs+1.43ms) by Tapper::Schema::TestrunDB::Result::TestrunScheduling::gen_schema_functions at line 100 of Tapper/Schema/TestrunDB/Result/TestrunScheduling.pm
sub next {
11921790449.7ms my ($self) = @_;
119323184.36ms if (my $cache = $self->get_cache) {
# spent 4.36ms making 2318 calls to DBIx::Class::ResultSet::get_cache, avg 2µs/call
1194 $self->{all_cache_position} ||= 0;
1195 return $cache->[$self->{all_cache_position}++];
1196 }
1197 if ($self->{attrs}{cache}) {
1198 delete $self->{pager};
1199 $self->{all_cache_position} = 1;
1200 return ($self->all)[0];
1201 }
1202 if ($self->{stashed_objects}) {
1203 my $obj = shift(@{$self->{stashed_objects}});
1204 delete $self->{stashed_objects} unless @{$self->{stashed_objects}};
1205 return $obj;
1206 }
1207 my @row = (
1208 exists $self->{stashed_row}
120946362.66s ? @{delete $self->{stashed_row}}
# spent 2.29s making 2318 calls to DBIx::Class::Storage::DBI::Cursor::next, avg 990µs/call # spent 368ms making 2318 calls to DBIx::Class::ResultSet::cursor, avg 159µs/call
1210 : $self->cursor->next
1211 );
1212 return undef unless (@row);
12131332163ms my ($row, @more) = $self->_construct_object(@row);
# spent 163ms making 1332 calls to DBIx::Class::ResultSet::_construct_object, avg 122µs/call
1214 $self->{stashed_objects} = \@more if @more;
1215 return $row;
1216}
1217
1218
# spent 676ms (107+569) within DBIx::Class::ResultSet::_construct_object which was called 4717 times, avg 143µs/call: # 1819 times (44.5ms+241ms) by DBIx::Class::ResultSet::all at line 1651, avg 157µs/call # 1566 times (37.2ms+190ms) by DBIx::Class::ResultSet::single at line 1036, avg 145µs/call # 1332 times (25.0ms+138ms) by DBIx::Class::ResultSet::next at line 1213, avg 122µs/call
sub _construct_object {
12192358596.0ms my ($self, @row) = @_;
1220
12214717399ms my $info = $self->_collapse_result($self->{_attrs}{as}, \@row)
# spent 399ms making 4717 calls to DBIx::Class::ResultSet::_collapse_result, avg 85µs/call
1222 or return ();
12239435170ms my @new = $self->result_class->inflate_result($self->result_source, @$info);
# spent 148ms making 4717 calls to DBIx::Class::Row::inflate_result, avg 31µs/call # spent 21.7ms making 4717 calls to DBIx::Class::ResultSet::result_class, avg 5µs/call # spent 2µs making 1 call to DBIx::Class::ResultSet::result_source
1224 @new = $self->{_attrs}{record_filter}->(@new)
1225 if exists $self->{_attrs}{record_filter};
1226 return @new;
1227}
1228
1229
# spent 399ms (322+77.5) within DBIx::Class::ResultSet::_collapse_result which was called 4717 times, avg 85µs/call: # 4717 times (322ms+77.5ms) by DBIx::Class::ResultSet::_construct_object at line 1221, avg 85µs/call
sub _collapse_result {
123070755117ms my ($self, $as_proto, $row) = @_;
1231
1232 my @copy = @$row;
1233
1234 # 'foo' => [ undef, 'foo' ]
1235 # 'foo.bar' => [ 'foo', 'bar' ]
1236 # 'foo.bar.baz' => [ 'foo.bar', 'baz' ]
1237
123835425168ms3542572.6ms my @construct_as = map { [ (/^(?:(.*)\.)?([^.]+)$/) ] } @$as_proto;
# spent 72.6ms making 35425 calls to DBIx::Class::ResultSet::CORE:match, avg 2µs/call
1239
1240 my %collapse = %{$self->{_attrs}{collapse}||{}};
1241
1242 my @pri_index;
1243
1244 # if we're doing collapsing (has_many prefetch) we need to grab records
1245 # until the PK changes, so fill @pri_index. if not, we leave it empty so
1246 # we know we don't have to bother.
1247
1248 # the reason for not using the collapse stuff directly is because if you
1249 # had for e.g. two artists in a row with no cds, the collapse info for
1250 # both would be NULL (undef) so you'd lose the second artist
1251
1252 # store just the index so we can check the array positions from the row
1253 # without having to contruct the full hash
1254
1255 if (keys %collapse) {
1256 my %pri = map { ($_ => 1) } $self->result_source->_pri_cols;
1257 foreach my $i (0 .. $#construct_as) {
1258 next if defined($construct_as[$i][0]); # only self table
1259 if (delete $pri{$construct_as[$i][1]}) {
1260 push(@pri_index, $i);
1261 }
1262 last unless keys %pri; # short circuit (Johnny Five Is Alive!)
1263 }
1264 }
1265
1266 # no need to do an if, it'll be empty if @pri_index is empty anyway
1267
1268 my %pri_vals = map { ($_ => $copy[$_]) } @pri_index;
1269
1270 my @const_rows;
1271
1272 do { # no need to check anything at the front, we always want the first row
1273
1274 my %const;
1275
1276 foreach my $this_as (@construct_as) {
12773542554.8ms $const{$this_as->[0]||''}{$this_as->[1]} = shift(@copy);
1278 }
1279
1280 push(@const_rows, \%const);
1281
1282 } until ( # no pri_index => no collapse => drop straight out
1283 !@pri_index
1284 or
12851415116.5ms do { # get another row, stash it, drop out if different PK
1286
1287 @copy = $self->cursor->next;
1288 $self->{stashed_row} = \@copy;
1289
1290 # last thing in do block, counts as true if anything doesn't match
1291
1292 # check xor defined first for NULL vs. NOT NULL then if one is
1293 # defined the other must be so check string equality
1294
1295 grep {
1296 (defined $pri_vals{$_} ^ defined $copy[$_])
1297 || (defined $pri_vals{$_} && ($pri_vals{$_} ne $copy[$_]))
1298 } @pri_index;
1299 }
1300 );
1301
1302 my $alias = $self->{attrs}{alias};
1303 my $info = [];
1304
1305 my %collapse_pos;
1306
1307 my @const_keys;
1308
1309 foreach my $const (@const_rows) {
1310943436.7ms47174.91ms scalar @const_keys or do {
# spent 4.91ms making 4717 calls to DBIx::Class::ResultSet::CORE:sort, avg 1µs/call
1311 @const_keys = sort { length($a) <=> length($b) } keys %$const;
1312 };
1313 foreach my $key (@const_keys) {
1314943413.2ms if (length $key) {
1315 my $target = $info;
1316 my @parts = split(/\./, $key);
1317 my $cur = '';
1318 my $data = $const->{$key};
1319 foreach my $p (@parts) {
1320 $target = $target->[1]->{$p} ||= [];
1321 $cur .= ".${p}";
1322 if ($cur eq ".${key}" && (my @ckey = @{$collapse{$cur}||[]})) {
1323 # collapsing at this point and on final part
1324 my $pos = $collapse_pos{$cur};
1325 CK: foreach my $ck (@ckey) {
1326 if (!defined $pos->{$ck} || $pos->{$ck} ne $data->{$ck}) {
1327 $collapse_pos{$cur} = $data;
1328 delete @collapse_pos{ # clear all positioning for sub-entries
1329 grep { m/^\Q${cur}.\E/ } keys %collapse_pos
1330 };
1331 push(@$target, []);
1332 last CK;
1333 }
1334 }
1335 }
1336 if (exists $collapse{$cur}) {
1337 $target = $target->[-1];
1338 }
1339 }
1340 $target->[0] = $data;
1341 } else {
1342 $info->[0] = $const->{$key};
1343 }
1344 }
1345 }
1346
1347 return $info;
1348}
1349
1350=head2 result_source
1351
1352=over 4
1353
1354=item Arguments: $result_source?
1355
1356=item Return Value: $result_source
1357
1358=back
1359
1360An accessor for the primary ResultSource object from which this ResultSet
1361is derived.
1362
1363=head2 result_class
1364
1365=over 4
1366
1367=item Arguments: $result_class?
1368
1369=item Return Value: $result_class
1370
1371=back
1372
1373An accessor for the class to use when creating row objects. Defaults to
1374C<< result_source->result_class >> - which in most cases is the name of the
1375L<"table"|DBIx::Class::Manual::Glossary/"ResultSource"> class.
1376
1377Note that changing the result_class will also remove any components
1378that were originally loaded in the source class via
1379L<DBIx::Class::ResultSource/load_components>. Any overloaded methods
1380in the original source class will not run.
1381
1382=cut
1383
1384
# spent 351ms (215+136) within DBIx::Class::ResultSet::result_class which was called 31809 times, avg 11µs/call: # 24636 times (185ms+136ms) by DBIx::Class::ResultSet::new at line 218, avg 13µs/call # 4717 times (21.7ms+0s) by DBIx::Class::ResultSet::_construct_object at line 1223, avg 5µs/call # 2007 times (5.78ms+0s) by DBIx::Class::ResultSet::find at line 803, avg 3µs/call # 449 times (2.05ms+0s) by DBIx::Class::ResultSet::new_result at line 2213, avg 5µs/call
sub result_class {
138595427139ms my ($self, $result_class) = @_;
13864927293.3ms if ($result_class) {
138724636135ms unless (ref $result_class) { # don't fire this for an object
# spent 135ms making 24636 calls to Class::C3::Componentised::ensure_class_loaded, avg 5µs/call
1388 $self->ensure_class_loaded($result_class);
1389 }
13902165µs $self->_result_class($result_class);
# spent 165µs making 2 calls to DBIx::Class::ResultSet::_result_class, avg 82µs/call
1391 # THIS LINE WOULD BE A BUG - this accessor specifically exists to
1392 # permit the user to set result class on one result set only; it only
1393 # chains if provided to search()
1394 #$self->{attrs}{result_class} = $result_class if ref $self;
1395 }
13961600ns $self->_result_class;
# spent 600ns making 1 call to DBIx::Class::ResultSet::_result_class
1397}
1398
1399=head2 count
1400
1401=over 4
1402
1403=item Arguments: $cond, \%attrs??
1404
1405=item Return Value: $count
1406
1407=back
1408
1409Performs an SQL C<COUNT> with the same query as the resultset was built
1410with to find the number of elements. Passing arguments is equivalent to
1411C<< $rs->search ($cond, \%attrs)->count >>
1412
1413=cut
1414
1415
# spent 5.59s (117ms+5.47) within DBIx::Class::ResultSet::count which was called 1949 times, avg 2.87ms/call: # 594 times (32.7ms+1.40s) by Tapper::Schema::TestrunDB::Result::TestrunScheduling::fits at line 154 of Tapper/Schema/TestrunDB/Result/TestrunScheduling.pm, avg 2.42ms/call # 496 times (27.1ms+1.17s) by Tapper::Schema::TestrunDB::Result::TestrunScheduling::fits at line 179 of Tapper/Schema/TestrunDB/Result/TestrunScheduling.pm, avg 2.42ms/call # 330 times (18.4ms+988ms) by Tapper::MCP::Scheduler::Controller::toggle_bandwith_color at line 42 of lib/Tapper/MCP/Scheduler/Controller.pm, avg 3.05ms/call # 201 times (11.0ms+476ms) by Tapper::MCP::Scheduler::Controller::toggle_bandwith_color at line 44 of lib/Tapper/MCP/Scheduler/Controller.pm, avg 2.42ms/call # 147 times (15.4ms+807ms) by Tapper::Schema::TestrunDB::Result::Testrun::rerun at line 162 of Tapper/Schema/TestrunDB/Result/Testrun.pm, avg 5.59ms/call # 147 times (10.6ms+503ms) by Tapper::Schema::TestrunDB::Result::Testrun::rerun at line 168 of Tapper/Schema/TestrunDB/Result/Testrun.pm, avg 3.49ms/call # 34 times (2.24ms+123ms) by main::toggle_host_free at line 57 of xt/tapper-mcp-scheduler-with-db-longrun.t, avg 3.70ms/call
sub count {
14162533765.3ms my $self = shift;
1417 return $self->search(@_)->count if @_ and defined $_[0];
141819492.36ms return scalar @{ $self->get_cache } if $self->get_cache;
# spent 2.36ms making 1949 calls to DBIx::Class::ResultSet::get_cache, avg 1µs/call
1419
14201949361ms my $attrs = $self->_resolved_attrs_copy;
# spent 361ms making 1949 calls to DBIx::Class::ResultSet::_resolved_attrs_copy, avg 185µs/call
1421
1422 # this is a little optimization - it is faster to do the limit
1423 # adjustments in software, instead of a subquery
1424 my $rows = delete $attrs->{rows};
1425 my $offset = delete $attrs->{offset};
1426
1427 my $crs;
142819496.10ms194936.9ms if ($self->_has_resolved_attr (qw/collapse group_by/)) {
# spent 36.9ms making 1949 calls to DBIx::Class::ResultSet::_has_resolved_attr, avg 19µs/call
1429 $crs = $self->_count_subq_rs ($attrs);
1430 }
1431 else {
143219491.40s $crs = $self->_count_rs ($attrs);
# spent 1.40s making 1949 calls to DBIx::Class::ResultSet::_count_rs, avg 717µs/call
1433 }
143419493.60s my $count = $crs->next;
# spent 3.60s making 1949 calls to DBIx::Class::ResultSetColumn::next, avg 1.85ms/call
1435
1436 $count -= $offset if $offset;
1437 $count = $rows if $rows and $rows < $count;
1438 $count = 0 if ($count < 0);
1439
1440 return $count;
1441}
1442
1443=head2 count_rs
1444
1445=over 4
1446
1447=item Arguments: $cond, \%attrs??
1448
1449=item Return Value: $count_rs
1450
1451=back
1452
1453Same as L</count> but returns a L<DBIx::Class::ResultSetColumn> object.
1454This can be very handy for subqueries:
1455
1456 ->search( { amount => $some_rs->count_rs->as_query } )
1457
1458As with regular resultsets the SQL query will be executed only after
1459the resultset is accessed via L</next> or L</all>. That would return
1460the same single value obtainable via L</count>.
1461
1462=cut
1463
1464sub count_rs {
1465 my $self = shift;
1466 return $self->search(@_)->count_rs if @_;
1467
1468 # this may look like a lack of abstraction (count() does about the same)
1469 # but in fact an _rs *must* use a subquery for the limits, as the
1470 # software based limiting can not be ported if this $rs is to be used
1471 # in a subquery itself (i.e. ->as_query)
1472 if ($self->_has_resolved_attr (qw/collapse group_by offset rows/)) {
1473 return $self->_count_subq_rs;
1474 }
1475 else {
1476 return $self->_count_rs;
1477 }
1478}
1479
1480#
1481# returns a ResultSetColumn object tied to the count query
1482#
1483
# spent 1.40s (75.0ms+1.32) within DBIx::Class::ResultSet::_count_rs which was called 1949 times, avg 717µs/call: # 1949 times (75.0ms+1.32s) by DBIx::Class::ResultSet::count at line 1432, avg 717µs/call
sub _count_rs {
14841949066.2ms my ($self, $attrs) = @_;
1485
148611µs my $rsrc = $self->result_source;
# spent 1µs making 1 call to DBIx::Class::ResultSet::result_source
1487 $attrs ||= $self->_resolved_attrs;
1488
1489 my $tmp_attrs = { %$attrs };
1490 # take off any limits, record_filter is cdbi, and no point of ordering nor locking a count
1491 delete @{$tmp_attrs}{qw/rows offset order_by record_filter for/};
1492
1493 # overwrite the selector (supplied by the storage)
1494389869.4ms $tmp_attrs->{select} = $rsrc->storage->_count_select ($rsrc, $attrs);
# spent 61.8ms making 1949 calls to DBIx::Class::ResultSource::storage, avg 32µs/call # spent 7.59ms making 1949 calls to DBIx::Class::Storage::DBI::_count_select, avg 4µs/call
1495 $tmp_attrs->{as} = 'count';
1496 delete @{$tmp_attrs}{qw/columns/};
1497
149858471.25s my $tmp_rs = $rsrc->resultset_class->new($rsrc, $tmp_attrs)->get_column ('count');
# spent 986ms making 1949 calls to DBIx::Class::ResultSet::get_column, avg 506µs/call # spent 231ms making 1949 calls to DBIx::Class::ResultSet::new, avg 118µs/call # spent 36.4ms making 1949 calls to DBIx::Class::ResultSource::resultset_class, avg 19µs/call
1499
1500 return $tmp_rs;
1501}
1502
1503#
1504# same as above but uses a subquery
1505#
1506sub _count_subq_rs {
1507 my ($self, $attrs) = @_;
1508
1509 my $rsrc = $self->result_source;
1510 $attrs ||= $self->_resolved_attrs;
1511
1512 my $sub_attrs = { %$attrs };
1513 # extra selectors do not go in the subquery and there is no point of ordering it, nor locking it
1514 delete @{$sub_attrs}{qw/collapse columns as select _prefetch_selector_range order_by for/};
1515
1516 # if we multi-prefetch we group_by primary keys only as this is what we would
1517 # get out of the rs via ->next/->all. We *DO WANT* to clobber old group_by regardless
1518 if ( keys %{$attrs->{collapse}} ) {
1519 $sub_attrs->{group_by} = [ map { "$attrs->{alias}.$_" } ($rsrc->_pri_cols) ]
1520 }
1521
1522 # Calculate subquery selector
1523 if (my $g = $sub_attrs->{group_by}) {
1524
1525 my $sql_maker = $rsrc->storage->sql_maker;
1526
1527 # necessary as the group_by may refer to aliased functions
1528 my $sel_index;
1529 for my $sel (@{$attrs->{select}}) {
1530 $sel_index->{$sel->{-as}} = $sel
1531 if (ref $sel eq 'HASH' and $sel->{-as});
1532 }
1533
1534 # anything from the original select mentioned on the group-by needs to make it to the inner selector
1535 # also look for named aggregates referred in the having clause
1536 # having often contains scalarrefs - thus parse it out entirely
1537 my @parts = @$g;
1538 if ($attrs->{having}) {
1539 local $sql_maker->{having_bind};
1540 local $sql_maker->{quote_char} = $sql_maker->{quote_char};
1541 local $sql_maker->{name_sep} = $sql_maker->{name_sep};
1542 unless (defined $sql_maker->{quote_char} and length $sql_maker->{quote_char}) {
1543 $sql_maker->{quote_char} = [ "\x00", "\xFF" ];
1544 # if we don't unset it we screw up retarded but unfortunately working
1545 # 'MAX(foo.bar)' => { '>', 3 }
1546 $sql_maker->{name_sep} = '';
1547 }
1548
1549 my ($lquote, $rquote, $sep) = map { quotemeta $_ } ($sql_maker->_quote_chars, $sql_maker->name_sep);
1550
1551 my $sql = $sql_maker->_parse_rs_attrs ({ having => $attrs->{having} });
1552
1553 # search for both a proper quoted qualified string, for a naive unquoted scalarref
1554 # and if all fails for an utterly naive quoted scalar-with-function
1555 while ($sql =~ /
1556 $rquote $sep $lquote (.+?) $rquote
1557 |
1558 [\s,] \w+ \. (\w+) [\s,]
1559 |
1560 [\s,] $lquote (.+?) $rquote [\s,]
1561 /gx) {
1562 push @parts, ($1 || $2 || $3); # one of them matched if we got here
1563 }
1564 }
1565
1566 for (@parts) {
1567 my $colpiece = $sel_index->{$_} || $_;
1568
1569 # unqualify join-based group_by's. Arcane but possible query
1570 # also horrible horrible hack to alias a column (not a func.)
1571 # (probably need to introduce SQLA syntax)
1572 if ($colpiece =~ /\./ && $colpiece !~ /^$attrs->{alias}\./) {
1573 my $as = $colpiece;
1574 $as =~ s/\./__/;
1575 $colpiece = \ sprintf ('%s AS %s', map { $sql_maker->_quote ($_) } ($colpiece, $as) );
1576 }
1577 push @{$sub_attrs->{select}}, $colpiece;
1578 }
1579 }
1580 else {
1581 my @pcols = map { "$attrs->{alias}.$_" } ($rsrc->primary_columns);
1582 $sub_attrs->{select} = @pcols ? \@pcols : [ 1 ];
1583 }
1584
1585 return $rsrc->resultset_class
1586 ->new ($rsrc, $sub_attrs)
1587 ->as_subselect_rs
1588 ->search ({}, { columns => { count => $rsrc->storage->_count_select ($rsrc, $attrs) } })
1589 ->get_column ('count');
1590}
1591
1592
# spent 5.01ms within DBIx::Class::ResultSet::_bool which was called 1909 times, avg 3µs/call: # 1909 times (5.01ms+0s) by DBIx::Class::Relationship::Base::related_resultset at line 408 of DBIx/Class/Relationship/Base.pm, avg 3µs/call
sub _bool {
159319097.82ms return 1;
1594}
1595
1596=head2 count_literal
1597
1598=over 4
1599
1600=item Arguments: $sql_fragment, @bind_values
1601
1602=item Return Value: $count
1603
1604=back
1605
1606Counts the results in a literal query. Equivalent to calling L</search_literal>
1607with the passed arguments, then L</count>.
1608
1609=cut
1610
1611sub count_literal { shift->search_literal(@_)->count; }
1612
1613=head2 all
1614
1615=over 4
1616
1617=item Arguments: none
1618
1619=item Return Value: @objects
1620
1621=back
1622
1623Returns all elements in the resultset.
1624
1625=cut
1626
1627
# spent 3.22s (63.7ms+3.16) within DBIx::Class::ResultSet::all which was called 1610 times, avg 2.00ms/call: # 477 times (16.2ms+1.06s) by Tapper::Schema::TestrunDB::Result::Queue::get_first_fitting at line 55 of Tapper/Schema/TestrunDB/Result/Queue.pm, avg 2.25ms/call # 421 times (14.4ms+615ms) by Tapper::Schema::TestrunDB::Result::TestrunScheduling::fits at line 179 of Tapper/Schema/TestrunDB/Result/TestrunScheduling.pm, avg 1.50ms/call # 331 times (10.1ms+517ms) by DBIx::Class::ResultSet::search at line 276, avg 1.59ms/call # 201 times (6.88ms+294ms) by Tapper::MCP::Scheduler::Controller::toggle_bandwith_color at line 47 of lib/Tapper/MCP/Scheduler/Controller.pm, avg 1.50ms/call # 180 times (16.2ms+674ms) by main::toggle_host_free at line 55 of xt/tapper-mcp-scheduler-with-db-longrun.t, avg 3.84ms/call
sub all {
16281127037.7ms my $self = shift;
1629 if(@_) {
1630 $self->throw_exception("all() doesn't take any arguments, you probably wanted ->search(...)->all()");
1631 }
1632
163316102.22ms return @{ $self->get_cache } if $self->get_cache;
# spent 2.22ms making 1610 calls to DBIx::Class::ResultSet::get_cache, avg 1µs/call
1634
1635 my @obj;
1636
1637161018.8ms1610312ms if (keys %{$self->_resolved_attrs->{collapse}}) {
# spent 312ms making 1610 calls to DBIx::Class::ResultSet::_resolved_attrs, avg 194µs/call
1638 # Using $self->cursor->all is really just an optimisation.
1639 # If we're collapsing has_many prefetches it probably makes
1640 # very little difference, and this is cleaner than hacking
1641 # _construct_object to survive the approach
1642 $self->cursor->reset;
1643 my @row = $self->cursor->next;
1644 while (@row) {
1645 push(@obj, $self->_construct_object(@row));
1646 @row = (exists $self->{stashed_row}
1647 ? @{delete $self->{stashed_row}}
1648 : $self->cursor->next);
1649 }
1650 } else {
165150392.84s @obj = map { $self->_construct_object(@$_) } $self->cursor->all;
# spent 2.34s making 1610 calls to DBIx::Class::Storage::DBI::Cursor::all, avg 1.46ms/call # spent 286ms making 1819 calls to DBIx::Class::ResultSet::_construct_object, avg 157µs/call # spent 213ms making 1610 calls to DBIx::Class::ResultSet::cursor, avg 132µs/call
1652 }
1653
1654 $self->set_cache(\@obj) if $self->{attrs}{cache};
1655
1656 return @obj;
1657}
1658
1659=head2 reset
1660
1661=over 4
1662
1663=item Arguments: none
1664
1665=item Return Value: $self
1666
1667=back
1668
1669Resets the resultset's cursor, so you can iterate through the elements again.
1670Implicitly resets the storage cursor, so a subsequent L</next> will trigger
1671another query.
1672
1673=cut
1674
1675
# spent 49.7ms (1.51+48.2) within DBIx::Class::ResultSet::reset which was called 148 times, avg 336µs/call: # 148 times (1.51ms+48.2ms) by DBIx::Class::ResultSet::first at line 1699, avg 336µs/call
sub reset {
16767401.49ms my ($self) = @_;
1677 delete $self->{_attrs} if exists $self->{_attrs};
1678 $self->{all_cache_position} = 0;
167929648.2ms $self->cursor->reset;
# spent 46.4ms making 148 calls to DBIx::Class::ResultSet::cursor, avg 313µs/call # spent 1.80ms making 148 calls to DBIx::Class::Storage::DBI::Cursor::reset, avg 12µs/call
1680 return $self;
1681}
1682
1683=head2 first
1684
1685=over 4
1686
1687=item Arguments: none
1688
1689=item Return Value: $object | undef
1690
1691=back
1692
1693Resets the resultset and returns an object for the first result (or C<undef>
1694if the resultset is empty).
1695
1696=cut
1697
1698
# spent 289ms (1.32+288) within DBIx::Class::ResultSet::first which was called 148 times, avg 1.96ms/call: # 147 times (1.31ms+285ms) by Tapper::Schema::TestrunDB::Result::Testrun::rerun at line 132 of Tapper/Schema/TestrunDB/Result/Testrun.pm, avg 1.95ms/call # once (16µs+2.94ms) by Tapper::Model::model at line 51 of Tapper/Model.pm
sub first {
16991481.26ms296288ms return $_[0]->reset->next;
# spent 238ms making 148 calls to DBIx::Class::ResultSet::next, avg 1.61ms/call # spent 49.7ms making 148 calls to DBIx::Class::ResultSet::reset, avg 336µs/call
1700}
1701
1702
1703# _rs_update_delete
1704#
1705# Determines whether and what type of subquery is required for the $rs operation.
1706# If grouping is necessary either supplies its own, or verifies the current one
1707# After all is done delegates to the proper storage method.
1708
1709
# spent 2.16s (1.10ms+2.16) within DBIx::Class::ResultSet::_rs_update_delete which was called 19 times, avg 114ms/call: # 19 times (1.10ms+2.16s) by DBIx::Class::ResultSet::delete at line 1877, avg 114ms/call
sub _rs_update_delete {
171095377µs my ($self, $op, $values) = @_;
1711
171212µs my $rsrc = $self->result_source;
# spent 2µs making 1 call to DBIx::Class::ResultSet::result_source
1713
1714198.66ms my $needs_group_by_subq = $self->_has_resolved_attr (qw/collapse group_by -join/);
# spent 8.66ms making 19 calls to DBIx::Class::ResultSet::_has_resolved_attr, avg 456µs/call
171519507µs my $needs_subq = $needs_group_by_subq || $self->_has_resolved_attr(qw/rows offset/);
# spent 507µs making 19 calls to DBIx::Class::ResultSet::_has_resolved_attr, avg 27µs/call
1716
171738538µs if ($needs_group_by_subq or $needs_subq) {
1718
1719 # make a new $rs selecting only the PKs (that's all we really need)
1720 my $attrs = $self->_resolved_attrs_copy;
1721
1722
1723 delete $attrs->{$_} for qw/collapse _collapse_order_by select _prefetch_selector_range as/;
1724 $attrs->{columns} = [ map { "$attrs->{alias}.$_" } ($self->result_source->_pri_cols) ];
1725
1726 if ($needs_group_by_subq) {
1727 # make sure no group_by was supplied, or if there is one - make sure it matches
1728 # the columns compiled above perfectly. Anything else can not be sanely executed
1729 # on most databases so croak right then and there
1730
1731 if (my $g = $attrs->{group_by}) {
1732 my @current_group_by = map
1733 { $_ =~ /\./ ? $_ : "$attrs->{alias}.$_" }
1734 @$g
1735 ;
1736
1737 if (
1738 join ("\x00", sort @current_group_by)
1739 ne
1740 join ("\x00", sort @{$attrs->{columns}} )
1741 ) {
1742 $self->throw_exception (
1743 "You have just attempted a $op operation on a resultset which does group_by"
1744 . ' on columns other than the primary keys, while DBIC internally needs to retrieve'
1745 . ' the primary keys in a subselect. All sane RDBMS engines do not support this'
1746 . ' kind of queries. Please retry the operation with a modified group_by or'
1747 . ' without using one at all.'
1748 );
1749 }
1750 }
1751 else {
1752 $attrs->{group_by} = $attrs->{columns};
1753 }
1754 }
1755
1756 my $subrs = (ref $self)->new($rsrc, $attrs);
1757 return $self->result_source->storage->_subq_update_delete($subrs, $op, $values);
1758 }
1759 else {
1760 # Most databases do not allow aliasing of tables in UPDATE/DELETE. Thus
1761 # a condition containing 'me' or other table prefixes will not work
1762 # at all. What this code tries to do (badly) is to generate a condition
1763 # with the qualifiers removed, by exploiting the quote mechanism of sqla
1764 #
1765 # this is atrocious and should be replaced by normal sqla introspection
1766 # one sunny day
1767 my ($sql, @bind) = do {
1768 my $sqla = $rsrc->storage->sql_maker;
1769 local $sqla->{_dequalify_idents} = 1;
1770 $sqla->_recurse_where($self->{cond});
1771 } if $self->{cond};
1772
1773381.25ms return $rsrc->storage->$op(
# spent 1.03ms making 19 calls to DBIx::Class::ResultSource::storage, avg 54µs/call # spent 219µs making 19 calls to DBIx::Class::Storage::DBI::delete, avg 12µs/call
1774 $rsrc,
1775 $op eq 'update' ? $values : (),
1776 $self->{cond} ? \[$sql, @bind] : (),
1777 );
1778 }
1779}
1780
1781=head2 update
1782
1783=over 4
1784
1785=item Arguments: \%values
1786
1787=item Return Value: $storage_rv
1788
1789=back
1790
1791Sets the specified columns in the resultset to the supplied values in a
1792single query. Note that this will not run any accessor/set_column/update
1793triggers, nor will it update any row object instances derived from this
1794resultset (this includes the contents of the L<resultset cache|/set_cache>
1795if any). See L</update_all> if you need to execute any on-update
1796triggers or cascades defined either by you or a
1797L<result component|DBIx::Class::Manual::Component/WHAT_IS_A_COMPONENT>.
1798
1799The return value is a pass through of what the underlying
1800storage backend returned, and may vary. See L<DBI/execute> for the most
1801common case.
1802
1803=head3 CAVEAT
1804
1805Note that L</update> does not process/deflate any of the values passed in.
1806This is unlike the corresponding L<DBIx::Class::Row/update>. The user must
1807ensure manually that any value passed to this method will stringify to
1808something the RDBMS knows how to deal with. A notable example is the
1809handling of L<DateTime> objects, for more info see:
1810L<DBIx::Class::Manual::Cookbook/Formatting_DateTime_objects_in_queries>.
1811
1812=cut
1813
1814sub update {
1815 my ($self, $values) = @_;
1816 $self->throw_exception('Values for update must be a hash')
1817 unless ref $values eq 'HASH';
1818
1819 return $self->_rs_update_delete ('update', $values);
1820}
1821
1822=head2 update_all
1823
1824=over 4
1825
1826=item Arguments: \%values
1827
1828=item Return Value: 1
1829
1830=back
1831
1832Fetches all objects and updates them one at a time via
1833L<DBIx::Class::Row/update>. Note that C<update_all> will run DBIC defined
1834triggers, while L</update> will not.
1835
1836=cut
1837
1838sub update_all {
1839 my ($self, $values) = @_;
1840 $self->throw_exception('Values for update_all must be a hash')
1841 unless ref $values eq 'HASH';
1842
1843 my $guard = $self->result_source->schema->txn_scope_guard;
1844 $_->update({%$values}) for $self->all; # shallow copy - update will mangle it
1845 $guard->commit;
1846 return 1;
1847}
1848
1849=head2 delete
1850
1851=over 4
1852
1853=item Arguments: none
1854
1855=item Return Value: $storage_rv
1856
1857=back
1858
1859Deletes the rows matching this resultset in a single query. Note that this
1860will not run any delete triggers, nor will it alter the
1861L<in_storage|DBIx::Class::Row/in_storage> status of any row object instances
1862derived from this resultset (this includes the contents of the
1863L<resultset cache|/set_cache> if any). See L</delete_all> if you need to
1864execute any on-delete triggers or cascades defined either by you or a
1865L<result component|DBIx::Class::Manual::Component/WHAT_IS_A_COMPONENT>.
1866
1867The return value is a pass through of what the underlying storage backend
1868returned, and may vary. See L<DBI/execute> for the most common case.
1869
1870=cut
1871
1872
# spent 2.16s (373µs+2.16) within DBIx::Class::ResultSet::delete which was called 19 times, avg 114ms/call: # 19 times (373µs+2.16s) by Test::Fixture::DBIC::Schema::_delete_all at line 66 of Test/Fixture/DBIC/Schema.pm, avg 114ms/call
sub delete {
187357327µs my $self = shift;
1874 $self->throw_exception('delete does not accept any arguments')
1875 if @_;
1876
1877192.16s return $self->_rs_update_delete ('delete');
# spent 2.16s making 19 calls to DBIx::Class::ResultSet::_rs_update_delete, avg 114ms/call
1878}
1879
1880=head2 delete_all
1881
1882=over 4
1883
1884=item Arguments: none
1885
1886=item Return Value: 1
1887
1888=back
1889
1890Fetches all objects and deletes them one at a time via
1891L<DBIx::Class::Row/delete>. Note that C<delete_all> will run DBIC defined
1892triggers, while L</delete> will not.
1893
1894=cut
1895
1896sub delete_all {
1897 my $self = shift;
1898 $self->throw_exception('delete_all does not accept any arguments')
1899 if @_;
1900
1901 my $guard = $self->result_source->schema->txn_scope_guard;
1902 $_->delete for $self->all;
1903 $guard->commit;
1904 return 1;
1905}
1906
1907=head2 populate
1908
1909=over 4
1910
1911=item Arguments: \@data;
1912
1913=back
1914
1915Accepts either an arrayref of hashrefs or alternatively an arrayref of arrayrefs.
1916For the arrayref of hashrefs style each hashref should be a structure suitable
1917for submitting to a $resultset->create(...) method.
1918
1919In void context, C<insert_bulk> in L<DBIx::Class::Storage::DBI> is used
1920to insert the data, as this is a faster method.
1921
1922Otherwise, each set of data is inserted into the database using
1923L<DBIx::Class::ResultSet/create>, and the resulting objects are
1924accumulated into an array. The array itself, or an array reference
1925is returned depending on scalar or list context.
1926
1927Example: Assuming an Artist Class that has many CDs Classes relating:
1928
1929 my $Artist_rs = $schema->resultset("Artist");
1930
1931 ## Void Context Example
1932 $Artist_rs->populate([
1933 { artistid => 4, name => 'Manufactured Crap', cds => [
1934 { title => 'My First CD', year => 2006 },
1935 { title => 'Yet More Tweeny-Pop crap', year => 2007 },
1936 ],
1937 },
1938 { artistid => 5, name => 'Angsty-Whiny Girl', cds => [
1939 { title => 'My parents sold me to a record company', year => 2005 },
1940 { title => 'Why Am I So Ugly?', year => 2006 },
1941 { title => 'I Got Surgery and am now Popular', year => 2007 }
1942 ],
1943 },
1944 ]);
1945
1946 ## Array Context Example
1947 my ($ArtistOne, $ArtistTwo, $ArtistThree) = $Artist_rs->populate([
1948 { name => "Artist One"},
1949 { name => "Artist Two"},
1950 { name => "Artist Three", cds=> [
1951 { title => "First CD", year => 2007},
1952 { title => "Second CD", year => 2008},
1953 ]}
1954 ]);
1955
1956 print $ArtistOne->name; ## response is 'Artist One'
1957 print $ArtistThree->cds->count ## reponse is '2'
1958
1959For the arrayref of arrayrefs style, the first element should be a list of the
1960fieldsnames to which the remaining elements are rows being inserted. For
1961example:
1962
1963 $Arstist_rs->populate([
1964 [qw/artistid name/],
1965 [100, 'A Formally Unknown Singer'],
1966 [101, 'A singer that jumped the shark two albums ago'],
1967 [102, 'An actually cool singer'],
1968 ]);
1969
1970Please note an important effect on your data when choosing between void and
1971wantarray context. Since void context goes straight to C<insert_bulk> in
1972L<DBIx::Class::Storage::DBI> this will skip any component that is overriding
1973C<insert>. So if you are using something like L<DBIx-Class-UUIDColumns> to
1974create primary keys for you, you will find that your PKs are empty. In this
1975case you will have to use the wantarray context in order to create those
1976values.
1977
1978=cut
1979
1980sub populate {
1981 my $self = shift;
1982
1983 # cruft placed in standalone method
1984 my $data = $self->_normalize_populate_args(@_);
1985
1986 return unless @$data;
1987
1988 if(defined wantarray) {
1989 my @created;
1990 foreach my $item (@$data) {
1991 push(@created, $self->create($item));
1992 }
1993 return wantarray ? @created : \@created;
1994 }
1995 else {
1996 my $first = $data->[0];
1997
1998 # if a column is a registered relationship, and is a non-blessed hash/array, consider
1999 # it relationship data
2000 my (@rels, @columns);
2001 my $rsrc = $self->result_source;
2002 my $rels = { map { $_ => $rsrc->relationship_info($_) } $rsrc->relationships };
2003 for (keys %$first) {
2004 my $ref = ref $first->{$_};
2005 $rels->{$_} && ($ref eq 'ARRAY' or $ref eq 'HASH')
2006 ? push @rels, $_
2007 : push @columns, $_
2008 ;
2009 }
2010
2011 my @pks = $rsrc->primary_columns;
2012
2013 ## do the belongs_to relationships
2014 foreach my $index (0..$#$data) {
2015
2016 # delegate to create() for any dataset without primary keys with specified relationships
2017 if (grep { !defined $data->[$index]->{$_} } @pks ) {
2018 for my $r (@rels) {
2019 if (grep { ref $data->[$index]{$r} eq $_ } qw/HASH ARRAY/) { # a related set must be a HASH or AoH
2020 my @ret = $self->populate($data);
2021 return;
2022 }
2023 }
2024 }
2025
2026 foreach my $rel (@rels) {
2027 next unless ref $data->[$index]->{$rel} eq "HASH";
2028 my $result = $self->related_resultset($rel)->create($data->[$index]->{$rel});
2029 my ($reverse_relname, $reverse_relinfo) = %{$rsrc->reverse_relationship_info($rel)};
2030 my $related = $result->result_source->_resolve_condition(
2031 $reverse_relinfo->{cond},
2032 $self,
2033 $result,
2034 $rel,
2035 );
2036
2037 delete $data->[$index]->{$rel};
2038 $data->[$index] = {%{$data->[$index]}, %$related};
2039
2040 push @columns, keys %$related if $index == 0;
2041 }
2042 }
2043
2044 ## inherit the data locked in the conditions of the resultset
2045 my ($rs_data) = $self->_merge_with_rscond({});
2046 delete @{$rs_data}{@columns};
2047 my @inherit_cols = keys %$rs_data;
2048 my @inherit_data = values %$rs_data;
2049
2050 ## do bulk insert on current row
2051 $rsrc->storage->insert_bulk(
2052 $rsrc,
2053 [@columns, @inherit_cols],
2054 [ map { [ @$_{@columns}, @inherit_data ] } @$data ],
2055 );
2056
2057 ## do the has_many relationships
2058 foreach my $item (@$data) {
2059
2060 my $main_row;
2061
2062 foreach my $rel (@rels) {
2063 next unless ref $item->{$rel} eq "ARRAY" && @{ $item->{$rel} };
2064
2065 $main_row ||= $self->new_result({map { $_ => $item->{$_} } @pks});
2066
2067 my $child = $main_row->$rel;
2068
2069 my $related = $child->result_source->_resolve_condition(
2070 $rels->{$rel}{cond},
2071 $child,
2072 $main_row,
2073 $rel,
2074 );
2075
2076 my @rows_to_add = ref $item->{$rel} eq 'ARRAY' ? @{$item->{$rel}} : ($item->{$rel});
2077 my @populate = map { {%$_, %$related} } @rows_to_add;
2078
2079 $child->populate( \@populate );
2080 }
2081 }
2082 }
2083}
2084
2085
2086# populate() argumnets went over several incarnations
2087# What we ultimately support is AoH
2088sub _normalize_populate_args {
2089 my ($self, $arg) = @_;
2090
2091 if (ref $arg eq 'ARRAY') {
2092 if (!@$arg) {
2093 return [];
2094 }
2095 elsif (ref $arg->[0] eq 'HASH') {
2096 return $arg;
2097 }
2098 elsif (ref $arg->[0] eq 'ARRAY') {
2099 my @ret;
2100 my @colnames = @{$arg->[0]};
2101 foreach my $values (@{$arg}[1 .. $#$arg]) {
2102 push @ret, { map { $colnames[$_] => $values->[$_] } (0 .. $#colnames) };
2103 }
2104 return \@ret;
2105 }
2106 }
2107
2108 $self->throw_exception('Populate expects an arrayref of hashrefs or arrayref of arrayrefs');
2109}
2110
2111=head2 pager
2112
2113=over 4
2114
2115=item Arguments: none
2116
2117=item Return Value: $pager
2118
2119=back
2120
2121Return Value a L<Data::Page> object for the current resultset. Only makes
2122sense for queries with a C<page> attribute.
2123
2124To get the full count of entries for a paged resultset, call
2125C<total_entries> on the L<Data::Page> object.
2126
2127=cut
2128
2129sub pager {
2130 my ($self) = @_;
2131
2132 return $self->{pager} if $self->{pager};
2133
2134 my $attrs = $self->{attrs};
2135 if (!defined $attrs->{page}) {
2136 $self->throw_exception("Can't create pager for non-paged rs");
2137 }
2138 elsif ($attrs->{page} <= 0) {
2139 $self->throw_exception('Invalid page number (page-numbers are 1-based)');
2140 }
2141 $attrs->{rows} ||= 10;
2142
2143 # throw away the paging flags and re-run the count (possibly
2144 # with a subselect) to get the real total count
2145 my $count_attrs = { %$attrs };
2146 delete $count_attrs->{$_} for qw/rows offset page pager/;
2147
2148 my $total_rs = (ref $self)->new($self->result_source, $count_attrs);
2149
2150 require DBIx::Class::ResultSet::Pager;
2151 return $self->{pager} = DBIx::Class::ResultSet::Pager->new(
2152 sub { $total_rs->count }, #lazy-get the total
2153 $attrs->{rows},
2154 $self->{attrs}{page},
2155 );
2156}
2157
2158=head2 page
2159
2160=over 4
2161
2162=item Arguments: $page_number
2163
2164=item Return Value: $rs
2165
2166=back
2167
2168Returns a resultset for the $page_number page of the resultset on which page
2169is called, where each page contains a number of rows equal to the 'rows'
2170attribute set on the resultset (10 by default).
2171
2172=cut
2173
2174sub page {
2175 my ($self, $page) = @_;
2176 return (ref $self)->new($self->result_source, { %{$self->{attrs}}, page => $page });
2177}
2178
2179=head2 new_result
2180
2181=over 4
2182
2183=item Arguments: \%vals
2184
2185=item Return Value: $rowobject
2186
2187=back
2188
2189Creates a new row object in the resultset's result class and returns
2190it. The row is not inserted into the database at this point, call
2191L<DBIx::Class::Row/insert> to do that. Calling L<DBIx::Class::Row/in_storage>
2192will tell you whether the row object has been inserted or not.
2193
2194Passes the hashref of input on to L<DBIx::Class::Row/new>.
2195
2196=cut
2197
2198
# spent 285ms (19.5+265) within DBIx::Class::ResultSet::new_result which was called 449 times, avg 634µs/call: # 425 times (17.9ms+249ms) by DBIx::Class::ResultSet::new at line 192, avg 628µs/call # 24 times (1.61ms+16.2ms) by DBIx::Class::ResultSet::create at line 2545, avg 741µs/call
sub new_result {
2199224516.9ms my ($self, $values) = @_;
2200 $self->throw_exception( "new_result needs a hash" )
2201 unless (ref $values eq 'HASH');
2202
220344937.2ms my ($merged_cond, $cols_from_relations) = $self->_merge_with_rscond($values);
# spent 37.2ms making 449 calls to DBIx::Class::ResultSet::_merge_with_rscond, avg 83µs/call
2204
220514µs my %new = (
# spent 4µs making 1 call to DBIx::Class::ResultSet::result_source
2206 %$merged_cond,
2207 @$cols_from_relations
2208 ? (-cols_from_relations => $cols_from_relations)
2209 : (),
2210 -result_source => $self->result_source, # DO NOT REMOVE THIS, REQUIRED
2211 );
2212
2213898228ms return $self->result_class->new(\%new);
# spent 226ms making 449 calls to DBIx::Class::Row::new, avg 503µs/call # spent 2.05ms making 449 calls to DBIx::Class::ResultSet::result_class, avg 5µs/call
2214}
2215
2216# _merge_with_rscond
2217#
2218# Takes a simple hash of K/V data and returns its copy merged with the
2219# condition already present on the resultset. Additionally returns an
2220# arrayref of value/condition names, which were inferred from related
2221# objects (this is needed for in-memory related objects)
2222
# spent 50.8ms (18.4+32.5) within DBIx::Class::ResultSet::_merge_with_rscond which was called 806 times, avg 63µs/call: # 449 times (12.2ms+25.0ms) by DBIx::Class::ResultSet::new_result at line 2203, avg 83µs/call # 357 times (6.18ms+7.47ms) by DBIx::Class::ResultSet::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/ResultSet.pm:858] at line 857, avg 38µs/call
sub _merge_with_rscond {
2223483618.3ms my ($self, $data) = @_;
2224
2225 my (%new_data, @cols_from_relations);
2226
2227 my $alias = $self->{attrs}{alias};
2228
2229 if (! defined $self->{cond}) {
2230 # just massage $data below
2231 }
2232 elsif ($self->{cond} eq $DBIx::Class::ResultSource::UNRESOLVABLE_CONDITION) {
2233 %new_data = %{ $self->{attrs}{related_objects} || {} }; # nothing might have been inserted yet
2234 @cols_from_relations = keys %new_data;
2235 }
2236 elsif (ref $self->{cond} ne 'HASH') {
2237 $self->throw_exception(
2238 "Can't abstract implicit construct, resultset condition not a hash"
2239 );
2240 }
2241 else {
2242 # precendence must be given to passed values over values inherited from
2243 # the cond, so the order here is important.
2244 my $collapsed_cond = $self->_collapse_cond($self->{cond});
2245 my %implied = %{$self->_remove_alias($collapsed_cond, $alias)};
2246
2247 while ( my($col, $value) = each %implied ) {
2248 my $vref = ref $value;
2249 if (
2250 $vref eq 'HASH'
2251 and
2252 keys(%$value) == 1
2253 and
2254 (keys %$value)[0] eq '='
2255 ) {
2256 $new_data{$col} = $value->{'='};
2257 }
2258 elsif( !$vref or $vref eq 'SCALAR' or blessed($value) ) {
2259 $new_data{$col} = $value;
2260 }
2261 }
2262 }
2263
2264 %new_data = (
2265 %new_data,
226680632.5ms %{ $self->_remove_alias($data, $alias) },
# spent 32.5ms making 806 calls to DBIx::Class::ResultSet::_remove_alias, avg 40µs/call
2267 );
2268
2269 return (\%new_data, \@cols_from_relations);
2270}
2271
2272# _has_resolved_attr
2273#
2274# determines if the resultset defines at least one
2275# of the attributes supplied
2276#
2277# used to determine if a subquery is neccessary
2278#
2279# supports some virtual attributes:
2280# -join
2281# This will scan for any joins being present on the resultset.
2282# It is not a mere key-search but a deep inspection of {from}
2283#
2284
2285
# spent 70.3ms (37.2+33.0) within DBIx::Class::ResultSet::_has_resolved_attr which was called 2134 times, avg 33µs/call: # 1949 times (33.5ms+3.38ms) by DBIx::Class::ResultSet::count at line 1428, avg 19µs/call # 147 times (2.47ms+21.8ms) by DBIx::Class::ResultSet::_chain_relationship at line 3065, avg 165µs/call # 19 times (860µs+7.80ms) by DBIx::Class::ResultSet::_rs_update_delete at line 1714, avg 456µs/call # 19 times (428µs+79µs) by DBIx::Class::ResultSet::_rs_update_delete at line 1715, avg 27µs/call
sub _has_resolved_attr {
22861280421.9ms my ($self, @attr_names) = @_;
2287
2288213433.0ms my $attrs = $self->_resolved_attrs;
# spent 33.0ms making 2134 calls to DBIx::Class::ResultSet::_resolved_attrs, avg 15µs/call
2289
2290 my %extra_checks;
2291
2292 for my $n (@attr_names) {
22931571113.0ms if (grep { $n eq $_ } (qw/-join/) ) {
2294 $extra_checks{$n}++;
2295 next;
2296 }
2297
2298 my $attr = $attrs->{$n};
2299
2300 next if not defined $attr;
2301
2302 if (ref $attr eq 'HASH') {
2303 return 1 if keys %$attr;
2304 }
2305 elsif (ref $attr eq 'ARRAY') {
2306 return 1 if @$attr;
2307 }
2308 else {
2309 return 1 if $attr;
2310 }
2311 }
2312
2313 # a resolved join is expressed as a multi-level from
2314 return 1 if (
2315 $extra_checks{-join}
2316 and
2317 ref $attrs->{from} eq 'ARRAY'
2318 and
2319 @{$attrs->{from}} > 1
2320 );
2321
2322 return 0;
2323}
2324
2325# _collapse_cond
2326#
2327# Recursively collapse the condition.
2328
2329sub _collapse_cond {
2330 my ($self, $cond, $collapsed) = @_;
2331
2332 $collapsed ||= {};
2333
2334 if (ref $cond eq 'ARRAY') {
2335 foreach my $subcond (@$cond) {
2336 next unless ref $subcond; # -or
2337 $collapsed = $self->_collapse_cond($subcond, $collapsed);
2338 }
2339 }
2340 elsif (ref $cond eq 'HASH') {
2341 if (keys %$cond and (keys %$cond)[0] eq '-and') {
2342 foreach my $subcond (@{$cond->{-and}}) {
2343 $collapsed = $self->_collapse_cond($subcond, $collapsed);
2344 }
2345 }
2346 else {
2347 foreach my $col (keys %$cond) {
2348 my $value = $cond->{$col};
2349 $collapsed->{$col} = $value;
2350 }
2351 }
2352 }
2353
2354 return $collapsed;
2355}
2356
2357# _remove_alias
2358#
2359# Remove the specified alias from the specified query hash. A copy is made so
2360# the original query is not modified.
2361
2362
# spent 32.5ms (28.9+3.56) within DBIx::Class::ResultSet::_remove_alias which was called 806 times, avg 40µs/call: # 806 times (28.9ms+3.56ms) by DBIx::Class::ResultSet::_merge_with_rscond at line 2266, avg 40µs/call
sub _remove_alias {
2363403015.8ms my ($self, $query, $alias) = @_;
2364
2365 my %orig = %{ $query || {} };
2366 my %unaliased;
2367
2368 foreach my $key (keys %orig) {
2369715819.1ms23863.56ms if ($key !~ /\./) {
# spent 3.56ms making 2386 calls to DBIx::Class::ResultSet::CORE:match, avg 1µs/call
2370 $unaliased{$key} = $orig{$key};
2371 next;
2372 }
2373 $unaliased{$1} = $orig{$key}
2374 if $key =~ m/^(?:\Q$alias\E\.)?([^.]+)$/;
2375 }
2376
2377 return \%unaliased;
2378}
2379
2380=head2 as_query
2381
2382=over 4
2383
2384=item Arguments: none
2385
2386=item Return Value: \[ $sql, @bind ]
2387
2388=back
2389
2390Returns the SQL query and bind vars associated with the invocant.
2391
2392This is generally used as the RHS for a subquery.
2393
2394=cut
2395
2396sub as_query {
2397 my $self = shift;
2398
2399 my $attrs = $self->_resolved_attrs_copy;
2400
2401 # For future use:
2402 #
2403 # in list ctx:
2404 # my ($sql, \@bind, \%dbi_bind_attrs) = _select_args_to_query (...)
2405 # $sql also has no wrapping parenthesis in list ctx
2406 #
2407 my $sqlbind = $self->result_source->storage
2408 ->_select_args_to_query ($attrs->{from}, $attrs->{select}, $attrs->{where}, $attrs);
2409
2410 return $sqlbind;
2411}
2412
2413=head2 find_or_new
2414
2415=over 4
2416
2417=item Arguments: \%vals, \%attrs?
2418
2419=item Return Value: $rowobject
2420
2421=back
2422
2423 my $artist = $schema->resultset('Artist')->find_or_new(
2424 { artist => 'fred' }, { key => 'artists' });
2425
2426 $cd->cd_to_producer->find_or_new({ producer => $producer },
2427 { key => 'primary });
2428
2429Find an existing record from this resultset using L</find>. if none exists,
2430instantiate a new result object and return it. The object will not be saved
2431into your storage until you call L<DBIx::Class::Row/insert> on it.
2432
2433You most likely want this method when looking for existing rows using a unique
2434constraint that is not the primary key, or looking for related rows.
2435
2436If you want objects to be saved immediately, use L</find_or_create> instead.
2437
2438B<Note>: Make sure to read the documentation of L</find> and understand the
2439significance of the C<key> attribute, as its lack may skew your search, and
2440subsequently result in spurious new objects.
2441
2442B<Note>: Take care when using C<find_or_new> with a table having
2443columns with default values that you intend to be automatically
2444supplied by the database (e.g. an auto_increment primary key column).
2445In normal usage, the value of such columns should NOT be included at
2446all in the call to C<find_or_new>, even when set to C<undef>.
2447
2448=cut
2449
2450sub find_or_new {
2451 my $self = shift;
2452 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
2453 my $hash = ref $_[0] eq 'HASH' ? shift : {@_};
2454 if (keys %$hash and my $row = $self->find($hash, $attrs) ) {
2455 return $row;
2456 }
2457 return $self->new_result($hash);
2458}
2459
2460=head2 create
2461
2462=over 4
2463
2464=item Arguments: \%vals
2465
2466=item Return Value: a L<DBIx::Class::Row> $object
2467
2468=back
2469
2470Attempt to create a single new row or a row with multiple related rows
2471in the table represented by the resultset (and related tables). This
2472will not check for duplicate rows before inserting, use
2473L</find_or_create> to do that.
2474
2475To create one row for this resultset, pass a hashref of key/value
2476pairs representing the columns of the table and the values you wish to
2477store. If the appropriate relationships are set up, foreign key fields
2478can also be passed an object representing the foreign row, and the
2479value will be set to its primary key.
2480
2481To create related objects, pass a hashref of related-object column values
2482B<keyed on the relationship name>. If the relationship is of type C<multi>
2483(L<DBIx::Class::Relationship/has_many>) - pass an arrayref of hashrefs.
2484The process will correctly identify columns holding foreign keys, and will
2485transparently populate them from the keys of the corresponding relation.
2486This can be applied recursively, and will work correctly for a structure
2487with an arbitrary depth and width, as long as the relationships actually
2488exists and the correct column data has been supplied.
2489
2490
2491Instead of hashrefs of plain related data (key/value pairs), you may
2492also pass new or inserted objects. New objects (not inserted yet, see
2493L</new>), will be inserted into their appropriate tables.
2494
2495Effectively a shortcut for C<< ->new_result(\%vals)->insert >>.
2496
2497Example of creating a new row.
2498
2499 $person_rs->create({
2500 name=>"Some Person",
2501 email=>"somebody@someplace.com"
2502 });
2503
2504Example of creating a new row and also creating rows in a related C<has_many>
2505or C<has_one> resultset. Note Arrayref.
2506
2507 $artist_rs->create(
2508 { artistid => 4, name => 'Manufactured Crap', cds => [
2509 { title => 'My First CD', year => 2006 },
2510 { title => 'Yet More Tweeny-Pop crap', year => 2007 },
2511 ],
2512 },
2513 );
2514
2515Example of creating a new row and also creating a row in a related
2516C<belongs_to> resultset. Note Hashref.
2517
2518 $cd_rs->create({
2519 title=>"Music for Silly Walks",
2520 year=>2000,
2521 artist => {
2522 name=>"Silly Musician",
2523 }
2524 });
2525
2526=over
2527
2528=item WARNING
2529
2530When subclassing ResultSet never attempt to override this method. Since
2531it is a simple shortcut for C<< $self->new_result($attrs)->insert >>, a
2532lot of the internals simply never call it, so your override will be
2533bypassed more often than not. Override either L<new|DBIx::Class::Row/new>
2534or L<insert|DBIx::Class::Row/insert> depending on how early in the
2535L</create> process you need to intervene.
2536
2537=back
2538
2539=cut
2540
2541
# spent 2.78s (858µs+2.78) within DBIx::Class::ResultSet::create which was called 24 times, avg 116ms/call: # 22 times (763µs+2.57s) by Test::Fixture::DBIC::Schema::_insert at line 76 of Test/Fixture/DBIC/Schema.pm, avg 117ms/call # 2 times (95µs+213ms) by DBIx::Class::Schema::Versioned::_set_db_version at line 713 of DBIx/Class/Schema/Versioned.pm, avg 107ms/call
sub create {
254272883µs my ($self, $attrs) = @_;
2543 $self->throw_exception( "create needs a hashref" )
2544 unless ref $attrs eq 'HASH';
2545482.78s return $self->new_result($attrs)->insert;
# spent 2.77s making 24 calls to DBIx::Class::Row::insert, avg 115ms/call # spent 17.8ms making 24 calls to DBIx::Class::ResultSet::new_result, avg 741µs/call
2546}
2547
2548=head2 find_or_create
2549
2550=over 4
2551
2552=item Arguments: \%vals, \%attrs?
2553
2554=item Return Value: $rowobject
2555
2556=back
2557
2558 $cd->cd_to_producer->find_or_create({ producer => $producer },
2559 { key => 'primary' });
2560
2561Tries to find a record based on its primary key or unique constraints; if none
2562is found, creates one and returns that instead.
2563
2564 my $cd = $schema->resultset('CD')->find_or_create({
2565 cdid => 5,
2566 artist => 'Massive Attack',
2567 title => 'Mezzanine',
2568 year => 2005,
2569 });
2570
2571Also takes an optional C<key> attribute, to search by a specific key or unique
2572constraint. For example:
2573
2574 my $cd = $schema->resultset('CD')->find_or_create(
2575 {
2576 artist => 'Massive Attack',
2577 title => 'Mezzanine',
2578 },
2579 { key => 'cd_artist_title' }
2580 );
2581
2582B<Note>: Make sure to read the documentation of L</find> and understand the
2583significance of the C<key> attribute, as its lack may skew your search, and
2584subsequently result in spurious row creation.
2585
2586B<Note>: Because find_or_create() reads from the database and then
2587possibly inserts based on the result, this method is subject to a race
2588condition. Another process could create a record in the table after
2589the find has completed and before the create has started. To avoid
2590this problem, use find_or_create() inside a transaction.
2591
2592B<Note>: Take care when using C<find_or_create> with a table having
2593columns with default values that you intend to be automatically
2594supplied by the database (e.g. an auto_increment primary key column).
2595In normal usage, the value of such columns should NOT be included at
2596all in the call to C<find_or_create>, even when set to C<undef>.
2597
2598See also L</find> and L</update_or_create>. For information on how to declare
2599unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
2600
2601=cut
2602
2603sub find_or_create {
2604 my $self = shift;
2605 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
2606 my $hash = ref $_[0] eq 'HASH' ? shift : {@_};
2607 if (keys %$hash and my $row = $self->find($hash, $attrs) ) {
2608 return $row;
2609 }
2610 return $self->create($hash);
2611}
2612
2613=head2 update_or_create
2614
2615=over 4
2616
2617=item Arguments: \%col_values, { key => $unique_constraint }?
2618
2619=item Return Value: $row_object
2620
2621=back
2622
2623 $resultset->update_or_create({ col => $val, ... });
2624
2625Like L</find_or_create>, but if a row is found it is immediately updated via
2626C<< $found_row->update (\%col_values) >>.
2627
2628
2629Takes an optional C<key> attribute to search on a specific unique constraint.
2630For example:
2631
2632 # In your application
2633 my $cd = $schema->resultset('CD')->update_or_create(
2634 {
2635 artist => 'Massive Attack',
2636 title => 'Mezzanine',
2637 year => 1998,
2638 },
2639 { key => 'cd_artist_title' }
2640 );
2641
2642 $cd->cd_to_producer->update_or_create({
2643 producer => $producer,
2644 name => 'harry',
2645 }, {
2646 key => 'primary',
2647 });
2648
2649B<Note>: Make sure to read the documentation of L</find> and understand the
2650significance of the C<key> attribute, as its lack may skew your search, and
2651subsequently result in spurious row creation.
2652
2653B<Note>: Take care when using C<update_or_create> with a table having
2654columns with default values that you intend to be automatically
2655supplied by the database (e.g. an auto_increment primary key column).
2656In normal usage, the value of such columns should NOT be included at
2657all in the call to C<update_or_create>, even when set to C<undef>.
2658
2659See also L</find> and L</find_or_create>. For information on how to declare
2660unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
2661
2662=cut
2663
2664sub update_or_create {
2665 my $self = shift;
2666 my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
2667 my $cond = ref $_[0] eq 'HASH' ? shift : {@_};
2668
2669 my $row = $self->find($cond, $attrs);
2670 if (defined $row) {
2671 $row->update($cond);
2672 return $row;
2673 }
2674
2675 return $self->create($cond);
2676}
2677
2678=head2 update_or_new
2679
2680=over 4
2681
2682=item Arguments: \%col_values, { key => $unique_constraint }?
2683
2684=item Return Value: $rowobject
2685
2686=back
2687
2688 $resultset->update_or_new({ col => $val, ... });
2689
2690Like L</find_or_new> but if a row is found it is immediately updated via
2691C<< $found_row->update (\%col_values) >>.
2692
2693For example:
2694
2695 # In your application
2696 my $cd = $schema->resultset('CD')->update_or_new(
2697 {
2698 artist => 'Massive Attack',
2699 title => 'Mezzanine',
2700 year => 1998,
2701 },
2702 { key => 'cd_artist_title' }
2703 );
2704
2705 if ($cd->in_storage) {
2706 # the cd was updated
2707 }
2708 else {
2709 # the cd is not yet in the database, let's insert it
2710 $cd->insert;
2711 }
2712
2713B<Note>: Make sure to read the documentation of L</find> and understand the
2714significance of the C<key> attribute, as its lack may skew your search, and
2715subsequently result in spurious new objects.
2716
2717B<Note>: Take care when using C<update_or_new> with a table having
2718columns with default values that you intend to be automatically
2719supplied by the database (e.g. an auto_increment primary key column).
2720In normal usage, the value of such columns should NOT be included at
2721all in the call to C<update_or_new>, even when set to C<undef>.
2722
2723See also L</find>, L</find_or_create> and L</find_or_new>.
2724
2725=cut
2726
2727sub update_or_new {
2728 my $self = shift;
2729 my $attrs = ( @_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {} );
2730 my $cond = ref $_[0] eq 'HASH' ? shift : {@_};
2731
2732 my $row = $self->find( $cond, $attrs );
2733 if ( defined $row ) {
2734 $row->update($cond);
2735 return $row;
2736 }
2737
2738 return $self->new_result($cond);
2739}
2740
2741=head2 get_cache
2742
2743=over 4
2744
2745=item Arguments: none
2746
2747=item Return Value: \@cache_objects | undef
2748
2749=back
2750
2751Gets the contents of the cache for the resultset, if the cache is set.
2752
2753The cache is populated either by using the L</prefetch> attribute to
2754L</search> or by calling L</set_cache>.
2755
2756=cut
2757
2758
# spent 26.3ms within DBIx::Class::ResultSet::get_cache which was called 13565 times, avg 2µs/call: # 7541 times (17.2ms+0s) by DBIx::Class::ResultSet::search_rs at line 332, avg 2µs/call # 2318 times (4.36ms+0s) by DBIx::Class::ResultSet::next at line 1193, avg 2µs/call # 1949 times (2.36ms+0s) by DBIx::Class::ResultSet::count at line 1418, avg 1µs/call # 1610 times (2.22ms+0s) by DBIx::Class::ResultSet::all at line 1633, avg 1µs/call # 147 times (220µs+0s) by DBIx::Class::ResultSet::related_resultset at line 2889, avg 1µs/call
sub get_cache {
27591356546.7ms shift->{all_cache};
2760}
2761
2762=head2 set_cache
2763
2764=over 4
2765
2766=item Arguments: \@cache_objects
2767
2768=item Return Value: \@cache_objects
2769
2770=back
2771
2772Sets the contents of the cache for the resultset. Expects an arrayref
2773of objects of the same class as those produced by the resultset. Note that
2774if the cache is set the resultset will return the cached objects rather
2775than re-querying the database even if the cache attr is not set.
2776
2777The contents of the cache can also be populated by using the
2778L</prefetch> attribute to L</search>.
2779
2780=cut
2781
2782sub set_cache {
2783 my ( $self, $data ) = @_;
2784 $self->throw_exception("set_cache requires an arrayref")
2785 if defined($data) && (ref $data ne 'ARRAY');
2786 $self->{all_cache} = $data;
2787}
2788
2789=head2 clear_cache
2790
2791=over 4
2792
2793=item Arguments: none
2794
2795=item Return Value: undef
2796
2797=back
2798
2799Clears the cache for the resultset.
2800
2801=cut
2802
2803sub clear_cache {
2804 shift->set_cache(undef);
2805}
2806
2807=head2 is_paged
2808
2809=over 4
2810
2811=item Arguments: none
2812
2813=item Return Value: true, if the resultset has been paginated
2814
2815=back
2816
2817=cut
2818
2819sub is_paged {
2820 my ($self) = @_;
2821 return !!$self->{attrs}{page};
2822}
2823
2824=head2 is_ordered
2825
2826=over 4
2827
2828=item Arguments: none
2829
2830=item Return Value: true, if the resultset has been ordered with C<order_by>.
2831
2832=back
2833
2834=cut
2835
2836sub is_ordered {
2837 my ($self) = @_;
2838 return scalar $self->result_source->storage->_extract_order_criteria($self->{attrs}{order_by});
2839}
2840
2841=head2 related_resultset
2842
2843=over 4
2844
2845=item Arguments: $relationship_name
2846
2847=item Return Value: $resultset
2848
2849=back
2850
2851Returns a related resultset for the supplied relationship name.
2852
2853 $artist_rs = $schema->resultset('CD')->related_resultset('Artist');
2854
2855=cut
2856
2857
# spent 124ms (9.13+115) within DBIx::Class::ResultSet::related_resultset which was called 147 times, avg 846µs/call: # 147 times (9.13ms+115ms) by DBIx::Class::ResultSet::search_related at line 923, avg 846µs/call
sub related_resultset {
28584411.04ms my ($self, $rel) = @_;
2859
2860 $self->{related_resultsets} ||= {};
286120584.58ms return $self->{related_resultsets}{$rel} ||= do {
286211µs my $rsrc = $self->result_source;
# spent 1µs making 1 call to DBIx::Class::ResultSet::result_source
2863147417µs my $rel_info = $rsrc->relationship_info($rel);
# spent 417µs making 147 calls to DBIx::Class::ResultSource::relationship_info, avg 3µs/call
2864
2865 $self->throw_exception(
2866 "search_related: result source '" . $rsrc->source_name .
2867 "' has no such relationship $rel")
2868 unless $rel_info;
2869
287014758.1ms my $attrs = $self->_chain_relationship($rel);
# spent 58.1ms making 147 calls to DBIx::Class::ResultSet::_chain_relationship, avg 395µs/call
2871
2872 my $join_count = $attrs->{seen_join}{$rel};
2873
28742952.64ms my $alias = $self->result_source->storage
# spent 2.30ms making 147 calls to DBIx::Class::ResultSource::storage, avg 16µs/call # spent 345µs making 147 calls to DBIx::Class::Storage::DBI::relname_to_table_alias, avg 2µs/call # spent 900ns making 1 call to DBIx::Class::ResultSet::result_source
2875 ->relname_to_table_alias($rel, $join_count);
2876
2877 # since this is search_related, and we already slid the select window inwards
2878 # (the select/as attrs were deleted in the beginning), we need to flip all
2879 # left joins to inner, so we get the expected results
2880 # read the comment on top of the actual function to see what this does
28814416.39ms $attrs->{from} = $rsrc->schema->storage->_inner_join_to_node ($attrs->{from}, $alias);
# spent 4.91ms making 147 calls to DBIx::Class::Storage::DBIHacks::_inner_join_to_node, avg 33µs/call # spent 1.26ms making 147 calls to DBIx::Class::Schema::storage, avg 9µs/call # spent 215µs making 147 calls to DBIx::Class::ResultSource::schema, avg 1µs/call
2882
2883
2884 #XXX - temp fix for result_class bug. There likely is a more elegant fix -groditi
2885 delete @{$attrs}{qw(result_class alias)};
2886
2887 my $new_cache;
2888
2889147220µs if (my $cache = $self->get_cache) {
# spent 220µs making 147 calls to DBIx::Class::ResultSet::get_cache, avg 1µs/call
2890 if ($cache->[0] && $cache->[0]->related_resultset($rel)->get_cache) {
2891 $new_cache = [ map { @{$_->related_resultset($rel)->get_cache} }
2892 @$cache ];
2893 }
2894 }
2895
28961477.65ms my $rel_source = $rsrc->related_source($rel);
# spent 7.65ms making 147 calls to DBIx::Class::ResultSource::related_source, avg 52µs/call
2897
28984411.83ms my $new = do {
2899
2900 # The reason we do this now instead of passing the alias to the
2901 # search_rs below is that if you wrap/overload resultset on the
2902 # source you need to know what alias it's -going- to have for things
2903 # to work sanely (e.g. RestrictWithObject wants to be able to add
2904 # extra query restrictions, and these may need to be $alias.)
2905
29062195µs my $rel_attrs = $rel_source->resultset_attributes;
2907 local $rel_attrs->{alias} = $alias;
2908
290929439.5ms $rel_source->resultset
# spent 20.8ms making 147 calls to DBIx::Class::ResultSource::resultset, avg 141µs/call # spent 18.8ms making 147 calls to DBIx::Class::ResultSet::search_rs, avg 128µs/call
2910 ->search_rs(
2911 undef, {
2912 %$attrs,
2913 where => $attrs->{where},
2914 });
2915 };
2916 $new->set_cache($new_cache) if $new_cache;
2917 $new;
2918 };
2919}
2920
2921=head2 current_source_alias
2922
2923=over 4
2924
2925=item Arguments: none
2926
2927=item Return Value: $source_alias
2928
2929=back
2930
2931Returns the current table alias for the result source this resultset is built
2932on, that will be used in the SQL query. Usually it is C<me>.
2933
2934Currently the source alias that refers to the result set returned by a
2935L</search>/L</find> family method depends on how you got to the resultset: it's
2936C<me> by default, but eg. L</search_related> aliases it to the related result
2937source name (and keeps C<me> referring to the original result set). The long
2938term goal is to make L<DBIx::Class> always alias the current resultset as C<me>
2939(and make this method unnecessary).
2940
2941Thus it's currently necessary to use this method in predefined queries (see
2942L<DBIx::Class::Manual::Cookbook/Predefined searches>) when referring to the
2943source alias of the current result set:
2944
2945 # in a result set class
2946 sub modified_by {
2947 my ($self, $user) = @_;
2948
2949 my $me = $self->current_source_alias;
2950
2951 return $self->search(
2952 "$me.modified" => $user->id,
2953 );
2954 }
2955
2956=cut
2957
2958
# spent 6.79ms within DBIx::Class::ResultSet::current_source_alias which was called 1954 times, avg 3µs/call: # 1954 times (6.79ms+0s) by DBIx::Class::ResultSetColumn::new at line 49 of DBIx/Class/ResultSetColumn.pm, avg 3µs/call
sub current_source_alias {
2959390810.1ms my ($self) = @_;
2960
2961 return ($self->{attrs} || {})->{alias} || 'me';
2962}
2963
2964=head2 as_subselect_rs
2965
2966=over 4
2967
2968=item Arguments: none
2969
2970=item Return Value: $resultset
2971
2972=back
2973
2974Act as a barrier to SQL symbols. The resultset provided will be made into a
2975"virtual view" by including it as a subquery within the from clause. From this
2976point on, any joined tables are inaccessible to ->search on the resultset (as if
2977it were simply where-filtered without joins). For example:
2978
2979 my $rs = $schema->resultset('Bar')->search({'x.name' => 'abc'},{ join => 'x' });
2980
2981 # 'x' now pollutes the query namespace
2982
2983 # So the following works as expected
2984 my $ok_rs = $rs->search({'x.other' => 1});
2985
2986 # But this doesn't: instead of finding a 'Bar' related to two x rows (abc and
2987 # def) we look for one row with contradictory terms and join in another table
2988 # (aliased 'x_2') which we never use
2989 my $broken_rs = $rs->search({'x.name' => 'def'});
2990
2991 my $rs2 = $rs->as_subselect_rs;
2992
2993 # doesn't work - 'x' is no longer accessible in $rs2, having been sealed away
2994 my $not_joined_rs = $rs2->search({'x.other' => 1});
2995
2996 # works as expected: finds a 'table' row related to two x rows (abc and def)
2997 my $correctly_joined_rs = $rs2->search({'x.name' => 'def'});
2998
2999Another example of when one might use this would be to select a subset of
3000columns in a group by clause:
3001
3002 my $rs = $schema->resultset('Bar')->search(undef, {
3003 group_by => [qw{ id foo_id baz_id }],
3004 })->as_subselect_rs->search(undef, {
3005 columns => [qw{ id foo_id }]
3006 });
3007
3008In the above example normally columns would have to be equal to the group by,
3009but because we isolated the group by into a subselect the above works.
3010
3011=cut
3012
3013sub as_subselect_rs {
3014 my $self = shift;
3015
3016 my $attrs = $self->_resolved_attrs;
3017
3018 my $fresh_rs = (ref $self)->new (
3019 $self->result_source
3020 );
3021
3022 # these pieces will be locked in the subquery
3023 delete $fresh_rs->{cond};
3024 delete @{$fresh_rs->{attrs}}{qw/where bind/};
3025
3026 return $fresh_rs->search( {}, {
3027 from => [{
3028 $attrs->{alias} => $self->as_query,
3029 -alias => $attrs->{alias},
3030 -rsrc => $self->result_source,
3031 }],
3032 alias => $attrs->{alias},
3033 });
3034}
3035
3036# This code is called by search_related, and makes sure there
3037# is clear separation between the joins before, during, and
3038# after the relationship. This information is needed later
3039# in order to properly resolve prefetch aliases (any alias
3040# with a relation_chain_depth less than the depth of the
3041# current prefetch is not considered)
3042#
3043# The increments happen twice per join. An even number means a
3044# relationship specified via a search_related, whereas an odd
3045# number indicates a join/prefetch added via attributes
3046#
3047# Also this code will wrap the current resultset (the one we
3048# chain to) in a subselect IFF it contains limiting attributes
3049
# spent 58.1ms (7.75+50.4) within DBIx::Class::ResultSet::_chain_relationship which was called 147 times, avg 395µs/call: # 147 times (7.75ms+50.4ms) by DBIx::Class::ResultSet::related_resultset at line 2870, avg 395µs/call
sub _chain_relationship {
305026466.29ms my ($self, $rel) = @_;
30511500ns my $source = $self->result_source;
# spent 500ns making 1 call to DBIx::Class::ResultSet::result_source
3052 my $attrs = { %{$self->{attrs}||{}} };
3053
3054 # we need to take the prefetch the attrs into account before we
3055 # ->_resolve_join as otherwise they get lost - captainL
3056147526µs my $join = $self->_merge_joinpref_attr( $attrs->{join}, $attrs->{prefetch} );
# spent 526µs making 147 calls to DBIx::Class::ResultSet::_merge_joinpref_attr, avg 4µs/call
3057
3058 delete @{$attrs}{qw/join prefetch collapse group_by distinct select as columns +select +as +columns/};
3059
3060 my $seen = { %{ (delete $attrs->{seen_join}) || {} } };
3061
3062 my $from;
3063 my @force_subq_attrs = qw/offset rows group_by having/;
3064
3065147604µs14724.2ms if (
# spent 24.2ms making 147 calls to DBIx::Class::ResultSet::_has_resolved_attr, avg 165µs/call
3066 ($attrs->{from} && ref $attrs->{from} ne 'ARRAY')
3067 ||
3068 $self->_has_resolved_attr (@force_subq_attrs)
3069 ) {
3070 # Nuke the prefetch (if any) before the new $rs attrs
3071 # are resolved (prefetch is useless - we are wrapping
3072 # a subquery anyway).
3073 my $rs_copy = $self->search;
3074 $rs_copy->{attrs}{join} = $self->_merge_joinpref_attr (
3075 $rs_copy->{attrs}{join},
3076 delete $rs_copy->{attrs}{prefetch},
3077 );
3078
3079 $from = [{
3080 -rsrc => $source,
3081 -alias => $attrs->{alias},
3082 $attrs->{alias} => $rs_copy->as_query,
3083 }];
3084 delete @{$attrs}{@force_subq_attrs, qw/where bind/};
3085 $seen->{-relation_chain_depth} = 0;
3086 }
3087 elsif ($attrs->{from}) { #shallow copy suffices
3088 $from = [ @{$attrs->{from}} ];
3089 }
3090 else {
3091147259µs $from = [{
# spent 259µs making 147 calls to DBIx::Class::ResultSource::Table::from, avg 2µs/call
3092 -rsrc => $source,
3093 -alias => $attrs->{alias},
3094 $attrs->{alias} => $source->from,
3095 }];
3096 }
3097
3098 my $jpath = ($seen->{-relation_chain_depth})
3099 ? $from->[-1][0]{-join_path}
3100 : [];
3101
3102147971µs my @requested_joins = $source->_resolve_join(
# spent 971µs making 147 calls to DBIx::Class::ResultSource::_resolve_join, avg 7µs/call
3103 $join,
3104 $attrs->{alias},
3105 $seen,
3106 $jpath,
3107 );
3108
3109 push @$from, @requested_joins;
3110
3111 $seen->{-relation_chain_depth}++;
3112
3113 # if $self already had a join/prefetch specified on it, the requested
3114 # $rel might very well be already included. What we do in this case
3115 # is effectively a no-op (except that we bump up the chain_depth on
3116 # the join in question so we could tell it *is* the search_related)
3117 my $already_joined;
3118
3119 # we consider the last one thus reverse
3120 for my $j (reverse @requested_joins) {
3121 my ($last_j) = keys %{$j->[0]{-join_path}[-1]};
3122 if ($rel eq $last_j) {
3123 $j->[0]{-relation_chain_depth}++;
3124 $already_joined++;
3125 last;
3126 }
3127 }
3128
312914724.4ms unless ($already_joined) {
# spent 24.4ms making 147 calls to DBIx::Class::ResultSource::_resolve_join, avg 166µs/call
3130 push @$from, $source->_resolve_join(
3131 $rel,
3132 $attrs->{alias},
3133 $seen,
3134 $jpath,
3135 );
3136 }
3137
3138 $seen->{-relation_chain_depth}++;
3139
3140 return {%$attrs, from => $from, seen_join => $seen};
3141}
3142
3143# too many times we have to do $attrs = { %{$self->_resolved_attrs} }
3144
# spent 845ms (104+741) within DBIx::Class::ResultSet::_resolved_attrs_copy which was called 9987 times, avg 85µs/call: # 6031 times (54.7ms+400ms) by DBIx::Class::ResultSet::cursor at line 955, avg 75µs/call # 2007 times (25.8ms+3.97ms) by DBIx::Class::ResultSet::single at line 1011, avg 15µs/call # 1949 times (23.9ms+337ms) by DBIx::Class::ResultSet::count at line 1420, avg 185µs/call
sub _resolved_attrs_copy {
314519974100ms my $self = shift;
31469987741ms return { %{$self->_resolved_attrs (@_)} };
# spent 741ms making 9987 calls to DBIx::Class::ResultSet::_resolved_attrs, avg 74µs/call
3147}
3148
3149
# spent 1.75s (1.17+582ms) within DBIx::Class::ResultSet::_resolved_attrs which was called 17692 times, avg 99µs/call: # 9987 times (486ms+254ms) by DBIx::Class::ResultSet::_resolved_attrs_copy at line 3146, avg 74µs/call # 2134 times (22.9ms+10.1ms) by DBIx::Class::ResultSet::_has_resolved_attr at line 2288, avg 15µs/call # 2007 times (348ms+146ms) by DBIx::Class::ResultSet::find at line 804, avg 246µs/call # 1954 times (92.6ms+74.7ms) by DBIx::Class::ResultSetColumn::new at line 48 of DBIx/Class/ResultSetColumn.pm, avg 86µs/call # 1610 times (215ms+97.0ms) by DBIx::Class::ResultSet::all at line 1637, avg 194µs/call
sub _resolved_attrs {
3150315534487ms my $self = shift;
3151 return $self->{_attrs} if $self->{_attrs};
3152
3153 my $attrs = { %{ $self->{attrs} || {} } };
315412µs my $source = $self->result_source;
# spent 2µs making 1 call to DBIx::Class::ResultSet::result_source
3155 my $alias = $attrs->{alias};
3156
3157 # default selection list
3158 $attrs->{columns} = [ $source->columns ]
31593919478.6ms1764684.4ms unless List::Util::first { exists $attrs->{$_} } qw/columns cols select as/;
# spent 45.1ms making 6871 calls to DBIx::Class::ResultSource::columns, avg 7µs/call # spent 39.4ms making 10775 calls to List::Util::first, avg 4µs/call
3160
3161 # merge selectors together
3162 for (qw/columns select as/) {
31633232583.9ms14678385ms $attrs->{$_} = $self->_merge_attr($attrs->{$_}, delete $attrs->{"+$_"})
# spent 385ms making 14678 calls to DBIx::Class::ResultSet::_merge_attr, avg 26µs/call
3164 if $attrs->{$_} or $attrs->{"+$_"};
3165 }
3166
3167 # disassemble columns
3168 my (@sel, @as);
3169687211.7ms if (my $cols = delete $attrs->{columns}) {
3170 for my $c (ref $cols eq 'ARRAY' ? @$cols : $cols) {
317112718272.7ms if (ref $c eq 'HASH') {
3172 for my $as (keys %$c) {
3173 push @sel, $c->{$as};
3174 push @as, $as;
3175 }
3176 }
3177 else {
3178 push @sel, $c;
3179 push @as, $c;
3180 }
3181 }
3182 }
3183
3184 # when trying to weed off duplicates later do not go past this point -
3185 # everything added from here on is unbalanced "anyone's guess" stuff
3186 my $dedup_stop_idx = $#as;
3187
3188 push @as, @{ ref $attrs->{as} eq 'ARRAY' ? $attrs->{as} : [ $attrs->{as} ] }
3189 if $attrs->{as};
3190 push @sel, @{ ref $attrs->{select} eq 'ARRAY' ? $attrs->{select} : [ $attrs->{select} ] }
3191 if $attrs->{select};
3192
3193 # assume all unqualified selectors to apply to the current alias (legacy stuff)
3194 for (@sel) {
319546297158ms4239927.0ms $_ = (ref $_ or $_ =~ /\./) ? $_ : "$alias.$_";
# spent 27.0ms making 42399 calls to DBIx::Class::ResultSet::CORE:match, avg 638ns/call
3196 }
3197
3198 # disqualify all $alias.col as-bits (collapser mandated)
3199 for (@as) {
320046297251ms9259452.3ms $_ = ($_ =~ /^\Q$alias.\E(.+)$/) ? $1 : $_;
# spent 36.7ms making 46297 calls to DBIx::Class::ResultSet::CORE:regcomp, avg 792ns/call # spent 15.7ms making 46297 calls to DBIx::Class::ResultSet::CORE:match, avg 338ns/call
3201 }
3202
3203 # de-duplicate the result (remove *identical* select/as pairs)
3204 # and also die on duplicate {as} pointing to different {select}s
3205 # not using a c-style for as the condition is prone to shrinkage
3206 my $seen;
3207 my $i = 0;
3208 while ($i <= $dedup_stop_idx) {
320984788127ms if ($seen->{"$sel[$i] \x00\x00 $as[$i]"}++) {
3210 splice @sel, $i, 1;
3211 splice @as, $i, 1;
3212 $dedup_stop_idx--;
3213 }
3214 elsif ($seen->{$as[$i]}++) {
3215 $self->throw_exception(
3216 "inflate_result() alias '$as[$i]' specified twice with different SQL-side {select}-ors"
3217 );
3218 }
3219 else {
3220 $i++;
3221 }
3222 }
3223
3224 $attrs->{select} = \@sel;
3225 $attrs->{as} = \@as;
3226
3227673032.9ms $attrs->{from} ||= [{
# spent 32.9ms making 6730 calls to DBIx::Class::ResultSource::Table::from, avg 5µs/call
3228 -rsrc => $source,
3229 -alias => $self->{attrs}{alias},
3230 $self->{attrs}{alias} => $source->from,
3231 }];
3232
3233 if ( $attrs->{join} || $attrs->{prefetch} ) {
3234
3235 $self->throw_exception ('join/prefetch can not be used with a custom {from}')
3236 if ref $attrs->{from} ne 'ARRAY';
3237
3238 my $join = (delete $attrs->{join}) || {};
3239
3240 if ( defined $attrs->{prefetch} ) {
3241 $join = $self->_merge_joinpref_attr( $join, $attrs->{prefetch} );
3242 }
3243
3244 $attrs->{from} = # have to copy here to avoid corrupting the original
3245 [
3246 @{ $attrs->{from} },
3247 $source->_resolve_join(
3248 $join,
3249 $alias,
3250 { %{ $attrs->{seen_join} || {} } },
3251 ( $attrs->{seen_join} && keys %{$attrs->{seen_join}})
3252 ? $attrs->{from}[-1][0]{-join_path}
3253 : []
3254 ,
3255 )
3256 ];
3257 }
3258
3259 if ( defined $attrs->{order_by} ) {
3260 $attrs->{order_by} = (
3261 ref( $attrs->{order_by} ) eq 'ARRAY'
3262 ? [ @{ $attrs->{order_by} } ]
3263 : [ $attrs->{order_by} || () ]
3264 );
3265 }
3266
3267 if ($attrs->{group_by} and ref $attrs->{group_by} ne 'ARRAY') {
3268 $attrs->{group_by} = [ $attrs->{group_by} ];
3269 }
3270
3271 # generate the distinct induced group_by early, as prefetch will be carried via a
3272 # subquery (since a group_by is present)
3273118µs if (delete $attrs->{distinct}) {
3274 if ($attrs->{group_by}) {
3275 carp_unique ("Useless use of distinct on a grouped resultset ('distinct' is ignored when a 'group_by' is present)");
3276 }
3277 else {
3278 # distinct affects only the main selection part, not what prefetch may
3279 # add below.
32802373µs $attrs->{group_by} = $source->storage->_group_over_selection (
# spent 353µs making 1 call to DBIx::Class::Storage::DBIHacks::_group_over_selection # spent 20µs making 1 call to DBIx::Class::ResultSource::storage
3281 $attrs->{from},
3282 $attrs->{select},
3283 $attrs->{order_by},
3284 );
3285 }
3286 }
3287
3288 $attrs->{collapse} ||= {};
3289 if ($attrs->{prefetch}) {
3290
3291 $self->throw_exception("Unable to prefetch, resultset contains an unnamed selector $attrs->{_dark_selector}{string}")
3292 if $attrs->{_dark_selector};
3293
3294 my $prefetch = $self->_merge_joinpref_attr( {}, delete $attrs->{prefetch} );
3295
3296 my $prefetch_ordering = [];
3297
3298 # this is a separate structure (we don't look in {from} directly)
3299 # as the resolver needs to shift things off the lists to work
3300 # properly (identical-prefetches on different branches)
3301 my $join_map = {};
3302 if (ref $attrs->{from} eq 'ARRAY') {
3303
3304 my $start_depth = $attrs->{seen_join}{-relation_chain_depth} || 0;
3305
3306 for my $j ( @{$attrs->{from}}[1 .. $#{$attrs->{from}} ] ) {
3307 next unless $j->[0]{-alias};
3308 next unless $j->[0]{-join_path};
3309 next if ($j->[0]{-relation_chain_depth} || 0) < $start_depth;
3310
3311 my @jpath = map { keys %$_ } @{$j->[0]{-join_path}};
3312
3313 my $p = $join_map;
3314 $p = $p->{$_} ||= {} for @jpath[ ($start_depth/2) .. $#jpath]; #only even depths are actual jpath boundaries
3315 push @{$p->{-join_aliases} }, $j->[0]{-alias};
3316 }
3317 }
3318
3319 my @prefetch =
3320 $source->_resolve_prefetch( $prefetch, $alias, $join_map, $prefetch_ordering, $attrs->{collapse} );
3321
3322 # we need to somehow mark which columns came from prefetch
3323 if (@prefetch) {
3324 my $sel_end = $#{$attrs->{select}};
3325 $attrs->{_prefetch_selector_range} = [ $sel_end + 1, $sel_end + @prefetch ];
3326 }
3327
3328 push @{ $attrs->{select} }, (map { $_->[0] } @prefetch);
3329 push @{ $attrs->{as} }, (map { $_->[1] } @prefetch);
3330
3331 push( @{$attrs->{order_by}}, @$prefetch_ordering );
3332 $attrs->{_collapse_order_by} = \@$prefetch_ordering;
3333 }
3334
3335
3336 # if both page and offset are specified, produce a combined offset
3337 # even though it doesn't make much sense, this is what pre 081xx has
3338 # been doing
3339 if (my $page = delete $attrs->{page}) {
3340 $attrs->{offset} =
3341 ($attrs->{rows} * ($page - 1))
3342 +
3343 ($attrs->{offset} || 0)
3344 ;
3345 }
3346
3347 return $self->{_attrs} = $attrs;
3348}
3349
3350sub _rollout_attr {
3351 my ($self, $attr) = @_;
3352
3353 if (ref $attr eq 'HASH') {
3354 return $self->_rollout_hash($attr);
3355 } elsif (ref $attr eq 'ARRAY') {
3356 return $self->_rollout_array($attr);
3357 } else {
3358 return [$attr];
3359 }
3360}
3361
3362sub _rollout_array {
3363 my ($self, $attr) = @_;
3364
3365 my @rolled_array;
3366 foreach my $element (@{$attr}) {
3367 if (ref $element eq 'HASH') {
3368 push( @rolled_array, @{ $self->_rollout_hash( $element ) } );
3369 } elsif (ref $element eq 'ARRAY') {
3370 # XXX - should probably recurse here
3371 push( @rolled_array, @{$self->_rollout_array($element)} );
3372 } else {
3373 push( @rolled_array, $element );
3374 }
3375 }
3376 return \@rolled_array;
3377}
3378
3379sub _rollout_hash {
3380 my ($self, $attr) = @_;
3381
3382 my @rolled_array;
3383 foreach my $key (keys %{$attr}) {
3384 push( @rolled_array, { $key => $attr->{$key} } );
3385 }
3386 return \@rolled_array;
3387}
3388
3389sub _calculate_score {
3390 my ($self, $a, $b) = @_;
3391
3392 if (defined $a xor defined $b) {
3393 return 0;
3394 }
3395 elsif (not defined $a) {
3396 return 1;
3397 }
3398
3399 if (ref $b eq 'HASH') {
3400 my ($b_key) = keys %{$b};
3401 if (ref $a eq 'HASH') {
3402 my ($a_key) = keys %{$a};
3403 if ($a_key eq $b_key) {
3404 return (1 + $self->_calculate_score( $a->{$a_key}, $b->{$b_key} ));
3405 } else {
3406 return 0;
3407 }
3408 } else {
3409 return ($a eq $b_key) ? 1 : 0;
3410 }
3411 } else {
3412 if (ref $a eq 'HASH') {
3413 my ($a_key) = keys %{$a};
3414 return ($b eq $a_key) ? 1 : 0;
3415 } else {
3416 return ($b eq $a) ? 1 : 0;
3417 }
3418 }
3419}
3420
3421
# spent 7.74ms within DBIx::Class::ResultSet::_merge_joinpref_attr which was called 2101 times, avg 4µs/call: # 1954 times (7.21ms+0s) by DBIx::Class::ResultSetColumn::new at line 86 of DBIx/Class/ResultSetColumn.pm, avg 4µs/call # 147 times (526µs+0s) by DBIx::Class::ResultSet::_chain_relationship at line 3056, avg 4µs/call
sub _merge_joinpref_attr {
3422420211.5ms my ($self, $orig, $import) = @_;
3423
3424 return $import unless defined($orig);
3425 return $orig unless defined($import);
3426
3427 $orig = $self->_rollout_attr($orig);
3428 $import = $self->_rollout_attr($import);
3429
3430 my $seen_keys;
3431 foreach my $import_element ( @{$import} ) {
3432 # find best candidate from $orig to merge $b_element into
3433 my $best_candidate = { position => undef, score => 0 }; my $position = 0;
3434 foreach my $orig_element ( @{$orig} ) {
3435 my $score = $self->_calculate_score( $orig_element, $import_element );
3436 if ($score > $best_candidate->{score}) {
3437 $best_candidate->{position} = $position;
3438 $best_candidate->{score} = $score;
3439 }
3440 $position++;
3441 }
3442 my ($import_key) = ( ref $import_element eq 'HASH' ) ? keys %{$import_element} : ($import_element);
3443 $import_key = '' if not defined $import_key;
3444
3445 if ($best_candidate->{score} == 0 || exists $seen_keys->{$import_key}) {
3446 push( @{$orig}, $import_element );
3447 } else {
3448 my $orig_best = $orig->[$best_candidate->{position}];
3449 # merge orig_best and b_element together and replace original with merged
3450 if (ref $orig_best ne 'HASH') {
3451 $orig->[$best_candidate->{position}] = $import_element;
3452 } elsif (ref $import_element eq 'HASH') {
3453 my ($key) = keys %{$orig_best};
3454 $orig->[$best_candidate->{position}] = { $key => $self->_merge_joinpref_attr($orig_best->{$key}, $import_element->{$key}) };
3455 }
3456 }
3457 $seen_keys->{$import_key} = 1; # don't merge the same key twice
3458 }
3459
3460 return $orig;
3461}
3462
3463{
34642900ns my $hm;
3465
3466
# spent 696ms (149+547) within DBIx::Class::ResultSet::_merge_attr which was called 34199 times, avg 20µs/call: # 14678 times (87.6ms+297ms) by DBIx::Class::ResultSet::_resolved_attrs at line 3163, avg 26µs/call # 7806 times (27.2ms+111ms) by DBIx::Class::ResultSet::_normalize_selection at line 526, avg 18µs/call # 7806 times (22.7ms+94.4ms) by DBIx::Class::ResultSet::_normalize_selection at line 527, avg 15µs/call # 3909 times (11.5ms+43.5ms) by DBIx::Class::ResultSet::search_rs at line 372, avg 14µs/call
sub _merge_attr {
346768402156ms $hm ||= do {
3468 require Hash::Merge;
3469121µs my $hm = Hash::Merge->new;
# spent 21µs making 1 call to Hash::Merge::new
3470
3471 $hm->specify_behavior({
3472 SCALAR => {
3473 SCALAR => sub {
3474 my ($defl, $defr) = map { defined $_ } (@_[0,1]);
3475
3476 if ($defl xor $defr) {
3477 return [ $defl ? $_[0] : $_[1] ];
3478 }
3479 elsif (! $defl) {
3480 return [];
3481 }
3482 elsif (__HM_DEDUP and $_[0] eq $_[1]) {
3483 return [ $_[0] ];
3484 }
3485 else {
3486 return [$_[0], $_[1]];
3487 }
3488 },
3489
# spent 28.6ms within DBIx::Class::ResultSet::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/ResultSet.pm:3493] which was called 19521 times, avg 1µs/call: # 19521 times (28.6ms+0s) by Hash::Merge::merge at line 198 of Hash/Merge.pm, avg 1µs/call
ARRAY => sub {
34901952149.7ms return $_[1] if !defined $_[0];
3491 return $_[1] if __HM_DEDUP and List::Util::first { $_ eq $_[0] } @{$_[1]};
3492 return [$_[0], @{$_[1]}]
3493 },
3494 HASH => sub {
3495 return [] if !defined $_[0] and !keys %{$_[1]};
3496 return [ $_[1] ] if !defined $_[0];
3497 return [ $_[0] ] if !keys %{$_[1]};
3498 return [$_[0], $_[1]]
3499 },
3500 },
3501 ARRAY => {
3502
# spent 34.4ms within DBIx::Class::ResultSet::__ANON__[/2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/ResultSet.pm:3506] which was called 14678 times, avg 2µs/call: # 14678 times (34.4ms+0s) by Hash::Merge::merge at line 198 of Hash/Merge.pm, avg 2µs/call
SCALAR => sub {
35031467849.9ms return $_[0] if !defined $_[1];
3504 return $_[0] if __HM_DEDUP and List::Util::first { $_ eq $_[1] } @{$_[0]};
3505 return [@{$_[0]}, $_[1]]
3506 },
3507 ARRAY => sub {
3508 my @ret = @{$_[0]} or return $_[1];
3509 return [ @ret, @{$_[1]} ] unless __HM_DEDUP;
3510 my %idx = map { $_ => 1 } @ret;
3511 push @ret, grep { ! defined $idx{$_} } (@{$_[1]});
3512 \@ret;
3513 },
3514 HASH => sub {
3515 return [ $_[1] ] if ! @{$_[0]};
3516 return $_[0] if !keys %{$_[1]};
3517 return $_[0] if __HM_DEDUP and List::Util::first { $_ eq $_[1] } @{$_[0]};
3518 return [ @{$_[0]}, $_[1] ];
3519 },
3520 },
3521 HASH => {
3522 SCALAR => sub {
3523 return [] if !keys %{$_[0]} and !defined $_[1];
3524 return [ $_[0] ] if !defined $_[1];
3525 return [ $_[1] ] if !keys %{$_[0]};
3526 return [$_[0], $_[1]]
3527 },
3528 ARRAY => sub {
3529 return [] if !keys %{$_[0]} and !@{$_[1]};
3530 return [ $_[0] ] if !@{$_[1]};
3531 return $_[1] if !keys %{$_[0]};
3532 return $_[1] if __HM_DEDUP and List::Util::first { $_ eq $_[0] } @{$_[1]};
3533 return [ $_[0], @{$_[1]} ];
3534 },
3535 HASH => sub {
3536 return [] if !keys %{$_[0]} and !keys %{$_[1]};
3537 return [ $_[0] ] if !keys %{$_[1]};
3538 return [ $_[1] ] if !keys %{$_[0]};
3539 return [ $_[0] ] if $_[0] eq $_[1];
3540 return [ $_[0], $_[1] ];
3541 },
3542 }
3543167µs } => 'DBIC_RS_ATTR_MERGER');
# spent 67µs making 1 call to Hash::Merge::specify_behavior
3544 $hm;
3545 };
3546
354734199546ms return $hm->merge ($_[1], $_[2]);
# spent 546ms making 34199 calls to Hash::Merge::merge, avg 16µs/call
3548 }
3549}
3550
3551sub STORABLE_freeze {
3552 my ($self, $cloning) = @_;
3553 my $to_serialize = { %$self };
3554
3555 # A cursor in progress can't be serialized (and would make little sense anyway)
3556 delete $to_serialize->{cursor};
3557
3558 # nor is it sensical to store a not-yet-fired-count pager
3559 if ($to_serialize->{pager} and ref $to_serialize->{pager}{total_entries} eq 'CODE') {
3560 delete $to_serialize->{pager};
3561 }
3562
3563 Storable::nfreeze($to_serialize);
3564}
3565
3566# need this hook for symmetry
3567sub STORABLE_thaw {
3568 my ($self, $cloning, $serialized) = @_;
3569
3570 %$self = %{ Storable::thaw($serialized) };
3571
3572 $self;
3573}
3574
3575
3576=head2 throw_exception
3577
3578See L<DBIx::Class::Schema/throw_exception> for details.
3579
3580=cut
3581
3582sub throw_exception {
3583 my $self=shift;
3584
3585 if (ref $self and my $rsrc = $self->result_source) {
3586 $rsrc->throw_exception(@_)
3587 }
3588 else {
3589 DBIx::Class::Exception->throw(@_);
3590 }
3591}
3592
3593# XXX: FIXME: Attributes docs need clearing up
3594
3595=head1 ATTRIBUTES
3596
3597Attributes are used to refine a ResultSet in various ways when
3598searching for data. They can be passed to any method which takes an
3599C<\%attrs> argument. See L</search>, L</search_rs>, L</find>,
3600L</count>.
3601
3602These are in no particular order:
3603
3604=head2 order_by
3605
3606=over 4
3607
3608=item Value: ( $order_by | \@order_by | \%order_by )
3609
3610=back
3611
3612Which column(s) to order the results by.
3613
3614[The full list of suitable values is documented in
3615L<SQL::Abstract/"ORDER BY CLAUSES">; the following is a summary of
3616common options.]
3617
3618If a single column name, or an arrayref of names is supplied, the
3619argument is passed through directly to SQL. The hashref syntax allows
3620for connection-agnostic specification of ordering direction:
3621
3622 For descending order:
3623
3624 order_by => { -desc => [qw/col1 col2 col3/] }
3625
3626 For explicit ascending order:
3627
3628 order_by => { -asc => 'col' }
3629
3630The old scalarref syntax (i.e. order_by => \'year DESC') is still
3631supported, although you are strongly encouraged to use the hashref
3632syntax as outlined above.
3633
3634=head2 columns
3635
3636=over 4
3637
3638=item Value: \@columns
3639
3640=back
3641
3642Shortcut to request a particular set of columns to be retrieved. Each
3643column spec may be a string (a table column name), or a hash (in which
3644case the key is the C<as> value, and the value is used as the C<select>
3645expression). Adds C<me.> onto the start of any column without a C<.> in
3646it and sets C<select> from that, then auto-populates C<as> from
3647C<select> as normal. (You may also use the C<cols> attribute, as in
3648earlier versions of DBIC.)
3649
3650Essentially C<columns> does the same as L</select> and L</as>.
3651
3652 columns => [ 'foo', { bar => 'baz' } ]
3653
3654is the same as
3655
3656 select => [qw/foo baz/],
3657 as => [qw/foo bar/]
3658
3659=head2 +columns
3660
3661=over 4
3662
3663=item Value: \@columns
3664
3665=back
3666
3667Indicates additional columns to be selected from storage. Works the same
3668as L</columns> but adds columns to the selection. (You may also use the
3669C<include_columns> attribute, as in earlier versions of DBIC). For
3670example:-
3671
3672 $schema->resultset('CD')->search(undef, {
3673 '+columns' => ['artist.name'],
3674 join => ['artist']
3675 });
3676
3677would return all CDs and include a 'name' column to the information
3678passed to object inflation. Note that the 'artist' is the name of the
3679column (or relationship) accessor, and 'name' is the name of the column
3680accessor in the related table.
3681
3682B<NOTE:> You need to explicitly quote '+columns' when defining the attribute.
3683Not doing so causes Perl to incorrectly interpret +columns as a bareword with a
3684unary plus operator before it.
3685
3686=head2 include_columns
3687
3688=over 4
3689
3690=item Value: \@columns
3691
3692=back
3693
3694Deprecated. Acts as a synonym for L</+columns> for backward compatibility.
3695
3696=head2 select
3697
3698=over 4
3699
3700=item Value: \@select_columns
3701
3702=back
3703
3704Indicates which columns should be selected from the storage. You can use
3705column names, or in the case of RDBMS back ends, function or stored procedure
3706names:
3707
3708 $rs = $schema->resultset('Employee')->search(undef, {
3709 select => [
3710 'name',
3711 { count => 'employeeid' },
3712 { max => { length => 'name' }, -as => 'longest_name' }
3713 ]
3714 });
3715
3716 # Equivalent SQL
3717 SELECT name, COUNT( employeeid ), MAX( LENGTH( name ) ) AS longest_name FROM employee
3718
3719B<NOTE:> You will almost always need a corresponding L</as> attribute when you
3720use L</select>, to instruct DBIx::Class how to store the result of the column.
3721Also note that the L</as> attribute has nothing to do with the SQL-side 'AS'
3722identifier aliasing. You can however alias a function, so you can use it in
3723e.g. an C<ORDER BY> clause. This is done via the C<-as> B<select function
3724attribute> supplied as shown in the example above.
3725
3726B<NOTE:> You need to explicitly quote '+select'/'+as' when defining the attributes.
3727Not doing so causes Perl to incorrectly interpret them as a bareword with a
3728unary plus operator before it.
3729
3730=head2 +select
3731
3732=over 4
3733
3734Indicates additional columns to be selected from storage. Works the same as
3735L</select> but adds columns to the default selection, instead of specifying
3736an explicit list.
3737
3738=back
3739
3740=head2 +as
3741
3742=over 4
3743
3744Indicates additional column names for those added via L</+select>. See L</as>.
3745
3746=back
3747
3748=head2 as
3749
3750=over 4
3751
3752=item Value: \@inflation_names
3753
3754=back
3755
3756Indicates column names for object inflation. That is L</as> indicates the
3757slot name in which the column value will be stored within the
3758L<Row|DBIx::Class::Row> object. The value will then be accessible via this
3759identifier by the C<get_column> method (or via the object accessor B<if one
3760with the same name already exists>) as shown below. The L</as> attribute has
3761B<nothing to do> with the SQL-side C<AS>. See L</select> for details.
3762
3763 $rs = $schema->resultset('Employee')->search(undef, {
3764 select => [
3765 'name',
3766 { count => 'employeeid' },
3767 { max => { length => 'name' }, -as => 'longest_name' }
3768 ],
3769 as => [qw/
3770 name
3771 employee_count
3772 max_name_length
3773 /],
3774 });
3775
3776If the object against which the search is performed already has an accessor
3777matching a column name specified in C<as>, the value can be retrieved using
3778the accessor as normal:
3779
3780 my $name = $employee->name();
3781
3782If on the other hand an accessor does not exist in the object, you need to
3783use C<get_column> instead:
3784
3785 my $employee_count = $employee->get_column('employee_count');
3786
3787You can create your own accessors if required - see
3788L<DBIx::Class::Manual::Cookbook> for details.
3789
3790=head2 join
3791
3792=over 4
3793
3794=item Value: ($rel_name | \@rel_names | \%rel_names)
3795
3796=back
3797
3798Contains a list of relationships that should be joined for this query. For
3799example:
3800
3801 # Get CDs by Nine Inch Nails
3802 my $rs = $schema->resultset('CD')->search(
3803 { 'artist.name' => 'Nine Inch Nails' },
3804 { join => 'artist' }
3805 );
3806
3807Can also contain a hash reference to refer to the other relation's relations.
3808For example:
3809
3810 package MyApp::Schema::Track;
3811 use base qw/DBIx::Class/;
3812 __PACKAGE__->table('track');
3813 __PACKAGE__->add_columns(qw/trackid cd position title/);
3814 __PACKAGE__->set_primary_key('trackid');
3815 __PACKAGE__->belongs_to(cd => 'MyApp::Schema::CD');
3816 1;
3817
3818 # In your application
3819 my $rs = $schema->resultset('Artist')->search(
3820 { 'track.title' => 'Teardrop' },
3821 {
3822 join => { cd => 'track' },
3823 order_by => 'artist.name',
3824 }
3825 );
3826
3827You need to use the relationship (not the table) name in conditions,
3828because they are aliased as such. The current table is aliased as "me", so
3829you need to use me.column_name in order to avoid ambiguity. For example:
3830
3831 # Get CDs from 1984 with a 'Foo' track
3832 my $rs = $schema->resultset('CD')->search(
3833 {
3834 'me.year' => 1984,
3835 'tracks.name' => 'Foo'
3836 },
3837 { join => 'tracks' }
3838 );
3839
3840If the same join is supplied twice, it will be aliased to <rel>_2 (and
3841similarly for a third time). For e.g.
3842
3843 my $rs = $schema->resultset('Artist')->search({
3844 'cds.title' => 'Down to Earth',
3845 'cds_2.title' => 'Popular',
3846 }, {
3847 join => [ qw/cds cds/ ],
3848 });
3849
3850will return a set of all artists that have both a cd with title 'Down
3851to Earth' and a cd with title 'Popular'.
3852
3853If you want to fetch related objects from other tables as well, see C<prefetch>
3854below.
3855
3856For more help on using joins with search, see L<DBIx::Class::Manual::Joining>.
3857
3858=head2 prefetch
3859
3860=over 4
3861
3862=item Value: ($rel_name | \@rel_names | \%rel_names)
3863
3864=back
3865
3866Contains one or more relationships that should be fetched along with
3867the main query (when they are accessed afterwards the data will
3868already be available, without extra queries to the database). This is
3869useful for when you know you will need the related objects, because it
3870saves at least one query:
3871
3872 my $rs = $schema->resultset('Tag')->search(
3873 undef,
3874 {
3875 prefetch => {
3876 cd => 'artist'
3877 }
3878 }
3879 );
3880
3881The initial search results in SQL like the following:
3882
3883 SELECT tag.*, cd.*, artist.* FROM tag
3884 JOIN cd ON tag.cd = cd.cdid
3885 JOIN artist ON cd.artist = artist.artistid
3886
3887L<DBIx::Class> has no need to go back to the database when we access the
3888C<cd> or C<artist> relationships, which saves us two SQL statements in this
3889case.
3890
3891Simple prefetches will be joined automatically, so there is no need
3892for a C<join> attribute in the above search.
3893
3894L</prefetch> can be used with the any of the relationship types and
3895multiple prefetches can be specified together. Below is a more complex
3896example that prefetches a CD's artist, its liner notes (if present),
3897the cover image, the tracks on that cd, and the guests on those
3898tracks.
3899
3900 # Assuming:
3901 My::Schema::CD->belongs_to( artist => 'My::Schema::Artist' );
3902 My::Schema::CD->might_have( liner_note => 'My::Schema::LinerNotes' );
3903 My::Schema::CD->has_one( cover_image => 'My::Schema::Artwork' );
3904 My::Schema::CD->has_many( tracks => 'My::Schema::Track' );
3905
3906 My::Schema::Artist->belongs_to( record_label => 'My::Schema::RecordLabel' );
3907
3908 My::Schema::Track->has_many( guests => 'My::Schema::Guest' );
3909
3910
3911 my $rs = $schema->resultset('CD')->search(
3912 undef,
3913 {
3914 prefetch => [
3915 { artist => 'record_label'}, # belongs_to => belongs_to
3916 'liner_note', # might_have
3917 'cover_image', # has_one
3918 { tracks => 'guests' }, # has_many => has_many
3919 ]
3920 }
3921 );
3922
3923This will produce SQL like the following:
3924
3925 SELECT cd.*, artist.*, record_label.*, liner_note.*, cover_image.*,
3926 tracks.*, guests.*
3927 FROM cd me
3928 JOIN artist artist
3929 ON artist.artistid = me.artistid
3930 JOIN record_label record_label
3931 ON record_label.labelid = artist.labelid
3932 LEFT JOIN track tracks
3933 ON tracks.cdid = me.cdid
3934 LEFT JOIN guest guests
3935 ON guests.trackid = track.trackid
3936 LEFT JOIN liner_notes liner_note
3937 ON liner_note.cdid = me.cdid
3938 JOIN cd_artwork cover_image
3939 ON cover_image.cdid = me.cdid
3940 ORDER BY tracks.cd
3941
3942Now the C<artist>, C<record_label>, C<liner_note>, C<cover_image>,
3943C<tracks>, and C<guests> of the CD will all be available through the
3944relationship accessors without the need for additional queries to the
3945database.
3946
3947However, there is one caveat to be observed: it can be dangerous to
3948prefetch more than one L<has_many|DBIx::Class::Relationship/has_many>
3949relationship on a given level. e.g.:
3950
3951 my $rs = $schema->resultset('CD')->search(
3952 undef,
3953 {
3954 prefetch => [
3955 'tracks', # has_many
3956 { cd_to_producer => 'producer' }, # has_many => belongs_to (i.e. m2m)
3957 ]
3958 }
3959 );
3960
3961In fact, C<DBIx::Class> will emit the following warning:
3962
3963 Prefetching multiple has_many rels tracks and cd_to_producer at top
3964 level will explode the number of row objects retrievable via ->next
3965 or ->all. Use at your own risk.
3966
3967The collapser currently can't identify duplicate tuples for multiple
3968L<has_many|DBIx::Class::Relationship/has_many> relationships and as a
3969result the second L<has_many|DBIx::Class::Relationship/has_many>
3970relation could contain redundant objects.
3971
3972=head3 Using L</prefetch> with L</join>
3973
3974L</prefetch> implies a L</join> with the equivalent argument, and is
3975properly merged with any existing L</join> specification. So the
3976following:
3977
3978 my $rs = $schema->resultset('CD')->search(
3979 {'record_label.name' => 'Music Product Ltd.'},
3980 {
3981 join => {artist => 'record_label'},
3982 prefetch => 'artist',
3983 }
3984 );
3985
3986... will work, searching on the record label's name, but only
3987prefetching the C<artist>.
3988
3989=head3 Using L</prefetch> with L</select> / L</+select> / L</as> / L</+as>
3990
3991L</prefetch> implies a L</+select>/L</+as> with the fields of the
3992prefetched relations. So given:
3993
3994 my $rs = $schema->resultset('CD')->search(
3995 undef,
3996 {
3997 select => ['cd.title'],
3998 as => ['cd_title'],
3999 prefetch => 'artist',
4000 }
4001 );
4002
4003The L</select> becomes: C<'cd.title', 'artist.*'> and the L</as>
4004becomes: C<'cd_title', 'artist.*'>.
4005
4006=head3 CAVEATS
4007
4008Prefetch does a lot of deep magic. As such, it may not behave exactly
4009as you might expect.
4010
4011=over 4
4012
4013=item *
4014
4015Prefetch uses the L</cache> to populate the prefetched relationships. This
4016may or may not be what you want.
4017
4018=item *
4019
4020If you specify a condition on a prefetched relationship, ONLY those
4021rows that match the prefetched condition will be fetched into that relationship.
4022This means that adding prefetch to a search() B<may alter> what is returned by
4023traversing a relationship. So, if you have C<< Artist->has_many(CDs) >> and you do
4024
4025 my $artist_rs = $schema->resultset('Artist')->search({
4026 'cds.year' => 2008,
4027 }, {
4028 join => 'cds',
4029 });
4030
4031 my $count = $artist_rs->first->cds->count;
4032
4033 my $artist_rs_prefetch = $artist_rs->search( {}, { prefetch => 'cds' } );
4034
4035 my $prefetch_count = $artist_rs_prefetch->first->cds->count;
4036
4037 cmp_ok( $count, '==', $prefetch_count, "Counts should be the same" );
4038
4039that cmp_ok() may or may not pass depending on the datasets involved. This
4040behavior may or may not survive the 0.09 transition.
4041
4042=back
4043
4044=head2 page
4045
4046=over 4
4047
4048=item Value: $page
4049
4050=back
4051
4052Makes the resultset paged and specifies the page to retrieve. Effectively
4053identical to creating a non-pages resultset and then calling ->page($page)
4054on it.
4055
4056If L</rows> attribute is not specified it defaults to 10 rows per page.
4057
4058When you have a paged resultset, L</count> will only return the number
4059of rows in the page. To get the total, use the L</pager> and call
4060C<total_entries> on it.
4061
4062=head2 rows
4063
4064=over 4
4065
4066=item Value: $rows
4067
4068=back
4069
4070Specifies the maximum number of rows for direct retrieval or the number of
4071rows per page if the page attribute or method is used.
4072
4073=head2 offset
4074
4075=over 4
4076
4077=item Value: $offset
4078
4079=back
4080
4081Specifies the (zero-based) row number for the first row to be returned, or the
4082of the first row of the first page if paging is used.
4083
4084=head2 group_by
4085
4086=over 4
4087
4088=item Value: \@columns
4089
4090=back
4091
4092A arrayref of columns to group by. Can include columns of joined tables.
4093
4094 group_by => [qw/ column1 column2 ... /]
4095
4096=head2 having
4097
4098=over 4
4099
4100=item Value: $condition
4101
4102=back
4103
4104HAVING is a select statement attribute that is applied between GROUP BY and
4105ORDER BY. It is applied to the after the grouping calculations have been
4106done.
4107
4108 having => { 'count_employee' => { '>=', 100 } }
4109
4110or with an in-place function in which case literal SQL is required:
4111
4112 having => \[ 'count(employee) >= ?', [ count => 100 ] ]
4113
4114=head2 distinct
4115
4116=over 4
4117
4118=item Value: (0 | 1)
4119
4120=back
4121
4122Set to 1 to group by all columns. If the resultset already has a group_by
4123attribute, this setting is ignored and an appropriate warning is issued.
4124
4125=head2 where
4126
4127=over 4
4128
4129Adds to the WHERE clause.
4130
4131 # only return rows WHERE deleted IS NULL for all searches
4132 __PACKAGE__->resultset_attributes({ where => { deleted => undef } }); )
4133
4134Can be overridden by passing C<< { where => undef } >> as an attribute
4135to a resultset.
4136
4137=back
4138
4139=head2 cache
4140
4141Set to 1 to cache search results. This prevents extra SQL queries if you
4142revisit rows in your ResultSet:
4143
4144 my $resultset = $schema->resultset('Artist')->search( undef, { cache => 1 } );
4145
4146 while( my $artist = $resultset->next ) {
4147 ... do stuff ...
4148 }
4149
4150 $rs->first; # without cache, this would issue a query
4151
4152By default, searches are not cached.
4153
4154For more examples of using these attributes, see
4155L<DBIx::Class::Manual::Cookbook>.
4156
4157=head2 for
4158
4159=over 4
4160
4161=item Value: ( 'update' | 'shared' )
4162
4163=back
4164
4165Set to 'update' for a SELECT ... FOR UPDATE or 'shared' for a SELECT
4166... FOR SHARED.
4167
4168=cut
4169
4170144µs1619µs1;
 
# spent 119ms within DBIx::Class::ResultSet::CORE:match which was called 126866 times, avg 939ns/call: # 46297 times (15.7ms+0s) by DBIx::Class::ResultSet::_resolved_attrs at line 3200, avg 338ns/call # 42399 times (27.0ms+0s) by DBIx::Class::ResultSet::_resolved_attrs at line 3195, avg 638ns/call # 35425 times (72.6ms+0s) by DBIx::Class::ResultSet::_collapse_result at line 1238, avg 2µs/call # 2386 times (3.56ms+0s) by DBIx::Class::ResultSet::_remove_alias at line 2369, avg 1µs/call # 359 times (289µs+0s) by DBIx::Class::ResultSet::_qualify_cond_columns at line 843, avg 804ns/call
sub DBIx::Class::ResultSet::CORE:match; # opcode
# spent 36.7ms within DBIx::Class::ResultSet::CORE:regcomp which was called 46297 times, avg 792ns/call: # 46297 times (36.7ms+0s) by DBIx::Class::ResultSet::_resolved_attrs at line 3200, avg 792ns/call
sub DBIx::Class::ResultSet::CORE:regcomp; # opcode
# spent 5.01ms within DBIx::Class::ResultSet::CORE:sort which was called 4743 times, avg 1µs/call: # 4717 times (4.91ms+0s) by DBIx::Class::ResultSet::_collapse_result at line 1310, avg 1µs/call # 26 times (92µs+0s) by DBIx::Class::ResultSet::find at line 788, avg 4µs/call
sub DBIx::Class::ResultSet::CORE:sort; # opcode