X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2FID3FS%2FPath%2FNode.pm;h=3171dd4c87defd43c5103f06f417c5a2593ff6e3;hb=516b8d78e15c360c27b7043bb4a6690577f91f3c;hp=774af3afd301323e4ff96bd7d2985bdd9716adbe;hpb=9ae98c5aa5a031e834dbc2a4dbd7e009a88b3394;p=id3fs.git diff --git a/lib/ID3FS/Path/Node.pm b/lib/ID3FS/Path/Node.pm index 774af3a..3171dd4 100644 --- a/lib/ID3FS/Path/Node.pm +++ b/lib/ID3FS/Path/Node.pm @@ -82,7 +82,7 @@ sub to_sql $str .= "t" . scalar(@joins) . ".id='" . $self->{id} . "'"; if($not && !$hasvals) { - $str .= " AND fxt" . scalar(@joins) . ".files_id IS NULL"; + $str = "(" . $str . " AND fxt" . scalar(@joins) . ".files_id IS NULL)"; } return ($str, @outjoins); } @@ -90,73 +90,48 @@ sub to_sql my $left=$self->left(); my $right=$self->right(); return ("", @outjoins) unless($left || $right); + my ($leftstr, @leftjoins) = $left->to_sql($hasvals, $not, @joins) if($left); push(@joins, @leftjoins); push(@outjoins, @leftjoins); + my $op=$self->name(); - print "op: $op type: ", $self->type(), " not: $not\n"; if(defined($op)) { - # if we are ANDing, add an inner join + my $join=undef; + # if we are ANDing add an inner join # also if we are NOTing, but we are looking for a tag *value* if($op eq "AND") { - print "AND\n"; - # hack - if right child is a NOT, we don't need extra join/brackets + # if right child is a NOT, we don't need extra join/brackets # NOT will do the same and we will end up with an extra one - unless($right && $right->name() && $right->name() eq "NOT") - { - push(@joins, "INNER"); - push(@outjoins, "INNER"); - } + $join= "INNER" unless($right && $right->name() && $right->name() eq "NOT"); } elsif($op eq "NOT") { - print "NOT (was $not)\n"; $not=1; - # as above - if right child is a NOT, we don't need extra join/brackets - # NOT will do the same and we will end up with an extra one - unless($right && $right->name() && $right->name() eq "NOT") - { - if($hasvals) - { - push(@joins, "INNER"); - push(@outjoins, "INNER"); - } - else - { - push(@joins, "LEFT"); - push(@outjoins, "LEFT"); - } - } + $join = ($hasvals ? "INNER" : "LEFT"); } elsif($op eq "OR") { - print "OR\n"; - # if left child is a NOT, we need an extra (inner) join - # unless right child is also a NOT - if(($left && $left->name() && $left->name() eq "NOT") && - !($right && $right->name() && $right->name() eq "NOT")) - { - push(@joins, "INNER"); - push(@outjoins, "INNER"); - } + # if the rightmost part of the left sub-expression ends in + # NOT, then we need an extra join. This doesn't apply if + # (as above) the righthand expression is a NOT. + $join="INNER" if(($self->right_ends_in_not($left)) && + !($right && $right->name() && $right->name() eq "NOT")); + } + if($join) + { + push(@joins, $join); + push(@outjoins, $join); } } my ($rightstr, @rightjoins) = $right->to_sql($hasvals, $not, @joins) if($right); push(@outjoins, @rightjoins); -# print "LEFT (", scalar(@leftjoins), "): $leftstr\n"; -# print "RIGHT (", scalar(@rightjoins), "): $rightstr\n"; - $str=$leftstr; + $str = $leftstr; $str .= " $op " if($op && !$not); $str .= $rightstr; - if($op || ($left && $right)) - { - $str="(" . $str . ")"; - } -# print "STR: $str\n"; -# my @all=(@joins, @rightjoins); -# print "JOINS: RETURN ", scalar(@outjoins), " ALL ", scalar(@all), "\n"; + $str=("(" . $str . ")") if($op && $left && $right); return($str, @outjoins); } @@ -173,4 +148,19 @@ sub used_tags return $self->id(); } +sub right_ends_in_not +{ + my($self, $node)=@_; + return 0 unless($node); + my $right=$node->right(); + if($right && $right->type() == $TYPE_BOOL) + { + return $self->right_ends_in_not($right); + } + my $op=$node->name(); + return 0 unless($op); + return 1 if($op eq "NOT"); + return 0; +} + 1;