1 #pragma once 2 3 #include <string> 4 #include <vector> 5 #include <stdexcept> 6 #include <chrono> 7 #include <memory> 8 #include <mapbox/variant.hpp> 9 10 namespace mapbox { 11 namespace sqlite { 12 13 enum OpenFlag : int { 14 ReadOnly = 0b001, 15 ReadWriteCreate = 0b110, 16 }; 17 18 enum class ResultCode : int { 19 OK = 0, 20 Error = 1, 21 Internal = 2, 22 Perm = 3, 23 Abort = 4, 24 Busy = 5, 25 Locked = 6, 26 NoMem = 7, 27 ReadOnly = 8, 28 Interrupt = 9, 29 IOErr = 10, 30 Corrupt = 11, 31 NotFound = 12, 32 Full = 13, 33 CantOpen = 14, 34 Protocol = 15, 35 Schema = 17, 36 TooBig = 18, 37 Constraint = 19, 38 Mismatch = 20, 39 Misuse = 21, 40 NoLFS = 22, 41 Auth = 23, 42 Range = 25, 43 NotADB = 26 44 }; 45 46 class Exception : public std::runtime_error { 47 public: Exception(int err,const char * msg)48 Exception(int err, const char* msg) 49 : std::runtime_error(msg), code(static_cast<ResultCode>(err)) { 50 } Exception(ResultCode err,const char * msg)51 Exception(ResultCode err, const char* msg) 52 : std::runtime_error(msg), code(err) { 53 } Exception(int err,const std::string & msg)54 Exception(int err, const std::string& msg) 55 : std::runtime_error(msg), code(static_cast<ResultCode>(err)) { 56 } Exception(ResultCode err,const std::string & msg)57 Exception(ResultCode err, const std::string& msg) 58 : std::runtime_error(msg), code(err) { 59 } 60 const ResultCode code = ResultCode::OK; 61 }; 62 63 class DatabaseImpl; 64 class Statement; 65 class StatementImpl; 66 class Query; 67 class Transaction; 68 69 class Database { 70 private: 71 Database(std::unique_ptr<DatabaseImpl>); 72 Database(const Database &) = delete; 73 Database &operator=(const Database &) = delete; 74 75 public: 76 static mapbox::util::variant<Database, Exception> tryOpen(const std::string &filename, int flags = 0); 77 static Database open(const std::string &filename, int flags = 0); 78 79 Database(Database &&); 80 ~Database(); 81 Database &operator=(Database &&); 82 83 void setBusyTimeout(std::chrono::milliseconds); 84 void exec(const std::string &sql); 85 86 private: 87 std::unique_ptr<DatabaseImpl> impl; 88 89 friend class Statement; 90 friend class Transaction; 91 }; 92 93 // A Statement object represents a prepared statement that can be run repeatedly run with a Query object. 94 class Statement { 95 public: 96 Statement(Database& db, const char* sql); 97 Statement(const Statement&) = delete; 98 Statement(Statement&&) = delete; 99 Statement& operator=(const Statement&) = delete; 100 Statement& operator=(Statement&&) = delete; 101 ~Statement(); 102 103 friend class Query; 104 105 private: 106 std::unique_ptr<StatementImpl> impl; 107 108 #ifndef NDEBUG 109 // This flag stores whether there exists a Query object that uses this prepared statement. 110 // There may only be one Query object at a time. Statement objects must outlive Query objects. 111 // While a Query object exists, a Statement object may not be moved or deleted. 112 bool used = false; 113 #endif 114 }; 115 116 // A Query object is used to run a database query with a prepared statement (stored in a Statement 117 // object). There may only exist one Query object per Statement object. Query objects are designed 118 // to be constructed and destroyed frequently. 119 class Query { 120 public: 121 Query(Statement&); 122 Query(const Query&) = delete; 123 Query(Query&&) = delete; 124 Query& operator=(const Query&) = delete; 125 Query& operator=(Query&&) = delete; 126 ~Query(); 127 128 template <typename T> 129 void bind(int offset, T value); 130 131 // Text 132 void bind(int offset, const char*, std::size_t length, bool retain = true); 133 void bind(int offset, const std::string&, bool retain = true); 134 135 // Blob 136 void bindBlob(int offset, const void*, std::size_t length, bool retain = true); 137 void bindBlob(int offset, const std::vector<uint8_t>&, bool retain = true); 138 139 template <typename T> 140 T get(int offset); 141 142 bool run(); 143 void reset(); 144 void clearBindings(); 145 146 int64_t lastInsertRowId() const; 147 uint64_t changes() const; 148 149 private: 150 Statement& stmt; 151 }; 152 153 class Transaction { 154 private: 155 Transaction(const Transaction&) = delete; 156 Transaction(Transaction&&) = delete; 157 Transaction& operator=(const Transaction&) = delete; 158 159 public: 160 enum Mode { 161 Deferred, 162 Immediate, 163 Exclusive 164 }; 165 166 Transaction(Database&, Mode = Deferred); 167 ~Transaction(); 168 169 void commit(); 170 void rollback(); 171 172 private: 173 DatabaseImpl& dbImpl; 174 bool needRollback = true; 175 }; 176 177 } 178 } 179