From 252606c711c644d427edf1a5a079d1029f1c6621 Mon Sep 17 00:00:00 2001 From: Adrian Holovaty Date: Wed, 27 Dec 2006 05:14:02 +0000 Subject: [PATCH] Fixed #3115 -- Changed postgresql backend to convert all Unicode strings to bytestrings according to DEFAULT_CHARSET. This is necessary because psycopg1 does not apply database quoting to Unicode strings git-svn-id: http://code.djangoproject.com/svn/django/trunk@4244 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/backends/postgresql/base.py | 33 +++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/django/db/backends/postgresql/base.py b/django/db/backends/postgresql/base.py index e44bc0b560..20dd1dc2da 100644 --- a/django/db/backends/postgresql/base.py +++ b/django/db/backends/postgresql/base.py @@ -20,6 +20,38 @@ except ImportError: # Import copy of _thread_local.py from Python 2.4 from django.utils._threading_local import local +def smart_basestring(s, charset): + if isinstance(s, unicode): + return s.encode(charset) + return s + +class UnicodeCursorWrapper(object): + """ + A thin wrapper around psycopg cursors that allows them to accept Unicode + strings as params. + + This is necessary because psycopg doesn't apply any DB quoting to + parameters that are Unicode strings. If a param is Unicode, this will + convert it to a bytestring using DEFAULT_CHARSET before passing it to + psycopg. + """ + def __init__(self, cursor, charset): + self.cursor = cursor + self.charset = charset + + def execute(self, sql, params=()): + return self.cursor.execute(sql, [smart_basestring(p, self.charset) for p in params]) + + def executemany(self, sql, param_list): + new_param_list = [[smart_basestring(p, self.charset) for p in params] for params in param_list] + return self.cursor.executemany(sql, new_param_list) + + def __getattr__(self, attr): + if self.__dict__.has_key(attr): + return self.__dict__[attr] + else: + return getattr(self.cursor, attr) + class DatabaseWrapper(local): def __init__(self, **kwargs): self.connection = None @@ -45,6 +77,7 @@ class DatabaseWrapper(local): self.connection.set_isolation_level(1) # make transactions transparent to all cursors cursor = self.connection.cursor() cursor.execute("SET TIME ZONE %s", [settings.TIME_ZONE]) + cursor = UnicodeCursorWrapper(cursor, settings.DEFAULT_CHARSET) if settings.DEBUG: return util.CursorDebugWrapper(cursor, self) return cursor