3

おそらく非常にばかげた間違いであることはわかっていますが、文字通り何時間も座って数行のコードを見つめ、ドキュメントを実行してきましたが、なぜこれが起こるのかまだわかりません。

C++11 で SQLite C API の便利なラッパー クラスを作成しています。データベースへの接続が確立されると、関数sqlはステートメントを準備し、必要に応じて引数をそれにバインドし、後で実行します。準備と実行は正常に機能し、1 つの引数のバインドは正常に機能しますが、複数の引数をバインドする場合、すべての値は常にリストの最後の引数に設定されます。

関数は次のsqlようになります。

template <typename... Args>
bool sql(const std::string &query, const Args &... args)
{
    sql_statement call;
    if(sqlite3_prepare_v2(database_, query.data(), -1, &call.statement, nullptr)
       != SQLITE_OK)
    {
        return false;
    }

    if(!bind(call.statement, 1, args...)) {
        return false;
    }

    return sqlite3_step(call.statement) == SQLITE_DONE;
}

sql_statementsqlite3_stmtスコープ外になったときにステートメントを解放するだけのラッパー構造体です。database_作業データベースのハンドルです。ただし、この機能が問題と関係があるかどうかはわかりません。むしろトラブルメーカーとして気になるのは、bind関数内で呼び出されるsql関数です。ここにあります:

template <typename T, typename... Args>
bool bind(sqlite3_stmt *statement, int current, const T &first, const Args &... args)
{
    std::stringstream ss;
    ss << first;
    if(sqlite3_bind_text(statement, current,
        ss.str().data(), ss.str().length(), SQLITE_STATIC) != SQLITE_OK)
    {
        return false;
    }
    return bind(statement, current+1, args...);
}
bool bind(sqlite3_stmt *, int) { return true; }

エラーがないことに注意してください。関数は true を返します。これをさまざまな入力でデバッグしました。次の例を検討してください。

if(!db.sql("INSERT INTO test (name, age) VALUES (?, ?);", "nijansen", 23)) {
    std::cerr << db.error() << std::endl;
    return 1;
}

の関数呼び出しをデバッグするとbind、再帰が期待どおりに機能するため、関数に値[1] nijansen[2] 23. SQLite C API のドキュメントには、「一番左の SQL パラメータのインデックスは 1 です」と記載されているため、これは問題ではありません。それでも、データベースでは、クエリの結果は次のとおりid: 1, name: 23, age: 23です。この問題についてもう一度見ていただければ幸いです。

4

1 に答える 1