Rust postgres执行,如何将表名作为变量传递

时间:2019-08-17 20:48:41

标签: postgresql rust

我是Rust的新手,我想和postgres的箱子一起玩。我可以通过对表名进行硬编码来创建表,但是当试图从变量中传递表名时,总是会出现代码崩溃的情况。

rustc --version 1.36.0
cargo --version 1.36.0
postgres = "0.15"
fn main() {
  let conn = Connection::connect("postgresql://postgres:postgres@localhost/db1",
                                    TlsMode::None).unwrap();

  let tname = "message";
  conn.execute("CREATE TABLE IF NOT EXISTS $1 (
                    id              SERIAL PRIMARY KEY,
                    title           VARCHAR NOT NULL,
                    body            VARCHAR,
                )", &[&tname]).ok().expect("Table message creation failed");
thread 'main' panicked at 'Table message creation failed', src/libcore/option.rs:1036:5
stack backtrace:
   0: std::sys::unix::backtrace::tracing::imp::unwind_backtrace
             at src/libstd/sys/unix/backtrace/tracing/gcc_s.rs:39
   1: std::sys_common::backtrace::_print
             at src/libstd/sys_common/backtrace.rs:71
   2: std::panicking::default_hook::{{closure}}
             at src/libstd/sys_common/backtrace.rs:59
             at src/libstd/panicking.rs:197
   3: std::panicking::default_hook
             at src/libstd/panicking.rs:211
   4: std::panicking::rust_panic_with_hook
             at src/libstd/panicking.rs:474
   5: std::panicking::continue_panic_fmt
             at src/libstd/panicking.rs:381
   6: rust_begin_unwind
             at src/libstd/panicking.rs:308
   7: core::panicking::panic_fmt
             at src/libcore/panicking.rs:85
   8: core::option::expect_failed
             at src/libcore/option.rs:1036
   9: core::option::Option<T>::expect
             at /rustc/a53f9df32fbb0b5f4382caaad8f1a46f36ea887c/src/libcore/option.rs:314
  10: rustdb::main
             at ./main.rs:27
  11: std::rt::lang_start::{{closure}}
             at /rustc/a53f9df32fbb0b5f4382caaad8f1a46f36ea887c/src/libstd/rt.rs:64
  12: std::panicking::try::do_call
             at src/libstd/rt.rs:49
             at src/libstd/panicking.rs:293
  13: __rust_maybe_catch_panic
             at src/libpanic_unwind/lib.rs:85
  14: std::rt::lang_start_internal
             at src/libstd/panicking.rs:272
             at src/libstd/panic.rs:394
             at src/libstd/rt.rs:48
  15: std::rt::lang_start
             at /rustc/a53f9df32fbb0b5f4382caaad8f1a46f36ea887c/src/libstd/rt.rs:64
  16: main
  17: __libc_start_main
  18: _start

1 个答案:

答案 0 :(得分:1)

您不能使用占位符(例如$1)将表名替换为查询。

占位符的功能之一是允许查询准备一次,然后多次执行。这样可以节省每次使用查询时计划查询的开销,这可能会很大。但是,如果数据库甚至都不知道要查询哪个表,就不可能计划查询。

如果需要在运行时动态插入表名,则需要在rust中进行,然后再将SQL传递给数据库:

let sql = format!("CREATE TABLE IF NOT EXISTS {} (
                    id              SERIAL PRIMARY KEY,
                    title           VARCHAR NOT NULL,
                    body            VARCHAR,
                )", tname);

如果表名是从用户输入传递过来的,请不要忘记事先验证表名以防SQL注入。

还请注意,出现恐慌是由于使用了.ok().expect(....)

ok()将获得执行SQL的结果,并将其转换为Option。如果结果是错误,它将被丢弃,因此您永远不会看到错误消息,它可能会帮助您诊断问题。 Result直接实现expect,其优点是它不会丢弃错误,而是将其显示为Panic的一部分。因此,您最好使用:

conn.execute(sql, &[] as &[String]).expect("Failed creating table");

但是,如果现实情况中SQL语句将失败,则最好检查结果并更优雅地处理它,而不是使程序崩溃。