#
# 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}}
);
}
# construct the inner $from for the subquery
+ # we need to prune first, because this will determine if we need a group_bu 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
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;
}
}