【问题标题】:Results, such as RETURNING, from uncomitted execs?结果,例如返回,来自未提交的高管?
【发布时间】:2014-04-14 19:28:15
【问题描述】:

使用 libpqxx,是否可以让一个 execs 但尚未被 committed 的准备好的语句将结果存储在 result 中以供以后准备好的语句中使用?

如果是这样,如何做到这一点?

代码

为了便于阅读,我已经对其进行了精简,但这基本上是我想要做的:

void prepare_write_parent_table(connection_base &c){
    try
    {
        c.prepare("write_parent_table", 
            "INSERT INTO parent_table (column_1) "
            "SELECT $1 "
            "RETURNING id"
        )
        ("character", pqxx::prepare::treat_string);
    }
    catch (const exception &e)
    {
        cerr << e.what() << endl;
    }
}

string write_parent_table(transaction_base &t, string data){
    try
    {
        result parent_table_result = t.prepared("write_parent_table")(data).exec();
        return parent_table_result[0][0].c_str();

    }
    catch (const exception &e)
    {
        cerr << e.what() << endl;
        return "";
    }
}

void prepare_write_child_table(connection_base &c){
    try
    {
        c.prepare("write_child_table", 
            "INSERT INTO child_table (parent_table_id, column_a) "
            "SELECT $1, $2 "
        )
        ("character", pqxx::prepare::treat_string)
        ("character", pqxx::prepare::treat_string);
    }
    catch (const exception &e)
    {
        cerr << e.what() << endl;
    }
}

检查来自write_parent_tablereturn 以查看if( == "")。如果不是,则继续;否则,我将在那里commit 让它失败,或者如果可能的话最好取消交易;但是,如果可能的话,我还不知道该怎么做。

INSERTs 到 child_tableparent_table INSERT 的数量总是不确定的。

【问题讨论】:

  • for (result::size_type i=0; i &lt; Results.size(); ++i) other_prepare_object(Results[i]); pqxx.org/devprojects/libpqxx/doc/3.1/html/Reference/a00076.html
  • @CantChooseUsernames 谢谢 CantChooseUsernames!所以您是说可以从尚未提交的exec 返回结果?如果是这样,这是一个了不起的设置!
  • 我没有亲自尝试过,但值得一试。将该循环粘贴到您的代码中并打印Results[i] 的任何内容,然后查看.. 如果Results.size() &gt; 0 那么我说是的。否则没有。
  • 只要您准备下一个查询之后将结果保存到表(或临时表)中,同一事务中的所有内容都是可见的.
  • @ErwinBrandstetter 感谢您关注 Erwin Brandstetter!您介意在答案中澄清吗?我正在尝试将父表中的RETURNING id 用于引用父表的子表列中,方法是将其存储在来自execresult 中。在所有准备好的语句都是execed 之后,我然后commit。你是说事务需要分解,要获得RETURNING 值,必须首先是committed?如果是这样,我应该将隔离设置为SERIALIZABLE吗?如果是这样,怎么做?提前非常感谢您!

标签: c++ postgresql prepared-statement libpqxx


【解决方案1】:

通过使用data-modifying CTE 对两个插入使用单个 SQL 语句来简化操作。这比在客户端中存储中间状态要快得多。

子表中的INSERT 仅在父表中的第一个INSERT 成功并返回id 时发生:

void prepare_write_both_tables(connection_base &c){
    try
    {
       c.prepare("write_both_tables", 
          "WITH p AS ("
             "INSERT INTO parent_table (column_1) "
             "SELECT $1 "
             "RETURNING id) "
          "INSERT INTO child_table (parent_table_id, column_a) "
          "SELECT p.id, $2 "
          "FROM   p"
        )
        ("character", pqxx::prepare::treat_string)
        ("character", pqxx::prepare::treat_string);
    }
    catch (const exception &e)
    {
        cerr << e.what() << endl;
    }
}

Search for [postgres] & "data-modifying CTE" 了解更多示例。
也称为“可写 CTE”(或“可写 CTE”)。

多个孩子

对于 单个 父级和 0 到多个 子级:

void prepare_write_both_tables(connection_base &c){
    try
    {
       c.prepare("write_both_tables", 
          "WITH p AS ("
             "INSERT INTO parent_table (column_1) "
             "SELECT $1 "
             "RETURNING id) "
          "INSERT INTO child_table (parent_table_id, column_a) "
          "SELECT p.id, a "
          "FROM   p, unnest($2::text[]) AS a"
        )
        ("character", pqxx::prepare::treat_string)
        ("character", pqxx::prepare::treat_string);
    }
    catch (const exception &e)
    {
        cerr << e.what() << endl;
    }
}

其中第二个参数是文本表示形式的array of text。示例:

{foo,bar,baz}

这会插入与文本数组中的元素一样多的行。对于 0 个孩子,传递 NULL 或一个空数组 {}

【讨论】:

  • 仔细检查 C++ 语法。我是 Postgres 方面的专家,但不是 C++ 方面的专家。
  • @Gracchus:我为多个孩子添加了一个版本。
  • 这个接受数组的文本表示。也许有更优雅的方式来传递数组...
  • @Gracchus:这里不可能进行 SQL 注入。数据将仅被视为准备好的语句中的数据。如果语法无效,你会得到一个异常,一切都会回滚。
  • @Gracchus:你为什么要删除另一个问题?我在队列中有一个完成了一半的答案......
猜你喜欢
  • 1970-01-01
  • 2015-02-27
  • 1970-01-01
  • 2014-09-12
  • 1970-01-01
  • 1970-01-01
  • 2017-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多