From a0dbe3a95b86e153a444719ed9d3d24ec40d5be7 Mon Sep 17 00:00:00 2001 From: Jason Madden Date: Thu, 27 Aug 2020 12:02:05 -0500 Subject: [PATCH] Fix an AttributeError if a persistent site manager is installed and is a ghost and it's the first time the connection makes a load query. We don't need to adapt the query object to ITypedParams anyway, just check if it's implemented or not. --- CHANGES.rst | 5 +++++ src/relstorage/adapters/sql/dialect.py | 20 +++++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/CHANGES.rst b/CHANGES.rst index 9213ae8d..5153efff 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -18,6 +18,11 @@ variable ``RS_CACHE_POLL_TIMEOUT`` to a number of seconds before importing RelStorage to use this. +- Avoid an ``AttributeError`` if a persistent ``zope.component`` site + manager is installed as the current site, it's a ghost, and we're + making a load query for the first time in a particular connection. + See :issue:`411`. + 3.2.0 (2020-07-20) ================== diff --git a/src/relstorage/adapters/sql/dialect.py b/src/relstorage/adapters/sql/dialect.py index 76fceff9..815de1cb 100644 --- a/src/relstorage/adapters/sql/dialect.py +++ b/src/relstorage/adapters/sql/dialect.py @@ -177,11 +177,21 @@ def _quote_query_for_prepare(self, query): def _find_datatypes_for_prepared_query(self): # Deduce the datatypes based on the types of the columns # we're sending as params. - result = () - param_provider = ITypedParams(self.root, None) - if param_provider is not None: - result = param_provider.datatypes_for_parameters() # pylint:disable=assignment-from-no-return - return result + root = self.root + if ITypedParams.providedBy(root): + # Don't call the interface to adapt; that uses adapter + # hooks, which may be persistent objects and thus result + # in calling back into this method (if the query we're + # compiling for the first time is the load object query, + # and the site manager itself is a ghost). + # + # Since we don't actually expect to have any adapters, + # just an object (Insert or a subclass) that already + # provides the interface, all we need to do is check to + # see if it's provided; we don't need to query an adapter. + # See https://github.com/zodb/relstorage/issues/411 + return root.datatypes_for_parameters() + return () def prepare(self): # This is correct for PostgreSQL. This needs moved to a dialect specific