I have this working code:
extern crate rusqlite;
use rusqlite::Connection;
fn main() {
let conn = Connection::open("db.sqlite").unwrap();
conn.execute("CREATE TABLE toto (size INTEGER NOT NULL DEFAULT 0);", &[]).unwrap();
conn.execute("INSERT INTO toto(size) VALUES (42);", &[]).unwrap();
let filter = 0;
let i: i64 = conn.query_row("SELECT SUM(size) FROM toto", &[], |r| r.get(0)).unwrap();
println!("Coucou");
println!("Coucou: {}", i);
}
But if I switch
"SELECT SUM(size) FROM toto", &[]
to
"SELECT SUM(size) FROM toto WHERE size=?1", &[&filter]
and re-run, it panics:
rm db.sqlite
RUST_BACKTRACE=1 cargo run
Finished dev [unoptimized + debuginfo] target(s) in 0.0 secs
Running `target/debug/testsqlite`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: InvalidColumnType(0, Null)', /checkout/src/libcore/result.rs:860
If I execute this query in sqliteman, it works, so why does rusqlite panic?
If I run your query directly in the sqlite
command line utility, there is no value, the result is NULL
:
sqlite> SELECT SUM(size) FROM toto WHERE size=42;
sqlite> SELECT coalesce(SUM(size), 'NULL!') FROM toto WHERE size=42;
NULL!
sqlite>
Since there are no rows matching the where clause, the sum is NULL:
If there are no non-NULL input rows then sum() returns NULL but total() returns 0.0
Your NULL
result cannot be converted to an i64
, so you get an error:
InvalidColumnType(0, Null)
If you print that error out, it says the same thing:
let i: i64 = conn.query_row("SELECT SUM(size) FROM toto WHERE size = ?1", &[&filter], |r| {
match r.get_checked(0) {
Ok(v) => v,
Err(e) => panic!("query_row error: {}", e),
}
}).expect("select failed");
query_row error: Invalid column type Null at index: 0
Fixing it Rust-side
If you update your code to account for a NULL
by using an Option
, it will correctly execute:
let i: Option<i64> = conn.query_row(
"SELECT SUM(size) FROM toto WHERE size = ?1",
&[&filter],
|r| r.get(0)
).expect("select failed");
You can then use i.unwrap_or(0)
.
Fixing it SQL-side with TOTAL
let i: f64 = conn.query_row(
"SELECT TOTAL(size) FROM toto WHERE size = ?1",
&[&filter],
|r| r.get(0)
).expect("select failed");
Note that we switched to a f64
.
Fixing it SQL-side with COALESCE
let i: i64 = conn.query_row(
"SELECT COALESCE(SUM(size), 0) FROM toto WHERE size = ?1",
&[&filter],
|r| r.get(0)
).expect("select failed");