From: Matt S Trout Date: Fri, 1 Nov 2013 01:45:55 +0000 (+0000) Subject: rewrite GenericSubquery to handle multiple order columns X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=9c778d0f93c4a68ff4fbbee8cd8a8ffe5ef2b162;p=dbsrgits%2FData-Query.git rewrite GenericSubquery to handle multiple order columns --- diff --git a/lib/Data/Query/Renderer/SQL/Slice/GenericSubquery.pm b/lib/Data/Query/Renderer/SQL/Slice/GenericSubquery.pm index eb83c4c..5320cbb 100644 --- a/lib/Data/Query/Renderer/SQL/Slice/GenericSubquery.pm +++ b/lib/Data/Query/Renderer/SQL/Slice/GenericSubquery.pm @@ -20,25 +20,71 @@ sub _render_slice { my %remapped = $self->_subquery_remap($orig_select); my $first_from = $remapped{inner_body}; # Should we simply strip until we reach a join/alias/etc. here? - $first_from = $first_from->{from}{from} if is_Having($first_from); - $first_from = $first_from->{from} if is_Where($first_from); - while (is_Join $first_from) { - $first_from = $first_from->{left}; + STRIP: while ($first_from) { + if (is_Group($first_from)) { + $first_from = $first_from->{from}; + next STRIP; + } elsif (is_Where($first_from)) { + $first_from = $first_from->{from}; + next STRIP; + } elsif (is_Join($first_from)) { + $first_from = $first_from->{left}; + next STRIP; + } + last STRIP; } + die "WHAT" unless $first_from; $first_from = $first_from->{from} if is_Alias($first_from); - my $first_order = $remapped{inside_order}[0]{by}; - my $count_col = $first_order->{elements}[-1]; + my @main_order; + foreach my $i (0..$#{$remapped{inside_order}}) { + my $order = $remapped{inside_order}[$i]; + my $outside = $remapped{outside_order}[$i]; + if (is_Identifier($order->{by}) + and ( + (@{$order->{by}{elements}} == 2 + and $order->{by}{elements}[0] eq $remapped{default_inside_alias}) + or (@{$order->{by}{elements}} == 1)) + ) { + push @main_order, [ + $outside->{by}, $order->{by}{elements}[-1], $order->{reverse} + ]; + } else { + last; + } + } + my $count_alias = 'rownum__emulation'; + my ($op_and, $op_or) = map +{ 'SQL.Naive' => $_ }, qw(AND OR); + my $count_cond = compose { + my $lhs = $b->[0]; + my $rhs = Identifier($count_alias, $b->[1]); + ($lhs, $rhs) = ($rhs, $lhs) if $b->[2]; + my $this = Operator($op_or, [ + Operator($op_and, [ + Operator({ 'SQL.Naive' => 'IS NOT NULL' }, [ $lhs ]), + Operator({ 'SQL.Naive' => 'IS NULL' }, [ $rhs ]), + ]), + Operator({ 'SQL.Naive' => '>' }, [ $lhs, $rhs ]), + ]); + ($a + ? Operator($op_or, [ + $this, + Operator($op_and, [ + Operator($op_or, [ + Operator($op_and, [ + map Operator({ 'SQL.Naive' => 'IS NULL' }, [ $_ ]), $lhs, $rhs + ]), + Operator({ 'SQL.Naive' => '=' }, [ $lhs, $rhs ]) + ]), + $a + ]) + ]) + : $this) + } @main_order, undef; my $count_sel = Select( [ Operator({ 'SQL.Naive' => 'apply' }, [ Identifier('COUNT'), Identifier('*') ]) ], Where( - Operator( - { 'SQL.Naive' => ($remapped{inside_order}[0]{reverse} ? '>' : '<') }, - [ - Identifier($count_alias, $count_col), - $remapped{outside_order}[0]{by} - ] - ), + $count_cond, Alias($count_alias, $first_from) ) );