diff --git a/gertty/db.py b/gertty/db.py
index 332ed0e..335db9f 100644
--- a/gertty/db.py
+++ b/gertty/db.py
@@ -464,10 +464,11 @@ class DatabaseSession(object):
 
     def getChanges(self, query, unreviewed=False):
         self.database.log.debug("Search query: %s" % query)
-        search_filter = self.search.parse(query)
-        q = self.session().query(Change).filter(search_filter).order_by(change_table.c.number)
+        q = self.session().query(Change).filter(self.search.parse(query))
         if unreviewed:
             q = q.filter(change_table.c.hidden==False, change_table.c.reviewed==False)
+        q = q.order_by(change_table.c.number)
+        self.database.log.debug("Search SQL: %s" % q)
         try:
             return q.all()
         except sqlalchemy.orm.exc.NoResultFound:
diff --git a/gertty/search/__init__.py b/gertty/search/__init__.py
index da024ab..5837a05 100644
--- a/gertty/search/__init__.py
+++ b/gertty/search/__init__.py
@@ -12,15 +12,22 @@
 # License for the specific language governing permissions and limitations
 # under the License.
 
+import sqlalchemy.sql.expression
+
 from gertty.search import tokenizer, parser
+import gertty.db
+
 
 class SearchSyntaxError(Exception):
     pass
 
+
 class SearchCompiler(object):
     def __init__(self, app):
+        self.app = app
         self.lexer = tokenizer.SearchTokenizer()
         self.parser = parser.SearchParser()
 
     def parse(self, data):
+        self.parser.username = self.app.config.username
         return self.parser.parse(data, lexer=self.lexer)
diff --git a/gertty/search/parser.py b/gertty/search/parser.py
index 363f40b..438a556 100644
--- a/gertty/search/parser.py
+++ b/gertty/search/parser.py
@@ -16,7 +16,7 @@ import datetime
 import re
 
 import ply.yacc as yacc
-from sqlalchemy.sql.expression import and_, or_
+from sqlalchemy.sql.expression import and_, or_, not_, exists, select
 
 import gertty.db
 import gertty.search
@@ -53,7 +53,7 @@ def SearchParser():
     def p_negative_expr(p):
         '''negative_expr : NOT expression
                          | NEG expression'''
