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) {}
28 SQLException(
const std::string& what =
"SQL error") : std::runtime_error(what) {}
34 template <
typename... Types>
35 SQLiteStatement(sqlite3* db,
const std::string& zSql,
const Types&... args)
36 : db_(db), stmt_(
nullptr, sqlite3_finalize), bind_cnt_(1) {
37 sqlite3_stmt* statement;
39 if (sqlite3_prepare_v2(db_, zSql.c_str(), -1, &statement,
nullptr) != SQLITE_OK) {
40 LOG_ERROR <<
"Could not prepare statement: " << sqlite3_errmsg(db_);
43 stmt_.reset(statement);
45 bindArguments(args...);
48 inline sqlite3_stmt* get()
const {
return stmt_.get(); }
49 inline int step()
const {
return sqlite3_step(stmt_.get()); }
52 inline boost::optional<std::string> get_result_col_blob(
int iCol) {
53 auto b = reinterpret_cast<const char*>(sqlite3_column_blob(stmt_.get(), iCol));
57 auto length = static_cast<size_t>(sqlite3_column_bytes(stmt_.get(), iCol));
58 return std::string(b, length);
61 inline boost::optional<std::string> get_result_col_str(
int iCol) {
62 auto b = reinterpret_cast<const char*>(sqlite3_column_text(stmt_.get(), iCol));
66 return std::string(b);
69 inline int64_t get_result_col_int(
int iCol) {
return sqlite3_column_int64(stmt_.get(), iCol); }
72 void bindArgument(
int v) {
73 if (sqlite3_bind_int(stmt_.get(), bind_cnt_, v) != SQLITE_OK) {
74 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
75 throw std::runtime_error(
"SQLite bind error");
79 void bindArgument(int64_t v) {
80 if (sqlite3_bind_int64(stmt_.get(), bind_cnt_, v) != SQLITE_OK) {
81 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
82 throw std::runtime_error(
"SQLite bind error");
86 void bindArgument(
const std::string& v) {
87 owned_data_.push_back(v);
88 const std::string& oe = owned_data_.back();
90 if (sqlite3_bind_text(stmt_.get(), bind_cnt_, oe.c_str(), -1,
nullptr) != SQLITE_OK) {
91 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
92 throw std::runtime_error(
"SQLite bind error");
96 void bindArgument(
const char* v) { bindArgument(std::string(v)); }
98 void bindArgument(
const SQLBlob& blob) {
99 owned_data_.emplace_back(blob.content);
100 const std::string& oe = owned_data_.back();
102 if (sqlite3_bind_blob(stmt_.get(), bind_cnt_, oe.c_str(), static_cast<int>(oe.size()), SQLITE_STATIC) !=
104 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
105 throw std::runtime_error(
"SQLite bind error");
110 if (sqlite3_bind_zeroblob(stmt_.get(), bind_cnt_, static_cast<int>(blob.size)) != SQLITE_OK) {
111 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
112 throw std::runtime_error(
"SQLite bind error");
117 void bindArguments() {}
119 template <
typename T,
typename... Types>
120 void bindArguments(
const T& v,
const Types&... args) {
123 bindArguments(args...);
127 std::unique_ptr<sqlite3_stmt, int (*)(sqlite3_stmt*)> stmt_;
131 std::list<std::string> owned_data_;
135 extern std::mutex sql_mutex;
138 sqlite3* get() {
return handle_.get(); }
139 int get_rc() {
return rc_; }
141 explicit SQLite3Guard(
const char* path,
bool readonly) : handle_(
nullptr, sqlite3_close), rc_(0) {
142 if (sqlite3_threadsafe() == 0) {
143 throw std::runtime_error(
"sqlite3 has been compiled without multitheading support");
147 rc_ = sqlite3_open_v2(path, &h, SQLITE_OPEN_READONLY,
nullptr);
149 rc_ = sqlite3_open_v2(path, &h, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE | SQLITE_OPEN_NOMUTEX,
nullptr);
154 explicit SQLite3Guard(
const boost::filesystem::path& path,
bool readonly =
false)
160 int exec(
const char* sql,
int (*callback)(
void*,
int,
char**,
char**),
void* cb_arg) {
161 return sqlite3_exec(handle_.get(), sql, callback, cb_arg,
nullptr);
164 int exec(
const std::string& sql,
int (*callback)(
void*,
int,
char**,
char**),
void* cb_arg) {
165 return exec(sql.c_str(), callback, cb_arg);
168 template <
typename... Types>
169 SQLiteStatement prepareStatement(
const std::string& zSql,
const Types&... args) {
173 std::string errmsg()
const {
return sqlite3_errmsg(handle_.get()); }
183 bool beginTransaction() {
186 int ret = exec(
"BEGIN TRANSACTION;",
nullptr,
nullptr);
187 if (ret != SQLITE_OK) {
188 LOG_ERROR <<
"Can't begin transaction: " << errmsg();
190 return ret == SQLITE_OK;
193 bool commitTransaction() {
194 int ret = exec(
"COMMIT TRANSACTION;",
nullptr,
nullptr);
195 if (ret != SQLITE_OK) {
196 LOG_ERROR <<
"Can't commit transaction: " << errmsg();
198 return ret == SQLITE_OK;
201 bool rollbackTransaction() {
202 int ret = exec(
"ROLLBACK TRANSACTION;",
nullptr,
nullptr);
203 if (ret != SQLITE_OK) {
204 LOG_ERROR <<
"Can't rollback transaction: " << errmsg();
206 return ret == SQLITE_OK;
210 std::unique_ptr<sqlite3, int (*)(sqlite3*)> handle_;
214 #endif // SQL_UTILS_H_