Escape path queries for SQLite

Fixes #1146
This commit is contained in:
Thomas Scholtes 2014-12-21 12:26:04 +01:00
parent 02e341cded
commit ec65408c3e
2 changed files with 28 additions and 4 deletions

View file

@ -39,6 +39,10 @@ log = logging.getLogger('beets')
class PathQuery(dbcore.FieldQuery):
"""A query that matches all items under a given path."""
escape_re = re.compile(r'[\\_%]')
escape_char = '\\'
def __init__(self, field, pattern, fast=True):
super(PathQuery, self).__init__(field, pattern, fast)
@ -52,10 +56,12 @@ class PathQuery(dbcore.FieldQuery):
item.path.startswith(self.dir_path)
def clause(self):
dir_pat = buffer(self.dir_path + '%')
escape = lambda m: self.escape_char + m.group(0)
dir_pattern = self.escape_re.sub(escape, self.dir_path)
dir_pattern = buffer(dir_pattern + '%')
file_blob = buffer(self.file_path)
return '({0} = ?) || ({0} LIKE ?)'.format(self.field), \
(file_blob, dir_pat)
return '({0} = ?) || ({0} LIKE ? ESCAPE ?)'.format(self.field), \
(file_blob, dir_pattern, self.escape_char)
# Library-specific field types.

View file

@ -332,7 +332,7 @@ class MatchTest(_common.TestCase):
self.assertFalse(q.match(self.item))
class PathQueryTest(_common.LibTestCase, AssertsMixin):
class PathQueryTest(_common.LibTestCase, TestHelper, AssertsMixin):
def setUp(self):
super(PathQueryTest, self).setUp()
self.i.path = '/a/b/c.mp3'
@ -389,6 +389,24 @@ class PathQueryTest(_common.LibTestCase, AssertsMixin):
results = self.lib.items(q)
self.assert_matched(results, ['path item'])
def test_escape_underscore(self):
self.add_item(path='/a/_/title.mp3', title='with underscore')
q = 'path:/a/_'
results = self.lib.items(q)
self.assert_matched(results, ['with underscore'])
def test_escape_percent(self):
self.add_item(path='/a/%/title.mp3', title='with percent')
q = 'path:/a/%'
results = self.lib.items(q)
self.assert_matched(results, ['with percent'])
def test_escape_backslash(self):
self.add_item(path=r'/a/\x/title.mp3', title='with backslash')
q = r'path:/a/\\x'
results = self.lib.items(q)
self.assert_matched(results, ['with backslash'])
class IntQueryTest(unittest.TestCase, TestHelper):