From: Peter Rabbitson Date: Tue, 14 Jul 2009 12:07:11 +0000 (+0000) Subject: grouped prefetch fix X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=dace98195a6ec580bfa0acf1f673ccbbbf8f6ce3;p=dbsrgits%2FDBIx-Class-Historic.git grouped prefetch fix --- diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index 6f66848..1d1e57b 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -1480,7 +1480,7 @@ sub _adjust_select_args_for_complex_prefetch { my $alias = $attrs->{alias}; my $sql_maker = $self->sql_maker; - # create subquery select list - loop only over primary columns + # create subquery select list - consider only stuff *not* brought in by the prefetch my $sub_select = []; for my $i (0 .. @{$attrs->{select}} - @{$attrs->{prefetch_select}} - 1) { my $sel = $attrs->{select}[$i]; @@ -1489,7 +1489,7 @@ sub _adjust_select_args_for_complex_prefetch { # adjust the outer select accordingly if (ref $sel eq 'HASH' && !$sel->{-select}) { $sel = { -select => $sel, -as => $attrs->{as}[$i] }; - $select->[$i] = join ('.', $attrs->{alias}, $attrs->{as}[$i]); + $select->[$i] = join ('.', $attrs->{alias}, ($attrs->{as}[$i] || "select_$i") ); } push @$sub_select, $sel; @@ -1547,6 +1547,8 @@ sub _adjust_select_args_for_complex_prefetch { { # produce stuff unquoted, so it can be scanned local $sql_maker->{quote_char}; + my $sep = $self->_sql_maker_opts->{name_sep} || '.'; + $sep = "\Q$sep\E"; my @order_by = (map { ref $_ ? $_->[0] : $_ } @@ -1554,6 +1556,7 @@ sub _adjust_select_args_for_complex_prefetch { ); my $where_sql = $sql_maker->where ($where); + my $select_sql = $sql_maker->_recurse_fields ($sub_select); # sort needed joins for my $alias (keys %join_info) { @@ -1561,8 +1564,8 @@ sub _adjust_select_args_for_complex_prefetch { # any table alias found on a column name in where or order_by # gets included in %inner_joins # Also any parent joins that are needed to reach this particular alias - for my $piece ($where_sql, @order_by ) { - if ($piece =~ /\b$alias\./) { + for my $piece ($select_sql, $where_sql, @order_by ) { + if ($piece =~ /\b $alias $sep/x) { $inner_joins{$alias} = 1; } } diff --git a/t/prefetch/grouped.t b/t/prefetch/grouped.t index 3db5f9e..19fa923 100644 --- a/t/prefetch/grouped.t +++ b/t/prefetch/grouped.t @@ -28,7 +28,6 @@ for ($cd_rs->all) { my $track_rs = $schema->resultset ('Track')->search ( { 'me.cd' => { -in => [ $cd_rs->get_column ('cdid')->all ] } }, { - # the select/as is deliberately silly to test both funcs and refs below select => [ 'me.cd', { count => 'me.trackid' }, @@ -67,8 +66,6 @@ for ($cd_rs->all) { # Test sql by hand, as the sqlite db will simply paper over # improper group/select combinations # - # the exploded IN needs fixing below, coming in another branch - # is_same_sql_bind ( $track_rs->count_rs->as_query, '( @@ -131,14 +128,19 @@ for ($cd_rs->all) { # test a has_many/might_have prefetch at the same level # Note that one of the CDs now has 4 tracks instead of 3 { - my $most_tracks_rs = $cd_rs->search ({}, { - prefetch => 'liner_notes', # tracks are alredy prefetched - select => ['me.cdid', { count => 'tracks.trackid' } ], - as => [qw/cdid track_count/], - group_by => 'me.cdid', - order_by => { -desc => 'track_count' }, - rows => 2, - }); + my $most_tracks_rs = $schema->resultset ('CD')->search ( + { + 'me.cdid' => { '!=' => undef }, # duh - this is just to test WHERE + }, + { + prefetch => [qw/tracks liner_notes/], + select => ['me.cdid', { count => 'tracks.trackid' } ], + as => [qw/cdid track_count/], + group_by => 'me.cdid', + order_by => { -desc => 'track_count' }, + rows => 2, + } + ); is_same_sql_bind ( $most_tracks_rs->count_rs->as_query, @@ -149,7 +151,7 @@ for ($cd_rs->all) { FROM cd me LEFT JOIN track tracks ON tracks.cd = me.cdid LEFT JOIN liner_notes liner_notes ON liner_notes.liner_id = me.cdid - WHERE ( tracks.cd IS NOT NULL ) + WHERE ( me.cdid IS NOT NULL ) GROUP BY me.cdid LIMIT 2 ) count_subq @@ -166,14 +168,14 @@ for ($cd_rs->all) { SELECT me.cdid, COUNT( tracks.trackid ) AS track_count FROM cd me LEFT JOIN track tracks ON tracks.cd = me.cdid - WHERE ( tracks.cd IS NOT NULL ) + WHERE ( me.cdid IS NOT NULL ) GROUP BY me.cdid ORDER BY track_count DESC LIMIT 2 ) me LEFT JOIN track tracks ON tracks.cd = me.cdid LEFT JOIN liner_notes liner_notes ON liner_notes.liner_id = me.cdid - WHERE ( tracks.cd IS NOT NULL ) + WHERE ( me.cdid IS NOT NULL ) ORDER BY track_count DESC, tracks.cd )', [],