prisma / tiberius

TDS 7.2+ (Microsoft SQL Server) driver for Rust
Apache License 2.0
321 stars 118 forks source link

Cannot return value referencing local variable `row` returns a value referencing data owned by the current function #280

Closed ErtyDess closed 1 year ago

ErtyDess commented 1 year ago

I connect to a mssql database with tiberius and i get all the data i need into a struct and every struct into a vec, i would like my function to return my vec but i can't understand this borrow problem

cannot return value referencing local variable row

returns a value referencing data owned by the current function

mod.rs(32, 15): row is borrowed here

this is my function

  use tiberius::{Client, Config, AuthMethod, Query, Row};
  use tokio::net::TcpStream;
  use tokio_util::compat::TokioAsyncWriteCompatExt;
  pub mod structures;
  use structures::*;

  #[tokio::main]
  pub async fn get_fornitori() -> anyhow::Result<Vec<Fornitori<'static>>> {
      let mut config = Config::new();

      config.host("foo");
      config.port(1433);
      config.authentication(AuthMethod::sql_server("foo", "bar"));
      config.database("foo");
      config.trust_cert(); // on production, it is not a good idea to do this

      let tcp = TcpStream::connect(config.get_addr()).await?;
      tcp.set_nodelay(true)?;

      let mut client = Client::connect(config, tcp.compat_write()).await?;
      let params = vec![String::from("*")];
      let mut select = Query::new("SELECT TOP 3 * FROM foo");

      for param in params.into_iter() {
          select.bind(param);
      }

      let mut _res = select.query(&mut client).await?;
      let row: Vec<Vec<Row>> = _res.into_results().await?;

      let mut result_vec: Vec<Fornitori> = vec![];
      for i in &row[0] {
          let id_forn: Option<i32> = i.get(0);
          let nome_forn: Option<&str> = i.get(1);
          let pagamento_forn: Option<&str> = i.get(4);
          let forn = Fornitori {
              f_id: id_forn,
              fornitore: nome_forn,
              tipo_pagamento: pagamento_forn,
          };
          result_vec.push(forn);
      }
      println!("rvec: {:#?}", result_vec);

      Ok(result_vec)
  }

i get the error here:

Ok(result_vec)

i have the Fornitori struct in another file

  #[derive(Clone, Debug)]
      pub struct Fornitori<'a> {
          pub f_id: Option<i32>,
          pub fornitore: Option<&'a str>,
          pub tipo_pagamento: Option<&'a str>,
      }

i have replaced real values with "foo" and "bar"

somone can help me?

ErtyDess commented 1 year ago

SOLVED:

i changed the struct to this:

  use serde::{Serialize, Deserialize};
  [derive(Clone, Debug, Serialize, Deserialize)]
  pub struct Fornitori { 
      pub f_id: Option<i32>,
      pub fornitore: Option<String>,
      pub tipo_pagamento: Option<String>,
  }

and the function to this

  use tiberius::{Client, Config, AuthMethod, Query, Row};
  use tokio::net::TcpStream; use tokio_util::compat::TokioAsyncWriteCompatExt; pub mod structures; use structures::*;
  [tokio::main]
      pub async fn get_fornitori() -> anyhow::Result<Vec<Fornitori>> { let mut config = Config::new();
      config.host("foo");
      config.port(1433);
      config.authentication(AuthMethod::sql_server("bar", "foo"));
      config.database("foo");
      config.trust_cert(); // on production, it is not a good idea to do this

      let tcp = TcpStream::connect(config.get_addr()).await?;
      tcp.set_nodelay(true)?;

      let mut client = Client::connect(config, tcp.compat_write()).await?;
      let params = vec![String::from("*")];
      let mut select = Query::new("SELECT TOP 3 * FROM foo");

      for param in params.into_iter() {
          select.bind(param);
      }

      let mut _res = select.query(&mut client).await?;
      let row: Vec<Vec<Row>> = _res.into_results().await?;

      let mut result_vec: Vec<Fornitori> = vec![];
      for i in &row[0] {
          let f_id = i.get(0);
          let fornitore = i.get(1).map(|f: &str| f.to_string());
          let tipo_pagamento = i.get(4).map(|t: &str| t.to_string());
          let forn = Fornitori {
              f_id,
              fornitore,
              tipo_pagamento,
          };
          result_vec.push(forn);
      }
      println!("rvec: {:#?}", result_vec);

      Ok(result_vec)
  }