Using both mutable and immutable borrows

Hey all, I'm new to Rust, and I'm learning it as part of the Tauri framework to develop a fancy GUI for a Sqlite database I'm working with. I've got Rusqlite installed, but I'm running into an issue where I'm trying to access the names of the columns in a Statement while also then executing the statement. Here's the code I've got so far:

#[derive(Serialize)]
struct SqlResult<T> {
    columns: Vec<String>,
    rows: Vec<Vec<T>>,
}

#[tauri::command]
fn run_query(sql: String, app: tauri::AppHandle<Wry>) -> Result<SqlResult<String>, String> {
    let conn = Connection::open_with_flags(
        app.path_resolver()
            .resolve_resource("data.db")
            .expect("Error getting resource path"),
        OpenFlags::SQLITE_OPEN_READ_ONLY,
    )
    .or(Err("DB_CONNECTION_ERROR"))?;

    let mut statement = conn.prepare(&sql).or_else(|e| Err(e.to_string()))?;
    // Issue is here, I first call .column_names() which takes in &self...
    let cols = statement.column_names();

    // And then .query_map(), which takes in &mut self
    let response = statement
        .query_map([], |row| {
            let mut row_items = Vec::new();

            for index in 0..cols.len() {
                row_items.push(row.get(index).expect("Error getting column"));
            }

            Ok(row_items)
        })
        .expect("Error while mapping rows");

    let mut rows = Vec::new();

    for row in response {
        rows.push(row.expect("Error getting row in iterator"));
    }

    Ok(SqlResult {
        columns: cols.iter().map(|s| String::from(*s)).collect(),
        rows,
    })
}

I'm running into the error error[E0502]: cannot borrow statement as mutable because it is also borrowed as immutable, due to calling statement.column_names() (which takes in &self) followed by statement.query_map() (which takes in &mut self)

I've tried looking into solutions, but I haven't been able to get very far. How should I best go about tackling this problem?

You don't need column_names() until the very end. You are only using the number of columns inside the closure in query_map() which can be retrieved using column_count() if you look at the docs:

let mut statement = conn.prepare(&sql)..map_err(|e| e.to_string())?;
let num_cols = statement.column_count();

let response = statement
    .query_map([], |row| {
        let mut row_items = Vec::new();

        for index in 0..num_cols {
            row_items.push(row.get(index).expect("Error getting column"));
        }

        Ok(row_items)
    })
    .expect("Error while mapping rows");

let mut rows = Vec::new();

for row in response {
    rows.push(row.expect("Error getting row in iterator"));
}

Ok(SqlResult {
    columns: statement.column_names().iter().map(|&s| s.to_owned()).collect(),
    rows,
})

(Playground)

I have also corrected two un-idiomatic pieces: or_else(Err) is redundant, use map_err(); and the conversion of the column names to String was very convoluted, I replaced it with to_owned().

The allocation of two separate vectors for collecting the results (response and rows) is also unnecessary, but I didn't attempt to fix that one.

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.