Why this not work?

I try the next code work. What i doing wrong?.

use std::cell::RefCell;
use std::rc::Rc;

use sqlx::{Acquire, Error, MySql, Transaction};

type DBConn  = Rc<RefCell<sqlx::pool::PoolConnection<MySql>>>;
type DBTrans<'t> = Rc<RefCell<sqlx::Transaction<'t, MySql>>>;

// This work!!!. But is only the db connection
async fn connection_mysql<'c>(connection_pool: Option<&'c sqlx::Pool<sqlx::MySql>>) -> Result<DBConn, sqlx::Error> {
    match connection_pool {
        Some(connection_pool) => {

            let conn: sqlx::pool::PoolConnection<sqlx::MySql> = match connection_pool.acquire().await {
                Ok(conn) => conn,
                Err(error) => return Err(error),
            };

            let rc_conn: Rc<RefCell<sqlx::pool::PoolConnection<MySql>>> = Rc::new( RefCell::new( conn ) );

            Ok(rc_conn)

        }
        None => {
            Err(Error::PoolClosed)
        }
    }
}

//Not work. I Need the connection and the transaction
async fn begin_transaction_mysql<'c>(connection_pool: Option<&'c sqlx::Pool<sqlx::MySql>>) -> Result<(DBConn,DBTrans), sqlx::Error> {
    match connection_pool {
        Some(connection_pool) => {

            let conn: sqlx::pool::PoolConnection<sqlx::MySql> = match connection_pool.acquire().await {
                Ok(conn) => conn,
                Err(error) => return Err(error),
            };

            let rc_conn: Rc<RefCell<sqlx::pool::PoolConnection<MySql>>> = Rc::new( RefCell::new( conn ) );

            let mut trans = rc_conn.borrow_mut(); //I try with rc_conn.clone().borrow_mut(). Not work

            let rc_transaction: Rc<RefCell<Transaction<'_, MySql>>> = Rc::new( RefCell::new( trans.begin().await.unwrap()) );

            Ok(( rc_conn, rc_transaction)) //<-- Problem where

        }
        None => {
            Err(Error::PoolClosed)
        }
    }
}

The borrow checker has complaints. What i need to do for this work?

   Compiling sqlx_mysql_tokio_01 v0.1.0 (/home/dsystems01/Desktop/rust-lang/projects/test/sqlx_mysql_tokio_01)
error[E0515]: cannot return value referencing local variable `trans`
   --> src/main.rs:330:13
    |
328 |             let rc_transaction: Rc<RefCell<Transaction<'_, MySql>>> = Rc::new( RefCell::new( trans.begin().await.unwrap()) );
    |                                                                                              ----- `trans` is borrowed here
329 |
330 |             Ok(( rc_conn, rc_transaction))
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error[E0515]: cannot return value referencing local variable `rc_conn`
   --> src/main.rs:330:13
    |
326 |             let mut trans = rc_conn.as_ref().borrow_mut(); //.into_inner();
    |                             ------- `rc_conn` is borrowed here
...
330 |             Ok(( rc_conn, rc_transaction))
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error[E0505]: cannot move out of `rc_conn` because it is borrowed
   --> src/main.rs:330:18
    |
315 | async fn begin_transaction_mysql_01<'c>(connection_pool: Option<&'c sqlx::Pool<sqlx::MySql>>) -> Result<(DBConn,DBTrans), sqlx::Error> {
    |                                     -- lifetime `'c` defined here
...
324 |             let rc_conn: Rc<RefCell<sqlx::pool::PoolConnection<MySql>>> = Rc::new( RefCell::new( conn ) );
    |                 ------- binding `rc_conn` declared here
325 |
326 |             let mut trans = rc_conn.as_ref().borrow_mut(); //.into_inner();
    |                             ------- borrow of `rc_conn` occurs here
...
330 |             Ok(( rc_conn, rc_transaction))
    |             -----^^^^^^^------------------
    |             |    |
    |             |    move out of `rc_conn` occurs here
    |             returning this value requires that `rc_conn` is borrowed for `'c`

Some errors have detailed explanations: E0505, E0515.
For more information about an error, try `rustc --explain E0505`.

The message "returning this value requires that rc_conn is borrowed for 'c" what it mean?

Thanks for all help can get me.

Since both the connection and the transaction are behind the Rc smart pointer, you should simply return clones of them.

I changed the code but still get errors

//Not work. I Need the connection and the transaction
async fn begin_transaction_mysql<'c>(connection_pool: Option<&'c sqlx::Pool<sqlx::MySql>>) -> Result<(DBConn,DBTrans), sqlx::Error> {
    match connection_pool {
        Some(connection_pool) => {

            let conn: sqlx::pool::PoolConnection<sqlx::MySql> = match connection_pool.acquire().await {
                Ok(conn) => conn,
                Err(error) => return Err(error),
            };

            let rc_conn: Rc<RefCell<sqlx::pool::PoolConnection<MySql>>> = Rc::new( RefCell::new( conn ) );

            let rc_conn_cloned = rc_conn.clone();

            let rc_trans: Rc<RefCell<Transaction<'_, MySql>>> = Rc::new( RefCell::new( rc_conn_cloned.borrow_mut().begin().await.unwrap()) );

            let rc_trans_cloned = rc_trans.clone();

            Ok(( rc_conn, rc_trans_cloned))

        }
        None => {
            Err(Error::PoolClosed)
        }
    }
}
error[E0515]: cannot return value referencing temporary value
   --> src/main.rs:364:13
    |
360 |             let rc_trans: Rc<RefCell<Transaction<'_, MySql>>> = Rc::new( RefCell::new( rc_conn_cloned.borrow_mut().begin().await.unwrap()) );
    |                                                                                        --------------------------- temporary value created here
...
364 |             Ok(( rc_conn, rc_trans_cloned))
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

error[E0515]: cannot return value referencing local variable `rc_conn_cloned`
   --> src/main.rs:364:13
    |
360 |             let rc_trans: Rc<RefCell<Transaction<'_, MySql>>> = Rc::new( RefCell::new( rc_conn_cloned.borrow_mut().begin().await.unwrap()) );
    |                                                                                        -------------- `rc_conn_cloned` is borrowed here
...
364 |             Ok(( rc_conn, rc_trans_cloned))
    |             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

For more information about this error, try `rustc --explain E0515`.
error: could not compile `sqlx_mysql_tokio_01` (bin "sqlx_mysql_tokio_01") due to 2 previous errors

You are almost there.

Change this:

Result<(DBConn,DBTrans)

To this:

Result<(Rc<RefCell<DBConn>>,Rc<RefCell<DBTrans>>)

Is already defined in top. I think not need nested Rc RefCell.

Transaction<'c> contains a reference to the Connection, and this creates a self-referential struct, which is not allowed to exist in Rust.

You will never be able to have Connection and Transaction<'connection> in the same struct or tuple. You must refactor the code to create and return Connection first, and then create Transaction separately.

2 Likes

Sorry, I had not seen that you already had this on the type aliases.

It seems that the only way to make it work would be to receive a connection as a parameter rather than a pool.

Besides that, I don't think you should be using a transaction like that. They are meant to be guards when performing different database operations, so you should only receive a mutable reference to a transaction to commit every operation.

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.