This appears to be working. newdbschema
authorBenjamin Smedberg <benjamin@smedbergs.us>
Tue, 29 Sep 2009 13:08:14 -0400
branchnewdbschema
changeset 22 4c1458dcdab3
parent 21 b792fdef1b26
child 23 8894b0ca1189
push id13
push userbsmedberg@mozilla.com
push date2009-09-29 17:12 +0000
This appears to be working.
master.cfg
warning-ui/build.html
warning-ui/dbschema.sql
warning-ui/new.html
warning-ui/search.html
warning-ui/ui.py
warning-ui/warning.html
warningstep.py
--- a/master.cfg
+++ b/master.cfg
@@ -102,17 +102,17 @@ changesetLink = '<a href=http://hg.mozil
 f1.addStep(ShellCommand(command=['printf', 'TinderboxPrint:%s\n',
                                  WithProperties(changesetLink)]))
 
 f1.addStep(FileDownload(mastersrc="mozconfig", slavedest=".mozconfig"))
 
 f1.addStep(Compile(command='make -f client.mk -w >build.log 2>&1', env={'LANG': 'C'}, logfiles={'build': 'build.log'}, timeout=1800))
 f1.addStep(FileDownload(mastersrc="warning-parser.py", slavedest="warning-parser.py"))
 f1.addStep(FileDownload(mastersrc="cvsblame.db", slavedest="cvsblame.db"))
-f1.addStep(WarningParserStep(command=['python', 'warning-parser.py', '.', 'cvsblame.db', 'build.log'], dbfile='warnings.db'))
+f1.addStep(WarningParserStep(command=['python', 'warning-parser.py', '.', 'cvsblame.db', 'build.log'], connectargs=slaves.dbinfo))
 
 b1 = {'name': 'static-analysis-bsmedberg',
       'slavename': "staticanalysis-slave-linux",
       'builddir': "full",
       'factory': f1,
       }
 
 f2 = factory.BuildFactory()
--- a/warning-ui/build.html
+++ b/warning-ui/build.html
@@ -15,16 +15,19 @@
     </div>
     <div class="h2block" py:if="previd is not None and prevrev != rev">
       <h2>Changes since <a href="/build?id=${previd}">last build</a>:</h2>
       <a href="http://hg.mozilla.org/mozilla-central/pushloghtml?fromchange=${prevrev}&amp;tochange=${rev}">Log</a>
     </div>
     <div class="h2block">
       <h2>Unique warnings:</h2> ${unique}
     </div>
+    <div class="hsblock">
+      <h2>Total warnings:</h2> ${total}
+    </div>
 
     <py:if test="previd is not None">
       <div py:if="len(newwarnings)">
         <h3>New:</h3>
 
         <ul>
           <li py:for="id, file, lineno, msg in newwarnings">
             <a href="${genlink('warning', id=id)}">${file}:${lineno} - ${msg}</a>
--- a/warning-ui/dbschema.sql
+++ b/warning-ui/dbschema.sql
@@ -1,10 +1,9 @@
 DROP TABLE IF EXISTS buildwarninglines, buildwarnings, builds, warninglines, warnings, locations, messages;
