8 #include <boost/filesystem.hpp> 9 #include <boost/optional.hpp> 13 #include "logging/logging.h" 18 const std::string& content;
19 explicit SQLBlob(
const std::string& str) : content(str) {}
24 SQLException(
const std::string& what =
"SQL error") : std::runtime_error(what) {}
30 template <
typename... Types>
31 SQLiteStatement(sqlite3* db,
const std::string& zSql,
const Types&... args)
32 : db_(db), stmt_(
nullptr, sqlite3_finalize), bind_cnt_(1) {
33 sqlite3_stmt* statement;
35 if (sqlite3_prepare_v2(db_, zSql.c_str(), -1, &statement,
nullptr) != SQLITE_OK) {
36 LOG_ERROR <<
"Could not prepare statement: " << sqlite3_errmsg(db_);
39 stmt_.reset(statement);
41 bindArguments(args...);
44 inline sqlite3_stmt*
get()
const {
return stmt_.get(); }
45 inline int step()
const {
return sqlite3_step(stmt_.get()); }
48 inline boost::optional<std::string> get_result_col_blob(
int iCol) {
49 const auto* b =
reinterpret_cast<const char*
>(sqlite3_column_blob(stmt_.get(), iCol));
53 auto length =
static_cast<size_t>(sqlite3_column_bytes(stmt_.get(), iCol));
54 return std::string(b, length);
57 inline boost::optional<std::string> get_result_col_str(
int iCol) {
58 const auto* b =
reinterpret_cast<const char*
>(sqlite3_column_text(stmt_.get(), iCol));
62 return std::string(b);
65 inline int64_t get_result_col_int(
int iCol) {
return sqlite3_column_int64(stmt_.get(), iCol); }
68 void bindArgument(
int v) {
69 if (sqlite3_bind_int(stmt_.get(), bind_cnt_, v) != SQLITE_OK) {
70 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
71 throw std::runtime_error(
"SQLite bind error");
75 void bindArgument(int64_t v) {
76 if (sqlite3_bind_int64(stmt_.get(), bind_cnt_, v) != SQLITE_OK) {
77 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
78 throw std::runtime_error(
"SQLite bind error");
82 void bindArgument(
const std::string& v) {
83 owned_data_.push_back(v);
84 const std::string& oe = owned_data_.back();
86 if (sqlite3_bind_text(stmt_.get(), bind_cnt_, oe.c_str(), -1,
nullptr) != SQLITE_OK) {
87 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
88 throw std::runtime_error(
"SQLite bind error");
92 void bindArgument(
const char* v) { bindArgument(std::string(v)); }
94 void bindArgument(
const SQLBlob& blob) {
95 owned_data_.emplace_back(blob.content);
96 const std::string& oe = owned_data_.back();
98 if (sqlite3_bind_blob(stmt_.get(), bind_cnt_, oe.c_str(),
static_cast<int>(oe.size()), SQLITE_STATIC) !=
100 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
101 throw std::runtime_error(
"SQLite bind error");
106 void bindArguments() {}
108 template <
typename T,
typename... Types>
109 void bindArguments(
const T& v,
const Types&... args) {
112 bindArguments(args...);
116 std::unique_ptr<sqlite3_stmt, int (*)(sqlite3_stmt*)> stmt_;
120 std::list<std::string> owned_data_;
124 extern std::mutex sql_mutex;
127 sqlite3*
get() {
return handle_.get(); }
128 int get_rc()
const {
return rc_; }
130 explicit SQLite3Guard(
const char* path,
bool readonly, std::shared_ptr<std::mutex> mutex =
nullptr)
131 : handle_(
nullptr, sqlite3_close), rc_(0), m_(std::move(mutex)) {
135 if (sqlite3_threadsafe() == 0) {
136 throw std::runtime_error(
"sqlite3 has been compiled without multitheading support");
140 rc_ = sqlite3_open_v2(path, &h, SQLITE_OPEN_READONLY,
nullptr);
142 rc_ = sqlite3_open_v2(path, &h, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX,
nullptr);
146 sqlite3_busy_timeout(h, 2000);
151 explicit SQLite3Guard(
const boost::filesystem::path& path,
bool readonly =
false,
152 std::shared_ptr<std::mutex> mutex =
nullptr)
153 :
SQLite3Guard(path.c_str(), readonly, std::move(mutex)) {}
163 int exec(
const char* sql,
int (*callback)(
void*,
int,
char**,
char**),
void* cb_arg) {
164 return sqlite3_exec(handle_.get(), sql, callback, cb_arg,
nullptr);
167 int exec(
const std::string& sql,
int (*callback)(
void*,
int,
char**,
char**),
void* cb_arg) {
168 return exec(sql.c_str(), callback, cb_arg);
171 template <
typename... Types>
172 SQLiteStatement prepareStatement(
const std::string& zSql,
const Types&... args) {
176 std::string errmsg()
const {
return sqlite3_errmsg(handle_.get()); }
186 void beginTransaction() {
189 if (exec(
"BEGIN TRANSACTION;",
nullptr,
nullptr) != SQLITE_OK) {
190 LOG_ERROR <<
"Can't begin transaction: " << errmsg();
195 void commitTransaction() {
196 if (exec(
"COMMIT TRANSACTION;",
nullptr,
nullptr) != SQLITE_OK) {
197 LOG_ERROR <<
"Can't commit transaction: " << errmsg();
202 void rollbackTransaction() {
203 if (exec(
"ROLLBACK TRANSACTION;",
nullptr,
nullptr) != SQLITE_OK) {
204 LOG_ERROR <<
"Can't rollback transaction: " << errmsg();
210 std::unique_ptr<sqlite3, int (*)(sqlite3*)> handle_;
212 std::shared_ptr<std::mutex> m_ =
nullptr;
215 #endif // SQL_UTILS_H_