Rusqlite `Connection` and `Statement` lifetimes issue
⚓ Rust 📅 2026-02-16 👤 surdeus 👁️ 1I have the following code
let mut stmt = unwrap!(
conn.prepare_cached("SELECT EXISTS(SELECT 1 FROM users WHERE name = ?1);"),
|err| {
return Err((conn, db::Error::Rusqlite(err)));
},
);
let res = unwrap!(
stmt.query_row([&name], |row| row.get::<_, bool>(0)),
|err| {
return Err((conn, db::Error::Rusqlite(err)));
},
);
Ok((conn, res))
(unwrap! is just a shortcut for match x { Ok(x) => x, Err($err) => $action })
which basically runs the query and on success returns the connection to be reused and result, and on errors returns the connection and error.
The code does not compile
error[E0505]: cannot move out of `conn` because it is borrowed
--> src/main.rs:449:33
|
428 | async fn db_manager(mut cmd_rx: db::CmdRx, mut conn: Connection) {
| -------- binding `conn` declared here
...
447 | conn.prepare_cached("SELECT EXISTS(SELECT 1 FROM users WHERE name = ?1);"),
| --------------------------------------------------------------------------
| |
| borrow of `conn` occurs here
| a temporary with access to the borrow is created here ...
448 | |err| {
449 | return Err((conn, db::Error::Rusqlite(err)));
| ^^^^ move out of `conn` occurs here
450 | },
451 | );
| - ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Result<CachedStatement<'_>, rusqlite::Error>`
error[E0505]: cannot move out of `conn` because it is borrowed
--> src/main.rs:456:33
|
428 | async fn db_manager(mut cmd_rx: db::CmdRx, mut conn: Connection) {
| -------- binding `conn` declared here
...
447 | conn.prepare_cached("SELECT EXISTS(SELECT 1 FROM users WHERE name = ?1);"),
| ---- borrow of `conn` occurs here
...
456 | return Err((conn, db::Error::Rusqlite(err)));
| ^^^^ move out of `conn` occurs here
...
461 | })
| - borrow might be used here, when `stmt` is dropped and runs the `Drop` code for type `CachedStatement`
error[E0505]: cannot move out of `conn` because it is borrowed
--> src/main.rs:460:21
|
428 | async fn db_manager(mut cmd_rx: db::CmdRx, mut conn: Connection) {
| -------- binding `conn` declared here
...
447 | conn.prepare_cached("SELECT EXISTS(SELECT 1 FROM users WHERE name = ?1);"),
| ---- borrow of `conn` occurs here
...
460 | Ok((conn, res))
| ^^^^ move out of `conn` occurs here
461 | })
| - borrow might be used here, when `stmt` is dropped and runs the `Drop` code for type `CachedStatement`
For more information about this error, try `rustc --explain E0505`.
error: could not compile `db-server` (bin "db-server") due to 3 previous errors
so I add a few drop()s
let mut stmt = unwrap!(
conn.prepare_cached("SELECT EXISTS(SELECT 1 FROM users WHERE name = ?1);"),
|err| {
return Err((conn, db::Error::Rusqlite(err)));
},
);
let res = unwrap!(
stmt.query_row([&name], |row| row.get::<_, bool>(0)),
|err| {
drop(stmt);
return Err((conn, db::Error::Rusqlite(err)));
},
);
drop(stmt);
Ok((conn, res))
but it still does not compile
error[E0505]: cannot move out of `conn` because it is borrowed
--> src/main.rs:449:33
|
428 | async fn db_manager(mut cmd_rx: db::CmdRx, mut conn: Connection) {
| -------- binding `conn` declared here
...
447 | conn.prepare_cached("SELECT EXISTS(SELECT 1 FROM users WHERE name = ?1);"),
| --------------------------------------------------------------------------
| |
| borrow of `conn` occurs here
| a temporary with access to the borrow is created here ...
448 | |err| {
449 | return Err((conn, db::Error::Rusqlite(err)));
| ^^^^ move out of `conn` occurs here
450 | },
451 | );
| - ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Result<CachedStatement<'_>, rusqlite::Error>`
For more information about this error, try `rustc --explain E0505`.
error: could not compile `db-server` (bin "db-server") due to 1 previous error
so I think of moving the call to a variable so that I can drop it in the error path
let stmt =
conn.prepare_cached("SELECT EXISTS(SELECT 1 FROM users WHERE name = ?1);");
let mut stmt = unwrap!(stmt, |err| {
drop(stmt);
return Err((conn, db::Error::Rusqlite(err)));
});
let res = unwrap!(
stmt.query_row([&name], |row| row.get::<_, bool>(0)),
|err| {
drop(stmt);
return Err((conn, db::Error::Rusqlite(err)));
},
);
drop(stmt);
Ok((conn, res))
different errors than the first attempt
error[E0382]: use of partially moved value: `stmt`
--> src/main.rs:450:24
|
449 | let mut stmt = unwrap!(stmt, |err| {
| --- value partially moved here
450 | drop(stmt);
| ^^^^ value used here after partial move
|
= note: partial move occurs because value has type `rusqlite::Error`, which does not implement the `Copy` trait
help: borrow this binding in the pattern to avoid moving the value
|
449 | let mut stmt = unwrap!(stmt, |ref err| {
| +++
error[E0505]: cannot move out of `conn` because it is borrowed
--> src/main.rs:458:33
|
428 | async fn db_manager(mut cmd_rx: db::CmdRx, mut conn: Connection) {
| -------- binding `conn` declared here
...
447 | conn.prepare_cached("SELECT EXISTS(SELECT 1 FROM users WHERE name = ?1);");
| ---- borrow of `conn` occurs here
...
458 | return Err((conn, db::Error::Rusqlite(err)));
| ^^^^ move out of `conn` occurs here
...
464 | })
| - borrow might be used here, when `stmt` is dropped and runs the destructor for type `Result<CachedStatement<'_>, rusqlite::Error>`
error[E0505]: cannot move out of `conn` because it is borrowed
--> src/main.rs:463:21
|
428 | async fn db_manager(mut cmd_rx: db::CmdRx, mut conn: Connection) {
| -------- binding `conn` declared here
...
447 | conn.prepare_cached("SELECT EXISTS(SELECT 1 FROM users WHERE name = ?1);");
| ---- borrow of `conn` occurs here
...
463 | Ok((conn, res))
| ^^^^ move out of `conn` occurs here
464 | })
| - borrow might be used here, when `stmt` is dropped and runs the destructor for type `Result<CachedStatement<'_>, rusqlite::Error>`
Some errors have detailed explanations: E0382, E0505.
For more information about an error, try `rustc --explain E0382`.
error: could not compile `db-server` (bin "db-server") due to 3 previous errors
No matter what I tried I could not solve it. I do not understand why I cannot return conn in the error path as in that case nothing is borrowing it
5 posts - 2 participants
🏷️ Rust_feed