-DROP PROCEDURE IF EXISTS insertbuild;
 
 CREATE TABLE locations (
   locationid INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
   ltype VARCHAR(10) NOT NULL, -- 'cvs', 'hg', 'system' (will not have directory) or 'build'
   lfile VARCHAR(255) NOT NULL,
   lline INTEGER NOT NULL, -- use -1 for unknown
   lrev VARCHAR(40) NOT NULL,
   lwho VARCHAR(400) NOT NULL,
@@ -24,196 +23,225 @@ CREATE TABLE messages (
 INSERT INTO messages
   (msgid, msg)
 VALUES
   (-1, 'warningdb sentinel message');
 
 CREATE TABLE warnings (
   warningid INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
   linecount TINYINT NOT NULL,
-  primaryline TINYINT NOT NULL,
-  l0 INTEGER NOT NULL DEFAULT -1 REFERENCES locations (locationid),
-  msg0 INTEGER NOT NULL DEFAULT -1 REFERENCES messages (msgid),
-  l1 INTEGER NOT NULL DEFAULT -1 REFERENCES locations (locationid),
-  msg1 INTEGER NOT NULL DEFAULT -1 REFERENCES messages (msgid),
-  l2 INTEGER NOT NULL DEFAULT -1 REFERENCES locations (locationid),
-  msg2 INTEGER NOT NULL DEFAULT -1 REFERENCES messages (msgid),
-  l3 INTEGER NOT NULL DEFAULT -1 REFERENCES locations (locationid),
-  msg3 INTEGER NOT NULL DEFAULT -1 REFERENCES messages (msgid),
-  l4 INTEGER NOT NULL DEFAULT -1 REFERENCES locations (locationid),
-  msg4 INTEGER NOT NULL DEFAULT -1 REFERENCES messages (msgid),
-  l5 INTEGER NOT NULL DEFAULT -1 REFERENCES locations (locationid),
-  msg5 INTEGER NOT NULL DEFAULT -1 REFERENCES messages (msgid),
-  l6 INTEGER NOT NULL DEFAULT -1 REFERENCES locations (locationid),
-  msg6 INTEGER NOT NULL DEFAULT -1 REFERENCES messages (msgid),
-  l7 INTEGER NOT NULL DEFAULT -1 REFERENCES locations (locationid),
-  msg7 INTEGER NOT NULL DEFAULT -1 REFERENCES messages (msgid),
-  CONSTRAINT warnings_data_uniq UNIQUE (l0, msg0, l1, msg1, l2, msg2, l3, msg3, l4, msg4, l5, msg5, l6, msg6, l7, msg7)
+  primaryline TINYINT NOT NULL
 ) ENGINE=InnoDB;
 
-CREATE OR REPLACE
-ALGORITHM = MERGE
-VIEW v_warninglines_unjoined
+CREATE TABLE warninglines (
+  warningid INTEGER NOT NULL,
+  wline TINYINT NOT NULL,
+  CONSTRAINT warninglines_pkey PRIMARY KEY (warningid, wline),
+  CONSTRAINT warninglines_warningid_fkey
+    FOREIGN KEY (warningid) REFERENCES warnings (warningid),
+  locationid INTEGER NOT NULL REFERENCES locations (locationid),
+  msgid INTEGER NOT NULL REFERENCES messages (msgid)
+) ENGINE=InnoDB;
+CREATE INDEX idx_warninglines_wline ON warninglines (wline, locationid, msgid);
+
+CREATE OR REPLACE VIEW v_warninglines
 AS
-  SELECT warningid, l0 AS locationid, msg0 as msgid, 0 AS wline
-  FROM warnings
-  UNION SELECT warningid, l1 AS locationid, msg1 as msgid, 1 AS wline
-  FROM warnings
-  WHERE linecount > 1
-  UNION SELECT warningid, l2 AS locationid, msg2 as msgid, 2 AS wline
-  FROM warnings
-  WHERE linecount > 2
-  UNION SELECT warningid, l3 AS locationid, msg3 as msgid, 3 AS wline
-  FROM warnings
-  WHERE linecount > 3
-  UNION SELECT warningid, l4 AS locationid, msg4 as msgid, 4 AS wline
-  FROM warnings
-  WHERE linecount > 4
-  UNION SELECT warningid, l5 AS locationid, msg5 as msgid, 5 AS wline
-  FROM warnings
-  WHERE linecount > 5
-  UNION SELECT warningid, l6 AS locationid, msg6 as msgid, 6 AS wline
-  FROM warnings
-  WHERE linecount > 6
-  UNION SELECT warningid, l7 AS locationid, msg7 as msgid, 7 AS wline
-  FROM warnings
-  WHERE linecount > 7;
+  SELECT warningid, wline, ltype, lfile, lline, lrev, lwho, msg
+  FROM warninglines, locations, messages
+  WHERE locations.locationid = warninglines.locationid
+    AND messages.msgid = warninglines.msgid;
 
-CREATE OR REPLACE
-ALGORITHM = MERGE
-VIEW v_warninglines
+CREATE OR REPLACE VIEW v_warnings
 AS
-  SELECT warningid, ltype, lfile, lline, lrev, lwho, msg, wline
-  FROM v_warninglines_unjoined, locations, messages
-  WHERE locations.locationid = v_warninglines_unjoined.locationid
-    AND messages.msgid = v_warninglines_unjoined.msgid;
-
-CREATE OR REPLACE
-ALGORITHM = MERGE
-VIEW v_warningline_primary
-  AS
-    SELECT v_warninglines.warningid AS warningid, ltype, lfile, lline, lrev, lwho, msg
-    FROM v_warninglines, warnings
-    WHERE v_warninglines.warningid = warnings.warningid
-      AND v_warninglines.wline = warnings.primaryline;
+  SELECT warnings.warningid, linecount, primaryline, ltype, lfile, lline, lrev, lwho, msg
+  FROM warnings, warninglines, locations, messages
+  WHERE warninglines.warningid = warnings.warningid
+    AND warninglines.wline = warnings.primaryline
+    AND locations.locationid = warninglines.locationid
+    AND messages.msgid = warninglines.msgid;
 
 CREATE TABLE builds (
   buildnumber INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
   rev VARCHAR(40) NOT NULL
 ) ENGINE=InnoDB;
 
 CREATE TABLE buildwarnings (
   buildnumber INTEGER NOT NULL,
   CONSTRAINT buildwarnings_buildnumber_fkey FOREIGN KEY (buildnumber)
     REFERENCES builds (buildnumber),
   warningid INTEGER NOT NULL,
   CONSTRAINT buildwarnings_pkey PRIMARY KEY (buildnumber, warningid),
   wcount INTEGER NOT NULL DEFAULT 1
-) ENGINE=InnoDB;
+)  ENGINE=InnoDB ;
 CREATE INDEX idx_buildwarnings_warningid
   ON buildwarnings (warningid);
 
 CREATE TABLE buildwarninglines (
   buildnumber INTEGER NOT NULL,
   warningid INTEGER NOT NULL,
+  wline TINYINT NOT NULL,
   CONSTRAINT buildwarninglines_warningid_fkey FOREIGN KEY (buildnumber, warningid)
     REFERENCES buildwarnings (buildnumber, warningid),
-  wline INTEGER NOT NULL,
   CONSTRAINT buildwarninglines_pkey PRIMARY KEY (buildnumber, warningid, wline),
+  CONSTRAINT buildwarninglines_wline_fkey FOREIGN KEY (warningid, wline)
+    REFERENCES warninglines (warningid, wline),
   locationid INTEGER NOT NULL REFERENCES locations (locationid)
-) ENGINE=InnoDB;
+)  ENGINE=InnoDB ;
 
