From: Peter Rabbitson Date: Sat, 5 Dec 2009 09:29:50 +0000 (+0000) Subject: Wrap mssql selects in yet another subquery to make limited right-ordered join results... X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=b8d88d9b31a7bf9b755cc8b396d5c47cb5bcf3fb;p=dbsrgits%2FDBIx-Class-Historic.git Wrap mssql selects in yet another subquery to make limited right-ordered join resultsets possible --- diff --git a/lib/DBIx/Class/Storage/DBI.pm b/lib/DBIx/Class/Storage/DBI.pm index 123ecd1..28e3465 100644 --- a/lib/DBIx/Class/Storage/DBI.pm +++ b/lib/DBIx/Class/Storage/DBI.pm @@ -1765,12 +1765,52 @@ sub _select_args { if ( ( $attrs->{rows} && keys %{$attrs->{collapse}} ) || - ( $attrs->{group_by} && @{$attrs->{group_by}} && - $attrs->{_prefetch_select} && @{$attrs->{_prefetch_select}} ) + ( $attrs->{group_by} + && + @{$attrs->{group_by}} + && + $attrs->{_prefetch_select} + && + @{$attrs->{_prefetch_select}} + ) ) { + ($ident, $select, $where, $attrs) = $self->_adjust_select_args_for_complex_prefetch ($ident, $select, $where, $attrs); } + + elsif ( + ($attrs->{rows} || $attrs->{offset}) + && + ($sql_maker->limit_dialect eq 'RowNumberOver' || $sql_maker->limit_dialect eq 'Top' ) + && + (ref $ident eq 'ARRAY' && @$ident > 1) # indicates a join + && + scalar $sql_maker->_order_by_chunks ($attrs->{order_by}) + ) { + # the two limit dialects above mangle the SQL such that the join gets lost + # wrap a subquery here + + push @limit, delete @{$attrs}{qw/rows offset/}; + + my $subq = $self->_select_args_to_query ( + $ident, + $select, + $where, + $attrs, + ); + + $ident = { + -alias => $attrs->{alias}, + -source_handle => $ident->[0]{-source_handle}, + $attrs->{alias} => $subq, + }; + + # all part of the subquery now + delete @{$attrs}{qw/order_by group_by having/}; + $where = undef; + } + elsif (! $attrs->{software_limit} ) { push @limit, $attrs->{rows}, $attrs->{offset}; } diff --git a/lib/DBIx/Class/Storage/DBI/MSSQL.pm b/lib/DBIx/Class/Storage/DBI/MSSQL.pm index 28b87f2..cddfc5e 100644 --- a/lib/DBIx/Class/Storage/DBI/MSSQL.pm +++ b/lib/DBIx/Class/Storage/DBI/MSSQL.pm @@ -185,27 +185,14 @@ sub last_insert_id { shift->_identity } sub _select_args_to_query { my $self = shift; - # _select_args does some shady action at a distance - # see DBI.pm for more info - my $sql_maker = $self->sql_maker; - my ($op, $bind, $ident, $bind_attrs, $select, $cond, $order, $rows, $offset); - { - local $sql_maker->{_dbic_rs_attrs}; - ($op, $bind, $ident, $bind_attrs, $select, $cond, $order, $rows, $offset) = $self->_select_args(@_); - } + my ($sql, $prep_bind, @rest) = $self->next::method (@_); - if ( - ($rows || $offset) - || - not scalar $sql_maker->_order_by_chunks ($order->{order_by}) - ) { - # either limited RS or no ordering, just short circuit - return $self->next::method (@_); + # see if this is an ordered subquery + my $attrs = $_[3]; + if ( scalar $self->sql_maker->_order_by_chunks ($attrs->{order_by}) ) { + $sql =~ s/^ \s* SELECT \s/SELECT TOP 100 PERCENT /xi; } - my ($sql, $prep_bind, @rest) = $self->next::method (@_); - $sql =~ s/^ \s* SELECT \s/SELECT TOP 100 PERCENT /xi; - return wantarray ? ($sql, $prep_bind, @rest) : \[ "($sql)", @$prep_bind ] diff --git a/t/746mssql.t b/t/746mssql.t index e883c22..a261791 100644 --- a/t/746mssql.t +++ b/t/746mssql.t @@ -310,8 +310,6 @@ $schema->storage->_sql_maker->{name_sep} = '.'; prefetch => 'owner', rows => 2, # 3 results total order_by => { -desc => 'owner' }, - # there is no sane way to order by the right side of a grouped prefetch currently :( - #order_by => { -desc => 'owner.name' }, }, ); @@ -334,6 +332,25 @@ $schema->storage->_sql_maker->{name_sep} = '.'; is ($books->page(2)->count_rs->next, 1, 'Prefetched grouped search returns correct count_rs'); } +# make sure right-join-side ordering limit works +{ + my $rs = $schema->resultset ('BooksInLibrary')->search ( + { + 'owner.name' => [qw/wiggle woggle/], + }, + { + join => 'owner', + order_by => { -desc => 'owner.name' }, + } + ); + + is ($rs->all, 3, 'Correct amount of objects from right-sorted joined resultset'); + my $limited_rs = $rs->search ({}, {rows => 2, offset => 2}); + is ($limited_rs->count, 1, 'Correct count of limited right-sorted joined resultset'); + is ($limited_rs->count_rs->next, 1, 'Correct count_rs of limited right-sorted joined resultset'); + is ($limited_rs->all, 1, 'Correct amount of objects from limited right-sorted joined resultset'); +} + done_testing; # clean up our mess