diff --git a/trac/db/mysql_backend.py b/trac/db/mysql_backend.py
--- a/trac/db/mysql_backend.py
+++ b/trac/db/mysql_backend.py
@@ -214,6 +214,9 @@
         return 'concat(%s)' % ', '.join(args)
 
     def like(self):
+        return "LIKE %s ESCAPE '/'"
+
+    def ilike(self):
         return "LIKE %s COLLATE utf8_general_ci ESCAPE '/'"
 
     def like_escape(self, text):
diff --git a/trac/db/postgres_backend.py b/trac/db/postgres_backend.py
--- a/trac/db/postgres_backend.py
+++ b/trac/db/postgres_backend.py
@@ -197,8 +197,9 @@
         return '||'.join(args)
 
     def like(self):
-        # Temporary hack needed for the case-insensitive string matching in the
-        # search module
+        return "LIKE %s ESCAPE '/'"
+
+    def ilike(self):
         return "ILIKE %s ESCAPE '/'"
 
     def like_escape(self, text):
diff --git a/trac/db/sqlite_backend.py b/trac/db/sqlite_backend.py
--- a/trac/db/sqlite_backend.py
+++ b/trac/db/sqlite_backend.py
@@ -194,6 +194,43 @@
             raise TracError("Backup attempt failed")
         return dest_file
 
+
+def _sqlite_like(p, s):
+    """Function to be used as `s LIKE p` operator in SQLite statements.
+    
+    >>> _sqlite_like('Starts with%', 'Starts with this')
+    True
+    >>> _sqlite_like('Starts with%', ' Starts with this')
+    False
+    >>> _sqlite_like('%ends with', '... ends with')
+    True
+    >>> _sqlite_like('%ends with', ' ends with ...')
+    False
+    >>> _sqlite_like('%contains%', 'This contains the pattern')
+    True
+    >>> _sqlite_like('%contains%', "This doesn't contain the pattern")
+    False
+    >>> _sqlite_like('This is the pattern', 'This is the pattern')
+    True
+    >>> _sqlite_like('This is the pattern', 'This is not the pattern')
+    False
+    >>> _sqlite_like('', 'Anything')
+    True
+    """
+    if not p:
+        return True
+    l = p[-1] == '%'
+    if p[0] == '%':
+        if l:
+            return p[1:-1] in s
+        else:
+            return s.endswith(p[1:])
+    elif l:
+        return s.startswith(p[:-1])
+    else:
+        return s == p
+
+
 class SQLiteConnection(ConnectionWrapper):
     """Connection wrapper for SQLite."""
 
@@ -226,6 +263,8 @@
         cnx = sqlite.connect(path, detect_types=sqlite.PARSE_DECLTYPES,
                              check_same_thread=sqlite_version < 30301,
                              timeout=timeout)
+        if sqlite_version >= 30100:
+            cnx.create_function('like', 2, _sqlite_like)
             
         ConnectionWrapper.__init__(self, cnx, log)
 
@@ -253,6 +292,9 @@
         return '||'.join(args)
 
     def like(self):
+        return "LIKE %s"
+
+    def ilike(self):
         if sqlite_version >= 30100:
             return "LIKE %s ESCAPE '/'"
         else:
diff --git a/trac/db/tests/__init__.py b/trac/db/tests/__init__.py
--- a/trac/db/tests/__init__.py
+++ b/trac/db/tests/__init__.py
@@ -1,7 +1,7 @@
 import unittest
 
 from trac.db.tests import api
-from trac.db.tests import postgres_test
+from trac.db.tests import postgres_test, sqlite_test
 
 from trac.db.tests.functional import functionalSuite
 
@@ -10,6 +10,7 @@
     suite = unittest.TestSuite()
     suite.addTest(api.suite())
     suite.addTest(postgres_test.suite())
+    suite.addTest(sqlite_test.suite())
     return suite
 
 if __name__ == '__main__':
