2 * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 #ifndef TIZEN_DATABASE_DATABASE_HPP_
18 #define TIZEN_DATABASE_DATABASE_HPP_
33 namespace tizen_base {
35 template<std::size_t N>
37 static const constexpr auto value = N;
40 template <class F, std::size_t... Is>
41 void for_(F func, std::index_sequence<Is...>) {
42 (func(num<Is>{}), ...);
45 template <std::size_t N, typename F>
47 for_(func, std::make_index_sequence<N>());
50 using DbType = std::optional<std::variant<int, double, std::string,
51 std::vector<unsigned char>>>;
55 AutoDbType() = default;
56 explicit AutoDbType(DbType db_type) : db_type_(db_type) {}
58 explicit operator int () {
60 throw std::runtime_error("invalid type conversion from nullopt to int");
61 return std::get<int>(*db_type_);
64 explicit operator std::string () {
66 throw std::runtime_error(
67 "invalid type conversion from nullopt to string");
70 return std::get<std::string>(*db_type_);
73 explicit operator double () {
75 throw std::runtime_error(
76 "invalid type conversion from nullopt to double");
79 return std::get<double>(*db_type_);
82 explicit operator std::vector<unsigned char> () {
84 throw std::runtime_error(
85 "invalid type conversion from nullopt to std::vector<unsigned char>");
88 return std::get<std::vector<unsigned char>>(*db_type_);
91 operator std::optional<int> () {
94 return std::get<int>(*db_type_);
97 operator std::optional<std::string> () {
100 return std::get<std::string>(*db_type_);
103 operator std::optional<double> () {
106 return std::get<double>(*db_type_);
109 operator std::optional<std::vector<unsigned char>> () {
112 return std::get<std::vector<unsigned char>>(*db_type_);
119 using _ = AutoDbType;
123 class TransactionGuard {
125 TransactionGuard(const TransactionGuard&) = delete;
126 TransactionGuard& operator = (const TransactionGuard&) = delete;
128 TransactionGuard(TransactionGuard&& t) noexcept {
133 TransactionGuard& operator = (TransactionGuard&& t) noexcept {
136 sqlite3_exec(db_, "ROLLBACK", nullptr, nullptr, nullptr);
144 explicit TransactionGuard(sqlite3* db) : db_(db) {
145 if (sqlite3_exec(db, "BEGIN DEFERRED", nullptr, nullptr, nullptr)
147 throw std::runtime_error("begin transaction failed");
151 ~TransactionGuard() {
153 sqlite3_exec(db_, "ROLLBACK", nullptr, nullptr, nullptr);
157 int ret = sqlite3_exec(db_, "COMMIT", nullptr, nullptr, nullptr);
158 if (ret != SQLITE_OK) {
159 sqlite3_exec(db_, "ROLLBACK", nullptr, nullptr, nullptr);
167 sqlite3* db_ = nullptr;
172 Sql(std::string query) : query_(std::move(query)) {}
174 Sql& Bind(std::string val) {
175 if (empty_string_as_null_ && val.empty())
176 bindings_.push_back(DbType(std::nullopt));
178 bindings_.push_back(DbType(std::move(val)));
183 bindings_.push_back(DbType(val));
187 Sql& Bind(double val) {
188 bindings_.push_back(DbType(val));
192 Sql& Bind(std::vector<unsigned char> val) {
193 if (empty_vector_as_null_ && val.empty())
194 bindings_.push_back(DbType(std::nullopt));
196 bindings_.push_back(DbType(std::move(val)));
200 Sql& Bind(const std::nullopt_t val) {
201 bindings_.push_back(DbType(val));
205 Sql& Bind(int pos, std::string val) {
206 if (empty_string_as_null_ && val.empty())
207 binding_map_[pos] = DbType(std::nullopt);
209 binding_map_[pos] = DbType(std::move(val));
213 Sql& Bind(int pos, int val) {
214 binding_map_[pos] = DbType(val);
218 Sql& Bind(int pos, double val) {
219 binding_map_[pos] = DbType(val);
223 Sql& Bind(int pos, std::vector<unsigned char> val) {
224 if (empty_vector_as_null_ && val.empty())
225 binding_map_[pos] = DbType(std::nullopt);
227 binding_map_[pos] = DbType(std::move(val));
231 Sql& Bind(int pos, const std::nullopt_t& val) {
232 binding_map_[pos] = DbType(val);
236 Sql& Bind(std::string name, std::string val) {
237 if (empty_string_as_null_ && val.empty())
238 binding_name_map_[std::move(name)] = DbType(std::nullopt);
240 binding_name_map_[std::move(name)] = DbType(std::move(val));
244 Sql& Bind(std::string name, int val) {
245 binding_name_map_[std::move(name)] = DbType(val);
249 Sql& Bind(std::string name, double val) {
250 binding_name_map_[std::move(name)] = DbType(val);
254 Sql& Bind(std::string name, std::vector<unsigned char> val) {
255 if (empty_vector_as_null_ && val.empty())
256 binding_name_map_[std::move(name)] = DbType(std::nullopt);
258 binding_name_map_[std::move(name)] = DbType(std::move(val));
262 Sql& Bind(std::string name, const std::nullopt_t& val) {
263 binding_name_map_[std::move(name)] = DbType(val);
267 const std::vector<DbType>& GetBindings() const {
271 const std::map<int, DbType>& GetBindingMap() const {
275 const std::map<std::string, DbType>& GetBindingNameMap() const {
276 return binding_name_map_;
279 const std::string& GetQuery() const {
283 Sql& SetEmptyStringAsNull(bool as_null) {
284 empty_string_as_null_ = as_null;
288 Sql& SetEmptyVectorAsNull(bool as_null) {
289 empty_vector_as_null_ = as_null;
295 binding_map_.clear();
296 binding_name_map_.clear();
297 empty_string_as_null_ = false;
298 empty_vector_as_null_ = false;
304 std::vector<DbType> bindings_;
305 std::map<int, DbType> binding_map_;
306 std::map<std::string, DbType> binding_name_map_;
307 bool empty_string_as_null_ = false;
308 bool empty_vector_as_null_ = false;
316 sqlite3_finalize(stmt_);
319 Result(const Result&) = delete;
320 Result& operator = (const Result&) = delete;
322 Result(Result&& r) noexcept {
327 Result& operator = (Result&& r) noexcept {
330 sqlite3_finalize(stmt_);
340 explicit Record(const sqlite3_stmt* stmt) : stmt_(stmt) {}
342 AutoDbType Get(int pos) const {
343 sqlite3_stmt* stmt = const_cast<sqlite3_stmt*>(stmt_);
344 int type = sqlite3_column_type(stmt, pos);
347 if (type == SQLITE_TEXT) {
348 dbt = DbType(reinterpret_cast<const char*>(
349 sqlite3_column_text(stmt, pos)));
350 } else if (type == SQLITE_INTEGER) {
351 dbt = DbType(sqlite3_column_int(stmt, pos));
352 } else if (type == SQLITE_FLOAT) {
353 dbt = DbType(sqlite3_column_double(stmt, pos));
354 } else if (type == SQLITE_BLOB) {
355 const unsigned char* val = reinterpret_cast<const unsigned char*>(
356 sqlite3_column_blob(stmt, pos));
357 int len = sqlite3_column_bytes(stmt, pos);
359 if (!val || len < 0) {
360 throw std::runtime_error("invalid blob");;
362 dbt = DbType(std::vector<unsigned char>(val, val + len));
364 } else if (type == SQLITE_NULL) {
365 dbt = DbType(std::nullopt);
367 throw std::runtime_error("invalid column type");
370 return AutoDbType(dbt);
373 template <typename ...Types>
375 std::tuple<Types...> t;
377 for_<std::tuple_size_v<std::tuple<Types...>>>([&] (auto i) {
378 std::get<i.value>(t) = Get(pos++);
385 const sqlite3_stmt* stmt_;
390 explicit Iterator(sqlite3_stmt* stmt) : stmt_(stmt) {}
392 Record operator*() { return Record(stmt_); }
394 bool operator != (const Iterator& rhs) const {
395 return stmt_ != rhs.stmt_;
399 int r = sqlite3_step(stmt_);
405 sqlite3_stmt* stmt_ = nullptr;
408 Iterator begin() const {
409 return Iterator(stmt_);
412 Iterator end() const {
413 return Iterator(nullptr);
416 explicit operator bool() {
417 if (stmt_ == nullptr)
422 explicit operator int() {
425 return sqlite3_errcode(db_);
428 operator const char*() {
431 return sqlite3_errmsg(db_);
435 std::vector<T> ToVector() {
436 if (stmt_ == nullptr)
440 for (const auto& rec : *this) {
443 vec.push_back(std::move(t));
450 std::list<T> ToList() {
451 if (stmt_ == nullptr)
455 for (const auto& rec : *this) {
458 l.push_back(std::move(t));
465 std::optional<T> GetFirst() {
466 if (stmt_ == nullptr)
468 for (const auto& rec : *this) {
477 std::optional<Record> GetFirstRecord() {
478 if (stmt_ == nullptr)
480 for (const auto& rec : *this) {
487 sqlite3_stmt* GetRaw() const {
491 const std::string& GetQuery() const {
496 friend class Database;
497 Result(sqlite3_stmt* stmt, sqlite3* db, std::string query)
498 : stmt_(stmt), db_(db), query_(std::move(query)) {}
500 sqlite3_stmt* stmt_ = nullptr;
501 sqlite3* db_ = nullptr;
505 Database(std::string db, int flags) {
506 int r = sqlite3_open_v2(db.c_str(), &db_, flags, nullptr);
508 throw std::runtime_error("open failed");
511 Database(std::string db, int flags, std::function<bool(int)> busy_handler) {
512 int r = sqlite3_open_v2(db.c_str(), &db_, flags, nullptr);
514 throw std::runtime_error("sqlite3_open_v2() failed");
516 busy_handler_ = std::move(busy_handler);
517 r = sqlite3_busy_handler(db_, [](void* data, int count) {
518 Database* pDb = static_cast<Database*>(data);
519 if (pDb->busy_handler_(count))
524 if (r != SQLITE_OK) {
525 sqlite3_close_v2(db_);
526 throw std::runtime_error("sqlite3_busy_handler() failed");
532 sqlite3_close_v2(db_);
535 Database() = default;
536 Database(const Database&) = delete;
537 Database& operator = (const Database&) = delete;
539 Database(Database&& db) noexcept {
544 explicit operator bool() {
550 Database& operator = (Database&& db) noexcept {
553 sqlite3_close_v2(db_);
561 TransactionGuard CreateTransactionGuard() {
562 return TransactionGuard(db_);
565 Result Exec(const Sql& sql) const {
567 throw std::runtime_error("Not opened");
569 sqlite3_stmt* stmt = nullptr;
570 int r = sqlite3_prepare_v2(db_, sql.GetQuery().c_str(),
572 if (r != SQLITE_OK) {
573 return { nullptr, nullptr, "" };
576 std::unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)*> stmt_auto(stmt,
579 for (const auto& i : sql.GetBindings()) {
580 Bind(pos++, i, stmt);
583 for (const auto& i : sql.GetBindingMap()) {
584 Bind(i.first, i.second, stmt);
587 for (const auto& i : sql.GetBindingNameMap()) {
588 int pos = sqlite3_bind_parameter_index(stmt, i.first.c_str());
590 throw std::runtime_error("Invalid binding");
591 Bind(pos, i.second, stmt);
594 r = sqlite3_step(stmt);
595 if (r != SQLITE_ROW && r != SQLITE_DONE) {
596 return { nullptr, db_, "" };
599 return { stmt_auto.release(), db_, sql.GetQuery() };
602 bool Exec(const Sql& sql, const Result& previous_stmt) {
603 if (sql.GetQuery() != previous_stmt.GetQuery())
604 throw std::runtime_error("Query is different");
606 sqlite3_stmt* stmt = previous_stmt.GetRaw();
610 int r = sqlite3_reset(stmt);
611 if (r != SQLITE_ROW && r != SQLITE_DONE && r != SQLITE_OK)
615 for (const auto& i : sql.GetBindings()) {
616 Bind(pos++, i, stmt);
619 for (const auto& i : sql.GetBindingMap()) {
620 Bind(i.first, i.second, stmt);
623 for (const auto& i : sql.GetBindingNameMap()) {
624 int pos = sqlite3_bind_parameter_index(stmt, i.first.c_str());
626 throw std::runtime_error("Invalid binding");
627 Bind(pos, i.second, stmt);
630 r = sqlite3_step(stmt);
631 if (r != SQLITE_ROW && r != SQLITE_DONE)
638 void Bind(int pos, const DbType& type, sqlite3_stmt* stmt) const {
641 r = sqlite3_bind_null(stmt, pos);
642 if (r != SQLITE_OK) {
643 throw std::runtime_error("Invalid binding");
649 if (const std::string* pstr = std::get_if<std::string>(&(*type))) {
650 r = sqlite3_bind_text(stmt, pos, (*pstr).c_str(), -1,
652 } else if (const int* pint = std::get_if<int>(&(*type))) {
653 r = sqlite3_bind_int(stmt, pos, (*pint));
654 } else if (const double* pdouble = std::get_if<double>(&(*type))) {
655 r = sqlite3_bind_double(stmt, pos, (*pdouble));
656 } else if (const std::vector<unsigned char>* pvector =
657 std::get_if<std::vector<unsigned char>>(&(*type))) {
658 r = sqlite3_bind_blob(stmt, pos, (*pvector).data(),
659 (*pvector).size(), nullptr);
664 if (r != SQLITE_OK) {
665 throw std::runtime_error("Invalid binding");
670 sqlite3* db_ = nullptr;
671 std::function<bool(int)> busy_handler_;
674 } // namespace tizen_base
676 #endif // TIZEN_DATABASE_DATABASE_HPP_