special-case /NOT
authorIan Beckwith <ianb@erislabs.net>
Fri, 15 Oct 2010 00:13:50 +0000 (01:13 +0100)
committerIan Beckwith <ianb@erislabs.net>
Fri, 15 Oct 2010 00:13:50 +0000 (01:13 +0100)
lib/ID3FS/Path.pm
lib/ID3FS/Path/Node.pm

index 0f3241c..39aab39 100644 (file)
@@ -132,6 +132,9 @@ sub parse
     my @parts=@{$self->{components}};
     my($tag, $tagval);
     $self->{elements}=[];
+    $self->{bare_not}=0;
+    my $root_not=0;
+    my $tags_seen=0;
     while(defined(my $name=shift @parts))
     {
 #      print "NAME: $name\n";
@@ -150,6 +153,7 @@ sub parse
            }
            elsif($name eq "NOT")
            {
+               $root_not=1;
                push(@{$self->{elements}}, ID3FS::PathElement::Boolean->new($self->{db}, $name));
                $self->state($STATE_BOOLEAN);
            }
@@ -159,6 +163,7 @@ sub parse
                if($tag)
                {
                    push(@{$self->{elements}}, $tag);
+                   $tags_seen++;
                    $self->state($STATE_TAG);
                }
                else
@@ -243,6 +248,7 @@ sub parse
                if($tag)
                {
                    push(@{$self->{elements}}, $tag);
+                   $tags_seen++;
                    $self->state($STATE_TAG);
                }
                else
@@ -326,6 +332,13 @@ sub parse
            $self->state($STATE_INVALID);
        }
     }
+
+    print "ROOT_NOT: $root_not TAGS_SEEN: $tags_seen\n";
+    if($root_not && ($tags_seen < 2))
+    {
+       $self->{bare_not}=1;
+    }
+
     # remove trailing boolean
     my @elements=@{$self->{elements}};
     while(@elements && ref($elements[$#elements]) eq "ID3FS::PathElement::Boolean")
@@ -708,6 +721,12 @@ sub filename
 sub tags_subselect
 {
     my($self)=@_;
+    # we need to specially handle a bare /NOT/tag with no other clauses,
+    # using a simple WHERE id !='tagid' instead of a LEFT JOIN
+    if($self->{bare_not})
+    {
+       return $self->bare_not_subselect();
+    }
     my $tree=$self->{tagtree};
     my $hasvals=$self->tag_has_values();
     my $parent=$self->trailing_tag_parent();
@@ -751,6 +770,27 @@ sub tags_subselect
     return $sql;
 }
 
+sub bare_not_subselect
+{
+    my($self)=@_;
+    my @tags=grep { ref($_) eq "ID3FS::PathElement::Tag"; } @{$self->{elements}};
+    my $sql=("\tSELECT f1.id AS files_id FROM files f1 WHERE f1.id NOT IN (\n" .
+            "\t\tSELECT fxt1.files_id FROM tags t1\n" .
+            "\t\tINNER JOIN files_x_tags fxt1 ON t1.id=fxt1.tags_id\n" .
+            "\t\tWHERE ");
+    if(scalar(@tags) > 1)
+    {
+       $sql .= ("(t1.parents_id='" . $tags[0]->{id} . "' AND t1.id='" .
+                $tags[1]->{id} . "')");
+    }
+    else
+    {
+       $sql .= ("(t1.parents_id='' AND t1.id='" . $tags[0]->{id} . "')");
+    }
+    $sql .= "\n\t\tGROUP BY fxt1.files_id\n\t)\n";
+    return($sql);
+}
+
 sub tags_subselect_and_not
 {
     my($self,@constraints)=@_;
index 68515e3..8ce259e 100644 (file)
@@ -85,8 +85,8 @@ sub to_sql
            $not=1;
            push(@joins, "LEFT");
            push(@outjoins, "LEFT");
-           print("LEFT: ", $left->print(), "\n") if ($left);
-           print("RIGHT: ", $right->print(), "\n") if($right);
+#          print("LEFT: ", $left->print(), "\n") if ($left);
+#          print("RIGHT: ", $right->print(), "\n") if($right);
        }
     }
     my ($rightstr, @rightjoins) = $self->node_to_sql($right, $not, @joins);