0
votes

This is my code

extern crate postgres;

use postgres::{Connection, SslMode};

struct User {
    reference: String,
    email: String
}

static DB_URI: &'static str = "postgres://postgres:postgres@localhost/test";

fn main() {

    let conn = Connection::connect(DB_URI, &SslMode::None).unwrap();
    let trans = conn.transaction().unwrap();

    let user = User {
        reference: "123abc".to_string(),
        email: "[email protected]".to_string()
    };

    let result = insert_user(&trans, &user);

    trans.set_commit();
    trans.finish();

}

fn insert_user<'_>(trans: &postgres::Transaction<'_>, user: &User) -> postgres::Result<postgres::rows::Rows<'_>> {
    let query = "INSERT INTO usr (reference, email) VALUES ($1, $2)";
    trans.prepare(query).unwrap().query(&[&user.reference, &user.email])
}

It's producing an error:

src/main.rs:31:2: 31:31 error: borrowed value does not live long enough
src/main.rs:31  trans.prepare(query).unwrap().query(&[&user.reference, &user.email])
                ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~
src/main.rs:29:114: 32:2 note: reference must be valid for the lifetime '_ as defined on the block at 29:113...
src/main.rs:29 fn insert_user<'_>(trans: &postgres::Transaction<'_>, user: &User) -> postgres::Result<postgres::rows::Rows<'_>> {
src/main.rs:30  let query = "INSERT INTO usr (reference, email) VALUES ($1, $2)";
src/main.rs:31  trans.prepare(query).unwrap().query(&[&user.reference, &user.email])
src/main.rs:32 }
src/main.rs:29:114: 32:2 note: ...but borrowed value is only valid for the block at 29:113
src/main.rs:29 fn insert_user<'_>(trans: &postgres::Transaction<'_>, user: &User) -> postgres::Result<postgres::rows::Rows<'_>> {
src/main.rs:30  let query = "INSERT INTO usr (reference, email) VALUES ($1, $2)";
src/main.rs:31  trans.prepare(query).unwrap().query(&[&user.reference, &user.email])
src/main.rs:32 }
error: aborting due to previous error
Could not compile `test`.

What is the problem here?

1
There are many questions here with the same error. Please show that you have done the required legwork and explain how this is different than existing questions.Shepmaster

1 Answers

3
votes

I believe the problem is here:

fn insert_user<'a>(trans: &postgres::Transaction<'a>, user: &User) -> postgres::Result<postgres::rows::Rows<'a>> {

(I've changed the lifetime parameter name to some usual one)

Here you are stating that lifetime in Rows parameter in the result should be the same as the lifetime in Transaction parameter (which is essentially a lifetime of Connection object). However, lifetime parameter of Rows equals to the lifetime of a Statement, and Statement value (created by the call of prepare() method) is a local variable, so it is strictly smaller than required (lifetimes of local variables are always smaller than lifetimes specified in parameters).

This error is legitimate - Rust prevented an actual logic mistake here. Rows iterator requires a Statement to load its data, but in this case Statement is destroyed while Rows is still alive.

What you need to do is to collect the data from Rows to some container (e.g. Vec) and return it. However, insert_user() seems to be a query which does not return anything from the database. For such queries you should use execute() method on Statement, and your function should look like this:

fn insert_user(trans: &postgres::Transaction, user: &User) -> postgres::Result<u64> {
    let query = "INSERT INTO usr (reference, email) VALUES ($1, $2)";
    trans.prepare(query).unwrap().execute(&[&user.reference, &user.email])
}