[storm] What's the best way to handle Python Boolean values with Oracle?
Jason Baker
jbaker at zeomega.com
Tue Jun 23 16:15:23 BST 2009
On Tue, Jun 23, 2009 at 9:30 AM, Drew Smathers<drew.smathers at gmail.com> wrote:
> On Tue, Jun 23, 2009 at 5:16 AM, James Henstridge<james at jamesh.id.au> wrote:
>> On Mon, Jun 22, 2009 at 11:44 PM, Jason Baker<jbaker at zeomega.com> wrote:
>>> There are two tests left that are giving me trouble:
>>>
>>> def test_is_in_empty_result_set(self):
>>> result1 = self.store.find(Foo, Foo.id < 10)
>>> result2 = self.store.find(Foo, Or(Foo.id > 20, Foo.id.is_in(result1)))
>>> self.assertEquals(result2.count(), 1)
>>>
>>> def test_is_in_empty_list(self):
>>> result2 = self.store.find(Foo, Eq(False, And(True, Foo.id.is_in([]))))
>>> self.assertEquals(result2.count(), 3)
>>>
>>> Both of these tests pass a Python Boolean to the backend. The problem
>>> is that these both pass a boolean value in the WHERE clause, which
>>> there's really not any direct translation for in Oracle. I tried it
>>> with this compile function:
>>>
>>> @compile.when(bool)
>>> def compile_bool(compile, expr, state):
>>> return compile_eq(compile, Eq(1, int(expr)), state)
>>>
>>> This essentially converts a bool to a 1=1 or 1=0 expression. This
>>> works with the first test, but the second one gives me this:
>>>
>>> [10:27:38.064000] EXECUTE: 'SELECT COUNT(*) FROM foo WHERE 1 = 0 = (1
>>> = 1 AND 1 = 0)', (1, 0, 1, 1, 1, 0)
>>> [10:27:38.111000] ERROR: ORA-00933: SQL command not properly ended
>>>
>>> Which is of course gibberish in Oracle. I can run the test without a
>>> WHERE clause and have it work, but will anything break if the backend
>>> can't handle an expression of the form FALSE = (TRUE AND FALSE)? Or
>>> is there a better way to do this that I'm missing?
>>
>> If this is just a case of parentheses, it might be easiest to do the following:
>>
>> @compile.when(bool)
>> def compile_bool(compile, expr, state):
>> if expr:
>> return "(1=1)"
>> else:
>> return "(1=0)"
>>
>> That should avoid the operator precedence problems.
>>
>> James.
>>
>
> The problem is more than operator precendence with Oracle; Oracle
> simply doesn't have a boolean type (outside of PL/SQL) and can't
> understand a boolean comparison: (1=0) = (1=1). This would result in
> an ORA-00933. In that respect, I don't see how it's possible to make
> test_is_in_empty_list pass since it involves a boolean comparison.
> Given that boolean data type is optional in the SQL spec, would it not
> be sufficient to skip this test for oracle?
>
> -Drew
>
I don't think it's necessary to skip the test altogether. The problem
as I see it is in this function (storm/expr.py line 479 in trunk):
def is_in(self, others):
if not isinstance(others, Expr):
others = list(others)
if not others:
return False
variable_factory = getattr(self, "variable_factory", Variable)
for i, other in enumerate(others):
if not isinstance(other, (Expr, Variable)):
others[i] = variable_factory(value=other)
return In(self, others)
Or more specifically, these lines:
if not others:
return False
Thus, it makes sense to test that the back end can handle this kind of
value. However, I think a case can be made that the test as written
is a bit overreaching. This is because it not only tests that the
back end can handle receiving a False value from this function, but
also that it can handle an expression FALSE = (TRUE AND FALSE). I can
get the test to pass if it were changed to this:
def test_is_in_empty_list(self):
result2 = self.store.find(Foo, Foo.id.is_in([]))
self.assertEquals(result2.count(), 0)
...which is a more focused (and I would argue better) test. However,
is there any other code which may require more advanced boolean
handling to even worry about *having* a test for FALSE = (TRUE AND
FALSE)? I'm no SQL guru, but I don't see that as being a very common
SQL Statement.
Jason
More information about the storm
mailing list