私はおそらくそれは非常にばかげた間違いであることは知っていますが、私は文字通り数行のコードを見て、文書を通していました。 :最後の引数はSQLiteバインディングの前の引数をオーバーライドします
私は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_
は、作業データベースのハンドルです。私はこの機能が問題と何か関係があっても、私は確信していません。トラブルメーカーとしてsql
関数内で呼び出されるbind
関数です。ここにあります:
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
を渡すをデバッグするとき。 The documentation of the SQLite C APIは "一番左のSQLパラメータは1のインデックスを持っている"と言っているので、問題ではないはずです。それでも、データベースでは、クエリの結果はid: 1, name: 23, age: 23
です。私はこの問題をもう一度見ていただきたいと思います。