From 3dfbaae32b2e87fd1f47b569f973fb3f76602137 Mon Sep 17 00:00:00 2001 From: Malcolm Tredinnick Date: Fri, 24 Oct 2008 09:36:22 +0000 Subject: [PATCH] Fixed #9307 -- Added the ability to pickle the Query class used by the Oracle backend. This allows Querysets to be cached for Oracle and should provide a model for adding pickling support to other (external) database backends that need a custom Query class. Thanks to Justin Bronn for some assistance with this patch. git-svn-id: http://code.djangoproject.com/svn/django/trunk@9272 bcc190cf-cafb-0310-a4f2-bffc1f526a37 --- django/db/backends/oracle/query.py | 26 ++++++++++++++++++++++++++ django/db/models/sql/query.py | 8 +++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/django/db/backends/oracle/query.py b/django/db/backends/oracle/query.py index 6935f2c681..de169d6901 100644 --- a/django/db/backends/oracle/query.py +++ b/django/db/backends/oracle/query.py @@ -25,6 +25,18 @@ def query_class(QueryClass, Database): pass class OracleQuery(QueryClass): + def __reduce__(self): + """ + Enable pickling for this class (normal pickling handling doesn't + work as Python can only pickle module-level classes by default). + """ + if hasattr(QueryClass, '__getstate__'): + assert hasattr(QueryClass, '__setstate__') + data = self.__getstate__() + else: + data = self.__dict__ + return (unpickle_query_class, (QueryClass,), data) + def resolve_columns(self, row, fields=()): # If this query has limit/offset information, then we expect the # first column to be an extra "_RN" column that we need to throw @@ -120,3 +132,17 @@ def query_class(QueryClass, Database): _classes[QueryClass] = OracleQuery return OracleQuery + +def unpickle_query_class(QueryClass): + """ + Utility function, called by Python's unpickling machinery, that handles + unpickling of Oracle Query subclasses. + """ + # XXX: Would be nice to not have any dependency on cx_Oracle here. Since + # modules can't be pickled, we need a way to know to load the right module. + import cx_Oracle + + klass = query_class(QueryClass, cx_Oracle) + return klass.__new__(klass) +unpickle_query_class.__safe_for_unpickling__ = True + diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index ee63a0214f..3381b602b4 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -27,9 +27,9 @@ try: except NameError: from sets import Set as set # Python 2.3 fallback -__all__ = ['Query'] +__all__ = ['Query', 'BaseQuery'] -class Query(object): +class BaseQuery(object): """ A single SQL query. """ @@ -1757,7 +1757,9 @@ class Query(object): # Use the backend's custom Query class if it defines one. Otherwise, use the # default. if connection.features.uses_custom_query_class: - Query = connection.ops.query_class(Query) + Query = connection.ops.query_class(BaseQuery) +else: + Query = BaseQuery def get_order_dir(field, default='ASC'): """