Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upOur type system can panic when comparing nullable values #104
Comments
This comment has been minimized.
|
I've raised questions on the specialization RFC related to this. I think the real answer under specialization might involve adding a impl<T, U> Expression for Eq<T, U> where
T: Expression,
U: Expression<SqlType=T::SqlType>,
T::SqlType: NotNull,
{
type SqlType = Bool;
fn to_sql(...) { ... }
}
impl<T, U> Expression for Eq<T, U> where
T: Expression,
U: Expression<SqlType=T::SqlType>,
T::SqlType: IsNullable,
{
type SqlType = Nullable<Bool>;
fn to_sql(...) { // identical to previous }
}
impl<T, U> Expression for Eq<T, U> where
T: Expression,
U: Expression<SqlType=T::SqlType>,
T::SqlType: IsNullable + NotNull,
{
type SqlType = ();
fn to_sql(...) { unreachable!("No type should impl NotNull and IsNullable"); }
} |
This comment has been minimized.
|
As I think through this, I'm becoming more confident that this problem is scoped entirely too booleans coming from infix predicates. While technically you can run into the same problem with Given the idea of "truthy"/"falsey" in other languages, I think that treating As a side note, if we ignore other backends, this problem is not solved by just mapping I'm starting to become amicable to this over a solution which changes the type to Other cases where this does apply in SQL are essentially functions, and operators like |
This comment has been minimized.
|
Interesting point from IRC: We could actually handle |
sgrif
added
the
bug
label
Jan 17, 2016
sgrif
added this to the 1.0 milestone
Jan 17, 2016
This comment has been minimized.
|
I've decided to pull the trigger on treating We should continue to keep an eye on this and make sure it cannot manifest itself for any types other than I believe we might be able to fix this with specialization by specializing impl<T, U, QS, ST> SelectableExpression<QS, Bool> for Eq<T, U> where
ST: NotNull,
T: SelectableExpression<QS, ST>,
U: SelectableExpression<QS, ST>,
{
}impl<T, U, QS, ST> SelectableExpression<QS, Nullable<Bool>> for Eq<T, U> where
ST: NotNull,
T: SelectableExpression<QS, Nullable<ST>>,
U: SelectableExpression<QS, Nullable<ST>>,
{
} |
sgrif commentedJan 17, 2016
I should note that this is relatively hard to actually demonstrate in normal code. The issue here is that
x = NULLin SQL returnsNULL. I've managed to distill it into the following test case:The query here is ultimately
The problem is that the sql type of
Eq<T, U>is alwaysBool, and so we panic on an "unexpected null value" when trying to read it. We need to have the type ofEq<Nullable<T>, Nullable<U>>to beNullable<Bool>.I should also note that this only applies to these sorts of expressions appearing in a select clause. It does not affect us in places like
whereclauses. Also as an aside, in places like where clauses,NULLis effectively the same asfalsewhich is part of why I'm leaning towards the second answer.There are basically two answers here:
Nullable<Bool>where appropriate. This will almost certainly require specialization, and I'm not actually sure that specialization as proposed today will suffice.impl FromSql<Bool> for booltreatNULLasfalse. I'm actually fine with this, if we can be sure that infix predicates which would otherwise return a boolean are the only case where null can bubble up like this. It should be noted that this problem applies to all infix predicates, not just=. This also applies to>andANDfor example.