0

The situation is a bit of confusing. I'm trying to use odbc-api to query result from odbc datasources, and wrapped the functions into ffi.

odbc-api defines following structs as below,

struct Envirnoment {...}
struct Connection<'c> {...}


impl Envirnoment {
    pub fn connect_with_connection_string(
        &self,
        connection_string: &str,
    ) -> Result<Connection<'_>, Error> {...}
}

For my situation, on the C side, create_connection is called to return a connection handler defines in rust.

#[no_mangle]
pub unsafe extern "C" fn create_connection(c_str: *const c_char) -> *mut Connection<'static> {
    let env = Environment::new().unwrap();
    let conn = env.connect_with_connection_string(CStr::from_ptr(c_str).to_str().unwrap()).unwrap();
    Box::into_raw(Box::new(conn))
}

The compiler returns error as below.

error[E0515]: cannot return value referencing local variable `env`
  --> odbc-demo/src/main.rs:37:5
   |
36 |     let conn = env.connect_with_connection_string(CStr::from_ptr(c_str).to_str().unwrap()).unwrap();
   |                --- `env` is borrowed here
37 |     Box::into_raw(Box::new(conn))
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ returns a value referencing data owned by the current function

The lifetime of Connection cannot be resolved, since env is dropped when function returns. How can I bind env and connection into a single struct as a handler exposes to ffi? Is std::pin the solution? How to define the lifetime of connection in the handler struct?

Furthermore, I'd like to make env into a global static Arc object, so that I can create multiple connection from the single env.

lazy_static!{
    static ref ENV: Arc<Envirnoment> = Arc::new(Envirnoment::new().unwrap());
}

Then how to define the handler struct?

My expected handler looks like

#[repr(C)]
struct ConnectionHandler{
    env: Arc<Envirnoment>,
    conn: Connection<'_>,
}

Update:

My expected handler is to capture a lifetime bounded object and the bounded object, on stack, to extend the whole lifetime and transfer the ownership to ffi. I think std::pin should work as expect, since the expected handler works like an async function.

After reconsidering the whole design of my FFI implements, my design turns out that the connection object maintains in (green) thread, and use std::sync::mpsc to transfer the control to ffi.

LvLng
  • 1
  • 1
  • Hi LvLng! Welcome :) Could you share any error / compilation messages you're getting? Please can you do this by editing your Question so that it's easy for users coming across your question to see. – tjheslin1 Oct 22 '21 at 14:12
  • I think you're on the right track here. What error do you get if you use your global ENV instead of env inside create_connection? What's the purpose of ConnectionHandler? I'm curious, why do you want to call from C to Rust given that ODBC is a C API? (why not use it directly?) – battlmonstr Oct 24 '21 at 21:37
  • @battlmonstr I'm using arrow-odbc to retrive arrow tables from various backended DBMS. Sharing a connection is the very first step. After update of using `mpsc`, problems are not all solved. Assuming the connection is shared over queries. Then how can I spawn a sub-thread to exeucte query on the shared connection. The the problem turns back to how to defince a wrapped struct with all references captured, so that the object is not lifetime bounded. – LvLng Oct 25 '21 at 12:30
  • 1
    Does this answer your question? [Why can't I store a value and a reference to that value in the same struct?](https://stackoverflow.com/questions/32300132/why-cant-i-store-a-value-and-a-reference-to-that-value-in-the-same-struct) – kmdreko Oct 30 '21 at 05:21
  • 1
    If your `ENV` is available globally, then your connection handler can simply have a `Connection<'static>` – kmdreko Oct 30 '21 at 05:25
  • Hi author of `odbc-api` here. Just stumbled over this. You can create multiple connections with static lifetime from a `lazy_static` environment. No Arc needed. I also used a C-Interface in `arrow-odbc-py` to create the Python binding for `arrow-odbc` in case you want to take a look. – Markus Klein Aug 16 '22 at 21:07

0 Answers0