diff --git a/ldapdb/backends/ldap/compiler.py b/ldapdb/backends/ldap/compiler.py index 1d9e771..970b081 100644 --- a/ldapdb/backends/ldap/compiler.py +++ b/ldapdb/backends/ldap/compiler.py @@ -15,7 +15,8 @@ from ldapdb.models.fields import ListField _ORDER_BY_LIMIT_OFFSET_RE = re.compile( - r'(?:\bORDER BY\b\s+(.+?))?\s*(?:\bLIMIT\b\s+(-?\d+))?\s*(?:\bOFFSET\b\s+(\d+))?$') + r"(?:\bORDER BY\b\s+([\w\.]+)\s(?P\bASC\b)|(\bDESC\b))\s{1,2}(?:\bLIMIT\b\s+(?P-?\d+))?[\)\s]?(?:\bOFFSET\b\s+(?P(\d+)))?" # noqa: E501 +) class LdapDBError(Exception): @@ -146,12 +147,13 @@ def execute_sql(self, result_type=compiler.SINGLE, chunked_fetch=False, if hasattr(self.query, 'subquery') and self.query.subquery: sql = self.query.subquery m = _ORDER_BY_LIMIT_OFFSET_RE.search(sql) - limit = m.group(2) - offset = m.group(3) - if limit and int(limit) >= 0: - output.append(int(limit)) - elif offset: - output.append(len(vals) - int(offset)) + if m: + limit = m.group('limit') + offset = m.group('offset') + if limit and int(limit) >= 0: + output.append(int(limit)) + elif offset: + output.append(len(vals) - int(offset)) else: output.append(len(vals)) else: diff --git a/ldapdb/tests.py b/ldapdb/tests.py index 2aca0a0..8929126 100644 --- a/ldapdb/tests.py +++ b/ldapdb/tests.py @@ -246,3 +246,32 @@ def test_or(self): where.add(self._build_lookup("cn", 'exact', "foo", field=fields.CharField), AND) where.add(self._build_lookup("givenName", 'exact', "bar", field=fields.CharField), OR) self.assertEqual(self._where_as_ldap(where), "(|(cn=foo)(givenName=bar))") + + +class CompilerRegexTestCase(TestCase): + + def _run_regex(self, sql): + match = ldapdb_compiler._ORDER_BY_LIMIT_OFFSET_RE.search(sql) + self.assertIsNotNone(match) + return match + + def test_regex(self): + sql = "SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT 2" # noqa: E501 + match = self._run_regex(sql) + self.assertEqual(match.group('limit'), '2') + self.assertEqual(match.group('offset'), None) + + sql = "SELECT COUNT(*) FROM (SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT 2) subquery" # noqa: E501 + match = self._run_regex(sql) + self.assertEqual(match.group('limit'), '2') + + sql = "SELECT COUNT(*) FROM (SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT -1 OFFSET 1) subquery" # noqa: E501 + match = self._run_regex(sql) + self.assertEqual(match.group('limit'), '-1') + self.assertEqual(match.group('offset'), '1') + + def test_regex_django22(self): + sql = "SELECT examples_ldapgroup.cn AS Col1 FROM examples_ldapgroup ORDER BY examples_ldapgroup.gidNumber ASC LIMIT 2" # noqa: E501 + match = self._run_regex(sql) + self.assertEqual(match.group('limit'), '2') + self.assertEqual(match.group('offset'), None)