おそらく非常にばかげた間違いであることはわかっていますが、文字通り何時間も座って数行のコードを見つめ、ドキュメントを実行してきましたが、なぜこれが起こるのかまだわかりません。
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_statement
sqlite3_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
です。この問題についてもう一度見ていただければ幸いです。