diff --git a/trac/db/tests/api.py b/trac/db/tests/api.py
--- a/trac/db/tests/api.py
+++ b/trac/db/tests/api.py
@@ -108,10 +108,55 @@
         self.assertEqual([(u'<em>märkup</em>',)], cursor.fetchall())
 
 
+class LikeTestCase(unittest.TestCase):
+    
+    def setUp(self):
+        self.env = EnvironmentStub()
+    
+    def test_like(self):
+        db = self.env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.executemany("INSERT INTO system (name,value) VALUES (%s,%s)",
+                           [('name', 'value'), ('NAME', 'value')])
+        db.commit()
+        cursor.execute("SELECT name FROM system WHERE name %s" % db.like(),
+                       ('name',))
+        self.assertEqual(1, len(list(cursor)))
+        cursor.execute("SELECT name FROM system WHERE name %s" % db.like(),
+                       ('na%',))
+        self.assertEqual(1, len(list(cursor)))
+        cursor.execute("SELECT name FROM system WHERE name %s" % db.like(),
+                       ('%me',))
+        self.assertEqual(1, len(list(cursor)))
+        cursor.execute("SELECT name FROM system WHERE name %s" % db.like(),
+                       ('%am%',))
+        self.assertEqual(1, len(list(cursor)))
+
+    def test_ilike(self):
+        db = self.env.get_db_cnx()
+        cursor = db.cursor()
+        cursor.executemany("INSERT INTO system (name,value) VALUES (%s,%s)",
+                           [('like', 'value'), ('LIKE', 'value')])
+        db.commit()
+        cursor.execute("SELECT name FROM system WHERE name %s" % db.ilike(),
+                       ('like',))
+        self.assertEqual(2, len(list(cursor)))
+        cursor.execute("SELECT name FROM system WHERE name %s" % db.ilike(),
+                       ('li%',))
+        self.assertEqual(2, len(list(cursor)))
+        cursor.execute("SELECT name FROM system WHERE name %s" % db.ilike(),
+                       ('%ke',))
+        self.assertEqual(2, len(list(cursor)))
+        cursor.execute("SELECT name FROM system WHERE name %s" % db.ilike(),
+                       ('%ik%',))
+        self.assertEqual(2, len(list(cursor)))
+
+
 def suite():
     suite = unittest.TestSuite()
     suite.addTest(unittest.makeSuite(ParseConnectionStringTestCase, 'test'))
     suite.addTest(unittest.makeSuite(StringsTestCase, 'test'))
+    suite.addTest(unittest.makeSuite(LikeTestCase, 'test'))
     return suite
 
 if __name__ == '__main__':
diff --git a/trac/db/tests/sqlite_test.py b/trac/db/tests/sqlite_test.py
new file mode 100644
--- /dev/null
+++ b/trac/db/tests/sqlite_test.py
@@ -0,0 +1,26 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright (C) 2009 Edgewall Software
+# All rights reserved.
+#
+# This software is licensed as described in the file COPYING, which
+# you should have received as part of this distribution. The terms
+# are also available at http://trac.edgewall.org/wiki/TracLicense.
+#
+# This software consists of voluntary contributions made by many
+# individuals. For the exact contribution history, see the revision
+# history and logs, available at http://trac.edgewall.org/log/.
+
+import doctest
+import unittest
+
+import trac.db.sqlite_backend
+
+
+def suite():
+    suite = unittest.TestSuite()
+    suite.addTest(doctest.DocTestSuite(trac.db.sqlite_backend))
+    return suite
+
+if __name__ == '__main__':
+    unittest.main(defaultTest='suite')
diff --git a/trac/search/api.py b/trac/search/api.py
--- a/trac/search/api.py
+++ b/trac/search/api.py
@@ -47,7 +47,7 @@
     """
     assert columns and terms
 
-    likes = ['%s %s' % (i, db.like()) for i in columns]
+    likes = ['%s %s' % (i, db.ilike()) for i in columns]
     c = ' OR '.join(likes)
     sql = '(' + ') AND ('.join([c] * len(terms)) + ')'
     args = []
diff --git a/trac/ticket/query.py b/trac/ticket/query.py
--- a/trac/ticket/query.py
+++ b/trac/ticket/query.py
@@ -511,7 +511,7 @@
                         if not word:
                             continue
                     clauses.append("COALESCE(%s,'') %s%s" % (col, cneg,
-                                                             db.like()))
+                                                             db.ilike()))
                     args.append('%' + db.like_escape(word) + '%')
                 if not clauses:
                     return None
@@ -532,7 +532,7 @@
             elif mode == '$':
                 value = '%' + value
             return ("COALESCE(%s,'') %s%s" % (col, neg and 'NOT ' or '',
-                                              db.like()),
+                                              db.ilike()),
                     (value, ))
 
         def get_clause_sql(constraints):
diff --git a/trac/ticket/tests/query.py b/trac/ticket/tests/query.py
--- a/trac/ticket/tests/query.py
+++ b/trac/ticket/tests/query.py
@@ -210,7 +210,7 @@
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE ((COALESCE(t.owner,'') %(like)s))
-ORDER BY COALESCE(t.id,0)=0,t.id""" %  {'like': self.env.get_db_cnx().like()})
+ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().ilike()})
         self.assertEqual(['%someone%'], args)
         tickets = query.execute(self.req)
 
