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) {}
36 template <
typename... Types>
37 SQLiteStatement(sqlite3* db,
const std::string& zSql,
const Types&... args)
38 : db_(db), stmt_(
nullptr, sqlite3_finalize), bind_cnt_(1) {
39 sqlite3_stmt* statement;
41 if (sqlite3_prepare_v2(db_, zSql.c_str(), -1, &statement,
nullptr) != SQLITE_OK) {
42 LOG_ERROR <<
"Could not prepare statement: " << sqlite3_errmsg(db_);
45 stmt_.reset(statement);
47 bindArguments(args...);
50 inline sqlite3_stmt* get()
const {
return stmt_.get(); }
51 inline int step()
const {
return sqlite3_step(stmt_.get()); }
54 inline boost::optional<std::string> get_result_col_blob(
int iCol) {
55 const auto* b =
reinterpret_cast<const char*
>(sqlite3_column_blob(stmt_.get(), iCol));
59 auto length =
static_cast<size_t>(sqlite3_column_bytes(stmt_.get(), iCol));
60 return std::string(b, length);
63 inline boost::optional<std::string> get_result_col_str(
int iCol) {
64 const auto* b =
reinterpret_cast<const char*
>(sqlite3_column_text(stmt_.get(), iCol));
68 return std::string(b);
71 inline int64_t get_result_col_int(
int iCol) {
return sqlite3_column_int64(stmt_.get(), iCol); }
74 void bindArgument(
int v) {
75 if (sqlite3_bind_int(stmt_.get(), bind_cnt_, v) != SQLITE_OK) {
76 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
81 void bindArgument(int64_t v) {
82 if (sqlite3_bind_int64(stmt_.get(), bind_cnt_, v) != SQLITE_OK) {
83 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
88 void bindArgument(
const std::string& v) {
89 owned_data_.push_back(v);
90 const std::string& oe = owned_data_.back();
92 if (sqlite3_bind_text(stmt_.get(), bind_cnt_, oe.c_str(), -1,
nullptr) != SQLITE_OK) {
93 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
98 void bindArgument(
const char* v) { bindArgument(std::string(v)); }
100 void bindArgument(
const SQLBlob& blob) {
101 owned_data_.emplace_back(blob.content);
102 const std::string& oe = owned_data_.back();
104 if (sqlite3_bind_blob(stmt_.get(), bind_cnt_, oe.c_str(),
static_cast<int>(oe.size()), SQLITE_STATIC) !=
106 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
112 void bindArguments() {}
114 template <
typename T,
typename... Types>
115 void bindArguments(
const T& v,
const Types&... args) {
118 bindArguments(args...);
122 std::unique_ptr<sqlite3_stmt, int (*)(sqlite3_stmt*)> stmt_;
126 std::list<std::string> owned_data_;
130 extern std::mutex sql_mutex;
133 sqlite3* get() {
return handle_.get(); }
134 int get_rc()
const {
return rc_; }
136 explicit SQLite3Guard(
const char* path,
bool readonly, std::shared_ptr<std::mutex> mutex =
nullptr)
137 : handle_(
nullptr, sqlite3_close), rc_(0), m_(std::move(mutex)) {
141 if (sqlite3_threadsafe() == 0) {
146 rc_ = sqlite3_open_v2(path, &h, SQLITE_OPEN_READONLY,
nullptr);
148 rc_ = sqlite3_open_v2(path, &h, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX,
nullptr);
152 sqlite3_busy_timeout(h, 2000);
157 explicit SQLite3Guard(
const boost::filesystem::path& path,
bool readonly =
false,
158 std::shared_ptr<std::mutex> mutex =
nullptr)
159 :
SQLite3Guard(path.c_str(), readonly, std::move(mutex)) {}
169 int exec(
const char* sql,
int (*callback)(
void*,
int,
char**,
char**),
void* cb_arg) {
170 return sqlite3_exec(handle_.get(), sql, callback, cb_arg,
nullptr);
173 int exec(
const std::string& sql,
int (*callback)(
void*,
int,
char**,
char**),
void* cb_arg) {
174 return exec(sql.c_str(), callback, cb_arg);
177 template <
typename... Types>
178 SQLiteStatement prepareStatement(
const std::string& zSql,
const Types&... args) {
182 std::string errmsg()
const {
return sqlite3_errmsg(handle_.get()); }
192 void beginTransaction() {
195 if (exec(
"BEGIN TRANSACTION;",
nullptr,
nullptr) != SQLITE_OK) {
196 LOG_ERROR <<
"Can't begin transaction: " << errmsg();
201 void commitTransaction() {
202 if (exec(
"COMMIT TRANSACTION;",
nullptr,
nullptr) != SQLITE_OK) {
203 LOG_ERROR <<
"Can't commit transaction: " << errmsg();
208 void rollbackTransaction() {
209 if (exec(
"ROLLBACK TRANSACTION;",
nullptr,
nullptr) != SQLITE_OK) {
210 LOG_ERROR <<
"Can't rollback transaction: " << errmsg();
216 std::unique_ptr<sqlite3, int (*)(sqlite3*)> handle_;
218 std::shared_ptr<std::mutex> m_ =
nullptr;
221 #endif // SQL_UTILS_H_