-CREATE VIEW v_buildwarninglines
+CREATE OR REPLACE VIEW v_buildwarninglines
 AS
   SELECT buildnumber, warningid, wline, ltype, lfile, lline, lrev, lwho
   FROM buildwarninglines, locations
   WHERE locations.locationid = buildwarninglines.locationid;
 
-CREATE VIEW v_buildwarningline_primary
+CREATE OR REPLACE VIEW v_buildwarnings
 AS
-  SELECT buildnumber, warningid, ltype, lfile, lline, lrev, lwho
-  FROM v_buildwarninglines, buildwarnings
+  SELECT v_buildwarninglines.buildnumber AS buildnumber,
+         v_buildwarninglines.warningid AS warningid,
+         v_buildwarninglines.lfile AS lfile,
+         v_buildwarninglines.lline AS lline,
+         msg, primaryline
+  FROM v_buildwarninglines, buildwarnings, v_warnings
   WHERE buildwarnings.warningid = v_buildwarninglines.warningid
-    AND v_buildwarninglines.wline = buidlwarnings.primaryline;
+    AND v_warnings.warningid = v_buildwarninglines.warningid
+    AND v_buildwarninglines.buildnumber = buildwarnings.buildnumber
+    AND v_buildwarninglines.wline = v_warnings.primaryline;
 
 delimiter /;
+
+DROP PROCEDURE IF EXISTS setuptables;
+CREATE PROCEDURE setuptables()
+MODIFIES SQL DATA
+BEGIN
+  CREATE TEMPORARY TABLE _BUILDDATA (
+    id INTEGER NOT NULL,
+    ord INTEGER NOT NULL,
+    CONSTRAINT PRIMARY KEY (id, ord),
+    wcount INTEGER NOT NULL DEFAULT 1,
+    file VARCHAR(255) NOT NULL,
+    line INTEGER,
+    msg VARCHAR(255) NOT NULL,
+    blametype VARCHAR(10),
+    blamewho VARCHAR(400),
+    blamefile VARCHAR(255),
+    blamerev VARCHAR(40),
+    blameline INTEGER);
+  CREATE TEMPORARY TABLE _WLINES (
+    wline INTEGER NOT NULL PRIMARY KEY,
+    locationid INTEGER NOT NULL,
+    msgid INTEGER NOT NULL
+  );
+  CREATE TEMPORARY TABLE _BUILDWARNINGS (
+    warningid INTEGER NOT NULL PRIMARY KEY,
+    id INTEGER NOT NULL,
+    wcount INTEGER NOT NULL DEFAULT 1
+  );
+  CREATE TEMPORARY TABLE _BUILDWARNINGLINES (
+    id INTEGER NOT NULL,
+    wline TINYINT NOT NULL,
+    CONSTRAINT PRIMARY KEY (id, wline),
+    locationid INTEGER NOT NULL
+  );
+END
+/;
+
+DROP FUNCTION IF EXISTS getwarningid;
+DROP PROCEDURE IF EXISTS getwarningid;
+CREATE PROCEDURE getwarningid(OUT _warningid INTEGER)
+MODIFIES SQL DATA
+BEGIN
+  -- Given the _WLINES temporary table, figure out the warningid, perhaps
+  -- by inserting a new one.
+  DECLARE haslock INTEGER;
+
+  REPEAT
+    SET @haslock = GET_LOCK('warningdb_warningid', 5);
+  UNTIL @haslock
+  END REPEAT;
+
+  SET _warningid = (
+    SELECT warningid
+    FROM warnings
+    WHERE linecount = (
+      SELECT COUNT(*)
+      FROM warninglines, _WLINES
+      WHERE warnings.warningid = warninglines.warningid
+        AND warninglines.wline = _WLINES.wline
+        AND warninglines.locationid = _WLINES.locationid
+        AND warninglines.msgid = _WLINES.msgid
+    )
+  );
+  IF _warningid IS NULL THEN
+    INSERT INTO warnings (linecount, primaryline)
+    VALUES (
+      (SELECT COUNT(*) FROM _WLINES),
+      0
+    );
+    SET _warningid = LAST_INSERT_ID();
+    INSERT INTO warninglines (warningid, wline, locationid, msgid)
+      SELECT _warningid, wline, locationid, msgid FROM _WLINES;
+    COMMIT;
+  END IF;
+
+  SET @haslock = RELEASE_LOCK('warningdb_warningid');
+END
+/;
+
+DROP PROCEDURE IF EXISTS insertbuild;
 CREATE PROCEDURE insertbuild(buildnumber INTEGER, rev VARCHAR(40))
 MODIFIES SQL DATA
 BEGIN
