【问题标题】:Continuous error 21: "library routine called out of sequence"连续错误 21:“库例程调用顺序错误”
【发布时间】:2016-07-13 20:15:29
【问题描述】:

我正在围绕 Sqlite C 函数编写一个简单的包装类。环境是Ubuntu 14_04,gcc 4.8.4版本,我通过apt-get安装了libsqlite-dev,我相信是3.8.2版本。

问题是这样的:如果我调用多个函数(c'tor 和exec),那么测试会失败。如果我将代码包装的 sqlite 函数(_open 和 _exec)函数放在一个函数中(我在构造函数中尝试过),那么它就会通过。失败是

err: 21 msg: 库例程调用乱序

而失败的单元测试是这样的:

TEST_FIXTURE(DatabaseFixture, TryToCreateATable)
{
    database db(test);
    REQUIRE CHECK(db);
    CHECK(db.exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)"));
    std::cout << db.error() << std::endl;
}

包装类如下。

database(const std::string& filename)
    : connected_(false), database_(nullptr)
{
    if (sqlite3_open(filename.c_str(), &database_) != SQLITE_OK)
    {
        const std::runtime_error ex(error());
        sqlite3_close(database_);
        throw ex;
    }
    connected_ = true;
}

bool exec(const std::string& query)
{
    assert(connected_ != false && "The connected is false");
    assert(database_ != nullptr && "The db_ is null");
    assert(!query.empty() && "The string is empty");
    sql_statement call;
    assert(call.statement == nullptr && "The call is not null");
    int result = sqlite3_exec(database_, query.c_str(), NULL, NULL, NULL);
    // int result = sqlite3_prepare_v2(database_, query.c_str(), -1, &call.statement, nullptr);
    if (result != SQLITE_OK)
    {
        std::cout << "err: " << result << " msg: " << error() << std::endl;
        return false;
    }
    return true;
}

sql_statement 是 _stmt 的一个小包装器,它将指针初始化为 null 并在析构函数中调用 _finalize。 'error()' returns the string from_errmsg`。

如您所见,我尝试使用 _prepare_v2 但失败并出现同样的错误。具有不同的 libsqlite 版本会有所不同 - 我希望它无法编译?如何检查 libsqlite 是否与安装的版本匹配?它应该有什么不同吗 - 我认为它不应该?

更新:我创建了一个新虚拟机并开始全新安装 Ubuntu 14_04。通过 apt-get 按以下顺序获得所需的一切:Git、CMake、g++、sqlite3、libsqlite3-dev。仍然表现出同样的问题。 UPDATE2:我使用 16_04 创建了一个全新的 VM。安装了我之前做的所有东西,除了 g++(已经安装)并且以相同的顺序。仍然表现出同样的问题。由于 SQL 的版本号不同,我认为可以排除?

【问题讨论】:

  • 在“如果我有多个功能则测试失败”中使用“多个功能”一词是什么意思?多个 TEST_FIXTURE 函数?
  • 通过在单元测试中单独调用函数。所以对 constructor 和 exec 的调用是不同的步骤。如果我将sqlite3_exec 调用放在构造函数中并注释掉对db.exec() 的调用,则测试通过。抱歉,如果不清楚。
  • 嗯,这些是返回此错误的原因:sqlite.org/cvstrac/wiki?p=LibraryRoutineCalledOutOfSequence。 sqlite3_errmsg 打开数据库后是否返回任何内容?
  • 我看过那个页面。构造函数中的错误消息给出C'tor: err: 0 msg: not an error。
  • 好的,所以您的连接似乎在sqlite3_open 和sqlite3_exec 之间的某个位置关闭。尝试使用sqlite3_status获取更多信息。 sqlite.org/c3ref/db_status.html

标签: c++ sqlite


【解决方案1】:

CHECK(db) 宏调用扩展为 UnitTest::Check(db) - 声明为:

   template< typename Value >
   bool Check(Value const value)
   {
      return !!value; // doing double negative to avoid silly VS warnings
   }

这意味着 db 被复制以便按值传递。

如果你有一个默认的复制构造函数并且你的析构函数使用它的数据库指针关闭数据库连接,我很确定这会产生你看到的效果。

编辑添加:https://github.com/unittest-cpp/unittest-cpp/issues/7

【讨论】:

  • 谢谢!我吃午饭时发现你已经完成了!
【解决方案2】:

问题似乎与 UnitTest++ 和 CHECK(db) 宏与代码的奇怪交互有关。删除该行允许单元测试完成并通过。我将进一步调查并将问题发布到 UnitTest++ 项目。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-04
    • 1970-01-01
    • 1970-01-01
    • 2013-07-23
    相关资源
    最近更新 更多