From: Ian Beckwith Date: Wed, 20 Oct 2010 21:26:25 +0000 (+0100) Subject: more special-casing joins X-Git-Tag: debian/1.0-1~13 X-Git-Url: http://erislabs.net/gitweb/?p=id3fs.git;a=commitdiff_plain;h=516b8d78e15c360c27b7043bb4a6690577f91f3c more special-casing joins --- diff --git a/lib/ID3FS/Path/Node.pm b/lib/ID3FS/Path/Node.pm index b71406d..3171dd4 100644 --- a/lib/ID3FS/Path/Node.pm +++ b/lib/ID3FS/Path/Node.pm @@ -99,25 +99,26 @@ sub to_sql if(defined($op)) { my $join=undef; - # 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 we are ANDing add an inner join + # also if we are NOTing, but we are looking for a tag *value* + if($op eq "AND") { - # if we are ANDing or ORing, add an inner join - # also if we are NOTing, but we are looking for a tag *value* - if($op eq "AND") - { - $join= "INNER"; - } - elsif($op eq "NOT") - { - $not=1; - $join = ($hasvals ? "INNER" : "LEFT"); - } - elsif($op eq "OR") - { - $join="INNER" unless($left && $left->name() && $left->name() eq "NOT") - } + # 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 + $join= "INNER" unless($right && $right->name() && $right->name() eq "NOT"); + } + elsif($op eq "NOT") + { + $not=1; + $join = ($hasvals ? "INNER" : "LEFT"); + } + elsif($op eq "OR") + { + # 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) { @@ -147,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;