Profile of DBIx/Class/ResultSet.pm

← 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:22:36 2012

Filename | /2home/ss5/perl5/perlbrew/perls/perl-5.12.3/lib/site_perl/5.12.3/DBIx/Class/ResultSet.pm
Statements | Executed 3369599 statements in 5.75s

Subroutines
Calls | P | F | Exclusive Time | Inclusive Time | Subroutine
--- | --- | --- | --- | --- | ---
17692 | 5 | 2 | 1.17s | 1.75s | DBIx::Class::ResultSet::::_resolved_attrsDBIx::Class::ResultSet::_resolved_attrs
16979 | 3 | 2 | 1.07s | 2.88s | DBIx::Class::ResultSet::::search_rsDBIx::Class::ResultSet::search_rs
33859 | 2 | 1 | 611ms | 866ms | DBIx::Class::ResultSet::::_normalize_selectionDBIx::Class::ResultSet::_normalize_selection
25061 | 8 | 4 | 604ms | 2.34s | DBIx::Class::ResultSet::::newDBIx::Class::ResultSet::new
4717 | 1 | 1 | 322ms | 399ms | DBIx::Class::ResultSet::::_collapse_resultDBIx::Class::ResultSet::_collapse_result
31809 | 4 | 1 | 215ms | 351ms | DBIx::Class::ResultSet::::result_classDBIx::Class::ResultSet::result_class
17623 | 1 | 1 | 205ms | 205ms | DBIx::Class::ResultSet::::_stack_condDBIx::Class::ResultSet::_stack_cond
34199 | 4 | 1 | 149ms | 696ms | DBIx::Class::ResultSet::::_merge_attrDBIx::Class::ResultSet::_merge_attr
126866 | 5 | 1 | 119ms | 119ms | DBIx::Class::ResultSet::::CORE:matchDBIx::Class::ResultSet::CORE:match (opcode)
1949 | 7 | 4 | 117ms | 5.59s | DBIx::Class::ResultSet::::countDBIx::Class::ResultSet::count
4717 | 3 | 1 | 107ms | 676ms | DBIx::Class::ResultSet::::_construct_objectDBIx::Class::ResultSet::_construct_object
2007 | 3 | 3 | 104ms | 4.94s | DBIx::Class::ResultSet::::findDBIx::Class::ResultSet::find
9987 | 3 | 1 | 104ms | 845ms | DBIx::Class::ResultSet::::_resolved_attrs_copyDBIx::Class::ResultSet::_resolved_attrs_copy
6031 | 5 | 3 | 104ms | 1.02s | DBIx::Class::ResultSet::::cursorDBIx::Class::ResultSet::cursor
14878 | 13 | 9 | 95.9ms | 3.15s | DBIx::Class::ResultSet::::searchDBIx::Class::ResultSet::search
1949 | 1 | 1 | 75.0ms | 1.40s | DBIx::Class::ResultSet::::_count_rsDBIx::Class::ResultSet::_count_rs
2007 | 1 | 1 | 74.2ms | 3.93s | DBIx::Class::ResultSet::::singleDBIx::Class::ResultSet::single
1610 | 5 | 5 | 63.7ms | 3.22s | DBIx::Class::ResultSet::::allDBIx::Class::ResultSet::all
2318 | 6 | 6 | 56.3ms | 2.89s | DBIx::Class::ResultSet::::nextDBIx::Class::ResultSet::next
2134 | 4 | 1 | 37.2ms | 70.3ms | DBIx::Class::ResultSet::::_has_resolved_attrDBIx::Class::ResultSet::_has_resolved_attr
46297 | 1 | 1 | 36.7ms | 36.7ms | DBIx::Class::ResultSet::::CORE:regcompDBIx::Class::ResultSet::CORE:regcomp (opcode)
14678 | 1 | 1 | 34.4ms | 34.4ms | DBIx::Class::ResultSet::::__ANON__[:3506]DBIx::Class::ResultSet::__ANON__[:3506]
806 | 1 | 1 | 28.9ms | 32.5ms | DBIx::Class::ResultSet::::_remove_aliasDBIx::Class::ResultSet::_remove_alias
19521 | 1 | 1 | 28.6ms | 28.6ms | DBIx::Class::ResultSet::::__ANON__[:3493]DBIx::Class::ResultSet::__ANON__[:3493]
13565 | 5 | 1 | 26.3ms | 26.3ms | DBIx::Class::ResultSet::::get_cacheDBIx::Class::ResultSet::get_cache
449 | 2 | 1 | 19.5ms | 285ms | DBIx::Class::ResultSet::::new_resultDBIx::Class::ResultSet::new_result
806 | 2 | 1 | 18.4ms | 50.8ms | DBIx::Class::ResultSet::::_merge_with_rscondDBIx::Class::ResultSet::_merge_with_rscond
1954 | 2 | 2 | 15.9ms | 1.01s | DBIx::Class::ResultSet::::get_columnDBIx::Class::ResultSet::get_column
357 | 2 | 1 | 13.4ms | 42.6ms | DBIx::Class::ResultSet::::_build_unique_condDBIx::Class::ResultSet::_build_unique_cond
147 | 1 | 1 | 9.13ms | 124ms | DBIx::Class::ResultSet::::related_resultsetDBIx::Class::ResultSet::related_resultset
147 | 1 | 1 | 7.75ms | 58.1ms | DBIx::Class::ResultSet::::_chain_relationshipDBIx::Class::ResultSet::_chain_relationship
2101 | 2 | 2 | 7.74ms | 7.74ms | DBIx::Class::ResultSet::::_merge_joinpref_attrDBIx::Class::ResultSet::_merge_joinpref_attr
1954 | 1 | 1 | 6.79ms | 6.79ms | DBIx::Class::ResultSet::::current_source_aliasDBIx::Class::ResultSet::current_source_alias
357 | 2 | 1 | 5.62ms | 5.91ms | DBIx::Class::ResultSet::::_qualify_cond_columnsDBIx::Class::ResultSet::_qualify_cond_columns
1909 | 1 | 1 | 5.01ms | 5.01ms | DBIx::Class::ResultSet::::_boolDBIx::Class::ResultSet::_bool
4743 | 2 | 1 | 5.01ms | 5.01ms | DBIx::Class::ResultSet::::CORE:sortDBIx::Class::ResultSet::CORE:sort (opcode)
357 | 1 | 1 | 2.57ms | 16.2ms | DBIx::Class::ResultSet::::__ANON__[:858]DBIx::Class::ResultSet::__ANON__[:858]
148 | 1 | 1 | 1.51ms | 49.7ms | DBIx::Class::ResultSet::::resetDBIx::Class::ResultSet::reset
1 | 1 | 1 | 1.40ms | 4.82ms | DBIx::Class::ResultSet::::BEGIN@11DBIx::Class::ResultSet::BEGIN@11
148 | 2 | 2 | 1.32ms | 289ms | DBIx::Class::ResultSet::::firstDBIx::Class::ResultSet::first
147 | 1 | 1 | 1.28ms | 146ms | DBIx::Class::ResultSet::::search_relatedDBIx::Class::ResultSet::search_related
19 | 1 | 1 | 1.10ms | 2.16s | DBIx::Class::ResultSet::::_rs_update_deleteDBIx::Class::ResultSet::_rs_update_delete
1 | 1 | 1 | 1.02ms | 1.40ms | DBIx::Class::ResultSet::::BEGIN@8DBIx::Class::ResultSet::BEGIN@8
24 | 2 | 2 | 858µs | 2.78s | DBIx::Class::ResultSet::::createDBIx::Class::ResultSet::create
19 | 1 | 1 | 373µs | 2.16s | DBIx::Class::ResultSet::::deleteDBIx::Class::ResultSet::delete
26 | 1 | 1 | 339µs | 6.23ms | DBIx::Class::ResultSet::::__ANON__[:793]DBIx::Class::ResultSet::__ANON__[:793]
1 | 1 | 1 | 11µs | 255µs | DBIx::Class::ResultSet::::BEGIN@22DBIx::Class::ResultSet::BEGIN@22
1 | 1 | 1 | 11µs | 13µs | DBIx::Class::ResultSet::::BEGIN@3DBIx::Class::ResultSet::BEGIN@3
1 | 1 | 1 | 9µs | 64µs | DBIx::Class::ResultSet::::BEGIN@25DBIx::Class::ResultSet::BEGIN@25
1 | 1 | 1 | 8µs | 51µs | DBIx::Class::ResultSet::::BEGIN@9DBIx::Class::ResultSet::BEGIN@9
1 | 1 | 1 | 8µs | 92µs | DBIx::Class::ResultSet::::BEGIN@6DBIx::Class::ResultSet::BEGIN@6
1 | 1 | 1 | 8µs | 40µs | DBIx::Class::ResultSet::::BEGIN@10DBIx::Class::ResultSet::BEGIN@10
1 | 1 | 1 | 7µs | 14µs | DBIx::Class::ResultSet::::BEGIN@4DBIx::Class::ResultSet::BEGIN@4
1 | 1 | 1 | 6µs | 65µs | DBIx::Class::ResultSet::::BEGIN@5DBIx::Class::ResultSet::BEGIN@5
1 | 1 | 1 | 6µs | 6µs | DBIx::Class::ResultSet::::BEGIN@14DBIx::Class::ResultSet::BEGIN@14
1 | 1 | 1 | 5µs | 5µs | DBIx::Class::ResultSet::::BEGIN@7DBIx::Class::ResultSet::BEGIN@7
1 | 1 | 1 | 5µs | 5µs | DBIx::Class::ResultSet::::BEGIN@16DBIx::Class::ResultSet::BEGIN@16
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::STORABLE_freezeDBIx::Class::ResultSet::STORABLE_freeze
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::STORABLE_thawDBIx::Class::ResultSet::STORABLE_thaw
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:2152]DBIx::Class::ResultSet::__ANON__[:2152]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3159]DBIx::Class::ResultSet::__ANON__[:3159]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:332]DBIx::Class::ResultSet::__ANON__[:332]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3488]DBIx::Class::ResultSet::__ANON__[:3488]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3491]DBIx::Class::ResultSet::__ANON__[:3491]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3499]DBIx::Class::ResultSet::__ANON__[:3499]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3504]DBIx::Class::ResultSet::__ANON__[:3504]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3513]DBIx::Class::ResultSet::__ANON__[:3513]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3517]DBIx::Class::ResultSet::__ANON__[:3517]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3519]DBIx::Class::ResultSet::__ANON__[:3519]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3527]DBIx::Class::ResultSet::__ANON__[:3527]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3532]DBIx::Class::ResultSet::__ANON__[:3532]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3534]DBIx::Class::ResultSet::__ANON__[:3534]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:3541]DBIx::Class::ResultSet::__ANON__[:3541]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:356]DBIx::Class::ResultSet::__ANON__[:356]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::__ANON__[:860]DBIx::Class::ResultSet::__ANON__[:860]
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::_calculate_scoreDBIx::Class::ResultSet::_calculate_score
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::_collapse_condDBIx::Class::ResultSet::_collapse_cond
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::_collapse_queryDBIx::Class::ResultSet::_collapse_query
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::_count_subq_rsDBIx::Class::ResultSet::_count_subq_rs
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::_non_unique_find_fallbackDBIx::Class::ResultSet::_non_unique_find_fallback
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::_normalize_populate_argsDBIx::Class::ResultSet::_normalize_populate_args
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::_rollout_arrayDBIx::Class::ResultSet::_rollout_array
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::_rollout_attrDBIx::Class::ResultSet::_rollout_attr
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::_rollout_hashDBIx::Class::ResultSet::_rollout_hash
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::as_queryDBIx::Class::ResultSet::as_query
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::as_subselect_rsDBIx::Class::ResultSet::as_subselect_rs
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::clear_cacheDBIx::Class::ResultSet::clear_cache
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::count_literalDBIx::Class::ResultSet::count_literal
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::count_rsDBIx::Class::ResultSet::count_rs
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::delete_allDBIx::Class::ResultSet::delete_all
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::find_or_createDBIx::Class::ResultSet::find_or_create
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::find_or_newDBIx::Class::ResultSet::find_or_new
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::is_orderedDBIx::Class::ResultSet::is_ordered
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::is_pagedDBIx::Class::ResultSet::is_paged
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::pageDBIx::Class::ResultSet::page
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::pagerDBIx::Class::ResultSet::pager
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::populateDBIx::Class::ResultSet::populate
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::search_likeDBIx::Class::ResultSet::search_like
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::search_literalDBIx::Class::ResultSet::search_literal
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::search_related_rsDBIx::Class::ResultSet::search_related_rs
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::set_cacheDBIx::Class::ResultSet::set_cache
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::sliceDBIx::Class::ResultSet::slice
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::throw_exceptionDBIx::Class::ResultSet::throw_exception
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::updateDBIx::Class::ResultSet::update
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::update_allDBIx::Class::ResultSet::update_all
0 | 0 | 0 | 0s | 0s | DBIx::Class::ResultSet::::update_or_createDBIx::Class::ResultSet::update_or_create
0 | 0 | 0 | 0s | 0s | DBIx::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
--- | --- | --- | --- | --- | ---
1 |  |  |  |  | package DBIx::Class::ResultSet;
2 |  |  |  |  |
3 | 3 | 17µs | 2 | 15µ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
4 | 3 | 19µs | 2 | 21µ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
5 | 3 | 19µs | 2 | 124µ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
6 | 3 | 20µs | 2 | 176µ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
7 | 3 | 18µs | 1 | 5µ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
8 | 3 | 101µs | 1 | 1.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
9 | 3 | 20µs | 2 | 94µ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
10 | 3 | 19µs | 2 | 73µ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
11 | 3 | 102µs | 1 | 4.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
14 | 3 | 38µs | 1 | 6µ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)
19 | 1 | 5µs |  |  | *__HM_DEDUP = sub () { 0 };
20 | 1 | 14µs | 1 | 5µs | } # spent 5µs making 1 call to DBIx::Class::ResultSet::BEGIN@16
21 |  |  |  |  |
22 | 3 | 30µs | 2 | 499µ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 |  |  |  |  |
24 |  |  |  |  | use overload
25 |  |  | 1 | 56µ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",
27 | 3 | 9.27ms | 1 | 64µs | fallback => 1; # spent 64µs making 1 call to DBIx::Class::ResultSet::BEGIN@25
28 |  |  |  |  |
29 | 1 | 16µs | 1 | 173µ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 |  |  |  |  |
33 |  |  |  |  | DBIx::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 |  |  |  |  |
47 |  |  |  |  | A ResultSet is an object which stores a set of conditions representing
48 |  |  |  |  | a query. It is the backbone of DBIx::Class (i.e. the really
49 |  |  |  |  | important/useful bit).
50 |  |  |  |  |
51 |  |  |  |  | No SQL is executed on the database when a ResultSet is created, it
52 |  |  |  |  | just stores all the conditions needed to create the query.
53 |  |  |  |  |
54 |  |  |  |  | A basic ResultSet representing the data of an entire table is returned
55 |  |  |  |  | by calling C<resultset> on a L<DBIx::Class::Schema> and passing in a
56 |  |  |  |  | L<Source|DBIx::Class::Manual::Glossary/Source> name.
57 |  |  |  |  |
58 |  |  |  |  | my $users_rs = $schema->resultset('User');
59 |  |  |  |  |
60 |  |  |  |  | A new ResultSet is returned from calling L</search> on an existing
61 |  |  |  |  | ResultSet. The new one will contain all the conditions of the
62 |  |  |  |  | original, plus any new conditions added in the C<search> call.
63 |  |  |  |  |
64 |  |  |  |  | A ResultSet also incorporates an implicit iterator. L</next> and L</reset>
65 |  |  |  |  | can be used to walk through all the L<DBIx::Class::Row>s the ResultSet
66 |  |  |  |  | represents.
67 |  |  |  |  |
68 |  |  |  |  | The query that the ResultSet represents is B<only> executed against
69 |  |  |  |  | the database when these methods are called:
70 |  |  |  |  | L</find>, L</next>, L</all>, L</first>, L</single>, L</count>.
71 |  |  |  |  |
72 |  |  |  |  | If a resultset is used in a numeric context it returns the L</count>.
73 |  |  |  |  | However, if it is used in a boolean context it is B<always> true. So if
74 |  |  |  |  | you 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 |  |  |  |  |
81 |  |  |  |  | Let's say you've got a query that needs to be run to return some data
82 |  |  |  |  | to the user. But, you have an authorization system in place that
83 |  |  |  |  | prevents certain users from seeing certain information. So, you want
84 |  |  |  |  | to construct the basic query in one method, but add constraints to it in
85 |  |  |  |  | another.
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 |  |  |  |  |
113 |  |  |  |  | When a resultset is chained from another resultset, conditions and
114 |  |  |  |  | attributes with the same keys need resolving.
115 |  |  |  |  |
116 |  |  |  |  | L</join>, L</prefetch>, L</+select>, L</+as> attributes are merged
117 |  |  |  |  | into the existing ones from the original resultset.
118 |  |  |  |  |
119 |  |  |  |  | The L</where> and L</having> attributes, and any search conditions, are
120 |  |  |  |  | merged with an SQL C<AND> to the existing condition from the original
121 |  |  |  |  | resultset.
122 |  |  |  |  |
123 |  |  |  |  | All other attributes are overridden by any new ones supplied in the
124 |  |  |  |  | search attributes.
125 |  |  |  |  |
126 |  |  |  |  | =head2 Multiple queries
127 |  |  |  |  |
128 |  |  |  |  | Since a resultset just defines a query, you can do all sorts of
129 |  |  |  |  | things 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 |  |  |  |  |
142 |  |  |  |  | And it's not just limited to SELECT statements.
143 |  |  |  |  |
144 |  |  |  |  | $cd_rs->delete();
145 |  |  |  |  |
146 |  |  |  |  | This is even cooler:
147 |  |  |  |  |
148 |  |  |  |  | $cd_rs->create({ artist => 'Fred' });
149 |  |  |  |  |
150 |  |  |  |  | Which is the same as:
151 |  |  |  |  |
152 |  |  |  |  | $schema->resultset('CD')->create({
153 |  |  |  |  | title => 'something',
154 |  |  |  |  | year => 2009,
155 |  |  |  |  | artist => 'Fred'
156 |  |  |  |  | });
157 |  |  |  |  |
158 |  |  |  |  | See: 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 |  |  |  |  |
172 |  |  |  |  | The resultset constructor. Takes a source object (usually a
173 |  |  |  |  | L<DBIx::Class::ResultSourceProxy::Table>) and an attribute hash (see
174 |  |  |  |  | L</ATTRIBUTES> below). Does not perform any queries -- these are
175 |  |  |  |  | executed as needed by the other methods.
176 |  |  |  |  |
177 |  |  |  |  | Generally you won't need to construct a resultset manually. You'll
178 |  |  |  |  | automatically get one from e.g. a L</search> called in scalar context:
179 |  |  |  |  |
180 |  |  |  |  | my $rs = $schema->resultset('CD')->search({ title => '100th Window' });
181 |  |  |  |  |
182 |  |  |  |  | IMPORTANT: If called on an object, proxies to new_result instead so
183 |  |  |  |  |
184 |  |  |  |  | my $cd = $schema->resultset('CD')->new({ title => 'Spoon' });
185 |  |  |  |  |
186 |  |  |  |  | will 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 {
191 | 271846 | 634ms |  |  | my $class = shift;
192 |  |  | 425 | 267ms | 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) = @_;
195 |  |  | 24636 | 67.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
215 |  |  | 24636 | 664ms | $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 |  |  |  |  |
218 |  |  | 47265 | 737ms | $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 |  |  |  |  |
241 |  |  |  |  | In list context, C<< ->all() >> is called implicitly on the resultset, thus
242 |  |  |  |  | returning a list of row objects instead. To avoid that, use L</search_rs>.
243 |  |  |  |  |
244 |  |  |  |  | If you need to pass in additional attributes but no additional condition,
245 |  |  |  |  | call 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 |  |  |  |  |
252 |  |  |  |  | For a list of attributes that can be passed to C<search>, see
253 |  |  |  |  | L</ATTRIBUTES>. For more examples of using this function, see
254 |  |  |  |  | L<Searching|DBIx::Class::Manual::Cookbook/Searching>. For a complete
255 |  |  |  |  | documentation for the first argument, see L<SQL::Abstract>
256 |  |  |  |  | and its extension L<DBIx::Class::SQLMaker>.
257 |  |  |  |  |
258 |  |  |  |  | For more help on using joins with search, see L<DBIx::Class::Manual::Joining>.
259 |  |  |  |  |
260 |  |  |  |  | =head3 CAVEAT
261 |  |  |  |  |
262 |  |  |  |  | Note that L</search> does not process/deflate any of the values passed in the
263 |  |  |  |  | L<SQL::Abstract>-compatible search condition structure. This is unlike other
264 |  |  |  |  | condition-bound methods L</new>, L</create> and L</find>. The user must ensure
265 |  |  |  |  | manually that any value passed to this method will stringify to something the
266 |  |  |  |  | RDBMS knows how to deal with. A notable example is the handling of L<DateTime>
267 |  |  |  |  | objects, for more info see:
268 |  |  |  |  | L<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 {
273 | 44634 | 88.7ms |  |  | my $self = shift;
274 |  |  | 14878 | 2.52s | my $rs = $self->search_rs( @_ ); # spent 2.52s making 14878 calls to DBIx::Class::ResultSet::search_rs, avg 169µs/call
275 |  |  |  |  |
276 |  |  | 331 | 527ms | 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 |  |  |  |  |
305 |  |  |  |  | This method does the same exact thing as search() except it will
306 |  |  |  |  | always 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 {
311 | 594429 | 983ms |  |  | 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 = {};
319 |  |  |  |  | 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);
332 | 9223 | 45.9ms | 24520 | 53.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 |  |  |  |  |
342 |  |  | 2 | 434µ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)
351 |  |  |  |  | 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
356 | 34935 | 58.1ms | 9223 | 29.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};
365 |  |  | 9223 | 203ms | $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) {
372 |  |  | 3909 | 55.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/) {
389 |  |  |  |  | $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
399 |  |  |  |  | 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) {
421 |  |  |  |  | if (defined $_) {
422 |  |  | 17623 | 205ms | $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 |  |  |  |  |
434 |  |  | 16979 | 1.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 |  |  |  |  |
441 | 1 | 300ns |  |  | my $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 {
443 | 854281 | 635ms |  |  | 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 {
465 |  |  |  |  | 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 |  |  |  |  |
475 |  |  |  |  | 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
526 |  |  | 7806 | 139ms | $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
527 |  |  | 7806 | 117ms | $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 {
532 | 163945 | 233ms |  |  | my ($self, $left, $right) = @_;
533 |  |  |  |  |
534 |  |  |  |  | # collapse single element top-level conditions
535 |  |  |  |  | # (single pass only, unlikely to need recursion)
536 |  |  |  |  | for ($left, $right) {
537 |  |  |  |  | if (ref $_ eq 'ARRAY') {
538 |  |  |  |  | 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
549 |  |  |  |  | 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)
565 |  |  |  |  | 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 |  |  |  |  |
579 |  |  |  |  | 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 |  |  |  |  |
603 |  |  |  |  | Pass a literal chunk of SQL to be added to the conditional part of the
604 |  |  |  |  | resultset query.
605 |  |  |  |  |
606 |  |  |  |  | CAVEAT: C<search_literal> is provided for Class::DBI compatibility and should
607 |  |  |  |  | only be used in that context. C<search_literal> is a convenience method.
608 |  |  |  |  | It is equivalent to calling $schema->search(\[]), but if you want to ensure
609 |  |  |  |  | columns are bound correctly, use C<search>.
610 |  |  |  |  |
611 |  |  |  |  | Example 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 |  |  |  |  |
617 |  |  |  |  | See L<DBIx::Class::Manual::Cookbook/Searching> and
618 |  |  |  |  | L<DBIx::Class::Manual::FAQ/Searching> for searching techniques that do not
619 |  |  |  |  | require C<search_literal>.
620 |  |  |  |  |
621 |  |  |  |  | =cut
622 |  |  |  |  |
623 |  |  |  |  | sub 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 |  |  |  |  |
642 |  |  |  |  | Finds and returns a single row based on supplied criteria. Takes either a
643 |  |  |  |  | hashref with the same format as L</create> (including inference of foreign
644 |  |  |  |  | keys from related objects), or a list of primary key values in the same
645 |  |  |  |  | order as the L<primary columns|DBIx::Class::ResultSource/primary_columns>
646 |  |  |  |  | declaration on the L</result_source>.
647 |  |  |  |  |
648 |  |  |  |  | In either case an attempt is made to combine conditions already existing on
649 |  |  |  |  | the resultset with the condition passed to this method.
650 |  |  |  |  |
651 |  |  |  |  | To aid with preparing the correct query for the storage you may supply the
652 |  |  |  |  | C<key> attribute, which is the name of a
653 |  |  |  |  | L<unique constraint|DBIx::Class::ResultSource/add_unique_constraint> (the
654 |  |  |  |  | unique constraint corresponding to the
655 |  |  |  |  | L<primary columns|DBIx::Class::ResultSource/primary_columns> is always named
656 |  |  |  |  | C<primary>). If the C<key> attribute has been supplied, and DBIC is unable
657 |  |  |  |  | to construct a query that satisfies the named unique constraint fully (
658 |  |  |  |  | non-NULL values for each column member of the constraint) an exception is
659 |  |  |  |  | thrown.
660 |  |  |  |  |
661 |  |  |  |  | If no C<key> is specified, the search is carried over all unique constraints
662 |  |  |  |  | which are fully defined by the available condition.
663 |  |  |  |  |
664 |  |  |  |  | If no such constraint is found, C<find> currently defaults to a simple
665 |  |  |  |  | C<< search->(\%column_values) >> which may or may not do what you expect.
666 |  |  |  |  | Note that this fallback behavior may be deprecated in further versions. If
667 |  |  |  |  | you need to search with arbitrary conditions - use L</search>. If the query
668 |  |  |  |  | resulting from this fallback produces more than one row, a warning to the
669 |  |  |  |  | effect is issued, though only the first row is constructed and returned as
670 |  |  |  |  | C<$row_object>.
671 |  |  |  |  |
672 |  |  |  |  | In addition to C<key>, L</find> recognizes and applies standard
673 |  |  |  |  | L<resultset attributes|/ATTRIBUTES> in the same way as L</search> does.
674 |  |  |  |  |
675 |  |  |  |  | Note that if you have extra concerns about the correctness of the resulting
676 |  |  |  |  | query you need to specify the C<key> attribute and supply the entire condition
677 |  |  |  |  | as an argument to find (since it is not always possible to perform the
678 |  |  |  |  | combination of the resultset condition with the supplied one, especially if
679 |  |  |  |  | the resultset condition contains literal sql).
680 |  |  |  |  |
681 |  |  |  |  | For example, to find a row by its primary key:
682 |  |  |  |  |
683 |  |  |  |  | my $cd = $schema->resultset('CD')->find(5);
684 |  |  |  |  |
685 |  |  |  |  | You 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 |  |  |  |  |
695 |  |  |  |  | See 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 {
700 | 34660 | 93.5ms |  |  | my $self = shift;
701 |  |  |  |  | my $attrs = (@_ > 1 && ref $_[$#_] eq 'HASH' ? pop(@_) : {});
702 |  |  |  |  |
703 |  |  | 1 | 2µ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 |  |  |  |  |
716 |  |  |  |  | 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 |  |  |  |  |
723 |  |  | 331 | 6.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) {
740 |  |  |  |  | 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;
762 |  |  | 662 | 41.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);
786 |  |  | 22 | 688µ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{
788 |  |  | 52 | 664µ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 {
792 | 26 | 315µs | 26 | 5.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
793 |  |  | 26 | 6.87ms | } || (); # spent 6.87ms making 26 calls to Try::Tiny::try, avg 264µs/call
794 |  |  |  |  | }
795 |  |  |  |  |
796 |  |  |  |  | $final_cond = @unique_queries
797 |  |  | 26 | 707µ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
803 |  |  | 4014 | 359ms | 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
804 |  |  | 2007 | 494ms | 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 {
810 |  |  | 2007 | 3.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
826 |  |  |  |  | sub _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 {
839 | 1787 | 6.28ms |  |  | my ($self, $cond, $alias) = @_;
840 |  |  |  |  |
841 |  |  |  |  | my %aliased = %$cond;
842 |  |  |  |  | for (keys %aliased) {
843 |  |  | 359 | 289µ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 {
851 | 2499 | 12.0ms |  |  | my ($self, $constraint_name, $extra_cond, $croak_on_null) = @_;
852 |  |  |  |  |
853 |  |  | 358 | 3.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 {
857 | 357 | 2.37ms | 357 | 13.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 }
860 |  |  | 714 | 21.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 |  |  |  |  |
912 |  |  |  |  | Searches the specified relationship, optionally specifying a condition and
913 |  |  |  |  | attributes for matching records. See L</ATTRIBUTES> for more information.
914 |  |  |  |  |
915 |  |  |  |  | In list context, C<< ->all() >> is called implicitly on the resultset, thus
916 |  |  |  |  | returning a list of row objects instead. To avoid that, use L</search_related_rs>.
917 |  |  |  |  |
918 |  |  |  |  | See 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 {
923 | 147 | 1.12ms | 294 | 145ms | 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 |  |  |  |  |
928 |  |  |  |  | This method works exactly the same as search_related, except that
929 |  |  |  |  | it guarantees a resultset, even in list context.
930 |  |  |  |  |
931 |  |  |  |  | =cut
932 |  |  |  |  |
933 |  |  |  |  | sub 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 |  |  |  |  |
947 |  |  |  |  | Returns a storage-driven cursor to the given resultset. See
948 |  |  |  |  | L<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 {
953 | 18093 | 72.8ms |  |  | my ($self) = @_;
954 |  |  |  |  |
955 |  |  | 6031 | 454ms | my $attrs = $self->_resolved_attrs_copy; # spent 454ms making 6031 calls to DBIx::Class::ResultSet::_resolved_attrs_copy, avg 75µs/call
956 |  |  |  |  |
957 |  |  | 9399 | 137ms | 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 |  |  |  |  |
974 |  |  |  |  | Inflates the first result without creating a cursor if the resultset has
975 |  |  |  |  | any records in it; if not returns C<undef>. Used by L</find> as a lean version
976 |  |  |  |  | of L</search>.
977 |  |  |  |  |
978 |  |  |  |  | While this method can take an optional search condition (just like L</search>)
979 |  |  |  |  | being a fast-code-path it does not recognize search attributes. If you need to
980 |  |  |  |  | add extra joins or similar, call L</search> and then chain-call L</single> on the
981 |  |  |  |  | L<DBIx::Class::ResultSet> returned.
982 |  |  |  |  |
983 |  |  |  |  | =over
984 |  |  |  |  |
985 |  |  |  |  | =item B<Note>
986 |  |  |  |  |
987 |  |  |  |  | As of 0.08100, this method enforces the assumption that the preceding
988 |  |  |  |  | query returns only one row. If more than one row is returned, you will receive
989 |  |  |  |  | a warning:
990 |  |  |  |  |
991 |  |  |  |  | Query returned more than one row
992 |  |  |  |  |
993 |  |  |  |  | In this case, you should be using L</next> or L</find> instead, or if you really
994 |  |  |  |  | know what you are doing, use the L</rows> attribute to explicitly limit the size
995 |  |  |  |  | of the resultset.
996 |  |  |  |  |
997 |  |  |  |  | This method will also throw an exception if it is called on a resultset prefetching
998 |  |  |  |  | has_many, as such a prefetch implies fetching multiple rows from the database in
999 |  |  |  |  | order 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 {
1006 | 14049 | 60.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 |  |  |  |  |
1011 |  |  | 2007 | 29.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 |  |  |  |  |
1031 |  |  | 4015 | 79.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 |  |  |  |  |
1036 |  |  | 1566 | 227ms | 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 |  |  |  |  |
1044 |  |  |  |  | sub _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 |  |  |  |  |
1084 |  |  |  |  | Returns 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 {
1089 | 5862 | 15.0ms |  |  | my ($self, $column) = @_;
1090 |  |  | 1954 | 998ms | 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 |  |  |  |  |
1107 |  |  |  |  | Performs a search, but uses C<LIKE> instead of C<=> as the condition. Note
1108 |  |  |  |  | that this is simply a convenience method retained for ex Class::DBI users.
1109 |  |  |  |  | You most likely want to use L</search> with specific operators.
1110 |  |  |  |  |
1111 |  |  |  |  | For more information, see L<DBIx::Class::Manual::Cookbook>.
1112 |  |  |  |  |
1113 |  |  |  |  | This method is deprecated and will be removed in 0.09. Use L</search()>
1114 |  |  |  |  | instead. An example conversion is:
1115 |  |  |  |  |
1116 |  |  |  |  | ->search_like({ foo => 'bar' });
1117 |  |  |  |  |
1118 |  |  |  |  | # Becomes
1119 |  |  |  |  |
1120 |  |  |  |  | ->search({ foo => { like => 'bar' } });
1121 |  |  |  |  |
1122 |  |  |  |  | =cut
1123 |  |  |  |  |
1124 |  |  |  |  | sub 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 |  |  |  |  |
1147 |  |  |  |  | Returns a resultset or object list representing a subset of elements from the
1148 |  |  |  |  | resultset slice is called on. Indexes are from 0, i.e., to get the first
1149 |  |  |  |  | three records, call:
1150 |  |  |  |  |
1151 |  |  |  |  | my ($one, $two, $three) = $rs->slice(0, 2);
1152 |  |  |  |  |
1153 |  |  |  |  | =cut
1154 |  |  |  |  |
1155 |  |  |  |  | sub 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 |  |  |  |  |
1176 |  |  |  |  | Returns the next element in the resultset (C<undef> is there is none).
1177 |  |  |  |  |
1178 |  |  |  |  | Can 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 |  |  |  |  |
1185 |  |  |  |  | Note that you need to store the resultset object, and call C<next> on it.
1186 |  |  |  |  | Calling C<< resultset('Table')->next >> repeatedly will always return the
1187 |  |  |  |  | first 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 {
1192 | 17904 | 49.7ms |  |  | my ($self) = @_;
1193 |  |  | 2318 | 4.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}
1209 |  |  | 4636 | 2.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);
1213 |  |  | 1332 | 163ms | 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 {
1219 | 23585 | 96.0ms |  |  | my ($self, @row) = @_;
1220 |  |  |  |  |
1221 |  |  | 4717 | 399ms | 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 ();
1223 |  |  | 9435 | 170ms | 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 {
1230 | 174624 | 406ms |  |  | 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 |  |  |  |  |
1238 |  |  | 35425 | 72.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) {
1277 |  |  |  |  | $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
1285 |  |  |  |  | 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) {
1310 |  |  | 4717 | 4.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) {
1314 |  |  |  |  | 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 |  |  |  |  |
1360 |  |  |  |  | An accessor for the primary ResultSource object from which this ResultSet
1361 |  |  |  |  | is 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 |  |  |  |  |
1373 |  |  |  |  | An accessor for the class to use when creating row objects. Defaults to
1374 |  |  |  |  | C<< result_source->result_class >> - which in most cases is the name of the
1375 |  |  |  |  | L<"table"|DBIx::Class::Manual::Glossary/"ResultSource"> class.
1376 |  |  |  |  |
1377 |  |  |  |  | Note that changing the result_class will also remove any components
1378 |  |  |  |  | that were originally loaded in the source class via
1379 |  |  |  |  | L<DBIx::Class::ResultSource/load_components>. Any overloaded methods
1380 |  |  |  |  | in 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 {
1385 | 144699 | 232ms |  |  | my ($self, $result_class) = @_;
1386 |  |  |  |  | if ($result_class) {
1387 |  |  | 24636 | 135ms | 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 |  |  |  |  | }
1390 |  |  | 2 | 165µ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 |  |  |  |  | }
1396 |  |  | 1 | 600ns | $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 |  |  |  |  |
1409 |  |  |  |  | Performs an SQL C<COUNT> with the same query as the resultset was built
1410 |  |  |  |  | with to find the number of elements. Passing arguments is equivalent to
1411 |  |  |  |  | C<< $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 {
1416 | 27286 | 71.4ms |  |  | my $self = shift;
1417 |  |  |  |  | return $self->search(@_)->count if @_ and defined $_[0];
1418 |  |  | 1949 | 2.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 |  |  |  |  |
1420 |  |  | 1949 | 361ms | 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;
1428 |  |  | 1949 | 36.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 {
1432 |  |  | 1949 | 1.40s | $crs = $self->_count_rs ($attrs); # spent 1.40s making 1949 calls to DBIx::Class::ResultSet::_count_rs, avg 717µs/call
1433 |  |  |  |  | }
1434 |  |  | 1949 | 3.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 |  |  |  |  |
1453 |  |  |  |  | Same as L</count> but returns a L<DBIx::Class::ResultSetColumn> object.
1454 |  |  |  |  | This can be very handy for subqueries:
1455 |  |  |  |  |
1456 |  |  |  |  | ->search( { amount => $some_rs->count_rs->as_query } )
1457 |  |  |  |  |
1458 |  |  |  |  | As with regular resultsets the SQL query will be executed only after
1459 |  |  |  |  | the resultset is accessed via L</next> or L</all>. That would return
1460 |  |  |  |  | the same single value obtainable via L</count>.
1461 |  |  |  |  |
1462 |  |  |  |  | =cut
1463 |  |  |  |  |
1464 |  |  |  |  | sub 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 {
1484 | 19490 | 66.2ms |  |  | my ($self, $attrs) = @_;
1485 |  |  |  |  |
1486 |  |  | 1 | 1µ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)
1494 |  |  | 3898 | 69.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 |  |  |  |  |
1498 |  |  | 5847 | 1.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 |  |  |  |  | #
1506 |  |  |  |  | sub _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 {
1593 | 1909 | 7.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 |  |  |  |  |
1606 |  |  |  |  | Counts the results in a literal query. Equivalent to calling L</search_literal>
1607 |  |  |  |  | with the passed arguments, then L</count>.
1608 |  |  |  |  |
1609 |  |  |  |  | =cut
1610 |  |  |  |  |
1611 |  |  |  |  | sub 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 |  |  |  |  |
1623 |  |  |  |  | Returns 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 {
1628 | 12880 | 56.5ms |  |  | my $self = shift;
1629 |  |  |  |  | if(@_) {
1630 |  |  |  |  | $self->throw_exception("all() doesn't take any arguments, you probably wanted ->search(...)->all()");
1631 |  |  |  |  | }
1632 |  |  |  |  |
1633 |  |  | 1610 | 2.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 |  |  |  |  |
1637 |  |  | 1610 | 312ms | 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 {
1651 |  |  | 5039 | 2.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 |  |  |  |  |
1669 |  |  |  |  | Resets the resultset's cursor, so you can iterate through the elements again.
1670 |  |  |  |  | Implicitly resets the storage cursor, so a subsequent L</next> will trigger
1671 |  |  |  |  | another 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 {
1676 | 740 | 1.49ms |  |  | my ($self) = @_;
1677 |  |  |  |  | delete $self->{_attrs} if exists $self->{_attrs};
1678 |  |  |  |  | $self->{all_cache_position} = 0;
1679 |  |  | 296 | 48.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 |  |  |  |  |
1693 |  |  |  |  | Resets the resultset and returns an object for the first result (or C<undef>
1694 |  |  |  |  | if 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 {
1699 | 148 | 1.26ms | 296 | 288ms | 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 {
1710 | 133 | 914µs |  |  | my ($self, $op, $values) = @_;
1711 |  |  |  |  |
1712 |  |  | 1 | 2µs | my $rsrc = $self->result_source; # spent 2µs making 1 call to DBIx::Class::ResultSet::result_source
1713 |  |  |  |  |
1714 |  |  | 19 | 8.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
1715 |  |  | 19 | 507µ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 |  |  |  |  |
1717 |  |  |  |  | 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 |  |  |  |  |
1773 |  |  | 38 | 1.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 |  |  |  |  |
1791 |  |  |  |  | Sets the specified columns in the resultset to the supplied values in a
1792 |  |  |  |  | single query. Note that this will not run any accessor/set_column/update
1793 |  |  |  |  | triggers, nor will it update any row object instances derived from this
1794 |  |  |  |  | resultset (this includes the contents of the L<resultset cache|/set_cache>
1795 |  |  |  |  | if any). See L</update_all> if you need to execute any on-update
1796 |  |  |  |  | triggers or cascades defined either by you or a
1797 |  |  |  |  | L<result component|DBIx::Class::Manual::Component/WHAT_IS_A_COMPONENT>.
1798 |  |  |  |  |
1799 |  |  |  |  | The return value is a pass through of what the underlying
1800 |  |  |  |  | storage backend returned, and may vary. See L<DBI/execute> for the most
1801 |  |  |  |  | common case.
1802 |  |  |  |  |
1803 |  |  |  |  | =head3 CAVEAT
1804 |  |  |  |  |
1805 |  |  |  |  | Note that L</update> does not process/deflate any of the values passed in.
1806 |  |  |  |  | This is unlike the corresponding L<DBIx::Class::Row/update>. The user must
1807 |  |  |  |  | ensure manually that any value passed to this method will stringify to
1808 |  |  |  |  | something the RDBMS knows how to deal with. A notable example is the
1809 |  |  |  |  | handling of L<DateTime> objects, for more info see:
1810 |  |  |  |  | L<DBIx::Class::Manual::Cookbook/Formatting_DateTime_objects_in_queries>.
1811 |  |  |  |  |
1812 |  |  |  |  | =cut
1813 |  |  |  |  |
1814 |  |  |  |  | sub 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 |  |  |  |  |
1832 |  |  |  |  | Fetches all objects and updates them one at a time via
1833 |  |  |  |  | L<DBIx::Class::Row/update>. Note that C<update_all> will run DBIC defined
1834 |  |  |  |  | triggers, while L</update> will not.
1835 |  |  |  |  |
1836 |  |  |  |  | =cut
1837 |  |  |  |  |
1838 |  |  |  |  | sub 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 |  |  |  |  |
1859 |  |  |  |  | Deletes the rows matching this resultset in a single query. Note that this
1860 |  |  |  |  | will not run any delete triggers, nor will it alter the
1861 |  |  |  |  | L<in_storage|DBIx::Class::Row/in_storage> status of any row object instances
1862 |  |  |  |  | derived from this resultset (this includes the contents of the
1863 |  |  |  |  | L<resultset cache|/set_cache> if any). See L</delete_all> if you need to
1864 |  |  |  |  | execute any on-delete triggers or cascades defined either by you or a
1865 |  |  |  |  | L<result component|DBIx::Class::Manual::Component/WHAT_IS_A_COMPONENT>.
1866 |  |  |  |  |
1867 |  |  |  |  | The return value is a pass through of what the underlying storage backend
1868 |  |  |  |  | returned, 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 {
1873 | 57 | 327µs |  |  | my $self = shift;
1874 |  |  |  |  | $self->throw_exception('delete does not accept any arguments')
1875 |  |  |  |  | if @_;
1876 |  |  |  |  |
1877 |  |  | 19 | 2.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 |  |  |  |  |
1890 |  |  |  |  | Fetches all objects and deletes them one at a time via
1891 |  |  |  |  | L<DBIx::Class::Row/delete>. Note that C<delete_all> will run DBIC defined
1892 |  |  |  |  | triggers, while L</delete> will not.
1893 |  |  |  |  |
1894 |  |  |  |  | =cut
1895 |  |  |  |  |
1896 |  |  |  |  | sub 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 |  |  |  |  |
1915 |  |  |  |  | Accepts either an arrayref of hashrefs or alternatively an arrayref of arrayrefs.
1916 |  |  |  |  | For the arrayref of hashrefs style each hashref should be a structure suitable
1917 |  |  |  |  | for submitting to a $resultset->create(...) method.
1918 |  |  |  |  |
1919 |  |  |  |  | In void context, C<insert_bulk> in L<DBIx::Class::Storage::DBI> is used
1920 |  |  |  |  | to insert the data, as this is a faster method.
1921 |  |  |  |  |
1922 |  |  |  |  | Otherwise, each set of data is inserted into the database using
1923 |  |  |  |  | L<DBIx::Class::ResultSet/create>, and the resulting objects are
1924 |  |  |  |  | accumulated into an array. The array itself, or an array reference
1925 |  |  |  |  | is returned depending on scalar or list context.
1926 |  |  |  |  |
1927 |  |  |  |  | Example: 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 |  |  |  |  |
1959 |  |  |  |  | For the arrayref of arrayrefs style, the first element should be a list of the
1960 |  |  |  |  | fieldsnames to which the remaining elements are rows being inserted. For
1961 |  |  |  |  | example:
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 |  |  |  |  |
1970 |  |  |  |  | Please note an important effect on your data when choosing between void and
1971 |  |  |  |  | wantarray context. Since void context goes straight to C<insert_bulk> in
1972 |  |  |  |  | L<DBIx::Class::Storage::DBI> this will skip any component that is overriding
1973 |  |  |  |  | C<insert>. So if you are using something like L<DBIx-Class-UUIDColumns> to
1974 |  |  |  |  | create primary keys for you, you will find that your PKs are empty. In this
1975 |  |  |  |  | case you will have to use the wantarray context in order to create those
1976 |  |  |  |  | values.
1977 |  |  |  |  |
1978 |  |  |  |  | =cut
1979 |  |  |  |  |
1980 |  |  |  |  | sub 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
2088 |  |  |  |  | sub _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 |  |  |  |  |
2121 |  |  |  |  | Return Value a L<Data::Page> object for the current resultset. Only makes
2122 |  |  |  |  | sense for queries with a C<page> attribute.
2123 |  |  |  |  |
2124 |  |  |  |  | To get the full count of entries for a paged resultset, call
2125 |  |  |  |  | C<total_entries> on the L<Data::Page> object.
2126 |  |  |  |  |
2127 |  |  |  |  | =cut
2128 |  |  |  |  |
2129 |  |  |  |  | sub 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 |  |  |  |  |
2168 |  |  |  |  | Returns a resultset for the $page_number page of the resultset on which page
2169 |  |  |  |  | is called, where each page contains a number of rows equal to the 'rows'
2170 |  |  |  |  | attribute set on the resultset (10 by default).
2171 |  |  |  |  |
2172 |  |  |  |  | =cut
2173 |  |  |  |  |
2174 |  |  |  |  | sub 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 |  |  |  |  |
2189 |  |  |  |  | Creates a new row object in the resultset's result class and returns
2190 |  |  |  |  | it. The row is not inserted into the database at this point, call
2191 |  |  |  |  | L<DBIx::Class::Row/insert> to do that. Calling L<DBIx::Class::Row/in_storage>
2192 |  |  |  |  | will tell you whether the row object has been inserted or not.
2193 |  |  |  |  |
2194 |  |  |  |  | Passes 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 {
2199 | 2245 | 16.9ms |  |  | my ($self, $values) = @_;
2200 |  |  |  |  | $self->throw_exception( "new_result needs a hash" )
2201 |  |  |  |  | unless (ref $values eq 'HASH');
2202 |  |  |  |  |
2203 |  |  | 449 | 37.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 |  |  |  |  |
2205 |  |  | 1 | 4µ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 |  |  |  |  |
2213 |  |  | 898 | 228ms | 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 {
2223 | 4836 | 18.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,
2266 |  |  | 806 | 32.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 {
2286 | 28515 | 35.0ms |  |  | my ($self, @attr_names) = @_;
2287 |  |  |  |  |
2288 |  |  | 2134 | 33.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) {
2293 |  |  |  |  | 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 |  |  |  |  |
2329 |  |  |  |  | sub _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 {
2363 | 11188 | 34.9ms |  |  | my ($self, $query, $alias) = @_;
2364 |  |  |  |  |
2365 |  |  |  |  | my %orig = %{ $query || {} };
2366 |  |  |  |  | my %unaliased;
2367 |  |  |  |  |
2368 |  |  |  |  | foreach my $key (keys %orig) {
2369 |  |  | 2386 | 3.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 |  |  |  |  |
2390 |  |  |  |  | Returns the SQL query and bind vars associated with the invocant.
2391 |  |  |  |  |
2392 |  |  |  |  | This is generally used as the RHS for a subquery.
2393 |  |  |  |  |
2394 |  |  |  |  | =cut
2395 |  |  |  |  |
2396 |  |  |  |  | sub 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 |  |  |  |  |
2429 |  |  |  |  | Find an existing record from this resultset using L</find>. if none exists,
2430 |  |  |  |  | instantiate a new result object and return it. The object will not be saved
2431 |  |  |  |  | into your storage until you call L<DBIx::Class::Row/insert> on it.
2432 |  |  |  |  |
2433 |  |  |  |  | You most likely want this method when looking for existing rows using a unique
2434 |  |  |  |  | constraint that is not the primary key, or looking for related rows.
2435 |  |  |  |  |
2436 |  |  |  |  | If you want objects to be saved immediately, use L</find_or_create> instead.
2437 |  |  |  |  |
2438 |  |  |  |  | B<Note>: Make sure to read the documentation of L</find> and understand the
2439 |  |  |  |  | significance of the C<key> attribute, as its lack may skew your search, and
2440 |  |  |  |  | subsequently result in spurious new objects.
2441 |  |  |  |  |
2442 |  |  |  |  | B<Note>: Take care when using C<find_or_new> with a table having
2443 |  |  |  |  | columns with default values that you intend to be automatically
2444 |  |  |  |  | supplied by the database (e.g. an auto_increment primary key column).
2445 |  |  |  |  | In normal usage, the value of such columns should NOT be included at
2446 |  |  |  |  | all in the call to C<find_or_new>, even when set to C<undef>.
2447 |  |  |  |  |
2448 |  |  |  |  | =cut
2449 |  |  |  |  |
2450 |  |  |  |  | sub 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 |  |  |  |  |
2470 |  |  |  |  | Attempt to create a single new row or a row with multiple related rows
2471 |  |  |  |  | in the table represented by the resultset (and related tables). This
2472 |  |  |  |  | will not check for duplicate rows before inserting, use
2473 |  |  |  |  | L</find_or_create> to do that.
2474 |  |  |  |  |
2475 |  |  |  |  | To create one row for this resultset, pass a hashref of key/value
2476 |  |  |  |  | pairs representing the columns of the table and the values you wish to
2477 |  |  |  |  | store. If the appropriate relationships are set up, foreign key fields
2478 |  |  |  |  | can also be passed an object representing the foreign row, and the
2479 |  |  |  |  | value will be set to its primary key.
2480 |  |  |  |  |
2481 |  |  |  |  | To create related objects, pass a hashref of related-object column values
2482 |  |  |  |  | B<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.
2484 |  |  |  |  | The process will correctly identify columns holding foreign keys, and will
2485 |  |  |  |  | transparently populate them from the keys of the corresponding relation.
2486 |  |  |  |  | This can be applied recursively, and will work correctly for a structure
2487 |  |  |  |  | with an arbitrary depth and width, as long as the relationships actually
2488 |  |  |  |  | exists and the correct column data has been supplied.
2489 |  |  |  |  |
2490 |  |  |  |  |
2491 |  |  |  |  | Instead of hashrefs of plain related data (key/value pairs), you may
2492 |  |  |  |  | also pass new or inserted objects. New objects (not inserted yet, see
2493 |  |  |  |  | L</new>), will be inserted into their appropriate tables.
2494 |  |  |  |  |
2495 |  |  |  |  | Effectively a shortcut for C<< ->new_result(\%vals)->insert >>.
2496 |  |  |  |  |
2497 |  |  |  |  | Example of creating a new row.
2498 |  |  |  |  |
2499 |  |  |  |  | $person_rs->create({
2500 |  |  |  |  | name=>"Some Person",
2501 |  |  |  |  | email=>"somebody@someplace.com"
2502 |  |  |  |  | });
2503 |  |  |  |  |
2504 |  |  |  |  | Example of creating a new row and also creating rows in a related C<has_many>
2505 |  |  |  |  | or 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 |  |  |  |  |
2515 |  |  |  |  | Example of creating a new row and also creating a row in a related
2516 |  |  |  |  | C<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 |  |  |  |  |
2530 |  |  |  |  | When subclassing ResultSet never attempt to override this method. Since
2531 |  |  |  |  | it is a simple shortcut for C<< $self->new_result($attrs)->insert >>, a
2532 |  |  |  |  | lot of the internals simply never call it, so your override will be
2533 |  |  |  |  | bypassed more often than not. Override either L<new|DBIx::Class::Row/new>
2534 |  |  |  |  | or L<insert|DBIx::Class::Row/insert> depending on how early in the
2535 |  |  |  |  | L</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 {
2542 | 72 | 883µs |  |  | my ($self, $attrs) = @_;
2543 |  |  |  |  | $self->throw_exception( "create needs a hashref" )
2544 |  |  |  |  | unless ref $attrs eq 'HASH';
2545 |  |  | 48 | 2.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 |  |  |  |  |
2561 |  |  |  |  | Tries to find a record based on its primary key or unique constraints; if none
2562 |  |  |  |  | is 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 |  |  |  |  |
2571 |  |  |  |  | Also takes an optional C<key> attribute, to search by a specific key or unique
2572 |  |  |  |  | constraint. 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 |  |  |  |  |
2582 |  |  |  |  | B<Note>: Make sure to read the documentation of L</find> and understand the
2583 |  |  |  |  | significance of the C<key> attribute, as its lack may skew your search, and
2584 |  |  |  |  | subsequently result in spurious row creation.
2585 |  |  |  |  |
2586 |  |  |  |  | B<Note>: Because find_or_create() reads from the database and then
2587 |  |  |  |  | possibly inserts based on the result, this method is subject to a race
2588 |  |  |  |  | condition. Another process could create a record in the table after
2589 |  |  |  |  | the find has completed and before the create has started. To avoid
2590 |  |  |  |  | this problem, use find_or_create() inside a transaction.
2591 |  |  |  |  |
2592 |  |  |  |  | B<Note>: Take care when using C<find_or_create> with a table having
2593 |  |  |  |  | columns with default values that you intend to be automatically
2594 |  |  |  |  | supplied by the database (e.g. an auto_increment primary key column).
2595 |  |  |  |  | In normal usage, the value of such columns should NOT be included at
2596 |  |  |  |  | all in the call to C<find_or_create>, even when set to C<undef>.
2597 |  |  |  |  |
2598 |  |  |  |  | See also L</find> and L</update_or_create>. For information on how to declare
2599 |  |  |  |  | unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
2600 |  |  |  |  |
2601 |  |  |  |  | =cut
2602 |  |  |  |  |
2603 |  |  |  |  | sub 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 |  |  |  |  |
2625 |  |  |  |  | Like L</find_or_create>, but if a row is found it is immediately updated via
2626 |  |  |  |  | C<< $found_row->update (\%col_values) >>.
2627 |  |  |  |  |
2628 |  |  |  |  |
2629 |  |  |  |  | Takes an optional C<key> attribute to search on a specific unique constraint.
2630 |  |  |  |  | For 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 |  |  |  |  |
2649 |  |  |  |  | B<Note>: Make sure to read the documentation of L</find> and understand the
2650 |  |  |  |  | significance of the C<key> attribute, as its lack may skew your search, and
2651 |  |  |  |  | subsequently result in spurious row creation.
2652 |  |  |  |  |
2653 |  |  |  |  | B<Note>: Take care when using C<update_or_create> with a table having
2654 |  |  |  |  | columns with default values that you intend to be automatically
2655 |  |  |  |  | supplied by the database (e.g. an auto_increment primary key column).
2656 |  |  |  |  | In normal usage, the value of such columns should NOT be included at
2657 |  |  |  |  | all in the call to C<update_or_create>, even when set to C<undef>.
2658 |  |  |  |  |
2659 |  |  |  |  | See also L</find> and L</find_or_create>. For information on how to declare
2660 |  |  |  |  | unique constraints, see L<DBIx::Class::ResultSource/add_unique_constraint>.
2661 |  |  |  |  |
2662 |  |  |  |  | =cut
2663 |  |  |  |  |
2664 |  |  |  |  | sub 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 |  |  |  |  |
2690 |  |  |  |  | Like L</find_or_new> but if a row is found it is immediately updated via
2691 |  |  |  |  | C<< $found_row->update (\%col_values) >>.
2692 |  |  |  |  |
2693 |  |  |  |  | For 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 |  |  |  |  |
2713 |  |  |  |  | B<Note>: Make sure to read the documentation of L</find> and understand the
2714 |  |  |  |  | significance of the C<key> attribute, as its lack may skew your search, and
2715 |  |  |  |  | subsequently result in spurious new objects.
2716 |  |  |  |  |
2717 |  |  |  |  | B<Note>: Take care when using C<update_or_new> with a table having
2718 |  |  |  |  | columns with default values that you intend to be automatically
2719 |  |  |  |  | supplied by the database (e.g. an auto_increment primary key column).
2720 |  |  |  |  | In normal usage, the value of such columns should NOT be included at
2721 |  |  |  |  | all in the call to C<update_or_new>, even when set to C<undef>.
2722 |  |  |  |  |
2723 |  |  |  |  | See also L</find>, L</find_or_create> and L</find_or_new>.
2724 |  |  |  |  |
2725 |  |  |  |  | =cut
2726 |  |  |  |  |
2727 |  |  |  |  | sub 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 |  |  |  |  |
2751 |  |  |  |  | Gets the contents of the cache for the resultset, if the cache is set.
2752 |  |  |  |  |
2753 |  |  |  |  | The cache is populated either by using the L</prefetch> attribute to
2754 |  |  |  |  | L</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 {
2759 | 13565 | 46.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 |  |  |  |  |
2772 |  |  |  |  | Sets the contents of the cache for the resultset. Expects an arrayref
2773 |  |  |  |  | of objects of the same class as those produced by the resultset. Note that
2774 |  |  |  |  | if the cache is set the resultset will return the cached objects rather
2775 |  |  |  |  | than re-querying the database even if the cache attr is not set.
2776 |  |  |  |  |
2777 |  |  |  |  | The contents of the cache can also be populated by using the
2778 |  |  |  |  | L</prefetch> attribute to L</search>.
2779 |  |  |  |  |
2780 |  |  |  |  | =cut
2781 |  |  |  |  |
2782 |  |  |  |  | sub 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 |  |  |  |  |
2799 |  |  |  |  | Clears the cache for the resultset.
2800 |  |  |  |  |
2801 |  |  |  |  | =cut
2802 |  |  |  |  |
2803 |  |  |  |  | sub 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 |  |  |  |  |
2819 |  |  |  |  | sub 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 |  |  |  |  |
2836 |  |  |  |  | sub 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 |  |  |  |  |
2851 |  |  |  |  | Returns 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 {
2858 | 2940 | 7.45ms |  |  | my ($self, $rel) = @_;
2859 |  |  |  |  |
2860 |  |  |  |  | $self->{related_resultsets} ||= {};
2861 |  |  |  |  | return $self->{related_resultsets}{$rel} ||= do {
2862 |  |  | 1 | 1µs | my $rsrc = $self->result_source; # spent 1µs making 1 call to DBIx::Class::ResultSet::result_source
2863 |  |  | 147 | 417µ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 |  |  |  |  |
2870 |  |  | 147 | 58.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 |  |  |  |  |
2874 |  |  | 295 | 2.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
2881 |  |  | 441 | 6.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 |  |  |  |  |
2889 |  |  | 147 | 220µ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 |  |  |  |  |
2896 |  |  | 147 | 7.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 |  |  |  |  |
2898 |  |  |  |  | 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 |  |  |  |  |
2906 |  |  | 2 | 195µs | my $rel_attrs = $rel_source->resultset_attributes; # spent 194µs making 1 call to DBIx::Class::ResultSource::resultset_attributes # spent 2µs making 1 call to DBIx::Class::ResultSource::Table::resultset_attributes
2907 |  |  |  |  | local $rel_attrs->{alias} = $alias;
2908 |  |  |  |  |
2909 |  |  | 294 | 39.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 |  |  |  |  |
2931 |  |  |  |  | Returns the current table alias for the result source this resultset is built
2932 |  |  |  |  | on, that will be used in the SQL query. Usually it is C<me>.
2933 |  |  |  |  |
2934 |  |  |  |  | Currently the source alias that refers to the result set returned by a
2935 |  |  |  |  | L</search>/L</find> family method depends on how you got to the resultset: it's
2936 |  |  |  |  | C<me> by default, but eg. L</search_related> aliases it to the related result
2937 |  |  |  |  | source name (and keeps C<me> referring to the original result set). The long
2938 |  |  |  |  | term goal is to make L<DBIx::Class> always alias the current resultset as C<me>
2939 |  |  |  |  | (and make this method unnecessary).
2940 |  |  |  |  |
2941 |  |  |  |  | Thus it's currently necessary to use this method in predefined queries (see
2942 |  |  |  |  | L<DBIx::Class::Manual::Cookbook/Predefined searches>) when referring to the
2943 |  |  |  |  | source 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 {
2959 | 3908 | 10.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 |  |  |  |  |
2974 |  |  |  |  | Act 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
2976 |  |  |  |  | point on, any joined tables are inaccessible to ->search on the resultset (as if
2977 |  |  |  |  | it 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 |  |  |  |  |
2999 |  |  |  |  | Another example of when one might use this would be to select a subset of
3000 |  |  |  |  | columns 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 |  |  |  |  |
3008 |  |  |  |  | In the above example normally columns would have to be equal to the group by,
3009 |  |  |  |  | but because we isolated the group by into a subselect the above works.
3010 |  |  |  |  |
3011 |  |  |  |  | =cut
3012 |  |  |  |  |
3013 |  |  |  |  | sub 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 {
3050 | 2793 | 6.89ms |  |  | my ($self, $rel) = @_;
3051 |  |  | 1 | 500ns | 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
3056 |  |  | 147 | 526µ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 |  |  |  |  |
3065 |  |  | 147 | 24.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 {
3091 |  |  | 147 | 259µ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 |  |  |  |  |
3102 |  |  | 147 | 971µ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 |  |  |  |  |
3129 |  |  | 147 | 24.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 {
3145 | 19974 | 100ms |  |  | my $self = shift;
3146 |  |  | 9987 | 741ms | 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 {
3150 | 659296 | 1.19s |  |  | my $self = shift;
3151 |  |  |  |  | return $self->{_attrs} if $self->{_attrs};
3152 |  |  |  |  |
3153 |  |  |  |  | my $attrs = { %{ $self->{attrs} || {} } };
3154 |  |  | 1 | 2µ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 ]
3159 | 39194 | 78.6ms | 17646 | 84.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/) {
3163 |  |  | 14678 | 385ms | $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);
3169 |  |  |  |  | if (my $cols = delete $attrs->{columns}) {
3170 |  |  |  |  | for my $c (ref $cols eq 'ARRAY' ? @$cols : $cols) {
3171 |  |  |  |  | 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) {
3195 |  |  | 42399 | 27.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) {
3200 |  |  | 92594 | 52.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) {
3209 |  |  |  |  | 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 |  |  |  |  |
3227 |  |  | 6730 | 32.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)
3273 |  |  |  |  | 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.
3280 |  |  | 2 | 373µ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 |  |  |  |  |
3350 |  |  |  |  | sub _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 |  |  |  |  |
3362 |  |  |  |  | sub _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 |  |  |  |  |
3379 |  |  |  |  | sub _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 |  |  |  |  |
3389 |  |  |  |  | sub _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 {
3422 | 4202 | 11.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 |  |  |  |  | {
3464 | 2 | 900ns |  |  | 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 {
3467 | 68402 | 156ms |  |  | $hm ||= do {
3468 |  |  |  |  | require Hash::Merge;
3469 |  |  | 1 | 21µ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 {
3490 | 19521 | 49.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 {
3503 | 14678 | 49.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 |  |  |  |  | }
3543 |  |  | 1 | 67µs | } => 'DBIC_RS_ATTR_MERGER'); # spent 67µs making 1 call to Hash::Merge::specify_behavior
3544 |  |  |  |  | $hm;
3545 |  |  |  |  | };
3546 |  |  |  |  |
3547 |  |  | 34199 | 546ms | return $hm->merge ($_[1], $_[2]); # spent 546ms making 34199 calls to Hash::Merge::merge, avg 16µs/call
3548 |  |  |  |  | }
3549 |  |  |  |  | }
3550 |  |  |  |  |
3551 |  |  |  |  | sub 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
3567 |  |  |  |  | sub STORABLE_thaw {
3568 |  |  |  |  | my ($self, $cloning, $serialized) = @_;
3569 |  |  |  |  |
3570 |  |  |  |  | %$self = %{ Storable::thaw($serialized) };
3571 |  |  |  |  |
3572 |  |  |  |  | $self;
3573 |  |  |  |  | }
3574 |  |  |  |  |
3575 |  |  |  |  |
3576 |  |  |  |  | =head2 throw_exception
3577 |  |  |  |  |
3578 |  |  |  |  | See L<DBIx::Class::Schema/throw_exception> for details.
3579 |  |  |  |  |
3580 |  |  |  |  | =cut
3581 |  |  |  |  |
3582 |  |  |  |  | sub 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 |  |  |  |  |
3597 |  |  |  |  | Attributes are used to refine a ResultSet in various ways when
3598 |  |  |  |  | searching for data. They can be passed to any method which takes an
3599 |  |  |  |  | C<\%attrs> argument. See L</search>, L</search_rs>, L</find>,
3600 |  |  |  |  | L</count>.
3601 |  |  |  |  |
3602 |  |  |  |  | These 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 |  |  |  |  |
3612 |  |  |  |  | Which column(s) to order the results by.
3613 |  |  |  |  |
3614 |  |  |  |  | [The full list of suitable values is documented in
3615 |  |  |  |  | L<SQL::Abstract/"ORDER BY CLAUSES">; the following is a summary of
3616 |  |  |  |  | common options.]
3617 |  |  |  |  |
3618 |  |  |  |  | If a single column name, or an arrayref of names is supplied, the
3619 |  |  |  |  | argument is passed through directly to SQL. The hashref syntax allows
3620 |  |  |  |  | for 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 |  |  |  |  |
3630 |  |  |  |  | The old scalarref syntax (i.e. order_by => \'year DESC') is still
3631 |  |  |  |  | supported, although you are strongly encouraged to use the hashref
3632 |  |  |  |  | syntax as outlined above.
3633 |  |  |  |  |
3634 |  |  |  |  | =head2 columns
3635 |  |  |  |  |
3636 |  |  |  |  | =over 4
3637 |  |  |  |  |
3638 |  |  |  |  | =item Value: \@columns
3639 |  |  |  |  |
3640 |  |  |  |  | =back
3641 |  |  |  |  |
3642 |  |  |  |  | Shortcut to request a particular set of columns to be retrieved. Each
3643 |  |  |  |  | column spec may be a string (a table column name), or a hash (in which
3644 |  |  |  |  | case the key is the C<as> value, and the value is used as the C<select>
3645 |  |  |  |  | expression). Adds C<me.> onto the start of any column without a C<.> in
3646 |  |  |  |  | it and sets C<select> from that, then auto-populates C<as> from
3647 |  |  |  |  | C<select> as normal. (You may also use the C<cols> attribute, as in
3648 |  |  |  |  | earlier versions of DBIC.)
3649 |  |  |  |  |
3650 |  |  |  |  | Essentially C<columns> does the same as L</select> and L</as>.
3651 |  |  |  |  |
3652 |  |  |  |  | columns => [ 'foo', { bar => 'baz' } ]
3653 |  |  |  |  |
3654 |  |  |  |  | is 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 |  |  |  |  |
3667 |  |  |  |  | Indicates additional columns to be selected from storage. Works the same
3668 |  |  |  |  | as L</columns> but adds columns to the selection. (You may also use the
3669 |  |  |  |  | C<include_columns> attribute, as in earlier versions of DBIC). For
3670 |  |  |  |  | example:-
3671 |  |  |  |  |
3672 |  |  |  |  | $schema->resultset('CD')->search(undef, {
3673 |  |  |  |  | '+columns' => ['artist.name'],
3674 |  |  |  |  | join => ['artist']
3675 |  |  |  |  | });
3676 |  |  |  |  |
3677 |  |  |  |  | would return all CDs and include a 'name' column to the information
3678 |  |  |  |  | passed to object inflation. Note that the 'artist' is the name of the
3679 |  |  |  |  | column (or relationship) accessor, and 'name' is the name of the column
3680 |  |  |  |  | accessor in the related table.
3681 |  |  |  |  |
3682 |  |  |  |  | B<NOTE:> You need to explicitly quote '+columns' when defining the attribute.
3683 |  |  |  |  | Not doing so causes Perl to incorrectly interpret +columns as a bareword with a
3684 |  |  |  |  | unary plus operator before it.
3685 |  |  |  |  |
3686 |  |  |  |  | =head2 include_columns
3687 |  |  |  |  |
3688 |  |  |  |  | =over 4
3689 |  |  |  |  |
3690 |  |  |  |  | =item Value: \@columns
3691 |  |  |  |  |
3692 |  |  |  |  | =back
3693 |  |  |  |  |
3694 |  |  |  |  | Deprecated. 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 |  |  |  |  |
3704 |  |  |  |  | Indicates which columns should be selected from the storage. You can use
3705 |  |  |  |  | column names, or in the case of RDBMS back ends, function or stored procedure
3706 |  |  |  |  | names:
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 |  |  |  |  |
3719 |  |  |  |  | B<NOTE:> You will almost always need a corresponding L</as> attribute when you
3720 |  |  |  |  | use L</select>, to instruct DBIx::Class how to store the result of the column.
3721 |  |  |  |  | Also note that the L</as> attribute has nothing to do with the SQL-side 'AS'
3722 |  |  |  |  | identifier aliasing. You can however alias a function, so you can use it in
3723 |  |  |  |  | e.g. an C<ORDER BY> clause. This is done via the C<-as> B<select function
3724 |  |  |  |  | attribute> supplied as shown in the example above.
3725 |  |  |  |  |
3726 |  |  |  |  | B<NOTE:> You need to explicitly quote '+select'/'+as' when defining the attributes.
3727 |  |  |  |  | Not doing so causes Perl to incorrectly interpret them as a bareword with a
3728 |  |  |  |  | unary plus operator before it.
3729 |  |  |  |  |
3730 |  |  |  |  | =head2 +select
3731 |  |  |  |  |
3732 |  |  |  |  | =over 4
3733 |  |  |  |  |
3734 |  |  |  |  | Indicates additional columns to be selected from storage. Works the same as
3735 |  |  |  |  | L</select> but adds columns to the default selection, instead of specifying
3736 |  |  |  |  | an explicit list.
3737 |  |  |  |  |
3738 |  |  |  |  | =back
3739 |  |  |  |  |
3740 |  |  |  |  | =head2 +as
3741 |  |  |  |  |
3742 |  |  |  |  | =over 4
3743 |  |  |  |  |
3744 |  |  |  |  | Indicates 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 |  |  |  |  |
3756 |  |  |  |  | Indicates column names for object inflation. That is L</as> indicates the
3757 |  |  |  |  | slot name in which the column value will be stored within the
3758 |  |  |  |  | L<Row|DBIx::Class::Row> object. The value will then be accessible via this
3759 |  |  |  |  | identifier by the C<get_column> method (or via the object accessor B<if one
3760 |  |  |  |  | with the same name already exists>) as shown below. The L</as> attribute has
3761 |  |  |  |  | B<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 |  |  |  |  |
3776 |  |  |  |  | If the object against which the search is performed already has an accessor
3777 |  |  |  |  | matching a column name specified in C<as>, the value can be retrieved using
3778 |  |  |  |  | the accessor as normal:
3779 |  |  |  |  |
3780 |  |  |  |  | my $name = $employee->name();
3781 |  |  |  |  |
3782 |  |  |  |  | If on the other hand an accessor does not exist in the object, you need to
3783 |  |  |  |  | use C<get_column> instead:
3784 |  |  |  |  |
3785 |  |  |  |  | my $employee_count = $employee->get_column('employee_count');
3786 |  |  |  |  |
3787 |  |  |  |  | You can create your own accessors if required - see
3788 |  |  |  |  | L<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 |  |  |  |  |
3798 |  |  |  |  | Contains a list of relationships that should be joined for this query. For
3799 |  |  |  |  | example:
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 |  |  |  |  |
3807 |  |  |  |  | Can also contain a hash reference to refer to the other relation's relations.
3808 |  |  |  |  | For 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 |  |  |  |  |
3827 |  |  |  |  | You need to use the relationship (not the table) name in conditions,
3828 |  |  |  |  | because they are aliased as such. The current table is aliased as "me", so
3829 |  |  |  |  | you 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 |  |  |  |  |
3840 |  |  |  |  | If the same join is supplied twice, it will be aliased to <rel>_2 (and
3841 |  |  |  |  | similarly 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 |  |  |  |  |
3850 |  |  |  |  | will return a set of all artists that have both a cd with title 'Down
3851 |  |  |  |  | to Earth' and a cd with title 'Popular'.
3852 |  |  |  |  |
3853 |  |  |  |  | If you want to fetch related objects from other tables as well, see C<prefetch>
3854 |  |  |  |  | below.
3855 |  |  |  |  |
3856 |  |  |  |  | For 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 |  |  |  |  |
3866 |  |  |  |  | Contains one or more relationships that should be fetched along with
3867 |  |  |  |  | the main query (when they are accessed afterwards the data will
3868 |  |  |  |  | already be available, without extra queries to the database). This is
3869 |  |  |  |  | useful for when you know you will need the related objects, because it
3870 |  |  |  |  | saves at least one query:
3871 |  |  |  |  |
3872 |  |  |  |  | my $rs = $schema->resultset('Tag')->search(
3873 |  |  |  |  | undef,
3874 |  |  |  |  | {
3875 |  |  |  |  | prefetch => {
3876 |  |  |  |  | cd => 'artist'
3877 |  |  |  |  | }
3878 |  |  |  |  | }
3879 |  |  |  |  | );
3880 |  |  |  |  |
3881 |  |  |  |  | The 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 |  |  |  |  |
3887 |  |  |  |  | L<DBIx::Class> has no need to go back to the database when we access the
3888 |  |  |  |  | C<cd> or C<artist> relationships, which saves us two SQL statements in this
3889 |  |  |  |  | case.
3890 |  |  |  |  |
3891 |  |  |  |  | Simple prefetches will be joined automatically, so there is no need
3892 |  |  |  |  | for a C<join> attribute in the above search.
3893 |  |  |  |  |
3894 |  |  |  |  | L</prefetch> can be used with the any of the relationship types and
3895 |  |  |  |  | multiple prefetches can be specified together. Below is a more complex
3896 |  |  |  |  | example that prefetches a CD's artist, its liner notes (if present),
3897 |  |  |  |  | the cover image, the tracks on that cd, and the guests on those
3898 |  |  |  |  | tracks.
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 |  |  |  |  |
3923 |  |  |  |  | This 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 |  |  |  |  |
3942 |  |  |  |  | Now the C<artist>, C<record_label>, C<liner_note>, C<cover_image>,
3943 |  |  |  |  | C<tracks>, and C<guests> of the CD will all be available through the
3944 |  |  |  |  | relationship accessors without the need for additional queries to the
3945 |  |  |  |  | database.
3946 |  |  |  |  |
3947 |  |  |  |  | However, there is one caveat to be observed: it can be dangerous to
3948 |  |  |  |  | prefetch more than one L<has_many|DBIx::Class::Relationship/has_many>
3949 |  |  |  |  | relationship 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 |  |  |  |  |
3961 |  |  |  |  | In 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 |  |  |  |  |
3967 |  |  |  |  | The collapser currently can't identify duplicate tuples for multiple
3968 |  |  |  |  | L<has_many|DBIx::Class::Relationship/has_many> relationships and as a
3969 |  |  |  |  | result the second L<has_many|DBIx::Class::Relationship/has_many>
3970 |  |  |  |  | relation could contain redundant objects.
3971 |  |  |  |  |
3972 |  |  |  |  | =head3 Using L</prefetch> with L</join>
3973 |  |  |  |  |
3974 |  |  |  |  | L</prefetch> implies a L</join> with the equivalent argument, and is
3975 |  |  |  |  | properly merged with any existing L</join> specification. So the
3976 |  |  |  |  | following:
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
3987 |  |  |  |  | prefetching the C<artist>.
3988 |  |  |  |  |
3989 |  |  |  |  | =head3 Using L</prefetch> with L</select> / L</+select> / L</as> / L</+as>
3990 |  |  |  |  |
3991 |  |  |  |  | L</prefetch> implies a L</+select>/L</+as> with the fields of the
3992 |  |  |  |  | prefetched 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 |  |  |  |  |
4003 |  |  |  |  | The L</select> becomes: C<'cd.title', 'artist.*'> and the L</as>
4004 |  |  |  |  | becomes: C<'cd_title', 'artist.*'>.
4005 |  |  |  |  |
4006 |  |  |  |  | =head3 CAVEATS
4007 |  |  |  |  |
4008 |  |  |  |  | Prefetch does a lot of deep magic. As such, it may not behave exactly
4009 |  |  |  |  | as you might expect.
4010 |  |  |  |  |
4011 |  |  |  |  | =over 4
4012 |  |  |  |  |
4013 |  |  |  |  | =item *
4014 |  |  |  |  |
4015 |  |  |  |  | Prefetch uses the L</cache> to populate the prefetched relationships. This
4016 |  |  |  |  | may or may not be what you want.
4017 |  |  |  |  |
4018 |  |  |  |  | =item *
4019 |  |  |  |  |
4020 |  |  |  |  | If you specify a condition on a prefetched relationship, ONLY those
4021 |  |  |  |  | rows that match the prefetched condition will be fetched into that relationship.
4022 |  |  |  |  | This means that adding prefetch to a search() B<may alter> what is returned by
4023 |  |  |  |  | traversing 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 |  |  |  |  |
4039 |  |  |  |  | that cmp_ok() may or may not pass depending on the datasets involved. This
4040 |  |  |  |  | behavior 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 |  |  |  |  |
4052 |  |  |  |  | Makes the resultset paged and specifies the page to retrieve. Effectively
4053 |  |  |  |  | identical to creating a non-pages resultset and then calling ->page($page)
4054 |  |  |  |  | on it.
4055 |  |  |  |  |
4056 |  |  |  |  | If L</rows> attribute is not specified it defaults to 10 rows per page.
4057 |  |  |  |  |
4058 |  |  |  |  | When you have a paged resultset, L</count> will only return the number
4059 |  |  |  |  | of rows in the page. To get the total, use the L</pager> and call
4060 |  |  |  |  | C<total_entries> on it.
4061 |  |  |  |  |
4062 |  |  |  |  | =head2 rows
4063 |  |  |  |  |
4064 |  |  |  |  | =over 4
4065 |  |  |  |  |
4066 |  |  |  |  | =item Value: $rows
4067 |  |  |  |  |
4068 |  |  |  |  | =back
4069 |  |  |  |  |
4070 |  |  |  |  | Specifies the maximum number of rows for direct retrieval or the number of
4071 |  |  |  |  | rows 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 |  |  |  |  |
4081 |  |  |  |  | Specifies the (zero-based) row number for the first row to be returned, or the
4082 |  |  |  |  | of 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 |  |  |  |  |
4092 |  |  |  |  | A 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 |  |  |  |  |
4104 |  |  |  |  | HAVING is a select statement attribute that is applied between GROUP BY and
4105 |  |  |  |  | ORDER BY. It is applied to the after the grouping calculations have been
4106 |  |  |  |  | done.
4107 |  |  |  |  |
4108 |  |  |  |  | having => { 'count_employee' => { '>=', 100 } }
4109 |  |  |  |  |
4110 |  |  |  |  | or 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 |  |  |  |  |
4122 |  |  |  |  | Set to 1 to group by all columns. If the resultset already has a group_by
4123 |  |  |  |  | attribute, this setting is ignored and an appropriate warning is issued.
4124 |  |  |  |  |
4125 |  |  |  |  | =head2 where
4126 |  |  |  |  |
4127 |  |  |  |  | =over 4
4128 |  |  |  |  |
4129 |  |  |  |  | Adds to the WHERE clause.
4130 |  |  |  |  |
4131 |  |  |  |  | # only return rows WHERE deleted IS NULL for all searches
4132 |  |  |  |  | __PACKAGE__->resultset_attributes({ where => { deleted => undef } }); )
4133 |  |  |  |  |
4134 |  |  |  |  | Can be overridden by passing C<< { where => undef } >> as an attribute
4135 |  |  |  |  | to a resultset.
4136 |  |  |  |  |
4137 |  |  |  |  | =back
4138 |  |  |  |  |
4139 |  |  |  |  | =head2 cache
4140 |  |  |  |  |
4141 |  |  |  |  | Set to 1 to cache search results. This prevents extra SQL queries if you
4142 |  |  |  |  | revisit 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 |  |  |  |  |
4152 |  |  |  |  | By default, searches are not cached.
4153 |  |  |  |  |
4154 |  |  |  |  | For more examples of using these attributes, see
4155 |  |  |  |  | L<DBIx::Class::Manual::Cookbook>.
4156 |  |  |  |  |
4157 |  |  |  |  | =head2 for
4158 |  |  |  |  |
4159 |  |  |  |  | =over 4
4160 |  |  |  |  |
4161 |  |  |  |  | =item Value: ( 'update' | 'shared' )
4162 |  |  |  |  |
4163 |  |  |  |  | =back
4164 |  |  |  |  |
4165 |  |  |  |  | Set to 'update' for a SELECT ... FOR UPDATE or 'shared' for a SELECT
4166 |  |  |  |  | ... FOR SHARED.
4167 |  |  |  |  |
4168 |  |  |  |  | =cut
4169 |  |  |  |  |
4170 | 1 | 44µs | 1 | 619µs | 1; # spent 619µs making 1 call to B::Hooks::EndOfScope::__ANON__[B/Hooks/EndOfScope.pm:26]
|  |  |  |  | # 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