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