-  -- Takes a temporary table #BUILDDATA and inserts the data in all the right places
-  -- Schema of #BUILDDATA should be id, ord, file, line, msg,
+  -- Takes a temporary table #BUILDDATA and inserts the data into the database.
+  -- Schema of #BUILDDATA should be id, count, ord, file, line, msg,
   --   blametype, blamewho, blamefile, blamerev, blameline, loc, blameloc, msgid
 
   DECLARE done INT DEFAULT 0;
-  DECLARE _curid, _curord, _id, _ord, _msgid, _warningid INTEGER;
+  DECLARE _curid, _curord, _id, _ord, _wcount, _msgid, _warningid INTEGER;
   DECLARE _blametype VARCHAR(10);
   DECLARE _file, _blamefile VARCHAR(255);
   DECLARE _line, _blameline INTEGER;
   DECLARE _loc, _blameloc INTEGER;
   DECLARE _blamerev VARCHAR(40);
   DECLARE _blamewho VARCHAR(400);
   DECLARE _msg VARCHAR(255);
-  DECLARE _loc0, _msg0, _loc1, _msg1, _loc2, _msg2, _loc3, _msg3, _loc4, _msg4, _loc5, _msg5, _loc6, _msg6, _loc7, _msg7 INTEGER DEFAULT -1;
 
   DECLARE readlocs CURSOR FOR
-    SELECT id, ord, file, line, msg, blametype, blamewho, blamefile, blamerev, blameline
+    SELECT id, ord, wcount, file, line, msg, blametype, blamewho, blamefile, blamerev, blameline
     FROM _BUILDDATA
     ORDER BY id, ord;
   DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
 
-  CREATE TEMPORARY TABLE IF NOT EXISTS _BUILDWARNINGS (
-    warningid INTEGER NOT NULL PRIMARY KEY,
-    id INTEGER NOT NULL,
-    wcount INTEGER NOT NULL DEFAULT 1
-  );
-  TRUNCATE _BUILDWARNINGS;
-  CREATE TEMPORARY TABLE IF NOT EXISTS _BUILDWARNINGLINES (
-    id INTEGER NOT NULL,
-    wline INTEGER NOT NULL,
-    CONSTRAINT PRIMARY KEY (id, wline),
-    locationid INTEGER NOT NULL
-  );
-  TRUNCATE _BUILDWARNINGLINES;
+  DELETE FROM _WLINES;
+  DELETE FROM _BUILDWARNINGS;
+  DELETE FROM _BUILDWARNINGLINES;
 
   OPEN readlocs;
   readloop: LOOP
     FETCH readlocs
-      INTO _id, _ord, _file, _line, _msg, _blametype, _blamewho, _blamefile, _blamerev, _blameline;
+      INTO _id, _ord, _wcount, _file, _line, _msg, _blametype, _blamewho, _blamefile, _blamerev, _blameline;
 
     IF done OR (_curid is not NULL and _curid != _id) THEN
-      INSERT INTO warnings (linecount, primaryline,
-          l0, msg0, l1, msg1, l2, msg2, l3, msg3,
-          l4, msg4, l5, msg5, l6, msg6, l7, msg7)
-        VALUES (_curord + 1, 0,
-          _loc0, _msg0, _loc1, _msg1, _loc2, _msg2, _loc3, _msg3,
-          _loc4, _msg4, _loc5, _msg5, _loc6, _msg6, _loc7, _msg7)
-        ON DUPLICATE KEY UPDATE warningid = LAST_INSERT_ID(warningid);
-      SET _warningid = LAST_INSERT_ID();
+      CALL getwarningid(_warningid);
+      DELETE FROM _WLINES;
 