@@ -222,7 +222,7 @@
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE ((COALESCE(t.owner,'') NOT %(like)s))
-ORDER BY COALESCE(t.id,0)=0,t.id""" %  {'like': self.env.get_db_cnx().like()})
+ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().ilike()})
         self.assertEqual(['%someone%'], args)
         tickets = query.execute(self.req)
 
@@ -234,7 +234,7 @@
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE ((COALESCE(t.owner,'') %(like)s))
-ORDER BY COALESCE(t.id,0)=0,t.id""" %  {'like': self.env.get_db_cnx().like()})
+ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().ilike()})
         self.assertEqual(['someone%'], args)
         tickets = query.execute(self.req)
 
@@ -246,7 +246,7 @@
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE ((COALESCE(t.owner,'') %(like)s))
-ORDER BY COALESCE(t.id,0)=0,t.id""" %  {'like': self.env.get_db_cnx().like()})
+ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().ilike()})
         self.assertEqual(['%someone'], args)
         tickets = query.execute(self.req)
 
@@ -313,7 +313,7 @@
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE ((COALESCE(t.owner,'') %(like)s OR COALESCE(t.owner,'') %(like)s))
-ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().like()})
+ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().ilike()})
         tickets = query.execute(self.req)
 
     def test_constrained_by_empty_value_contains(self):
@@ -423,7 +423,7 @@
 FROM ticket AS t
   LEFT OUTER JOIN enum AS priority ON (priority.type='priority' AND priority.name=priority)
 WHERE (((COALESCE(t.keywords,'') %(like)s AND COALESCE(t.keywords,'') NOT %(like)s AND COALESCE(t.keywords,'') %(like)s)))
-ORDER BY COALESCE(t.id,0)=0,t.id"""  % {'like': self.env.get_db_cnx().like()})
+ORDER BY COALESCE(t.id,0)=0,t.id""" % {'like': self.env.get_db_cnx().ilike()})
         self.assertEqual(['%foo%', '%bar%', '%baz%'], args)
         tickets = query.execute(self.req)
 
diff --git a/trac/versioncontrol/cache.py b/trac/versioncontrol/cache.py
--- a/trac/versioncontrol/cache.py
+++ b/trac/versioncontrol/cache.py
@@ -299,12 +299,12 @@
             args.append(path)
             sql += " OR "
             # changes on path children
-            sql += "path "+db.like()
-            args.append(db.like_escape(path+'/') + '%')
+            sql += "path " + db.like()
+            args.append(db.like_escape(path + '/') + '%')
             sql += " OR "
             # deletion of path ancestors
             components = path.lstrip('/').split('/')
-            for i in range(1, len(components)+1):
+            for i in range(1, len(components) + 1):
                 args.append('/'.join(components[:i]))
             parent_insert = ','.join(('%s',) * len(components))
             sql += " (path in (" + parent_insert + ") and change_type='D')"

