wxSQLite3中预准备语句重用的例外

时间:2014-12-15 15:25:43

标签: database sqlite wxwidgets

我正在编写一个使用wxSQLite3库的应用程序,该库是用于wxWidgets跨平台GUI编程框架的libsqlite3的包装器。尝试重用预准备语句时,会抛出wxSQLite3Exception。

此示例说明了问题:

#include <wx/string.h>
#include <wx/wxsqlite3.h>

int main() {
    wxSQLite3Database::InitializeSQLite();

    //create in-memory test database & populate it
    wxSQLite3Database db;
    db.Open(wxT(":memory:"));
    db.ExecuteUpdate(wxT("CREATE TABLE SimpleTable (id INT PRIMARY KEY, val INT);"));
    db.ExecuteUpdate(wxT("INSERT INTO SimpleTable VALUES (1, 10);"));
    db.ExecuteUpdate(wxT("INSERT INTO SimpleTable VALUES (2, 20);"));

    //create a prepared statement we can reuse
    wxSQLite3Statement stmt;
    stmt = db.PrepareStatement(wxT("SELECT * FROM SimpleTable WHERE id = ?;"));

    //first use of statement (works)
    stmt.Bind(1, 1);
    wxSQLite3ResultSet r_set = stmt.ExecuteQuery();
    if (r_set.NextRow()) {
        wxPrintf(wxT("id: %i   value: %i\n"), r_set.GetInt(wxT("id")), r_set.GetInt(wxT("val")));
    }
    r_set.Finalize();

    //reset and reuse statement
    stmt.Reset();
    stmt.Bind(1, 2); //**EXCEPTION THROWN HERE**
    wxSQLite3ResultSet r_set2 = stmt.ExecuteQuery();
    if (r_set2.NextRow()) {
        wxPrintf(wxT("id: %i   value: %i\n"), r_set2.GetInt(wxT("id")), r_set2.GetInt(wxT("val")));
    }
    r_set2.Finalize();

    //cleanup
    stmt.Finalize();
    db.Close();
    wxSQLite3Database::ShutdownSQLite();
    return 0;
}

为简洁起见,删除了异常处理,但来自异常的消息是:

WXSQLITE_ERROR[1000]: Statement not accessible

我使用libsqlite3在普通的C中写了大致相同的代码,它运行没有问题。有谁知道我做错了什么,或者这是否是wxSQLite3中的某种错误?提前感谢您的帮助!

2 个答案:

答案 0 :(得分:1)

在SQLite本身,语句和结果集实际上是同一个对象。

wxSQLite3使用引用计数,以便仅在释放最后一个wxSQLite3StatementwxSQLite3ResultSet对象时释放该语句。 这会在相应的析构函数中自动发生。

但是,显式调用Finalize()会绕过引用计数。

虽然没有必要,但如果要确保在下一个语句执行之前正确释放wxSQLite3ResultSet资源,只需破坏此对象:

wxSQLite3Statement stmt = ...;
...
{
    wxSQLite3ResultSet r_set = stmt.ExecuteQuery();
    ... r_set.NextRow() ...
    // r_set destructed here
}
...

答案 1 :(得分:1)

只要您打算重用准备好的SQL语句,即重置语句并将新值绑定到语句变量,就不能调用方法Finalize - 也不要在准备好的语句上对象本身或从该语句中检索的结果集。

作为方法名称,Finalize,建议,该方法通过调用sqlite3_finalize来完成基础SQLite语句对象(来自SQLite文档的引用:&#34;调用sqlite3_finalize()函数来删除预准备语句。&#34 ;)删除基础SQLite语句对象后,显然无法再访问它。因此你得到例外。

通常,您不需要明确调用方法Finalize。 wxSQLite3负责通过引用计数来完成语句。