-      INSERT INTO _BUILDWARNINGS (id, warningid) VALUES (_curid, _warningid)
-        ON DUPLICATE KEY UPDATE wcount = wcount + 1;
+      INSERT INTO _BUILDWARNINGS (warningid, id, wcount)
+        VALUES (_warningid, _curid, _wcount)
+        ON DUPLICATE KEY UPDATE wcount = wcount + _wcount;
 
-      SET _loc0 = -1, _msg0 = -1,
-          _loc1 = -1, _msg1 = -1,
-          _loc2 = -1, _msg2 = -1,
-          _loc3 = -1, _msg3 = -1,
-          _loc4 = -1, _msg4 = -1,
-          _loc5 = -1, _msg5 = -1,
-          _loc6 = -1, _msg6 = -1,
-          _loc7 = -1, _msg7 = -1,
-          _curord = NULL;
+      SET _curord = NULL;
     END IF;
 
     IF done THEN LEAVE readloop; END IF;
 
     SET _curid = _id;
     IF _curord IS NOT NULL AND _curord != _ord - 1 THEN
       PREPARE throw_err FROM 'CALL incoming_data_error, ord were not sequential';
       EXECUTE throw_err;
     END IF;
+
     SET _curord = _ord;
 
     IF _blametype IS NULL THEN
       SET _blametype = 'system';
     END IF;
     IF _line IS NULL THEN
       SET _line = -1;
     END IF;
@@ -243,35 +271,25 @@ BEGIN
     COMMIT;
 
     INSERT INTO messages (msg)
       VALUES (_msg)
       ON DUPLICATE KEY UPDATE msgid = LAST_INSERT_ID(msgid);
     SET _msgid = LAST_INSERT_ID();
     COMMIT;
 
+    INSERT INTO _WLINES (wline, locationid, msgid)
+      VALUES (_curord, _blameloc, _msgid);
     INSERT INTO _BUILDWARNINGLINES (id, wline, locationid)
       VALUES (_curid, _curord, _loc);
-
-    CASE _curord
-      WHEN 0 THEN SET _loc0 = _blameloc, _msg0 = _msgid;
-      WHEN 1 THEN SET _loc1 = _blameloc, _msg1 = _msgid;
-      WHEN 2 THEN SET _loc2 = _blameloc, _msg2 = _msgid;
-      WHEN 3 THEN SET _loc3 = _blameloc, _msg3 = _msgid;
-      WHEN 4 THEN SET _loc4 = _blameloc, _msg4 = _msgid;
-      WHEN 5 THEN SET _loc5 = _blameloc, _msg5 = _msgid;
-      WHEN 6 THEN SET _loc6 = _blameloc, _msg6 = _msgid;
-      WHEN 7 THEN SET _loc7 = _blameloc, _msg7 = _msgid;
-    END CASE;
   END LOOP;
 
   START TRANSACTION;
-  INSERT INTO builds(buildnumber, rev) VALUES (buildnumber, rev);
-  INSERT INTO buildwarnings(buildnumber, warningid, wcount)
-    SELECT buildnumber, warningid, wcount
-    FROM _BUILDWARNINGS;
-  INSERT INTO buildwarninglines(buildnumber, warningid, wline, locationid)
+  INSERT INTO builds (buildnumber, rev) VALUES (buildnumber, rev);
+  INSERT INTO buildwarnings (buildnumber, warningid, wcount)
+    SELECT buildnumber, warningid, wcount FROM _BUILDWARNINGS;
+  INSERT INTO buildwarninglines (buildnumber, warningid, wline, locationid)
     SELECT buildnumber, warningid, wline, locationid
-    FROM _BUILDWARNINGS, _BUILDWARNINGLINES
-    WHERE _BUILDWARNINGS.id = _BUILDWARNINGLINES.id;
+    FROM _BUILDWARNINGLINES, _BUILDWARNINGS
+    WHERE _BUILDWARNINGLINES.id = _BUILDWARNINGS.id;
   COMMIT;
 END
 /;
--- a/warning-ui/new.html
+++ b/warning-ui/new.html
@@ -6,14 +6,14 @@
   <head>
     <title>New Warnings</title>
   </head>
   <body class="build">
     <h1>New Warnings</h1>
     <p><em>Between build ${start} and ${end}</em></p>
 
     <ul>
-      <li py:for="signature, file, lineno, msg in newwarnings">
-        <a href="${genlink('warning', signature=signature)}">${file}:${lineno} - ${msg}</a>
+      <li py:for="id, file, lineno, msg in newwarnings">
+        <a href="${genlink('warning', id=id)}">${file}:${lineno} - ${msg}</a>
       </li>
     </ul>
   </body>
 </html>