-        p[0] = not p[1]
+        p[0] = not_(p[2])
 
     def p_term(p):
         '''term : age_term
@@ -120,15 +120,35 @@ def SearchParser():
 
     def p_owner_term(p):
         '''owner_term : OP_OWNER string'''
-        p[0] = gertty.db.change_table.c.owner == p[2]
+        if p[2] == 'self':
+            username = p.parser.username
+            p[0] = gertty.db.account_table.c.username == username
+        else:
+            p[0] = or_(gertty.db.account_table.c.username == p[2],
+                       gertty.db.account_table.c.email == p[2],
+                       gertty.db.account_table.c.name == p[2])
 
     def p_reviewer_term(p):
         '''reviewer_term : OP_REVIEWER string'''
-        p[0] = gertty.db.approval_table.c.name == p[2]
+        filters = []
+        filters.append(gertty.db.approval_table.c.change_key == gertty.db.change_table.c.key)
+        if p[2] == 'self':
+            username = p.parser.username
+            filters.append(gertty.db.account_table.c.username == username)
+        else:
+            filters.append(or_(gertty.db.account_table.c.username == p[2],
+                               gertty.db.account_table.c.email == p[2],
+                               gertty.db.account_table.c.name == p[2]))
+        s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
+        p[0] = gertty.db.change_table.c.key.in_(s)
 
     def p_commit_term(p):
         '''commit_term : OP_COMMIT string'''
-        p[0] = gertty.db.revision_table.c.commit == p[2]
+        filters = []
+        filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
+        filters.append(gertty.db.revision_table.c.commit == p[2])
+        s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
+        p[0] = gertty.db.change_table.c.key.in_(s)
 
     def p_project_term(p):
         '''project_term : OP_PROJECT string'''
@@ -167,6 +187,7 @@ def SearchParser():
         user = args.group('user')
 
         filters = []
+        filters.append(gertty.db.approval_table.c.change_key == gertty.db.change_table.c.key)
         filters.append(gertty.db.approval_table.c.category == label)
         if op == '=':
             filters.append(gertty.db.approval_table.c.value == value)
@@ -175,31 +196,58 @@ def SearchParser():
         elif op == '<=':
             filters.append(gertty.db.approval_table.c.value <= value)
         if user is not None:
-            filters.append(gertty.db.approval_table.c.name == user)
-        p[0] = and_(*filters)
+            filters.append(
+                or_(gertty.db.account_table.c.username == user,
+                    gertty.db.account_table.c.email == user,
+                    gertty.db.account_table.c.name == user))
+        s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
+        p[0] = gertty.db.change_table.c.key.in_(s)
 
     def p_message_term(p):
         '''message_term : OP_MESSAGE string'''
-        p[0] = gertty.db.revision_table.c.message.like(p[1])
+        filters = []
+        filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
+        filters.append(gertty.db.revision_table.c.message == p[2])
+        s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
+        p[0] = gertty.db.change_table.c.key.in_(s)
 
     def p_comment_term(p):
         '''comment_term : OP_COMMENT string'''
-        p[0] = and_(gertty.db.message_table.c.message.like(p[1]),
-                    gertty.db.comment_table.c.message.like(p[1]))
+        filters = []
+        filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
+        filters.append(gertty.db.revision_table.c.message == p[2])
+        revision_select = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
+        filters = []
+        filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
+        filters.append(gertty.db.comment_table.c.revision_key == gertty.db.revision_table.c.key)
+        filters.append(gertty.db.comment_table.c.message == p[2])
+        comment_select = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
+        p[0] = or_(gertty.db.change_table.c.key.in_(comment_select),
+                   gertty.db.change_table.c.key.in_(revision_select))
 
     def p_has_term(p):
         '''has_term : OP_HAS string'''
         #TODO: implement star
         if p[2] == 'draft':
-            p[0] = gertty.db.message_table.c.pending == True
+            filters = []
+            filters.append(gertty.db.revision_table.c.change_key == gertty.db.change_table.c.key)
+            filters.append(gertty.db.message_table.c.revision_key == gertty.db.revision_table.c.key)
+            filters.append(gertty.db.message_table.c.pending == True)
+            s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
+            p[0] = gertty.db.change_table.c.key.in_(s)
         else:
             raise gertty.search.SearchSyntaxError('Syntax error: has:%s is not supported' % p[2])
 
     def p_is_term(p):
         '''is_term : OP_IS string'''
         #TODO: implement starred, watched, owner, reviewer, draft
+        username = p.parser.username
         if p[2] == 'reviewed':
-            p[0] = gertty.db.approval_table.c.value != 0
+            filters = []
+            filters.append(gertty.db.approval_table.c.change_key == gertty.db.change_table.c.key)
+            filters.append(gertty.db.approval_table.c.value != 0)
+            s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
+            p[0] = gertty.db.change_table.c.key.in_(s)
         elif p[2] == 'open':
             p[0] = gertty.db.change_table.c.status.notin_(['MERGED', 'ABANDONED'])
         elif p[2] == 'closed':
@@ -210,6 +258,14 @@ def SearchParser():
             p[0] = gertty.db.change_table.c.status == 'MERGED'
         elif p[2] == 'abandoned':
             p[0] = gertty.db.change_table.c.status == 'ABANDONED'
+        elif p[2] == 'owner':
+            p[0] = gertty.db.account_table.c.username == username
+        elif p[2] == 'reviewer':
+            filters = []
+            filters.append(gertty.db.approval_table.c.change_key == gertty.db.change_table.c.key)
+            filters.append(gertty.db.account_table.c.username == username)
+            s = select([gertty.db.change_table.c.key], correlate=False).where(and_(*filters))
+            p[0] = gertty.db.change_table.c.key.in_(s)
         else:
             raise gertty.search.SearchSyntaxError('Syntax error: has:%s is not supported' % p[2])
 
diff --git a/gertty/search/test.py b/gertty/search/test.py
deleted file mode 100644
index 2e8cef0..0000000
--- a/gertty/search/test.py
+++ /dev/null
@@ -1,73 +0,0 @@
-import gertty.search
-import re
-import sys
-
-label_re = re.compile(r'(?P<label>[a-zA-Z0-9_-]+([a-zA-Z]|((?<![-+])[0-9])))'
-                      r'(?P<operator>[<>]?=?)(?P<value>[-+]?[0-9]+)'
-                      r'($|,user=(?P<user>\S+))')
-
-for a in [
-    'Code-Review=1',
-    'Code-Review=+1',
-    'Code-Review=-1',
-    'Code-Review>=+1',
-    'Code-Review<=-1',
-    'Code-Review+1',
-    'Code-Review-1',
-    ]:
-    for b in [
-        '',
-        ',user=corvus',
-        ]:
-        data = a+b
-        print
-        print data
-        m = label_re.match(data)
-        print 'res', m and m.groups()
-
-#sys.exit(0)
-parser = gertty.search.SearchCompiler(None)
-
-import tokenizer
-lexer = tokenizer.SearchTokenizer()
-lexer.input("project:foo/bar")
-
-# Tokenize
-while True:
-    tok = lexer.token()
-    if not tok: break      # No more input
-    print tok
-
-#TODO: unit test
-for a in [
-    'label:Code-Review=1',
-    'label:Code-Review=+1',
-    'label:Code-Review=-1',
-    'label:Code-Review>=+1',
-    'label:Code-Review<=-1',
-    'label:Code-Review+1',
-    'label:Code-Review-1',
-    ]:
-    for b in [
-        '',
-        ',user=corvus',
-        ]:
-        data = a+b
-        print
-        print data
-        result = parser.parse(data)
-        print 'res', str(result)
-
-for data in [
-    '_project_key:18 status:open',
-    'project:foo/bar status:open',
-    'project:foo and status:open',
-    'project:foo or status:open',
-    'project:foo and (status:merged or status:new)',
-    'project:foo or project:bar or project:baz',
-    'project:foo project:bar project:baz',
-    ]:
-    print
-    print data
-    result = parser.parse(data)
-    print 'res', str(result)