← Back to team overview

launchpad-reviewers team mailing list archive

[Merge] lp:~lifeless/launchpad/bug-705224 into lp:launchpad

 

Robert Collins has proposed merging lp:~lifeless/launchpad/bug-705224 into lp:launchpad.

Requested reviews:
  Launchpad code reviewers (launchpad-reviewers)
Related bugs:
  #705224 Distribution:EntryResource:searchTasks timeout
  https://bugs.launchpad.net/bugs/705224

For more details, see:
https://code.launchpad.net/~lifeless/launchpad/bug-705224/+merge/46873

Our bug search is UNIONing tag lookups together, but this performs poorly - the planner does separate traversals in the inner loop rather than combining the constraints; this changes the UNION into a simpler IN.
-- 
https://code.launchpad.net/~lifeless/launchpad/bug-705224/+merge/46873
Your team Launchpad code reviewers is requested to review the proposed merge of lp:~lifeless/launchpad/bug-705224 into lp:launchpad.
=== modified file 'lib/lp/bugs/model/bugtask.py'
--- lib/lp/bugs/model/bugtask.py	2011-01-14 21:20:46 +0000
+++ lib/lp/bugs/model/bugtask.py	2011-01-20 04:56:15 +0000
@@ -1401,6 +1401,7 @@
     :param tags: An iterable of valid tag names (not prefixed minus
         signs, not wildcards).
     """
+    tags = list(tags)
     if tags == []:
         return None
 
@@ -1411,6 +1412,20 @@
         for tag in sorted(tags))
 
 
+def _build_tag_set_query_any(tags):
+    """Return a query fragment for bugs matching any tag.
+
+    :param tags: An iterable of valid tags without - or + and not wildcards.
+    :return: A string SQL query fragment or None if no tags were provided.
+    """
+    tags = list(tags)
+    if tags == []:
+        return None
+    return ("EXISTS (SELECT TRUE FROM BugTag WHERE "
+        "BugTag.bug = Bug.id AND BugTag.tag IN %s)" 
+        % sqlvalues(sorted(tags)))
+
+
 def build_tag_search_clause(tags_spec):
     """Return a tag search clause.
 
@@ -1438,14 +1453,14 @@
         include_clause = build_tag_set_query("INTERSECT", include)
         # The set of bugs that have *any* of the tags requested for
         # *exclusion*.
-        exclude_clause = build_tag_set_query("UNION", exclude)
+        exclude_clause = _build_tag_set_query_any(exclude)
     else:
         # How to combine an include clause and an exclude clause when
         # both are generated.
         combine_with = 'OR'
         # The set of bugs that have *any* of the tags requested for
         # inclusion.
-        include_clause = build_tag_set_query("UNION", include)
+        include_clause = _build_tag_set_query_any(include)
         # The set of bugs that have *all* of the tags requested for
         # exclusion.
         exclude_clause = build_tag_set_query("INTERSECT", exclude)

=== modified file 'lib/lp/bugs/model/tests/test_bugtask.py'
--- lib/lp/bugs/model/tests/test_bugtask.py	2011-01-14 12:05:24 +0000
+++ lib/lp/bugs/model/tests/test_bugtask.py	2011-01-20 04:56:15 +0000
@@ -211,26 +211,33 @@
         self.assertEqual(self.searchClause(any()), None)
         self.assertEqual(self.searchClause(all()), None)
 
-    def test_single_tag_presence(self):
+    def test_single_tag_presence_any(self):
         # The WHERE clause to test for the presence of a single
