7 #include <boost/filesystem.hpp> 8 #include <boost/optional.hpp> 12 #include "logging/logging.h" 17 const std::string& content;
18 explicit SQLBlob(
const std::string& str) : content(str) {}
27 SQLException(
const std::string& what =
"SQL error") : std::runtime_error(what) {}
33 template <
typename... Types>
34 SQLiteStatement(sqlite3* db,
const std::string& zSql,
const Types&... args)
35 : db_(db), stmt_(
nullptr, sqlite3_finalize), bind_cnt_(1) {
36 sqlite3_stmt* statement;
38 if (sqlite3_prepare_v2(db_, zSql.c_str(), -1, &statement,
nullptr) != SQLITE_OK) {
39 LOG_ERROR <<
"Could not prepare statement: " << sqlite3_errmsg(db_);
42 stmt_.reset(statement);
44 bindArguments(args...);
47 inline sqlite3_stmt*
get()
const {
return stmt_.get(); }
48 inline int step()
const {
return sqlite3_step(stmt_.get()); }
51 inline boost::optional<std::string> get_result_col_blob(
int iCol) {
52 auto b =
reinterpret_cast<const char*
>(sqlite3_column_blob(stmt_.get(), iCol));
56 return std::string(b);
59 inline boost::optional<std::string> get_result_col_str(
int iCol) {
60 auto b =
reinterpret_cast<const char*
>(sqlite3_column_text(stmt_.get(), iCol));
64 return std::string(b);
67 inline int64_t get_result_col_int(
int iCol) {
return sqlite3_column_int64(stmt_.get(), iCol); }
70 void bindArgument(
int v) {
71 if (sqlite3_bind_int(stmt_.get(), bind_cnt_, v) != SQLITE_OK) {
72 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
73 throw std::runtime_error(
"SQLite bind error");
77 void bindArgument(int64_t v) {
78 if (sqlite3_bind_int64(stmt_.get(), bind_cnt_, v) != SQLITE_OK) {
79 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
80 throw std::runtime_error(
"SQLite bind error");
84 void bindArgument(
const std::string& v) {
85 owned_data_.push_back(v);
86 const std::string& oe = owned_data_.back();
88 if (sqlite3_bind_text(stmt_.get(), bind_cnt_, oe.c_str(), -1,
nullptr) != SQLITE_OK) {
89 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
90 throw std::runtime_error(
"SQLite bind error");
94 void bindArgument(
const char* v) { bindArgument(std::string(v)); }
96 void bindArgument(
const SQLBlob& blob) {
97 owned_data_.emplace_back(blob.content);
98 const std::string& oe = owned_data_.back();
100 if (sqlite3_bind_blob(stmt_.get(), bind_cnt_, oe.c_str(),
static_cast<int>(oe.size()), SQLITE_STATIC) !=
102 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
103 throw std::runtime_error(
"SQLite bind error");
108 if (sqlite3_bind_zeroblob(stmt_.get(), bind_cnt_,
static_cast<int>(blob.size)) != SQLITE_OK) {
109 LOG_ERROR <<
"Could not bind: " << sqlite3_errmsg(db_);
110 throw std::runtime_error(
"SQLite bind error");
115 void bindArguments() {}
117 template <
typename T,
typename... Types>
118 void bindArguments(
const T& v,
const Types&... args) {
121 bindArguments(args...);
125 std::unique_ptr<sqlite3_stmt, int (*)(sqlite3_stmt*)> stmt_;
129 std::list<std::string> owned_data_;
135 sqlite3*
get() {
return handle_.get(); }
136 int get_rc() {
return rc_; }
138 explicit SQLite3Guard(
const char* path,
bool readonly) : handle_(
nullptr, sqlite3_close), rc_(0) {
141 rc_ = sqlite3_open_v2(path, &h, SQLITE_OPEN_READONLY,
nullptr);
143 rc_ = sqlite3_open(path, &h);
148 explicit SQLite3Guard(
const boost::filesystem::path& path,
bool readonly =
false)
151 int exec(
const char* sql,
int (*callback)(
void*,
int,
char**,
char**),
void* cb_arg) {
152 return sqlite3_exec(handle_.get(), sql, callback, cb_arg,
nullptr);
155 int exec(
const std::string& sql,
int (*callback)(
void*,
int,
char**,
char**),
void* cb_arg) {
156 return exec(sql.c_str(), callback, cb_arg);
159 template <
typename... Types>
160 SQLiteStatement prepareStatement(
const std::string& zSql,
const Types&... args) {
164 std::string errmsg()
const {
return sqlite3_errmsg(handle_.get()); }
174 bool beginTransaction() {
177 int ret = exec(
"BEGIN TRANSACTION;",
nullptr,
nullptr);
178 if (ret != SQLITE_OK) {
179 LOG_ERROR <<
"Can't begin transaction: " << errmsg();
181 return ret == SQLITE_OK;
184 bool commitTransaction() {
185 int ret = exec(
"COMMIT TRANSACTION;",
nullptr,
nullptr);
186 if (ret != SQLITE_OK) {
187 LOG_ERROR <<
"Can't commit transaction: " << errmsg();
189 return ret == SQLITE_OK;
192 bool rollbackTransaction() {
193 int ret = exec(
"ROLLBACK TRANSACTION;",
nullptr,
nullptr);
194 if (ret != SQLITE_OK) {
195 LOG_ERROR <<
"Can't rollback transaction: " << errmsg();
197 return ret == SQLITE_OK;
201 std::unique_ptr<sqlite3, int (*)(sqlite3*)> handle_;
205 #endif // SQL_UTILS_H_