Comment 4 for bug 627442

Revision history for this message
Gary Poster (gary) wrote :

The sqlobject code that failed was in this method:

    def count(self):
        result_set = self._without_prejoins()._result_set
        return result_set.count()

The fix for non-sqlobject storm was in lib/canonical/launchpad/webapp/batching.py :

 49 resultset = removeSecurityProxy(self.context)
 50 if hasattr(resultset, '_select'):
 51 resultset._select.limit = Undef
 52 resultset._select.offset = Undef
 53 return self.context.count()

Therefore, naively, assuming the _select hack was the best we could do, until the Storm bug is fixed I think we need to sniff for sqlobject. Something on the order of the following might work.

# XXX The following code hacks around Storm bug 620508.
resultset = removeSecurityProxy(self.context)
if isinstance(resultset, storm.sqlobject.SQLObjectResultSet):
    # It is particularly annoying to handle the Storm bug here
    # because it requires fixing up a wrapped object.
    if zope.proxy.queryProxy(self.context, zope.security.proxy.Proxy):
        # This is a security-proxied object.
        # We need to manually check whether it is OK to access count,
        # because we are going to bypass the whole shebang.
        checker = zope.security.checker.getChecker(self.context)
        # This will raise the appropriate error if the checker would not
        # have allowed access.
        checker.checker.check_getattr(self.context, 'count')
    context = resultset._without_prejoins() # This is not proxied.
    resultset = context
else:
    context = self.context # This is proxied.
if getattr(resultset, '_select', None) is None: # hasattr swallows exceptions.
    resultset._select.limit = Undef
    resultset._select.offset = Undef
return context.count()

Now the questions are, (a) does anyone agree with me, and (b) how do we test this?