--- a/warning-ui/search.html
+++ b/warning-ui/search.html
@@ -14,18 +14,18 @@
       <li py:if="path != ''">Path LIKE '${path}'</li>
     </ul>
 
     <h2>Results</h2>
 
     <p py:if="len(results) == 0">No warnings found!</p>
 
     <ul py:if="len(results)">
-      <li py:for="signature, file, lineno, msg in results">
-        <a href="${genlink('warning', signature=signature)}">${file}:${lineno} - ${msg}</a>
+      <li py:for="id, file, lineno, msg in results">
+        <a href="${genlink('warning', id=id)}">${file}:${lineno} - ${msg}</a>
       </li>
     </ul>
 
     <h2>Search again:</h2>
     ${searchform(id, user, path, msg)}
 
   </body>
 </html>
--- a/warning-ui/ui.py
+++ b/warning-ui/ui.py
@@ -11,18 +11,18 @@ class Root(object):
 
     def render(self, tmpl, **kwargs):
         cherrypy.response.headers['Content-Type'] = 'application/xhtml+xml'
         tmpl = self.loader.load(tmpl)
         return tmpl.generate(**kwargs).render('xhtml', doctype='xhtml')
 
     @cherrypy.expose
     def index(self):
+        cur = self.dbcursor()
         try:
-            cur = self.dbcursor()
             cur.execute('''SELECT builds.buildnumber, builds.rev, count(*)
                            FROM builds, buildwarnings
                            WHERE builds.buildnumber = buildwarnings.buildnumber
                            GROUP BY builds.buildnumber
                            ORDER BY builds.buildnumber DESC LIMIT 100''')
             return self.render('index.html', builds=cur.fetchall())
         finally:
             cur.close()
@@ -39,85 +39,75 @@ Disallow: /"""
         span = int(span)
 
         cur = self.dbcursor()
         if end == -1:
             cur.execute('''SELECT max(builds.buildnumber)
                            FROM builds''')
             end, = cur.fetchone()
 
-        cur.execute('''SELECT min(builds.buildnumber)
-                       FROM builds
-                       WHERE builds.buildnumber > ?''', (end - span,))
+        cur.execute('''SELECT MIN(buildnumber)
+                       FROM (
+                         SELECT buildnumber FROM builds
+                         WHERE buildnumber <= %s
+                         ORDER BY buildnumber DESC LIMIT %s
+                       ) AS b''', (end, span))
 
         start, = cur.fetchone()
 
-        cur.execute('''SELECT warnings.signature, file, lineno, msg
-                       FROM warnings, wlines
+        cur.execute('''SELECT warningid, lfile, lline, msg
+                       FROM v_buildwarnings
                        WHERE
-                         warnings.buildnumber = wlines.buildnumber AND
-                         warnings.signature = wlines.signature AND
-                         wlines.wline = 0 AND
-                         warnings.buildnumber = ? AND
-                         NOT EXISTS (SELECT *
-                                     FROM warnings as oldwarnings
-                                     WHERE
-                                       oldwarnings.signature = warnings.signature AND
-                                       oldwarnings.buildnumber = ?)
-                       ORDER BY file''',
-                    (end, start))
+                         buildnumber = %s
+                         AND NOT EXISTS (
+                           SELECT * FROM buildwarnings AS oldwarnings
+                           WHERE oldwarnings.warningid = v_buildwarnings.warningid
+                           AND oldwarnings.buildnumber = %s)''',
+                         (end, start))
         newwarnings = cur.fetchall()
         cur.close()
         return self.render('new.html',
                            start=start,
                            end=end,
                            newwarnings=newwarnings)
-        
+
     @cherrypy.expose
     def search(self, id, user="", path="", msg=""):
         id = int(id)
         user = user.strip()
         path = path.strip()
         msg = msg.strip()
-        
+
         bindp = [id]
+        q = '''SELECT warningid, lfile, lline, msg
+               FROM v_buildwarnings AS bw
+               WHERE bw.buildnumber = %s '''
 
-        subclauses = []
         if user != '':
-            subclauses.append('AND wl2.blamewho LIKE ?')
+            q += '''AND EXISTS (
+                      SELECT * FROM v_warninglines AS vw
+                      WHERE vw.lwho LIKE %s
+                        AND vw.warningid = bw.warningid
+                        AND vw.wline = bw.primaryline
+                    ) '''
             bindp.append(user)
 
         if path != '':
-            subclauses.append('AND wl2.file LIKE ?')
+            q += '''AND bw.lline LIKE %s '''
             bindp.append(path)
 
         if msg != '':
-            subclauses.append('AND wl2.msg LIKE ?')
+            q += '''AND bw.msg LIKE %s '''
             bindp.append(msg)
 
-        if len(subclauses):
-            clause = '''AND EXISTS (SELECT *
-                                    FROM wlines AS wl2
-                                    WHERE
-                                      wl2.buildnumber = warnings.buildnumber AND
-                                      wl2.signature = warnings.signature %s)''' % ' '.join(subclauses)
-        else:
-            clause = ''
+        q += 'ORDER BY lfile, lline'
 
         try:
             cur = self.dbcursor()
-            q = '''SELECT warnings.signature, file, lineno, msg
-                   FROM warnings, wlines
-                   WHERE
-                     warnings.buildnumber = wlines.buildnumber AND
-                     warnings.signature = wlines.signature AND
-                     wlines.wline = 0 AND
-                     warnings.buildnumber = ? %s''' % (clause, )
-            print "Query: %s\nBind: %s" % (q, bindp)
-
+            print "sql: %s bind: %r" % (q, bindp)
             cur.execute(q, bindp)
 
             return self.render('search.html',
                                id=id,
                                user=user,
                                path=path,
                                msg=msg,
                                results=cur.fetchall())
@@ -129,80 +119,65 @@ Disallow: /"""
         id = int(id)
         try:
             cur = self.dbcursor()
             cur.execute('''SELECT rev
                            FROM builds
                            WHERE buildnumber = %s''', (id,))
             rev, = cur.fetchone()
 
