X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=blobdiff_plain;f=lib%2FDBIx%2FClass%2FStorage%2FDBIHacks.pm;h=4b66c4ebf65c80fae8414dde5c40a4e601bc89f1;hb=4d07e1ea9a5cec959c3dd3b13e880aa641342522;hp=f549204cea514652f1e6ae43fd635ac9417fdd9d;hpb=539ffe8768e85b2061aa3bb3616da4f848a582f3;p=dbsrgits%2FDBIx-Class.git diff --git a/lib/DBIx/Class/Storage/DBIHacks.pm b/lib/DBIx/Class/Storage/DBIHacks.pm index f549204..4b66c4e 100644 --- a/lib/DBIx/Class/Storage/DBIHacks.pm +++ b/lib/DBIx/Class/Storage/DBIHacks.pm @@ -17,24 +17,30 @@ use Carp::Clan qw/^DBIx::Class/; # # This code will remove non-selecting/non-restricting joins from -# {from} specs, aiding the RDBMS query optimizer. +# {from} specs, aiding the RDBMS query optimizer # sub _prune_unused_joins { - my $self = shift; + my ($self) = shift; + + my ($from, $select, $where, $attrs) = @_; - my $from = shift; if (ref $from ne 'ARRAY' || ref $from->[0] ne 'HASH' || ref $from->[1] ne 'ARRAY') { return $from; # only standard {from} specs are supported } - my $aliastypes = $self->_resolve_aliastypes_from_select_args($from, @_); + my $aliastypes = $self->_resolve_aliastypes_from_select_args(@_); + + # a grouped set will not be affected by amount of rows. Thus any + # {multiplying} joins can go + delete $aliastypes->{multiplying} if $attrs->{group_by}; + my @newfrom = $from->[0]; # FROM head is always present my %need_joins = (map { %{$_||{}} } (values %$aliastypes) ); for my $j (@{$from}[1..$#$from]) { push @newfrom, $j if ( - ! $j->[0]{-alias} # legacy crap + (! $j->[0]{-alias}) # legacy crap || $need_joins{$j->[0]{-alias}} ); @@ -43,7 +49,6 @@ sub _prune_unused_joins { return \@newfrom; } - # # This is the code producing joined subqueries like: # SELECT me.*, other.* FROM ( SELECT me.* FROM ... ) JOIN other ON ... @@ -92,6 +97,7 @@ sub _adjust_select_args_for_complex_prefetch { } # construct the inner $from for the subquery + # we need to prune first, because this will determine if we need a group_by below my $inner_from = $self->_prune_unused_joins ($from, $inner_select, $where, $inner_attrs); # if a multi-type join was needed in the subquery - add a group_by to simulate the @@ -222,10 +228,7 @@ sub _resolve_aliastypes_from_select_args { my $group_by_sql = $sql_maker->_order_by({ map { $_ => $attrs->{$_} } qw/group_by having/ }); - my @order_by_chunks = (map - { ref $_ ? $_->[0] : $_ } - $sql_maker->_order_by_chunks ($attrs->{order_by}) - ); + my @order_by_chunks = ($self->_parse_order_by ($attrs->{order_by}) ); # match every alias to the sql chunks above for my $alias (keys %$alias_list) { @@ -255,7 +258,7 @@ sub _resolve_aliastypes_from_select_args { for my $type (keys %$aliases_by_type) { for my $alias (keys %{$aliases_by_type->{$type}}) { $aliases_by_type->{$type}{$_} = 1 - for (@{ $alias_list->{$alias}{-join_path} || [] }); + for (map { keys %$_ } @{ $alias_list->{$alias}{-join_path} || [] }); } } @@ -400,7 +403,7 @@ sub _straight_join_to_node { # anyway, and deep cloning is just too fucking expensive # So replace the first hashref in the node arrayref manually my @new_from = ($from->[0]); - my $sw_idx = { map { $_ => 1 } @$switch_branch }; + my $sw_idx = { map { values %$_ => 1 } @$switch_branch }; for my $j (@{$from}[1 .. $#$from]) { my $jalias = $j->[0]{-alias}; @@ -453,13 +456,17 @@ sub _strip_cond_qualifiers { for (my $i = 0; $i < @cond; $i++) { my $entry = $cond[$i]; my $hash; - if (ref $entry eq 'HASH') { + my $ref = ref $entry; + if ($ref eq 'HASH' or $ref eq 'ARRAY') { $hash = $self->_strip_cond_qualifiers($entry); } - else { + elsif (! $ref) { $entry =~ /([^.]+)$/; $hash->{$1} = $cond[++$i]; } + else { + $self->throw_exception ("_strip_cond_qualifiers() is unable to handle a condition reftype $ref"); + } push @{$cond->{-and}}, $hash; } } @@ -477,5 +484,21 @@ sub _strip_cond_qualifiers { return $cond; } +sub _parse_order_by { + my ($self, $order_by) = @_; + + return scalar $self->sql_maker->_order_by_chunks ($order_by) + unless wantarray; + + my $sql_maker = $self->sql_maker; + local $sql_maker->{quote_char}; #disable quoting + my @chunks; + for my $chunk (map { ref $_ ? @$_ : $_ } ($sql_maker->_order_by_chunks ($order_by) ) ) { + $chunk =~ s/\s+ (?: ASC|DESC ) \s* $//ix; + push @chunks, $chunk; + } + + return @chunks; +} 1;