In the interest of answering the asked question, the idiomatic C++ way to do this is with std::ostringstream
. Note that this stream class is backed by memory, not a file on disk.
(There is also the snprintf()
option, which looks closer to Python string formatting but has a C-style interface and shouldn't be used from modern C++ without a good reason. If you are writing C++ then write C++, not C.)
std::string toSql(
std::string const & table,
std::string const & field,
std::string const & value
) {
std::ostringstream s;
s << "INSERT INTO " << table
<< " (" << field << ") VALUES (" << value << ")";
return s.str();
}
However, beware that this can open your program to SQL injection attacks if any of the arguments are unsanitized user input. You should instead use a prepared statement (sqlite3_prepare()
followed by sqlite3_bind_...()
) to bind value
into the statement -- but you will still have to build the string from the table
and field
arguments since database object names can't be bound this way.
You can use prepared statements "the C++ way" like this (C++11 or better required for std::unique_ptr
):
#include <memory>
#include <string>
#include <sqlite3.h>
// Deleter functor to properly sqlite3_finalize() statements when we
// are done with them.
struct sqlite3_stmt_deleter
{
void operator()(sqlite3_stmt * p) const {
sqlite3_finalize(p);
}
};
// Type alias for a std::unique_ptr that uses the above functor to
// clean up statements.
using sqlite3_prepared_stmt = std::unique_ptr<sqlite3_stmt, sqlite3_stmt_deleter>;
sqlite3_prepared_stmt prepare(sqlite3 * db, std::string const & sql)
{
sqlite3_stmt * stmt = nullptr;
// Note that we don't allow the caller to see any error information. A
// proper wrapper will want to throw if the return isn't SQLITE3_OK.
sqlite3_prepare_v2(db, sql.c_str(), -1, &stmt, nullptr);
return sqlite3_prepared_stmt(stmt);
}
void example() {
auto insert_stmt = prepare(
your_db,
"INSERT INTO foo (bar) VALUES (?)");
std::string value{"baz"};
// Bind value to the ? in the prepared statement
sqlite3_bind_text(insert_stmt.get(), 1, value.c_str(), -1, SQLITE_TRANSIENT);
// Execute statement.
sqlite3_step(insert_stmt.get());
// Reset statement so it can be used again with bind/step.
sqlite3_reset(insert_stmt.get());
// std::unique_ptr destructor will call sqlite3_finalize() for us.
}
Using this code, you can store a sqlite3_prepared_stmt
somewhere and reuse it.