Slicing a ResultSet breaks subsequent count() calls.
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
Storm |
Fix Released
|
High
|
Thomas Herve |
Bug Description
After making an optimization to lazr.batchnavigator I was blindsided by this backtrace in a Launchpad test:
File "/home/
if self.start >= self.listlength:
File "/home/
value = func(inst)
File "/home/
File "/home/
return len(results)
File "/home/
return self.context.
File "/home/
return int(self.
File "/home/
subquery = replace_
File "/home/
FeatureError: __contains__() does not yet support set expressions that combine ORDER BY with LIMIT/OFFSET
It would be nice if this query worked; it would let us use the batchnavigator optimization in Launchpad. As it is, I'm afraid to use that optimization because I'm afraid it'll cause OOPSes on Launchpad. (Yesterday I was able to get OOPSes on Launchpad with simple web service requests, which is why I'm scrambling to undo the optimization, but today it seems to be working.)
I'm very inexperienced with Storm and I can't figure out how to find the specific SQL query that is causing the problem. To me it looks like a complicated data structure with no string representation. I'm also not sure why a 'count' query even needs a LIMIT or OFFSET--seems like that could be stripped at some level.
Presumably this feature isn't supported because it's difficult to implement; but there must be other solutions to my problem besides just making this code work. I'd appreciate some advice on how to avoid this problem, and I'll provide whatever information you ask for.
Related branches
- Gustavo Niemeyer: Approve
- Jamu Kakar (community): Approve
-
Diff: 39 lines (+19/-0)2 files modifiedstorm/store.py (+4/-0)
tests/store/base.py (+15/-0)
summary: |
- "__contains__() does not yet support set expressions that combine ORDER - BY with LIMIT/OFFSET" + Slicing a ResultSet breaks subsequent len() calls. |
Changed in storm: | |
importance: | Undecided → High |
milestone: | none → 0.18 |
status: | New → Triaged |
summary: |
- Slicing a ResultSet breaks subsequent len() calls. + Slicing a ResultSet breaks subsequent count() calls. |
Changed in storm: | |
assignee: | nobody → Thomas Herve (therve) |
Changed in storm: | |
status: | Triaged → Fix Committed |
Changed in storm: | |
status: | Fix Committed → Fix Released |
OK, here is my real problem. 'foo' is a complex ResultSet.
>>> len(foo)
9
>>> tmp = foo[1:3]
>>> len(foo)
Traceback (most recent call last):
...
FeatureError: __contains__() does not yet support set expressions that combine ORDER BY with LIMIT/OFFSET
Here's the problem. When I slice the ResultSet, ResultSet. __getitem_ _ makes a copy of the ResultSet and configures the copy with the desired offset and limit. But the original and the copy share the same .select member. (This is an object from the storm.expr module.) When I call len(foo), ._select.limit and ._select.offset are populated for both the original and the copy.
When I call len() the second time. some code in _get_select() runs that looks like it should normalize the data.
if self._select is not Undef:
self. _select. order_by = self._order_by
self. _select. limit = self._limit
self. _select. offset = self._offset
if self._order_by is not Undef:
if self._limit is not Undef: # XXX UNTESTED!
if self._offset is not Undef: # XXX UNTESTED!
return self._select
But it doesn't work in this case. This code only overrides .limit or .offset if the new value is not Undef. So if I slice the list again:
>>> tmp2 = foo[1:6]
The old .limit '2' will be replaced by '5' and I will get the correct slice. But when I call len(), the new limit is Undef, so the old value for .limit is left in place, and I get the FeatureError.
There are two solutions. Either change _get_select() to override a non-Undef value with Undef, or change the copy() operation to copy ._select.