-            cur.execute('''SELECT count(*) as ucount
+            cur.execute('''SELECT count(*) as ucount, sum(wcount) as wcount
                            FROM buildwarnings
                            WHERE buildnumber = %s''', (id,))
-            unique, = cur.fetchone()
+            unique, total = cur.fetchone()
 
             cur.execute('''SELECT buildnumber, rev
                            FROM builds
                            WHERE
                              buildnumber < %s
                            ORDER BY buildnumber DESC
                            LIMIT 1''', (id,))
             prev = cur.fetchone()
             if prev is None:
                 previd = None
                 prevrev = None
                 newwarnings = None
                 fixedwarnings = None
             else:
                 previd, prevrev = prev
 
-                cur.execute('''SELECT buildwarnings.warningid,
-                                      locations.lfile, locations.lline, messages.msg
-                               FROM buildwarnings, buildwarninglines, locations,
-                                    warnings, messages
+                cur.execute('''SELECT warningid, lfile, lline, msg
+                               FROM v_buildwarnings
                                WHERE
-                                 buildwarnings.buildnumber = %s
+                                 buildnumber = %s
                                  AND NOT EXISTS (
                                    SELECT *
                                    FROM buildwarnings AS oldwarnings
-                                   WHERE oldwarnings.warningid = warnings.warningid
-                                     AND oldwarnings.buildnumber = %s)
-                                 AND buildwarninglines.buildnumber = buildwarnings.buildnumber
-                                 AND buildwarninglines.warningid = buildwarnings.warningid
-                                 AND buildwarninglines.wline = 0
-                                 AND locations.locationid = buildwarninglines.locationid
-                                 AND warnings.warningid = buildwarnings.warningid
-                                 AND messages.msgid = warnings.msg0''',
+                                   WHERE oldwarnings.warningid = v_buildwarnings.warningid
+                                     AND oldwarnings.buildnumber = %s)''',
                             (id, previd))
                 newwarnings = cur.fetchall()
 
-                cur.execute('''SELECT buildwarnings.warningid,
-                                      locations.lfile, locations.lline, messages.msg
-                               FROM buildwarnings, buildwarninglines, locations,
-                                    warnings, messages
+                cur.execute('''SELECT warningid, lfile, lline, msg
+                               FROM v_buildwarnings
                                WHERE
-                                 buildwarnings.buildnumber = %s
+                                 buildnumber = %s
                                  AND NOT EXISTS (
                                    SELECT *
                                    FROM buildwarnings AS oldwarnings
-                                   WHERE oldwarnings.warningid = warnings.warningid
-                                     AND oldwarnings.buildnumber = %s)
-                                 AND buildwarninglines.buildnumber = buildwarnings.buildnumber
-                                 AND buildwarninglines.warningid = buildwarnings.warningid
-                                 AND buildwarninglines.wline = 0
-                                 AND locations.locationid = buildwarninglines.locationid
-                                 AND warnings.warningid = buildwarnings.warningid
-                                 AND messages.msgid = warnings.msg0''',
+                                   WHERE oldwarnings.warningid = v_buildwarnings.warningid
+                                     AND oldwarnings.buildnumber = %s)''',
                             (previd, id))
                 fixedwarnings = cur.fetchall()
 
             return self.render('build.html',
                                rev=rev,
                                id=id,
                                unique=unique,
+                               total=total,
                                previd=previd,
                                prevrev=prevrev,
                                newwarnings=newwarnings,
                                fixedwarnings=fixedwarnings)
         finally:
             cur.close()
 
     @cherrypy.expose
@@ -226,22 +201,25 @@ Disallow: /"""
                                 SELECT MAX(buildnumber) AS buildnumber
                                 FROM buildwarnings
                                 WHERE warningid = %s
                              ) AS wmax
                            WHERE
                              builds.buildnumber = wmax.buildnumber''', (id,))
             lastid, lastrev = cur.fetchone()
 
