Is it possible to stream from a DB (read by Rust) to Python? #2707
-
Hello folks! First off, loving the project - great stuff. Super helpful community too. Thanks for your efforts. I'm curious as to whether or not it's possible to stream results out of a database read by rust, back to python? For instance, if I'm using the use postgres::{Client, NoTLS, RowIter};
#[pyfunction]
fn stream_from_db() -> Result<&PyAny> {
Ok(produce_stream()?);
}
fn produce_stream() -> Result<RowIter> {
let client = Client::connect("my_db_url", NoTLS)?;
let stream = client.query_raw("SELECT * FROM ...", &[¶ms])?;
Ok(stream)
} Obviously this is not going to work. The RowIter that comes back from postgres has a lifetime I thought perhaps to get around this I could pass a use postgres::{Client, NoTLS, RowIter};
#[pyfunction]
fn stream_from_db(py: Python) -> PyResult<&PyAny> {
Ok(produce_stream(py)?);
}
fn produce_stream<'a>(py: Python<'a>) -> PyResult<&'a PyAny> {
let client = Client::connect("my_db_url", NoTLS)?;
let stream = client.query_raw("SELECT * FROM ...", &[¶ms])?;
Ok(stream.into_py(py))
} But of course, this won't work because a RowIter can't do Another option I thought is I might be able to Box the postgres client to drop the lifetime, but that's really a shot in the dark. Ultimately what I want to do is, from Python, instruct Rust to execute a query and load results in an iterator fashion (such that I don't load all records into memory at once). Any suggestions would be most welcome! Thanks |
Beta Was this translation helpful? Give feedback.
Replies: 1 comment 3 replies
-
It doesn't solve the original question (how to provide a Python iterator of rows), but what I've done in a similar situation was to switch to internal iteration. Meaning, the Rust code that iterates over the rows gets a Python function that it executes for each row (or bunch of rows, or ...) and which can, if needed, indicate in its return value whether to break iteration. Regarding the original problem you could, maybe, move the Connection into a Python object - this guarantees a stable address - and then move the RowIter into another Python object that holds onto a reference to the Connection (this guarantees its being kept alive as long as needed), and the Rust lifetime erased/transmuted to But this is obviously very unsafe and probably not sound. |
Beta Was this translation helpful? Give feedback.
It doesn't solve the original question (how to provide a Python iterator of rows), but what I've done in a similar situation was to switch to internal iteration. Meaning, the Rust code that iterates over the rows gets a Python function that it executes for each row (or bunch of rows, or ...) and which can, if needed, indicate in its return value whether to break iteration.
Regarding the original problem you could, maybe, move the Connection into a Python object - this guarantees a stable address - and then move the RowIter into another Python object that holds onto a reference to the Connection (this guarantees its being kept alive as long as needed), and the Rust lifetime erased/transmut…