Fix Exec function to determine the cause of failure
[platform/core/base/bundle.git] / tizen-database / database.hpp
1 /*
2  * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 #ifndef TIZEN_DATABASE_DATABASE_HPP_
18 #define TIZEN_DATABASE_DATABASE_HPP_
19
20 #include <sqlite3.h>
21
22 #include <functional>
23 #include <list>
24 #include <map>
25 #include <memory>
26 #include <optional>
27 #include <stdexcept>
28 #include <string>
29 #include <tuple>
30 #include <utility>
31 #include <variant>
32 #include <vector>
33
34 namespace tizen_base {
35
36 template<std::size_t N>
37 struct num {
38   static const constexpr auto value = N;
39 };
40
41 template <class F, std::size_t... Is>
42 void for_(F func, std::index_sequence<Is...>) {
43   (func(num<Is>{}), ...);
44 }
45
46 template <std::size_t N, typename F>
47 void for_(F func) {
48   for_(func, std::make_index_sequence<N>());
49 }
50
51 using DbType = std::optional<std::variant<int64_t, double, std::string,
52     std::vector<unsigned char>>>;
53
54 class DbException : public std::runtime_error {
55  public:
56   explicit DbException(const std::string& msg, int code = SQLITE_ERROR)
57       : std::runtime_error(msg), code_(code) {
58   }
59
60   DbException(const std::string& msg, int code, const std::string& file,
61       int line) : std::runtime_error(msg), code_(code) {
62     msg_ = msg + " at " + file + ":" + std::to_string(line);
63   }
64
65   int code() const {
66     return code_;
67   }
68
69   const char* msg() const {
70     if (msg_.empty())
71       return what();
72     return msg_.c_str();
73   }
74
75  private:
76   int code_;
77   std::string msg_;
78 };
79
80 class AutoDbType {
81  public:
82   AutoDbType() = default;
83   explicit AutoDbType(DbType db_type, int real_type)
84       : db_type_(db_type), real_type_(real_type) {}
85
86   int GetType() const {
87     return real_type_;
88   }
89
90   explicit operator int () {
91     if (!db_type_)
92       throw DbException("invalid type conversion from nullopt to int");
93     if (real_type_ != SQLITE_INTEGER)
94       throw DbException("invalid type conversion to int");
95
96     return std::get<int64_t>(*db_type_);
97   }
98
99   explicit operator int64_t () {
100     if (!db_type_)
101       throw DbException("invalid type conversion from nullopt to int64_t");
102     if (real_type_ != SQLITE_INTEGER)
103       throw DbException("invalid type conversion to int64_t");
104
105     return std::get<int64_t>(*db_type_);
106   }
107
108   explicit operator std::string () {
109     if (!db_type_) {
110       throw DbException(
111           "invalid type conversion from nullopt to string");
112     }
113
114     if (real_type_ != SQLITE_TEXT)
115       throw DbException("invalid type conversion to string");
116
117     return std::get<std::string>(*db_type_);
118   }
119
120   explicit operator double () {
121     if (!db_type_) {
122       throw DbException(
123           "invalid type conversion from nullopt to double");
124     }
125
126     if (real_type_ != SQLITE_FLOAT)
127       throw DbException("invalid type conversion to double");
128
129     return std::get<double>(*db_type_);
130   }
131
132   explicit operator std::vector<unsigned char> () {
133     if (!db_type_) {
134       throw DbException(
135           "invalid type conversion from nullopt to std::vector<unsigned char>");
136     }
137
138     if (real_type_ != SQLITE_BLOB)
139       throw DbException("invalid type conversion to std::vector<unsigned char>");
140
141     return std::get<std::vector<unsigned char>>(*db_type_);
142   }
143
144   operator std::optional<int> () {
145     if (!db_type_)
146       return std::nullopt;
147     if (real_type_ != SQLITE_INTEGER)
148       throw DbException("invalid type conversion to int");
149
150     return std::get<int64_t>(*db_type_);
151   }
152
153   operator std::optional<int64_t> () {
154     if (!db_type_)
155       return std::nullopt;
156     if (real_type_ != SQLITE_INTEGER)
157       throw DbException("invalid type conversion to int64_t");
158
159     return std::get<int64_t>(*db_type_);
160   }
161
162   operator std::optional<std::string> () {
163     if (!db_type_)
164       return std::nullopt;
165     if (real_type_ != SQLITE_TEXT)
166       throw DbException("invalid type conversion to string");
167
168     return std::get<std::string>(*db_type_);
169   }
170
171   operator std::optional<double> () {
172     if (!db_type_)
173       return std::nullopt;
174     if (real_type_ != SQLITE_FLOAT)
175       throw DbException("invalid type conversion to double");
176
177     return std::get<double>(*db_type_);
178   }
179
180   operator std::optional<std::vector<unsigned char>> () {
181     if (!db_type_)
182       return std::nullopt;
183     if (real_type_ != SQLITE_BLOB)
184       throw DbException("invalid type conversion to std::vector<unsigned char>");
185
186     return std::get<std::vector<unsigned char>>(*db_type_);
187   }
188
189  private:
190   DbType db_type_;
191   int real_type_ = SQLITE_NULL;
192 };
193
194 using _ = AutoDbType;
195
196 class Database {
197  public:
198   class TransactionGuard {
199    public:
200     TransactionGuard(const TransactionGuard&) = delete;
201     TransactionGuard& operator = (const TransactionGuard&) = delete;
202
203     TransactionGuard(TransactionGuard&& t) noexcept {
204       db_ = std::move(t.db_);
205     }
206
207     TransactionGuard& operator = (TransactionGuard&& t) noexcept {
208       if (this != &t) {
209         if (!db_.expired())
210           sqlite3_exec(db_.lock().get(), "ROLLBACK", nullptr, nullptr, nullptr);
211         db_ = std::move(t.db_);
212       }
213
214       return *this;
215     }
216
217     explicit TransactionGuard(const std::shared_ptr<sqlite3>& db)
218         : db_(db) {
219       int r = sqlite3_exec(db_.lock().get(), "BEGIN DEFERRED",
220           nullptr, nullptr, nullptr);
221       if (r != SQLITE_OK) {
222         throw DbException("begin transaction failed", r);
223       }
224     }
225
226     ~TransactionGuard() {
227       if (!db_.expired())
228         sqlite3_exec(db_.lock().get(), "ROLLBACK", nullptr, nullptr, nullptr);
229     }
230
231     int Commit() {
232       if (db_.expired())
233         return SQLITE_OK;
234
235       auto db = db_.lock();
236       int ret = sqlite3_exec(db.get(), "COMMIT", nullptr, nullptr, nullptr);
237       if (ret != SQLITE_OK) {
238         sqlite3_exec(db.get(), "ROLLBACK", nullptr, nullptr, nullptr);
239       }
240
241       return ret;
242     }
243
244    private:
245     std::weak_ptr<sqlite3> db_;
246   };
247
248   class Sql {
249    public:
250     Sql(std::string query) : query_(std::move(query)) {}
251
252     Sql& Bind(const char* val) {
253       if (val == nullptr) {
254         bindings_.push_back(DbType(std::nullopt));
255       } else {
256         std::string str = val;
257         if (empty_string_as_null_ && str.empty())
258           bindings_.push_back(DbType(std::nullopt));
259         else
260           bindings_.push_back(DbType(std::move(str)));
261       }
262       return *this;
263     }
264
265     Sql& Bind(std::string val) {
266       if (empty_string_as_null_ && val.empty())
267         bindings_.push_back(DbType(std::nullopt));
268       else
269         bindings_.push_back(DbType(std::move(val)));
270       return *this;
271     }
272
273     Sql& Bind(int val) {
274       bindings_.push_back(DbType(static_cast<int64_t>(val)));
275       return *this;
276     }
277
278     Sql& Bind(int64_t val) {
279       bindings_.push_back(DbType(val));
280       return *this;
281     }
282
283     Sql& Bind(double val) {
284       bindings_.push_back(DbType(val));
285       return *this;
286     }
287
288     Sql& Bind(std::vector<unsigned char> val) {
289       if (empty_vector_as_null_ && val.empty())
290         bindings_.push_back(DbType(std::nullopt));
291       else
292         bindings_.push_back(DbType(std::move(val)));
293       return *this;
294     }
295
296     Sql& Bind(const std::nullopt_t val) {
297       bindings_.push_back(DbType(val));
298       return *this;
299     }
300
301     Sql& Bind(int pos, const char* val) {
302       if (val == nullptr) {
303         binding_map_[pos] = DbType(std::nullopt);
304       } else {
305         std::string str = val;
306         if (empty_string_as_null_ && str.empty())
307           binding_map_[pos] = DbType(std::nullopt);
308         else
309           binding_map_[pos] = DbType(std::move(str));
310       }
311       return *this;
312     }
313
314     Sql& Bind(int pos, std::string val) {
315       if (empty_string_as_null_ && val.empty())
316         binding_map_[pos] = DbType(std::nullopt);
317       else
318         binding_map_[pos] = DbType(std::move(val));
319       return *this;
320     }
321
322     Sql& Bind(int pos, int val) {
323       binding_map_[pos] = DbType(static_cast<int64_t>(val));
324       return *this;
325     }
326
327     Sql& Bind(int pos, int64_t val) {
328       binding_map_[pos] = DbType(val);
329       return *this;
330     }
331
332     Sql& Bind(int pos, double val) {
333       binding_map_[pos] = DbType(val);
334       return *this;
335     }
336
337     Sql& Bind(int pos, std::vector<unsigned char> val) {
338       if (empty_vector_as_null_ && val.empty())
339         binding_map_[pos] = DbType(std::nullopt);
340       else
341         binding_map_[pos] = DbType(std::move(val));
342       return *this;
343     }
344
345     Sql& Bind(int pos, const std::nullopt_t& val) {
346       binding_map_[pos] = DbType(val);
347       return *this;
348     }
349
350     Sql& Bind(std::string name, const char* val) {
351       if (val == nullptr) {
352         binding_name_map_[std::move(name)] = DbType(std::nullopt);
353       } else {
354         std::string str = val;
355         if (empty_string_as_null_ && str.empty())
356           binding_name_map_[std::move(name)] = DbType(std::nullopt);
357         else
358           binding_name_map_[std::move(name)] = DbType(std::move(str));
359       }
360       return *this;
361     }
362
363     Sql& Bind(std::string name, std::string val) {
364       if (empty_string_as_null_ && val.empty())
365         binding_name_map_[std::move(name)] = DbType(std::nullopt);
366       else
367         binding_name_map_[std::move(name)] = DbType(std::move(val));
368       return *this;
369     }
370
371     Sql& Bind(std::string name, int val) {
372       binding_name_map_[std::move(name)] = DbType(static_cast<int64_t>(val));
373       return *this;
374     }
375
376     Sql& Bind(std::string name, int64_t val) {
377       binding_name_map_[std::move(name)] = DbType(val);
378       return *this;
379     }
380
381     Sql& Bind(std::string name, double val) {
382       binding_name_map_[std::move(name)] = DbType(val);
383       return *this;
384     }
385
386     Sql& Bind(std::string name, std::vector<unsigned char> val) {
387       if (empty_vector_as_null_ && val.empty())
388         binding_name_map_[std::move(name)] = DbType(std::nullopt);
389       else
390         binding_name_map_[std::move(name)] = DbType(std::move(val));
391       return *this;
392     }
393
394     Sql& Bind(std::string name, const std::nullopt_t& val) {
395       binding_name_map_[std::move(name)] = DbType(val);
396       return *this;
397     }
398
399     const std::vector<DbType>& GetBindings() const {
400       return bindings_;
401     }
402
403     const std::map<int, DbType>& GetBindingMap() const {
404       return binding_map_;
405     }
406
407     const std::map<std::string, DbType>& GetBindingNameMap() const {
408       return binding_name_map_;
409     }
410
411     const std::string& GetQuery() const {
412       return query_;
413     }
414
415     Sql& SetEmptyStringAsNull(bool as_null) {
416       empty_string_as_null_ = as_null;
417       return *this;
418     }
419
420     Sql& SetEmptyVectorAsNull(bool as_null) {
421       empty_vector_as_null_ = as_null;
422       return *this;
423     }
424
425     Sql& Reset() {
426       bindings_.clear();
427       binding_map_.clear();
428       binding_name_map_.clear();
429       empty_string_as_null_ = false;
430       empty_vector_as_null_ = false;
431       return *this;
432     }
433
434    private:
435     std::string query_;
436     std::vector<DbType> bindings_;
437     std::map<int, DbType> binding_map_;
438     std::map<std::string, DbType> binding_name_map_;
439     bool empty_string_as_null_ = false;
440     bool empty_vector_as_null_ = false;
441   };
442
443   class Result {
444    public:
445     Result() = default;
446     ~Result() {
447       if (stmt_)
448         sqlite3_finalize(stmt_);
449     }
450
451     Result(const Result&) = delete;
452     Result& operator = (const Result&) = delete;
453
454     Result(Result&& r) noexcept {
455       stmt_ = r.stmt_;
456       r.stmt_ = nullptr;
457       query_ = std::move(r.query_);
458       is_done_ = r.is_done_;
459     }
460
461     Result& operator = (Result&& r) noexcept {
462       if (this != &r) {
463         if (stmt_)
464           sqlite3_finalize(stmt_);
465         stmt_ = r.stmt_;
466         r.stmt_ = nullptr;
467         query_ = std::move(r.query_);
468         is_done_ = r.is_done_;
469       }
470
471       return *this;
472     }
473
474     class Record {
475      public:
476       explicit Record(const sqlite3_stmt* stmt) : stmt_(stmt) {}
477
478       std::optional<std::string> GetString(int pos) const {
479         sqlite3_stmt* stmt = const_cast<sqlite3_stmt*>(stmt_);
480         const char* text = reinterpret_cast<const char*>(
481             sqlite3_column_text(stmt, pos));
482         if (!text)
483           return std::nullopt;
484
485         return text;
486       }
487
488       AutoDbType Get(int pos) const {
489         sqlite3_stmt* stmt = const_cast<sqlite3_stmt*>(stmt_);
490         int type = sqlite3_column_type(stmt, pos);
491
492         DbType dbt;
493         if (type == SQLITE_TEXT) {
494           dbt = DbType(reinterpret_cast<const char*>(
495               sqlite3_column_text(stmt, pos)));
496         } else if (type == SQLITE_INTEGER) {
497           dbt = DbType(static_cast<int64_t>(sqlite3_column_int64(stmt, pos)));
498         } else if (type == SQLITE_FLOAT) {
499           dbt = DbType(sqlite3_column_double(stmt, pos));
500         } else if (type == SQLITE_BLOB) {
501           const unsigned char* val = reinterpret_cast<const unsigned char*>(
502               sqlite3_column_blob(stmt, pos));
503           int len = sqlite3_column_bytes(stmt, pos);
504
505           if (!val || len < 0) {
506             throw DbException("invalid blob");;
507           } else {
508             dbt = DbType(std::vector<unsigned char>(val, val + len));
509           }
510         } else if (type == SQLITE_NULL) {
511           dbt = DbType(std::nullopt);
512         } else {
513           throw DbException("invalid column type", type);
514         }
515
516         return AutoDbType(dbt, type);
517       }
518
519       template <typename ...Types>
520       auto Get() const {
521         std::tuple<Types...> t;
522         int pos = 0;
523         for_<std::tuple_size_v<std::tuple<Types...>>>([&] (auto i) {
524           std::get<i.value>(t) = Get(pos++);
525         });
526
527         return t;
528       }
529
530      private:
531       const sqlite3_stmt* stmt_;
532     };
533
534     class Iterator {
535      public:
536       explicit Iterator(sqlite3_stmt* stmt) : stmt_(stmt) {}
537
538       Record operator*() { return Record(stmt_); }
539
540       bool operator != (const Iterator& rhs) const {
541         return stmt_ != rhs.stmt_;
542       }
543
544       void operator ++() {
545         int r = sqlite3_step(stmt_);
546         if (r != SQLITE_ROW)
547           stmt_ = nullptr;
548       }
549
550      private:
551       sqlite3_stmt* stmt_ = nullptr;
552     };
553
554     Iterator begin() const {
555       if (is_done_)
556         return Iterator(nullptr);
557       return Iterator(stmt_);
558     }
559
560     Iterator end() const {
561       return Iterator(nullptr);
562     }
563
564     operator bool() const {
565       if (stmt_ == nullptr)
566         return false;
567       return true;
568     }
569
570     explicit operator int() const {
571       auto db = db_.lock();
572       if (db == nullptr)
573         return SQLITE_ERROR;
574       return sqlite3_errcode(db.get());
575     }
576
577     explicit operator const char*() const {
578       auto db = db_.lock();
579       if (db == nullptr)
580         return "";
581       return sqlite3_errmsg(db.get());
582     }
583
584     template <class T>
585     std::vector<T> ToVector() {
586       if (stmt_ == nullptr)
587         return {};
588
589       std::vector<T> vec;
590       for (const auto& rec : *this) {
591         T t;
592         t(rec);
593         vec.push_back(std::move(t));
594       }
595
596       return vec;
597     }
598
599     template <class T>
600     std::list<T> ToList() {
601       if (stmt_ == nullptr)
602         return {};
603
604       std::list<T> l;
605       for (const auto& rec : *this) {
606         T t;
607         t(rec);
608         l.push_back(std::move(t));
609       }
610
611       return l;
612     }
613
614     template <class T>
615     std::optional<T> GetFirst() {
616       if (stmt_ == nullptr)
617         return std::nullopt;
618       for (const auto& rec : *this) {
619         T t;
620         t(rec);
621         return t;
622       }
623
624       return std::nullopt;
625     }
626
627     std::optional<Record> GetFirstRecord() {
628       if (stmt_ == nullptr)
629         return std::nullopt;
630       for (const auto& rec : *this) {
631         return rec;
632       }
633
634       return std::nullopt;
635     }
636
637     sqlite3_stmt* GetRaw() const {
638       return stmt_;
639     }
640
641     const std::string& GetQuery() const {
642       return query_;
643     }
644
645     void SetDone(bool is_done) {
646       is_done_ = is_done;
647     }
648
649     size_t GetColumnCount() const {
650       return sqlite3_column_count(stmt_);
651     }
652
653    private:
654     friend class Database;
655     Result(sqlite3_stmt* stmt, const std::shared_ptr<sqlite3>& db, std::string query, bool is_done)
656         : stmt_(stmt), db_(db), query_(std::move(query)), is_done_(is_done) {}
657
658     sqlite3_stmt* stmt_ = nullptr;
659     std::weak_ptr<sqlite3> db_;
660     std::string query_;
661     bool is_done_ = false;
662   };
663
664   Database(std::string db_path, int flags) {
665     sqlite3* raw_db = nullptr;
666     int r = sqlite3_open_v2(db_path.c_str(), &raw_db, flags, nullptr);
667     if (r != SQLITE_OK)
668       throw DbException("open failed", r);
669
670     db_.reset(raw_db, sqlite3_close_v2);
671   }
672
673   Database(std::string db_path, int flags,
674       std::function<bool(int)> busy_handler) {
675     sqlite3* raw_db = nullptr;
676     int r = sqlite3_open_v2(db_path.c_str(), &raw_db, flags, nullptr);
677     if (r != SQLITE_OK)
678       throw DbException("sqlite3_open_v2() failed", r);
679
680     db_.reset(raw_db, sqlite3_close_v2);
681     busy_handler_ = std::move(busy_handler);
682     r = sqlite3_busy_handler(db_.get(), [](void* data, int count) {
683       Database* pDb = static_cast<Database*>(data);
684       if (pDb->busy_handler_ && pDb->busy_handler_(count))
685         return 1;
686       return 0;
687     }, this);
688
689     if (r != SQLITE_OK)
690       throw DbException("sqlite3_busy_handler() failed", r);
691   }
692
693   ~Database() = default;
694   Database() = default;
695   Database(const Database&) = delete;
696   Database& operator = (const Database&) = delete;
697
698   Database(Database&& db) noexcept {
699     db_ = std::move(db.db_);
700     busy_handler_ = std::move(db.busy_handler_);
701     db.db_ = nullptr;
702     db.busy_handler_ = nullptr;
703
704     sqlite3_busy_handler(db_.get(), [](void* data, int count) {
705       Database* pDb = static_cast<Database*>(data);
706       if (pDb->busy_handler_ && pDb->busy_handler_(count))
707         return 1;
708       return 0;
709     }, this);
710   }
711
712   explicit operator bool() const {
713     if (db_ == nullptr)
714       return false;
715     return true;
716   }
717
718   Database& operator = (Database&& db) noexcept {
719     if (this != &db) {
720       db_ = std::move(db.db_);
721       busy_handler_ = std::move(db.busy_handler_);
722       db.db_ = nullptr;
723       db.busy_handler_ = nullptr;
724       sqlite3_busy_handler(db_.get(), [](void* data, int count) {
725         Database* pDb = static_cast<Database*>(data);
726         if (pDb->busy_handler_ && pDb->busy_handler_(count))
727           return 1;
728         return 0;
729       }, this);
730     }
731
732     return *this;
733   }
734
735   TransactionGuard CreateTransactionGuard() const {
736     return TransactionGuard(db_);
737   }
738
739   Result Prepare(const Sql& sql) const {
740     if (!db_)
741       throw DbException("Not opened");
742
743     sqlite3_stmt* stmt = nullptr;
744     int r = sqlite3_prepare_v2(db_.get(), sql.GetQuery().c_str(),
745         -1, &stmt, nullptr);
746     if (r != SQLITE_OK)
747       return { nullptr, db_, "", true };
748     return { stmt, db_, sql.GetQuery(), false };
749   }
750
751   Result Exec(const Sql& sql) const {
752     if (!db_)
753       throw DbException("Not opened");
754
755     sqlite3_stmt* stmt = nullptr;
756     int r = sqlite3_prepare_v2(db_.get(), sql.GetQuery().c_str(),
757         -1, &stmt, nullptr);
758     if (r != SQLITE_OK) {
759       return { nullptr, db_, "", true };
760     }
761
762     std::unique_ptr<sqlite3_stmt, decltype(sqlite3_finalize)*> stmt_auto(stmt,
763         sqlite3_finalize);
764     int pos = 1;
765     for (const auto& i : sql.GetBindings()) {
766       Bind(pos++, i, stmt);
767     }
768
769     for (const auto& i : sql.GetBindingMap()) {
770       Bind(i.first, i.second, stmt);
771     }
772
773     for (const auto& i : sql.GetBindingNameMap()) {
774       int pos = sqlite3_bind_parameter_index(stmt, i.first.c_str());
775       if (pos == 0)
776         throw DbException("Invalid binding");
777       Bind(pos, i.second, stmt);
778     }
779
780     r = sqlite3_step(stmt);
781     if (r != SQLITE_ROW && r != SQLITE_DONE) {
782       return { nullptr, db_, "", true };
783     }
784
785     return { stmt_auto.release(), db_, sql.GetQuery(),
786         r == SQLITE_DONE ? true : false };
787   }
788
789   bool Exec(const Sql& sql, Result& previous_stmt) const {
790     if (sql.GetQuery() != previous_stmt.GetQuery())
791       throw DbException("Query is different");
792
793     sqlite3_stmt* stmt = previous_stmt.GetRaw();
794     if (!stmt)
795       return false;
796
797     int r = sqlite3_reset(stmt);
798     if (r != SQLITE_ROW && r != SQLITE_DONE && r != SQLITE_OK)
799       return false;
800
801     int pos = 1;
802     for (const auto& i : sql.GetBindings()) {
803       Bind(pos++, i, stmt);
804     }
805
806     for (const auto& i : sql.GetBindingMap()) {
807       Bind(i.first, i.second, stmt);
808     }
809
810     for (const auto& i : sql.GetBindingNameMap()) {
811       int pos = sqlite3_bind_parameter_index(stmt, i.first.c_str());
812       if (pos == 0)
813         throw DbException("Invalid binding");
814       Bind(pos, i.second, stmt);
815     }
816
817     r = sqlite3_step(stmt);
818     if (r != SQLITE_ROW && r != SQLITE_DONE)
819       return false;
820
821     previous_stmt.SetDone(r == SQLITE_DONE ? true : false);
822     return true;
823   }
824
825   void OneStepExec(const Sql& sql) const {
826     char* errmsg = nullptr;
827     int ret = sqlite3_exec(db_.get(), sql.GetQuery().c_str(), nullptr, nullptr,
828         &errmsg);
829     if (ret != SQLITE_OK) {
830       std::unique_ptr<char, decltype(sqlite3_free)*> errmsg_auto(
831           errmsg, sqlite3_free);
832       throw DbException(errmsg);
833     }
834   }
835
836   sqlite3* GetRaw() const {
837     if (!db_)
838       throw DbException("Not opened");
839     return db_.get();
840   }
841
842  private:
843   void Bind(int pos, const DbType& type, sqlite3_stmt* stmt) const {
844     int r;
845     if (!type) {
846       r = sqlite3_bind_null(stmt, pos);
847       if (r != SQLITE_OK) {
848         throw DbException("Invalid binding", r);
849       }
850
851       return;
852     }
853
854     if (const std::string* pstr = std::get_if<std::string>(&(*type))) {
855       r = sqlite3_bind_text(stmt, pos, (*pstr).c_str(), -1,
856           SQLITE_TRANSIENT);
857     } else if (const int64_t* pint = std::get_if<int64_t>(&(*type))) {
858       r = sqlite3_bind_int64(stmt, pos, (*pint));
859     } else if (const double* pdouble = std::get_if<double>(&(*type))) {
860       r = sqlite3_bind_double(stmt, pos, (*pdouble));
861     } else if (const std::vector<unsigned char>* pvector =
862         std::get_if<std::vector<unsigned char>>(&(*type))) {
863       r = sqlite3_bind_blob(stmt, pos, (*pvector).data(),
864           (*pvector).size(), nullptr);
865     } else {
866       r = -1;
867     }
868
869     if (r != SQLITE_OK) {
870       throw DbException("Invalid binding");
871     }
872   }
873
874  private:
875   std::shared_ptr<sqlite3> db_ = nullptr;
876   std::function<bool(int)> busy_handler_;
877 };
878
879 }  // namespace tizen_base
880
881 #endif  // TIZEN_DATABASE_DATABASE_HPP_