有没有一种方法可以在循环中使用odbc :: Statement编写函数?

时间:2020-06-07 11:54:21

标签: rust

我有一个简单循环的工作示例(大部分取自odbc板条箱的示例):

use std::io;
use odbc::*;
use odbc_safe::AutocommitOn;
fn main(){
    let env = create_environment_v3().map_err(|e| e.unwrap()).unwrap();
    let conn = env.connect_with_connection_string(CONN_STRING).unwrap();
    let mut stmt = Statement::with_parent(&conn).unwrap();
    loop {
        let mut sql_text = String::new();
        println!("Please enter SQL statement string: ");
        io::stdin().read_line(&mut sql_text).unwrap();
        stmt = match stmt.exec_direct(&sql_text).unwrap() {
            Data(mut stmt) => {
                let cols = stmt.num_result_cols().unwrap();
                while let Some(mut cursor) = stmt.fetch().unwrap() {
                    for i in 1..(cols + 1) {
                        match cursor.get_data::<&str>(i as u16).unwrap() {
                            Some(val) => print!(" {}", val),
                            None => print!(" NULL"),
                        }
                    }
                    println!();
                }
                stmt.close_cursor().unwrap()
            }
            NoData(stmt) => {println!("Query executed, no data returned"); stmt}
        }
    }
}

我不想为每个查询创建新的Statements,因为我只能使用.close_cursor()。 我想将循环的主体提取为一个函数,如下所示:

fn exec_stmt(stmt: Statement<Allocated, NoResult, AutocommitOn>) {
    //loop's body here
}

但是我不能! .exec_direct()方法可变地消耗我的Statement并返回另一个。我尝试了不同的方法将Statement arg传递给函数(借用,RefCell等),但是在循环中使用时,它们都会失败。我仍然对Rust还是陌生的,所以很可能我只是不了解某些东西,或者.exec_direct的Statement消耗是否使它变得不可能?

2 个答案:

答案 0 :(得分:2)

没有很好的方法来移动然后通过参数后移值。最好复制.exec_direct所做的事情,同时也将函数的返回类型也声明为语句。

用法如下:

let mut stmt = Statement::with_parent(&conn).unwrap();
loop {
    stmt = exec_stmt(stmnt);
}

,您的函数签名为:

fn exec_stmt(stmt: Statement<...>) -> Statement<...> {
  match stmt.exec_direct() {
    ...
  }
}

我可能不建议这样做,但是如果您真的想使其工作,可以使用Option.take()方法。

fn exec_stmt(some_stmt: &mut Option<Statement<...>>) {
   let stmt = some_stmt.take().unwrap();
   // do stuff ...
   some_stmt.replace(stmt);
}

答案 1 :(得分:1)

odbc-safe crate 试图将 ODBC 的每个状态转换反映为不同的类型。 odbc-api crate 也试图保护您免受错误的影响,但它更微妙一些。您的用例将包含在 Preallocated 结构中。

odbc-api documentation 中的模拟示例如下所示:

use odbc_api::{Connection, Error};
use std::io::{self, stdin, Read};

fn interactive(conn: &Connection) -> io::Result<()>{
    let mut statement = conn.preallocate().unwrap();
    let mut query = String::new();
    stdin().read_line(&mut query)?;
    while !query.is_empty() {
        match statement.execute(&query, ()) {
            Err(e) => println!("{}", e),
            Ok(None) => println!("No results set generated."),
            Ok(Some(cursor)) => {
                // ...print cursor contents...
            },
        }
        stdin().read_line(&mut query)?;
    }
    Ok(())
}

这将使您可以毫无困难地声明一个函数:

use odbc_api::Preallocated;

fn exec_statement(stmt: &mut Preallocated) {
    // loops body here
}