-        # tag. Should be the same for an `any` query or an `all`
-        # query.
+        # tag where at least one tag is desired.
         expected_query = (
             """EXISTS
                  (SELECT TRUE FROM BugTag
                    WHERE BugTag.bug = Bug.id
-                     AND BugTag.tag = 'fred')""")
+                     AND BugTag.tag IN ('fred'))""")
         self.assertEqualIgnoringWhitespace(
             expected_query,
             self.searchClause(any(u'fred')))
+
+    def test_single_tag_presence_all(self):
+        # The WHERE clause to test for the presence of a single
+        # tag where all tags are desired.
+        expected_query = (
+            """EXISTS
+                 (SELECT TRUE FROM BugTag
+                   WHERE BugTag.bug = Bug.id
+                     AND BugTag.tag = 'fred')""")
         self.assertEqualIgnoringWhitespace(
             expected_query,
             self.searchClause(all(u'fred')))
 
-    def test_single_tag_absence(self):
+    def test_single_tag_absence_any(self):
         # The WHERE clause to test for the absence of a single
-        # tag. Should be the same for an `any` query or an `all`
-        # query.
+        # tag where at least one tag is desired.
         expected_query = (
             """NOT EXISTS
                  (SELECT TRUE FROM BugTag
@@ -239,6 +246,15 @@
         self.assertEqualIgnoringWhitespace(
             expected_query,
             self.searchClause(any(u'-fred')))
+
+    def test_single_tag_absence_all(self):
+        # The WHERE clause to test for the absence of a single
+        # tag where all tags are desired.
+        expected_query = (
+            """NOT EXISTS
+                 (SELECT TRUE FROM BugTag
+                   WHERE BugTag.bug = Bug.id
+                     AND BugTag.tag IN ('fred'))""")
         self.assertEqualIgnoringWhitespace(
             expected_query,
             self.searchClause(all(u'-fred')))
@@ -278,11 +294,7 @@
             """EXISTS
                  (SELECT TRUE FROM BugTag
                    WHERE BugTag.bug = Bug.id
-                     AND BugTag.tag = 'bob'
-                  UNION
-                  SELECT TRUE FROM BugTag
-                   WHERE BugTag.bug = Bug.id
-                     AND BugTag.tag = 'fred')""",
+                     AND BugTag.tag IN ('bob', 'fred'))""",
             self.searchClause(any(u'fred', u'bob')))
         # In an `any` query, a positive wildcard is dominant over
         # other positive tags because "bugs with one or more tags" is
@@ -347,11 +359,7 @@
             """NOT EXISTS
                  (SELECT TRUE FROM BugTag
                    WHERE BugTag.bug = Bug.id
-                     AND BugTag.tag = 'bob'
-                  UNION
-                  SELECT TRUE FROM BugTag
-                   WHERE BugTag.bug = Bug.id
-                     AND BugTag.tag = 'fred')""",
+                     AND BugTag.tag IN ('bob', 'fred'))""",
             self.searchClause(all(u'-fred', u'-bob')))
         # In an `all` query, a negative wildcard is dominant over
         # other negative tags because "bugs without any tags" is a
@@ -371,7 +379,7 @@
             """(EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'fred')
+                      AND BugTag.tag IN ('fred'))
                 OR NOT EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
@@ -381,11 +389,7 @@
             """(EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'eric'
-                   UNION
-                  SELECT TRUE FROM BugTag
-                    WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'fred')
+                      AND BugTag.tag IN ('eric', 'fred'))
                 OR NOT EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
@@ -415,11 +419,7 @@
             """(EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'eric'
-                   UNION
-                   SELECT TRUE FROM BugTag
-                    WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'fred')
+                      AND BugTag.tag IN ('eric', 'fred'))
                 OR NOT EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
@@ -431,11 +431,7 @@
             """(EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'eric'
-                   UNION
-                   SELECT TRUE FROM BugTag
-                    WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'fred')
+                      AND BugTag.tag IN ('eric', 'fred'))
                 OR NOT EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id))""",
@@ -465,7 +461,7 @@
                 AND NOT EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'bob'))""",
+                      AND BugTag.tag IN ('bob')))""",
             self.searchClause(all(u'fred', u'-bob')))
         self.assertEqualIgnoringWhitespace(
             """(EXISTS
@@ -479,11 +475,7 @@
                 AND NOT EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'bob'
-                   UNION
-                   SELECT TRUE FROM BugTag
-                    WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'harry'))""",
+                      AND BugTag.tag IN ('bob', 'harry')))""",
             self.searchClause(all(u'fred', u'-bob', u'eric', u'-harry')))
         # The positive wildcard is superfluous in the presence of
         # other positive tags.
@@ -495,11 +487,7 @@
                 AND NOT EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'bob'
-                   UNION
-                   SELECT TRUE FROM BugTag
-                    WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'harry'))""",
+                      AND BugTag.tag IN ('bob', 'harry')))""",
             self.searchClause(all(u'fred', u'-bob', u'*', u'-harry')))
         # The positive wildcard is not superfluous in the absence of
         # other positive tags.
@@ -510,11 +498,7 @@
                 AND NOT EXISTS
                   (SELECT TRUE FROM BugTag
                     WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'bob'
-                   UNION
-                   SELECT TRUE FROM BugTag
-                    WHERE BugTag.bug = Bug.id
-                      AND BugTag.tag = 'harry'))""",
+                      AND BugTag.tag IN ('bob', 'harry')))""",
             self.searchClause(all(u'-bob', u'*', u'-harry')))
         # The negative wildcard is dominant over other negative tags.
         self.assertEqualIgnoringWhitespace(