-            cur.execute('''SELECT file, lineno, msg, blametype, blamefile, blamerev, blameline, blamewho
-                           FROM wlines
-                           WHERE
-                             buildnumber = ? AND
-                             signature = ?
-                           ORDER BY wline ASC''', (firstid, signature))
+            cur.execute('''SELECT bwl.lfile, bwl.lline,
+                             wl.msg, wl.ltype, wl.lfile, wl.lline, wl.lrev, wl.lwho
+                           FROM v_buildwarninglines AS bwl,
+                             v_warninglines AS wl
+                           WHERE bwl.buildnumber = %s
+                             AND bwl.warningid = %s
+                             AND wl.warningid = bwl.warningid
+                             AND wl.wline = bwl.wline
+                           ORDER BY wl.wline ASC''', (lastid, id))
             wlines = cur.fetchall()
 
             if lastid == firstid:
                 lastid = None
                 lastrev = None
 
             return self.render('warning.html',
                                firstid=firstid, firstrev=firstrev,
--- a/warning-ui/warning.html
+++ b/warning-ui/warning.html
@@ -15,17 +15,17 @@
       <a href="${genlink('build', id=firstid)}">${firstrev}</a>
     </div>
     <div class="h2block" py:if="lastid is not None">
       <h2>Fixed in:</h2>
       <a href="${genlink('build', id=lastid)}">${lastrev}</a>
     </div>
 
     <dl>
-      <py:for each="file, lineno, msg, blametype, blamefile, blamerev, blameline, blamewho in wlines">
+      <py:for each="file, lineno, msg, blametype, blamefile, blameline, blamerev, blamewho in wlines">
         <dt>
           <a py:strip="blametype is None"
              href="http://hg.mozilla.org/mozilla-central/file/${firstrev}/${file}#l${lineno}">
             ${file}:${lineno}</a>:
           ${msg}
         </dt>
         <dd py:if="blametype is not None">
           <py:choose test="blametype">
--- a/warningstep.py
+++ b/warningstep.py
@@ -28,48 +28,35 @@ class WarningParserStep(ShellCommand):
 
         comparison = self.parseLog(log.getText(), self.getProperty('buildnumber'), self.getProperty('got_revision'))
         self.addCompleteLog('comparison', '\n'.join(comparison))
 
     def parseLog(self, logdata, buildnumber, revision):
         db = MySQLdb.connect(**self.connectargs)
         dbcur = db.cursor()
         dbcur.arraysize = 200
-        dbcur.execute('''CREATE TEMPORARY TABLE _BUILDDATA (
-                           id INTEGER NOT NULL,
-                           ord INTEGER NOT NULL,
-                           CONSTRAINT PRIMARY KEY (id, ord),
-                           file VARCHAR(255) NOT NULL,
-                           line INTEGER,
-                           msg VARCHAR(255) NOT NULL,
-                           blametype VARCHAR(10),
-                           blamewho VARCHAR(400),
-                           blamefile VARCHAR(255),
-                           blamerev VARCHAR(40),
-                           blameline INTEGER
-                         )''')
+
+        dbcur.callproc('setuptables')
 
         def getmany():
             i = 0
             for line in logdata.split('\n'):
                 if line.startswith('WARN-DB: '):
                     i += 1
                     d = eval(line[9:].strip())
                     print repr(d)
                     yield d
 
         dbcur.executemany('''INSERT INTO _BUILDDATA (id, ord, file, line, msg, blametype, blamewho, blamefile, blamerev, blameline) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s)''',
                           [eval(line[9:].strip())
                            for line in logdata.split('\n')
                            if line.startswith('WARN-DB: ')])
 
         dbcur.callproc('insertbuild', (buildnumber, revision))
-
-        # dbcur.execute('INSERT INTO builds (buildnumber, rev) VALUES ( %s, %s )',
-        #               (buildnumber, revision))
+        db.commit()
 
         # A list of line to stick in the comparison log
         comparison = []
 
         dbcur.execute('''SELECT COUNT(*) as unqiue, SUM(wcount) AS total
                        FROM buildwarnings
                        WHERE buildnumber = %s''', (buildnumber,))
         unique, total = dbcur.fetchone()