如何将所有行作为带有tiberius期货的向量?

时间:2017-09-21 12:59:09

标签: sql-server rust rust-tokio

我需要使用tiberius收集表的所有行并输出它们。我的简单代码是:

extern crate futures;
extern crate tokio_core;
extern crate tiberius;

use futures::Future;
use tokio_core::reactor::Core;
use tiberius::SqlConnection;
use tiberius::stmt::ResultStreamExt;

fn main() {
    let mut core = Core::new().unwrap();

    let future = SqlConnection::connect(core.handle(), "server=tcp:127.0.0.1,1433;username=SA;password=qweasdZXC123!!;")
        .and_then(|conn| {
            let mut v: Vec<String> = Vec::new();

            conn.simple_query("SELECT id, name FROM test").for_each_row(|row| {

                let id: i32 = row.get(0);
                let name: &str = row.get(1);

                v.push(format!("{} - {}", id, name));

                Ok(())
            });

            println!("{:?}", v);

            Ok(())
        });

    core.run(future).unwrap();
}

此代码打印一个空向量,但我需要完整的字符串向量。我读过一些关于期货的文章,但就像Rust的新手一样,它们对我来说太复杂了。

1 个答案:

答案 0 :(得分:1)

在原始代码中,您有

conn.simple_query("SELECT id, name FROM users").for_each_row(|row| {
    // ...
}).wait().unwrap();

你说&#34;它编译但是根据要求挂起。我认为wait()调用问题。&#34;。

如果你阅读了Future::wait的文档,你会看到这个警告,强调我的:

  

注意:此方法不适合调用事件循环或类似的I / O情况,因为它会阻止事件循环取得进展(这会阻塞线程)。只有在保证与此未来相关的阻止工作将由另一个线程完成时,才应调用此方法。

在更新的代码中,您有

conn.simple_query("SELECT id, name FROM test").for_each_row(|row| {
    // ...
});

这构建了一个未来,但随后立即将其丢弃,因此外部向量不会发生任何事情。由于这个原因,期货箱中的所有期货都附有警告:

  

警告:未使用的`期货:: FutureResult`必须使用:除非进行轮询,否则期货什么都不做

我已提交an issue,以便图书馆添加此内容。

这是完全未经测试的代码段。我没有一个SQL Server实例来实际测试它,但它确实编译并具有正确的形状。

extern crate futures;
extern crate futures_state_stream;
extern crate tokio_core;
extern crate tiberius;

use futures::{Future, Stream};
use futures_state_stream::StateStream;
use tiberius::SqlConnection;
use tokio_core::reactor::Core;

fn main() {
    let mut core = Core::new().unwrap();

    let connection_string = "server=tcp:127.0.0.1,1433;username=SA;password=qweasdZXC123!!;";

    let future = SqlConnection::connect(core.handle(), connection_string)
        .and_then(|conn| {

            let query = conn.query("SELECT * FROM test WHERE id > @P1", &[&0i32])
                .into_stream()
                .take(1);

            query.flatten()
                .map(|row| {
                    let id: i32 = row.get(0);
                    let name: &str = row.get(1);

                    format!("{} - {}", id, name)
                })
                .collect()
        });

    let all_rows = core.run(future).unwrap();
.
    println!("{:?}", all_rows);
}

重点:

  1. conn.query可与多个查询语句一起使用,因此它会返回结果集的
  2. conn.query实际上实现了StateStream,而不是futures::Stream。出于示例的目的,我将其转换回futures::Stream .into_stream()。这是不理想的,因为我们之后无法恢复conn
  3. 我只使用.take(1)的第一个结果集。
  4. 由于我们现在Stream Stream,我们使用Stream::flatten删除嵌套。
  5. 每行都mapString
  6. Streamcollect加入Future
  7. Vec<String> #include <stdio.h> #include <stdlib.h> void CreateFile(FILE *file){ file = fopen("file.txt","w"); if(file == NULL){ printf("Error : Could not create the file"); } } void WriteFile(FILE *file){ fprintf(file,"Hello !"); } int main() { FILE *file = NULL; CreateFile(file); WriteFile(file); fclose(file); return 0; }