From f1a8869339a4d6d004028c1234aaf706e420b5dd Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Mon, 21 Nov 2005 02:46:15 +0000 Subject: [PATCH] Fixed #800 -- Fixed bug in treatement of underscores and percent signs in SQLite backend. In order to do this, changed OPERATOR_MAPPING in DB backends to include a format string of the field value, because ESCAPE comes after the field value. git-svn-id: http://code.djangoproject.com/svn/django/trunk@1326 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/core/db/backends/ado_mssql.py | 26 ++++++++++++------------ django/core/db/backends/mysql.py | 26 ++++++++++++------------ django/core/db/backends/postgresql.py | 26 ++++++++++++------------ django/core/db/backends/sqlite3.py | 29 +++++++++++++++------------ django/core/meta/__init__.py | 2 +- 5 files changed, 56 insertions(+), 53 deletions(-) diff --git a/django/core/db/backends/ado_mssql.py b/django/core/db/backends/ado_mssql.py index 709d35a583..be215ed7e9 100644 --- a/django/core/db/backends/ado_mssql.py +++ b/django/core/db/backends/ado_mssql.py @@ -116,19 +116,19 @@ def get_relations(cursor, table_name): raise NotImplementedError OPERATOR_MAPPING = { - 'exact': '=', - 'iexact': 'LIKE', - 'contains': 'LIKE', - 'icontains': 'LIKE', - 'ne': '!=', - 'gt': '>', - 'gte': '>=', - 'lt': '<', - 'lte': '<=', - 'startswith': 'LIKE', - 'endswith': 'LIKE', - 'istartswith': 'LIKE', - 'iendswith': 'LIKE', + 'exact': '= %s', + 'iexact': 'LIKE %s', + 'contains': 'LIKE %s', + 'icontains': 'LIKE %s', + 'ne': '!= %s', + 'gt': '> %s', + 'gte': '>= %s', + 'lt': '< %s', + 'lte': '<= %s', + 'startswith': 'LIKE %s', + 'endswith': 'LIKE %s', + 'istartswith': 'LIKE %s', + 'iendswith': 'LIKE %s', } DATA_TYPES = { diff --git a/django/core/db/backends/mysql.py b/django/core/db/backends/mysql.py index 27d166f8d1..10379f9538 100644 --- a/django/core/db/backends/mysql.py +++ b/django/core/db/backends/mysql.py @@ -128,19 +128,19 @@ def get_relations(cursor, table_name): raise NotImplementedError OPERATOR_MAPPING = { - 'exact': '=', - 'iexact': 'LIKE', - 'contains': 'LIKE BINARY', - 'icontains': 'LIKE', - 'ne': '!=', - 'gt': '>', - 'gte': '>=', - 'lt': '<', - 'lte': '<=', - 'startswith': 'LIKE BINARY', - 'endswith': 'LIKE BINARY', - 'istartswith': 'LIKE', - 'iendswith': 'LIKE', + 'exact': '= %s', + 'iexact': 'LIKE %s', + 'contains': 'LIKE BINARY %s', + 'icontains': 'LIKE %s', + 'ne': '!= %s', + 'gt': '> %s', + 'gte': '>= %s', + 'lt': '< %s', + 'lte': '<= %s', + 'startswith': 'LIKE BINARY %s', + 'endswith': 'LIKE BINARY %s', + 'istartswith': 'LIKE %s', + 'iendswith': 'LIKE %s', } # This dictionary maps Field objects to their associated MySQL column diff --git a/django/core/db/backends/postgresql.py b/django/core/db/backends/postgresql.py index 03864a5707..487dd0da68 100644 --- a/django/core/db/backends/postgresql.py +++ b/django/core/db/backends/postgresql.py @@ -133,19 +133,19 @@ Database.register_type(Database.new_type((1114,1184), "TIMESTAMP", typecasts.typ Database.register_type(Database.new_type((16,), "BOOLEAN", typecasts.typecast_boolean)) OPERATOR_MAPPING = { - 'exact': '=', - 'iexact': 'ILIKE', - 'contains': 'LIKE', - 'icontains': 'ILIKE', - 'ne': '!=', - 'gt': '>', - 'gte': '>=', - 'lt': '<', - 'lte': '<=', - 'startswith': 'LIKE', - 'endswith': 'LIKE', - 'istartswith': 'ILIKE', - 'iendswith': 'ILIKE', + 'exact': '= %s', + 'iexact': 'ILIKE %s', + 'contains': 'LIKE %s', + 'icontains': 'ILIKE %s', + 'ne': '!= %s', + 'gt': '> %s', + 'gte': '>= %s', + 'lt': '< %s', + 'lte': '<= %s', + 'startswith': 'LIKE %s', + 'endswith': 'LIKE %s', + 'istartswith': 'ILIKE %s', + 'iendswith': 'ILIKE %s', } # This dictionary maps Field objects to their associated PostgreSQL column diff --git a/django/core/db/backends/sqlite3.py b/django/core/db/backends/sqlite3.py index 6fa49131ee..930bb7c290 100644 --- a/django/core/db/backends/sqlite3.py +++ b/django/core/db/backends/sqlite3.py @@ -131,20 +131,23 @@ def get_relations(cursor, table_name): # Operators and fields ######################################################## +# SQLite requires LIKE statements to include an ESCAPE clause if the value +# being escaped has a percent or underscore in it. +# See http://www.sqlite.org/lang_expr.html for an explanation. OPERATOR_MAPPING = { - 'exact': '=', - 'iexact': 'LIKE', - 'contains': 'LIKE', - 'icontains': 'LIKE', - 'ne': '!=', - 'gt': '>', - 'gte': '>=', - 'lt': '<', - 'lte': '<=', - 'startswith': 'LIKE', - 'endswith': 'LIKE', - 'istartswith': 'LIKE', - 'iendswith': 'LIKE', + 'exact': '= %s', + 'iexact': "LIKE %s ESCAPE '\\'", + 'contains': "LIKE %s ESCAPE '\\'", + 'icontains': "LIKE %s ESCAPE '\\'", + 'ne': '!= %s', + 'gt': '> %s', + 'gte': '>= %s', + 'lt': '< %s', + 'lte': '<= %s', + 'startswith': "LIKE %s ESCAPE '\\'", + 'endswith': "LIKE %s ESCAPE '\\'", + 'istartswith': "LIKE %s ESCAPE '\\'", + 'iendswith': "LIKE %s ESCAPE '\\'", } # SQLite doesn't actually support most of these types, but it "does the right diff --git a/django/core/meta/__init__.py b/django/core/meta/__init__.py index e6114449c1..b6a148bcf6 100644 --- a/django/core/meta/__init__.py +++ b/django/core/meta/__init__.py @@ -1127,7 +1127,7 @@ def _get_where_clause(lookup_type, table_prefix, field_name, value): table_prefix = db.db.quote_name(table_prefix[:-1])+'.' field_name = db.db.quote_name(field_name) try: - return '%s%s %s %%s' % (table_prefix, field_name, db.OPERATOR_MAPPING[lookup_type]) + return '%s%s %s' % (table_prefix, field_name, (db.OPERATOR_MAPPING[lookup_type] % '%s')) except KeyError: pass if lookup_type == 'in':