From: Peter Rabbitson Date: Wed, 27 Feb 2013 10:01:12 +0000 (+0100) Subject: MOAR optimization - tracking is_new_res is double work X-Git-Tag: v0.08242~13 X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=aa1d8a87;p=dbsrgits%2FDBIx-Class.git MOAR optimization - tracking is_new_res is double work We can get the root node assembler to do that for us instead Also remove more of the superfluous ||= assignments --- diff --git a/lib/DBIx/Class/ResultSource/RowParser/Util.pm b/lib/DBIx/Class/ResultSource/RowParser/Util.pm index 22b4150..e89d723 100644 --- a/lib/DBIx/Class/ResultSource/RowParser/Util.pm +++ b/lib/DBIx/Class/ResultSource/RowParser/Util.pm @@ -146,7 +146,7 @@ sub assemble_collapsing_parser { my ($data_assemblers, $stats) = __visit_infmap_collapse ($args); my @idcol_args = $args->{hri_style} ? ('', '') : ( - '%cur_row_ids, ', # only declare the variable if we'll use it + ', %cur_row_ids', # only declare the variable if we'll use it sprintf( <<'EOS', join ', ', sort { $a <=> $b } keys %{ $stats->{idcols_seen} } ), $cur_row_ids{$_} = defined($cur_row_data->[$_]) ? $cur_row_data->[$_] : "\0NULL\xFF$rows_pos\xFF$_\0" @@ -156,7 +156,9 @@ EOS my $parser_src = sprintf (<<'EOS', @idcol_args, $top_node_key_assembler||'', $top_node_key, join( "\n", @{$data_assemblers||[]} ) ); ### BEGIN LITERAL STRING EVAL - my ($rows_pos, $result_pos, $cur_row_data,%1$s @collapse_idx, $is_new_res) = (0,0); + my $rows_pos = 0; + my ($result_pos, @collapse_idx, $cur_row_data %1$s); + # this loop is a bit arcane - the rationale is that the passed in # $_[0] will either have only one row (->next) or will have all # rows already pulled in (->all and/or unordered). Given that the @@ -179,18 +181,18 @@ EOS # in the case of an underdefined root - calculate the virtual id (otherwise no code at all) %3$s - $is_new_res = ! $collapse_idx[0]%4$s and ( - $_[1] and $result_pos and (unshift @{$_[2]}, $cur_row_data) and last - ); + # if we were supplied a coderef - we are collapsing lazily (the set + # is ordered properly) + # as long as we have a result already and the next result is new we + # return the pre-read data and bail + $_[1] and $result_pos and ! $collapse_idx[0]%4$s and (unshift @{$_[2]}, $cur_row_data) and last; # the rel assemblers %5$s - $_[0][$result_pos++] = $collapse_idx[0]%4$s - if $is_new_res; } - splice @{$_[0]}, $result_pos; # truncate the passed in array for cases of collapsing ->all() + $#{$_[0]} = $result_pos - 1; # truncate the passed in array to where we filled it with results ### END LITERAL STRING EVAL EOS @@ -241,10 +243,10 @@ sub __visit_infmap_collapse { my @src; if ($cur_node_idx == 0) { - push @src, sprintf( '%s ||= %s;', + push @src, sprintf( '%s ||= $_[0][$result_pos++] = %s;', $node_idx_slot, - $me_struct, - ) if $me_struct; + $me_struct || '{}', + ); } else { my $parent_attach_slot = sprintf( '$collapse_idx[%d]%s%s{%s}', @@ -257,7 +259,7 @@ sub __visit_infmap_collapse { push @src, sprintf ( '%s ||= %s%s;', $parent_attach_slot, $node_idx_slot, - $me_struct ? " ||= $me_struct" : '', + $me_struct ? " = $me_struct" : '', ); } else { diff --git a/t/prefetch/manual.t b/t/prefetch/manual.t index 7ce13a7..222fe35 100644 --- a/t/prefetch/manual.t +++ b/t/prefetch/manual.t @@ -312,12 +312,29 @@ $schema->storage->debug($orig_debug); is ($queries, 2, "Only two queries for rwo prefetch calls total"); # can't cmp_deeply a random set - need *some* order -my @hris = sort { $a->{year} cmp $b->{year} } @{$rs->search({}, { +my $ord_rs = $rs->search({}, { order_by => [ 'tracks_2.title', 'tracks.title', 'cds.cdid', \ 'RANDOM()' ], -})->all_hri}; -is (@hris, 6, 'hri count matches' ); + result_class => 'DBIx::Class::ResultClass::HashRefInflator', +}); +my @hris_all = sort { $a->{year} cmp $b->{year} } $ord_rs->all; +is (@hris_all, 6, 'hri count matches' ); + +my $iter_rs = $rs->search({}, { + order_by => [ 'me.year', 'me.cdid', 'tracks_2.title', 'tracks.title', 'cds.cdid', \ 'RANDOM()' ], + result_class => 'DBIx::Class::ResultClass::HashRefInflator', +}); +my @hris_iter; +while (my $r = $iter_rs->next) { + push @hris_iter, $r; +} + +cmp_deeply( + \@hris_iter, + \@hris_all, + 'Iteration works correctly', +); -cmp_deeply (\@hris, [ +cmp_deeply (\@hris_all, [ { single_track => undef, tracks => [ @@ -464,4 +481,46 @@ cmp_deeply (\@hris, [ }, ], 'W00T, multi-has_many manual underdefined root prefetch with collapse works'); +$rs = $rs->search({}, { order_by => [ 'me.year', 'me.cdid', \ 'RANDOM()' ] }); +my @objs_iter; +while (my $r = $rs->next) { + push @objs_iter, $r; +} + +for my $i (0 .. $#objs_iter) { + is ($objs_iter[$i]->year, $hris_all[$i]{year}, "Expected year on object $i" ); + is ( + (defined $objs_iter[$i]->single_track), + (defined $hris_all[$i]{single_track}), + "Expected single relation on object $i" + ); +} + +$rs = $schema->resultset('Artist')->search({}, { + join => 'cds', + columns => ['cds.title', 'cds.artist' ], + collapse => 1, + order_by => [qw( me.name cds.title )], +}); + +$rs->create({ name => "${_}_cdless" }) + for (qw( Z A )); + +cmp_deeply ( + $rs->all_hri, + [ + { cds => [] }, + { cds => [ + { artist => 1, title => "Equinoxe" }, + { artist => 1, title => "Magnetic Fields" }, + { artist => 1, title => "Oxygene" }, + { artist => 1, title => "fuzzy_1" }, + { artist => 1, title => "fuzzy_2" }, + { artist => 1, title => "fuzzy_3" }, + ] }, + { cds => [] }, + ], + 'Expected HRI of 1:M with empty root selection', +); + done_testing; diff --git a/t/resultset/inflate_result_api.t b/t/resultset/inflate_result_api.t index a6914d9..db7c874 100644 --- a/t/resultset/inflate_result_api.t +++ b/t/resultset/inflate_result_api.t @@ -419,6 +419,43 @@ cmp_structures ( 'Non-Collapsing chained has_many' ); +$schema->resultset('Artist')->create({ name => "${_}_cdless" }) + for (qw( Z A )); + +cmp_structures ( + [$schema->resultset ('Artist')->search ({}, { + result_class => 'DBICTest::_IRCapture', + collapse => 1, + join => 'cds', + columns => [qw( cds.title cds.artist )], + order_by => [qw( me.name cds.title )], + })->all], + [ + [ + undef, + { cds => bless( [ + [ { artist => undef, title => undef } ] + ], 'DBIx::ResultParser::RelatedNullBranch' ) }, + ], + [ + undef, + { cds => [ + [ { artist => 1, title => "Equinoxe" } ], + [ { artist => 1, title => "Magnetic Fields" } ], + [ { artist => 1, title => "Oxygene" } ], + [ { artist => 1, title => "fuzzy_1" } ], + ] } + ], + [ + undef, + { cds => bless( [ + [ { artist => undef, title => undef } ] + ], 'DBIx::ResultParser::RelatedNullBranch' ) }, + ], + ], + 'Expected output of collapsing 1:M with empty root selection', +); + sub cmp_structures { my ($left, $right, $msg) = @_; diff --git a/t/resultset/rowparser_internals.t b/t/resultset/rowparser_internals.t index ebeb150..c7d8ac8 100644 --- a/t/resultset/rowparser_internals.t +++ b/t/resultset/rowparser_internals.t @@ -210,7 +210,8 @@ is_same_src ( inflate_map => $infmap, collapse => 1, }), - ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0); + ' my $rows_pos = 0; + my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids); while ($cur_row_data = ( ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } ) @@ -222,21 +223,20 @@ is_same_src ( for (0, 1, 3, 4, 5); # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2] - $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last - if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} ); + $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} and (unshift @{$_[2]}, $cur_row_data) and last; # the rowdata itself for root node - $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }]; + $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} ||= $_[0][$result_pos++] = [{ artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }]; # prefetch data of single_track (placed in root) - $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track} ||= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= []; + $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track} ||= $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = []; defined($cur_row_data->[1]) or bless( $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{single_track}, __NBC__ ); # prefetch data of cd (placed in single_track) - $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= []; + $collapse_idx[1]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = []; # prefetch data of artist ( placed in single_track->cd) - $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} ||= [{ artistid => $cur_row_data->[1] }]; + $collapse_idx[2]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}}{$cur_row_ids{4}}{$cur_row_ids{5}} = [{ artistid => $cur_row_data->[1] }]; # prefetch data of cds (if available) (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}} ) @@ -254,10 +254,8 @@ is_same_src ( ); defined($cur_row_data->[0]) or bless( $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{3}}{$cur_row_ids{4}}{$cur_row_ids{5}}[1]{tracks}, __NBC__ ); - $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{4}}{$cur_row_ids{5}} - if $is_new_res; } - splice @{$_[0]}, $result_pos; + $#{$_[0]} = $result_pos - 1; ', 'Same 1:1 descending terminating with chained 1:M:M but with collapse', ); @@ -268,7 +266,8 @@ is_same_src ( collapse => 1, hri_style => 1, }), - ' my($rows_pos, $result_pos, $cur_row_data, @collapse_idx, $is_new_res) = (0, 0); + ' my $rows_pos = 0; + my ($result_pos, @collapse_idx, $cur_row_data); while ($cur_row_data = ( ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } ) @@ -277,11 +276,10 @@ is_same_src ( ) { # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2] - $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last - if ( $is_new_res = ! $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]} ); + $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]} and (unshift @{$_[2]}, $cur_row_data) and last; # the rowdata itself for root node - $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]} ||= { artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }; + $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]} ||= $_[0][$result_pos++] = { artist => $cur_row_data->[5], title => $cur_row_data->[4], year => $cur_row_data->[2] }; # prefetch data of single_track (placed in root) (! defined($cur_row_data->[1]) ) ? $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]}{single_track} = undef : do { @@ -291,7 +289,7 @@ is_same_src ( $collapse_idx[1]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]}{cd} ||= $collapse_idx[2]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]}; # prefetch data of artist ( placed in single_track->cd) - $collapse_idx[2]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]}{artist} ||= $collapse_idx[3]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]} ||= { artistid => $cur_row_data->[1] }; + $collapse_idx[2]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]}{artist} ||= $collapse_idx[3]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]} = { artistid => $cur_row_data->[1] }; # prefetch data of cds (if available) (! defined $cur_row_data->[3] ) ? $collapse_idx[3]{$cur_row_data->[1]}{$cur_row_data->[4]}{$cur_row_data->[5]}{cds} = [] : do { @@ -313,11 +311,8 @@ is_same_src ( }; }; }; - - $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_data->[4]}{$cur_row_data->[5]} - if $is_new_res; } - splice @{$_[0]}, $result_pos; + $#{$_[0]} = $result_pos - 1; ', 'Same 1:1 descending terminating with chained 1:M:M but with collapse, HRI-direct', ); @@ -388,7 +383,8 @@ is_same_src ( inflate_map => $infmap, collapse => 1, }), - ' my ($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0,0); + ' my $rows_pos = 0; + my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids); while ($cur_row_data = ( ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } ) @@ -400,14 +396,13 @@ is_same_src ( for (0, 1, 5, 6, 8, 10); # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2] - $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last - if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{1}} ); + $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last; - $collapse_idx[0]{$cur_row_ids{1}} ||= [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }]; + $collapse_idx[0]{$cur_row_ids{1}} ||= $_[0][$result_pos++] = [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }]; - $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} ||= $collapse_idx[1]{$cur_row_ids{1}} ||= []; - $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}} ||= []; - $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}} ||= [{ artistid => $cur_row_data->[1] }]; + $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} ||= $collapse_idx[1]{$cur_row_ids{1}} = []; + $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}} = []; + $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }]; (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} ) and @@ -430,7 +425,7 @@ is_same_src ( ); defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ ); - $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} ||= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} ||= []; + $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} ||= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = []; defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ ); (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} ) @@ -438,12 +433,9 @@ is_same_src ( push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, ( $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }] ); - - $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{1}} - if $is_new_res; } - splice @{$_[0]}, $result_pos; + $#{$_[0]} = $result_pos - 1; ', 'Multiple has_many on multiple branches torture test', ); @@ -453,7 +445,8 @@ is_same_src ( inflate_map => $infmap, collapse => 1, }), - ' my ($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0,0); + ' my $rows_pos = 0; + my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids); while ($cur_row_data = ( ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } ) @@ -465,14 +458,13 @@ is_same_src ( for (0, 1, 5, 6, 8, 10); # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2] - $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last - if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{1}} ); + $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{1}} and (unshift @{$_[2]}, $cur_row_data) and last; - $collapse_idx[0]{$cur_row_ids{1}} ||= [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }]; + $collapse_idx[0]{$cur_row_ids{1}} ||= $_[0][$result_pos++] = [{ genreid => $cur_row_data->[4], latest_cd => $cur_row_data->[7], year => $cur_row_data->[3] }]; - $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} ||= $collapse_idx[1]{$cur_row_ids{1}} ||= []; - $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}} ||= []; - $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}} ||= [{ artistid => $cur_row_data->[1] }]; + $collapse_idx[0]{$cur_row_ids{1}}[1]{existing_single_track} ||= $collapse_idx[1]{$cur_row_ids{1}} = []; + $collapse_idx[1]{$cur_row_ids{1}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{1}} = []; + $collapse_idx[2]{$cur_row_ids{1}}[1]{artist} ||= $collapse_idx[3]{$cur_row_ids{1}} = [{ artistid => $cur_row_data->[1] }]; (! $collapse_idx[4]{$cur_row_ids{1}}{$cur_row_ids{6}} ) and @@ -495,7 +487,7 @@ is_same_src ( ); defined($cur_row_data->[5]) or bless( $collapse_idx[0]{$cur_row_ids{1}}[1]{tracks}, __NBC__ ); - $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} ||= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} ||= []; + $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics} ||= $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = []; defined($cur_row_data->[10]) or bless( $collapse_idx[6]{$cur_row_ids{1}}{$cur_row_ids{5}}[1]{lyrics}, __NBC__ ); (! $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} ) @@ -503,12 +495,9 @@ is_same_src ( push @{ $collapse_idx[7]{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}}[1]{existing_lyric_versions} }, ( $collapse_idx[8]{$cur_row_ids{0}}{$cur_row_ids{1}}{$cur_row_ids{5}}{$cur_row_ids{10}} = [{ lyric_id => $cur_row_data->[10], text => $cur_row_data->[0] }] ); - - $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{1}} - if $is_new_res; } - splice @{$_[0]}, $result_pos; + $#{$_[0]} = $result_pos - 1; ', 'Multiple has_many on multiple branches with branch torture test', ); @@ -566,7 +555,8 @@ is_same_src ( inflate_map => $infmap, collapse => 1, }), - ' my($rows_pos, $result_pos, $cur_row_data, %cur_row_ids, @collapse_idx, $is_new_res) = (0, 0); + ' my $rows_pos = 0; + my ($result_pos, @collapse_idx, $cur_row_data, %cur_row_ids); while ($cur_row_data = ( ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } ) @@ -587,17 +577,16 @@ is_same_src ( ); # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2] - $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last - if ( $is_new_res = ! $collapse_idx[0]{$cur_row_ids{10}} ); + $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_ids{10}} and (unshift @{$_[2]}, $cur_row_data) and last; - $collapse_idx[0]{$cur_row_ids{10}} ||= [{ year => $$cur_row_data[1] }]; + $collapse_idx[0]{$cur_row_ids{10}} ||= $_[0][$result_pos++] = [{ year => $$cur_row_data[1] }]; - $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} ||= ($collapse_idx[1]{$cur_row_ids{0}} ||= [{ trackid => $cur_row_data->[0] }]); + $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track} ||= ($collapse_idx[1]{$cur_row_ids{0}} = [{ trackid => $cur_row_data->[0] }]); defined($cur_row_data->[0]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{single_track}, __NBC__ ); - $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{0}} ||= []; + $collapse_idx[1]{$cur_row_ids{0}}[1]{cd} ||= $collapse_idx[2]{$cur_row_ids{0}} = []; - $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} ||= ($collapse_idx[3]{$cur_row_ids{0}} ||= [{ artistid => $cur_row_data->[6] }]); + $collapse_idx[2]{$cur_row_ids{0}}[1]{artist} ||= ($collapse_idx[3]{$cur_row_ids{0}} = [{ artistid => $cur_row_data->[6] }]); (! $collapse_idx[4]{$cur_row_ids{0}}{$cur_row_ids{4}} ) and @@ -619,12 +608,9 @@ is_same_src ( $collapse_idx[6]{$cur_row_ids{2}}{$cur_row_ids{3}} = [{ cd => $$cur_row_data[2], title => $cur_row_data->[3] }] ); defined($cur_row_data->[2]) or bless ( $collapse_idx[0]{$cur_row_ids{10}}[1]{tracks}, __NBC__ ); - - $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_ids{10}} - if $is_new_res; } - splice @{$_[0]}, $result_pos; + $#{$_[0]} = $result_pos - 1; ', 'Multiple has_many on multiple branches with underdefined root torture test', ); @@ -635,7 +621,8 @@ is_same_src ( collapse => 1, hri_style => 1, }), - ' my($rows_pos, $result_pos, $cur_row_data, @collapse_idx, $is_new_res) = (0, 0); + ' my $rows_pos = 0; + my ($result_pos, @collapse_idx, $cur_row_data); while ($cur_row_data = ( ( $rows_pos >= 0 and $_[0][$rows_pos++] ) or do { $rows_pos = -1; undef } ) @@ -653,18 +640,17 @@ is_same_src ( ); # a present cref in $_[1] implies lazy prefetch, implies a supplied stash in $_[2] - $_[1] and $result_pos and unshift(@{$_[2]}, $cur_row_data) and last - if ( $is_new_res = ! $collapse_idx[0]{$cur_row_data->[10]} ); + $_[1] and $result_pos and ! $collapse_idx[0]{$cur_row_data->[10]} and (unshift @{$_[2]}, $cur_row_data) and last; - $collapse_idx[0]{$cur_row_data->[10]} ||= { year => $$cur_row_data[1] }; + $collapse_idx[0]{$cur_row_data->[10]} ||= $_[0][$result_pos++] = { year => $$cur_row_data[1] }; (! defined $cur_row_data->[0] ) ? $collapse_idx[0]{$cur_row_data->[10]}{single_track} = undef : do { - $collapse_idx[0]{$cur_row_data->[10]}{single_track} ||= ($collapse_idx[1]{$cur_row_data->[0]} ||= { trackid => $$cur_row_data[0] }); + $collapse_idx[0]{$cur_row_data->[10]}{single_track} ||= ($collapse_idx[1]{$cur_row_data->[0]} = { trackid => $$cur_row_data[0] }); $collapse_idx[1]{$cur_row_data->[0]}{cd} ||= $collapse_idx[2]{$cur_row_data->[0]}; - $collapse_idx[2]{$cur_row_data->[0]}{artist} ||= ($collapse_idx[3]{$cur_row_data->[0]} ||= { artistid => $$cur_row_data[6] }); + $collapse_idx[2]{$cur_row_data->[0]}{artist} ||= ($collapse_idx[3]{$cur_row_data->[0]} = { artistid => $$cur_row_data[6] }); (! defined $cur_row_data->[4] ) ? $collapse_idx[3]{$cur_row_data->[0]}{cds} = [] : do { @@ -692,12 +678,9 @@ is_same_src ( $collapse_idx[6]{$cur_row_data->[2]}{$cur_row_data->[3]} = { cd => $$cur_row_data[2], title => $$cur_row_data[3] } ); }; - - $_[0][$result_pos++] = $collapse_idx[0]{$cur_row_data->[10]} - if $is_new_res; } - splice @{$_[0]}, $result_pos; + $#{$_[0]} = $result_pos - 1; ', 'Multiple has_many on multiple branches with underdefined root, HRI-direct torture test', );