1 #include "sqlite3.hpp"
2 #include <sqlite3.h>
3 
4 #include <cassert>
5 #include <cstring>
6 #include <cstdio>
7 #include <chrono>
8 #include <experimental/optional>
9 
10 #include <mbgl/util/logging.hpp>
11 
12 namespace mapbox {
13 namespace sqlite {
14 
15 class DatabaseImpl {
16 public:
DatabaseImpl(sqlite3 * db_)17     DatabaseImpl(sqlite3* db_)
18         : db(db_)
19     {
20     }
21 
~DatabaseImpl()22     ~DatabaseImpl()
23     {
24         const int error = sqlite3_close(db);
25         if (error != SQLITE_OK) {
26             mbgl::Log::Error(mbgl::Event::Database, "%s (Code %i)", sqlite3_errmsg(db), error);
27         }
28     }
29 
30     void setBusyTimeout(std::chrono::milliseconds timeout);
31     void exec(const std::string& sql);
32 
33     sqlite3* db;
34 };
35 
36 class StatementImpl {
37 public:
StatementImpl(sqlite3 * db,const char * sql)38     StatementImpl(sqlite3* db, const char* sql)
39     {
40         const int error = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr);
41         if (error != SQLITE_OK) {
42             stmt = nullptr;
43             throw Exception { error, sqlite3_errmsg(db) };
44         }
45     }
46 
~StatementImpl()47     ~StatementImpl()
48     {
49         if (!stmt) return;
50 
51         sqlite3_finalize(stmt);
52     }
53 
check(int err)54     void check(int err) {
55         if (err != SQLITE_OK) {
56             throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(stmt)) };
57         }
58     }
59 
60     sqlite3_stmt* stmt = nullptr;
61     int64_t lastInsertRowId = 0;
62     int64_t changes = 0;
63 };
64 
65 template <typename T>
66 using optional = std::experimental::optional<T>;
67 
errorLogCallback(void *,const int err,const char * msg)68 static void errorLogCallback(void *, const int err, const char *msg) {
69     mbgl::Log::Record(mbgl::EventSeverity::Info, mbgl::Event::Database, err, "%s", msg);
70 }
71 
__anon6ec336030102() 72 const static bool sqliteVersionCheck __attribute__((unused)) = []() {
73     if (sqlite3_libversion_number() / 1000000 != SQLITE_VERSION_NUMBER / 1000000) {
74         char message[96];
75         snprintf(message, 96,
76                  "sqlite3 libversion mismatch: headers report %d, but library reports %d",
77                  SQLITE_VERSION_NUMBER, sqlite3_libversion_number());
78         throw std::runtime_error(message);
79     }
80 
81     // Enable SQLite logging before initializing the database.
82     sqlite3_config(SQLITE_CONFIG_LOG, errorLogCallback, nullptr);
83 
84     return true;
85 }();
86 
tryOpen(const std::string & filename,int flags)87 mapbox::util::variant<Database, Exception> Database::tryOpen(const std::string &filename, int flags) {
88     sqlite3* db = nullptr;
89     const int error = sqlite3_open_v2(filename.c_str(), &db, flags, nullptr);
90     if (error != SQLITE_OK) {
91         const auto message = sqlite3_errmsg(db);
92         return Exception { error, message };
93     }
94     return Database(std::make_unique<DatabaseImpl>(db));
95 }
96 
open(const std::string & filename,int flags)97 Database Database::open(const std::string &filename, int flags) {
98     auto result = tryOpen(filename, flags);
99     if (result.is<Exception>()) {
100         throw result.get<Exception>();
101     } else {
102         return std::move(result.get<Database>());
103     }
104 }
105 
Database(std::unique_ptr<DatabaseImpl> impl_)106 Database::Database(std::unique_ptr<DatabaseImpl> impl_)
107     : impl(std::move(impl_))
108 {}
109 
Database(Database && other)110 Database::Database(Database &&other)
111     : impl(std::move(other.impl)) {}
112 
operator =(Database && other)113 Database &Database::operator=(Database &&other) {
114     std::swap(impl, other.impl);
115     return *this;
116 }
117 
118 Database::~Database() = default;
119 
setBusyTimeout(std::chrono::milliseconds timeout)120 void Database::setBusyTimeout(std::chrono::milliseconds timeout) {
121     assert(impl);
122     impl->setBusyTimeout(timeout);
123 }
124 
setBusyTimeout(std::chrono::milliseconds timeout)125 void DatabaseImpl::setBusyTimeout(std::chrono::milliseconds timeout) {
126     const int err = sqlite3_busy_timeout(db,
127         int(std::min<std::chrono::milliseconds::rep>(timeout.count(), std::numeric_limits<int>::max())));
128     if (err != SQLITE_OK) {
129         throw Exception { err, sqlite3_errmsg(db) };
130     }
131 }
132 
exec(const std::string & sql)133 void Database::exec(const std::string &sql) {
134     assert(impl);
135     impl->exec(sql);
136 }
137 
exec(const std::string & sql)138 void DatabaseImpl::exec(const std::string& sql) {
139     char *msg = nullptr;
140     const int err = sqlite3_exec(db, sql.c_str(), nullptr, nullptr, &msg);
141     if (msg) {
142         const std::string message = msg;
143         sqlite3_free(msg);
144         throw Exception { err, message };
145     } else if (err != SQLITE_OK) {
146         throw Exception { err, sqlite3_errmsg(db) };
147     }
148 }
149 
Statement(Database & db,const char * sql)150 Statement::Statement(Database& db, const char* sql)
151     : impl(std::make_unique<StatementImpl>(db.impl->db, sql)) {
152 }
153 
~Statement()154 Statement::~Statement() {
155 #ifndef NDEBUG
156     // Crash if we're destructing this object while we know a Query object references this.
157     assert(!used);
158 #endif
159 }
160 
Query(Statement & stmt_)161 Query::Query(Statement& stmt_) : stmt(stmt_) {
162     assert(stmt.impl);
163 
164 #ifndef NDEBUG
165     assert(!stmt.used);
166     stmt.used = true;
167 #endif
168 }
169 
~Query()170 Query::~Query() {
171     reset();
172     clearBindings();
173 
174 #ifndef NDEBUG
175     stmt.used = false;
176 #endif
177 }
178 
bind(int offset,std::nullptr_t)179 template <> void Query::bind(int offset, std::nullptr_t) {
180     assert(stmt.impl);
181     stmt.impl->check(sqlite3_bind_null(stmt.impl->stmt, offset));
182 }
183 
bind(int offset,int8_t value)184 template <> void Query::bind(int offset, int8_t value) {
185     assert(stmt.impl);
186     stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
187 }
188 
bind(int offset,int16_t value)189 template <> void Query::bind(int offset, int16_t value) {
190     assert(stmt.impl);
191     stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
192 }
193 
bind(int offset,int32_t value)194 template <> void Query::bind(int offset, int32_t value) {
195     assert(stmt.impl);
196     stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
197 }
198 
bind(int offset,int64_t value)199 template <> void Query::bind(int offset, int64_t value) {
200     assert(stmt.impl);
201     stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
202 }
203 
bind(int offset,uint8_t value)204 template <> void Query::bind(int offset, uint8_t value) {
205     assert(stmt.impl);
206     stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
207 }
208 
bind(int offset,uint16_t value)209 template <> void Query::bind(int offset, uint16_t value) {
210     assert(stmt.impl);
211     stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
212 }
213 
bind(int offset,uint32_t value)214 template <> void Query::bind(int offset, uint32_t value) {
215     assert(stmt.impl);
216     stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
217 }
218 
bind(int offset,float value)219 template <> void Query::bind(int offset, float value) {
220     assert(stmt.impl);
221     stmt.impl->check(sqlite3_bind_double(stmt.impl->stmt, offset, value));
222 }
223 
bind(int offset,double value)224 template <> void Query::bind(int offset, double value) {
225     assert(stmt.impl);
226     stmt.impl->check(sqlite3_bind_double(stmt.impl->stmt, offset, value));
227 }
228 
bind(int offset,bool value)229 template <> void Query::bind(int offset, bool value) {
230     assert(stmt.impl);
231     stmt.impl->check(sqlite3_bind_int(stmt.impl->stmt, offset, value));
232 }
233 
bind(int offset,const char * value)234 template <> void Query::bind(int offset, const char *value) {
235     assert(stmt.impl);
236     stmt.impl->check(sqlite3_bind_text(stmt.impl->stmt, offset, value, -1, SQLITE_STATIC));
237 }
238 
239 // We currently cannot use sqlite3_bind_blob64 / sqlite3_bind_text64 because they
240 // were introduced in SQLite 3.8.7, and we need to support earlier versions:
241 //    Android 11: 3.7
242 //    Android 21: 3.8
243 //    Android 24: 3.9
244 // Per https://developer.android.com/reference/android/database/sqlite/package-summary.
245 // The first iOS version with 3.8.7+ was 9.0, with 3.8.8.
246 
bind(int offset,const char * value,std::size_t length,bool retain)247 void Query::bind(int offset, const char * value, std::size_t length, bool retain) {
248     assert(stmt.impl);
249     if (length > std::numeric_limits<int>::max()) {
250         throw std::range_error("value too long for sqlite3_bind_text");
251     }
252     stmt.impl->check(sqlite3_bind_text(stmt.impl->stmt, offset, value, int(length),
253                             retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
254 }
255 
bind(int offset,const std::string & value,bool retain)256 void Query::bind(int offset, const std::string& value, bool retain) {
257     bind(offset, value.data(), value.size(), retain);
258 }
259 
bindBlob(int offset,const void * value,std::size_t length,bool retain)260 void Query::bindBlob(int offset, const void * value, std::size_t length, bool retain) {
261     assert(stmt.impl);
262     if (length > std::numeric_limits<int>::max()) {
263         throw std::range_error("value too long for sqlite3_bind_text");
264     }
265     stmt.impl->check(sqlite3_bind_blob(stmt.impl->stmt, offset, value, int(length),
266                             retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
267 }
268 
bindBlob(int offset,const std::vector<uint8_t> & value,bool retain)269 void Query::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
270     bindBlob(offset, value.data(), value.size(), retain);
271 }
272 
273 template <>
bind(int offset,std::chrono::time_point<std::chrono::system_clock,std::chrono::seconds> value)274 void Query::bind(
275         int offset, std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds> value) {
276     assert(stmt.impl);
277     stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, std::chrono::system_clock::to_time_t(value)));
278 }
279 
bind(int offset,optional<std::string> value)280 template <> void Query::bind(int offset, optional<std::string> value) {
281     if (!value) {
282         bind(offset, nullptr);
283     } else {
284         bind(offset, *value);
285     }
286 }
287 
288 template <>
bind(int offset,optional<std::chrono::time_point<std::chrono::system_clock,std::chrono::seconds>> value)289 void Query::bind(
290     int offset,
291     optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>> value) {
292     if (!value) {
293         bind(offset, nullptr);
294     } else {
295         bind(offset, *value);
296     }
297 }
298 
run()299 bool Query::run() {
300     assert(stmt.impl);
301     const int err = sqlite3_step(stmt.impl->stmt);
302     stmt.impl->lastInsertRowId = sqlite3_last_insert_rowid(sqlite3_db_handle(stmt.impl->stmt));
303     stmt.impl->changes = sqlite3_changes(sqlite3_db_handle(stmt.impl->stmt));
304     if (err == SQLITE_DONE) {
305         return false;
306     } else if (err == SQLITE_ROW) {
307         return true;
308     } else if (err != SQLITE_OK) {
309         throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(stmt.impl->stmt)) };
310     } else {
311         return false;
312     }
313 }
314 
get(int offset)315 template <> bool Query::get(int offset) {
316     assert(stmt.impl);
317     return sqlite3_column_int(stmt.impl->stmt, offset);
318 }
319 
get(int offset)320 template <> int Query::get(int offset) {
321     assert(stmt.impl);
322     return sqlite3_column_int(stmt.impl->stmt, offset);
323 }
324 
get(int offset)325 template <> int64_t Query::get(int offset) {
326     assert(stmt.impl);
327     return sqlite3_column_int64(stmt.impl->stmt, offset);
328 }
329 
get(int offset)330 template <> double Query::get(int offset) {
331     assert(stmt.impl);
332     return sqlite3_column_double(stmt.impl->stmt, offset);
333 }
334 
get(int offset)335 template <> std::string Query::get(int offset) {
336     assert(stmt.impl);
337     return {
338         reinterpret_cast<const char *>(sqlite3_column_blob(stmt.impl->stmt, offset)),
339         size_t(sqlite3_column_bytes(stmt.impl->stmt, offset))
340     };
341 }
342 
get(int offset)343 template <> std::vector<uint8_t> Query::get(int offset) {
344     assert(stmt.impl);
345     const auto* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt.impl->stmt, offset));
346     const uint8_t* end   = begin + sqlite3_column_bytes(stmt.impl->stmt, offset);
347     return { begin, end };
348 }
349 
350 template <>
351 std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
get(int offset)352 Query::get(int offset) {
353     assert(stmt.impl);
354     return std::chrono::time_point_cast<std::chrono::seconds>(
355         std::chrono::system_clock::from_time_t(sqlite3_column_int64(stmt.impl->stmt, offset)));
356 }
357 
get(int offset)358 template <> optional<int64_t> Query::get(int offset) {
359     assert(stmt.impl);
360     if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
361         return optional<int64_t>();
362     } else {
363         return get<int64_t>(offset);
364     }
365 }
366 
get(int offset)367 template <> optional<double> Query::get(int offset) {
368     assert(stmt.impl);
369     if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
370         return optional<double>();
371     } else {
372         return get<double>(offset);
373     }
374 }
375 
get(int offset)376 template <> optional<std::string> Query::get(int offset) {
377     assert(stmt.impl);
378     if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
379         return optional<std::string>();
380     } else {
381         return get<std::string>(offset);
382     }
383 }
384 
385 template <>
386 optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>>
get(int offset)387 Query::get(int offset) {
388     assert(stmt.impl);
389     if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
390         return {};
391     } else {
392         return get<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>>(
393             offset);
394     }
395 }
396 
reset()397 void Query::reset() {
398     assert(stmt.impl);
399     sqlite3_reset(stmt.impl->stmt);
400 }
401 
clearBindings()402 void Query::clearBindings() {
403     assert(stmt.impl);
404     sqlite3_clear_bindings(stmt.impl->stmt);
405 }
406 
lastInsertRowId() const407 int64_t Query::lastInsertRowId() const {
408     assert(stmt.impl);
409     return stmt.impl->lastInsertRowId;
410 }
411 
changes() const412 uint64_t Query::changes() const {
413     assert(stmt.impl);
414     auto changes_ = stmt.impl->changes;
415     return (changes_ < 0 ? 0 : changes_);
416 }
417 
Transaction(Database & db_,Mode mode)418 Transaction::Transaction(Database& db_, Mode mode)
419     : dbImpl(*db_.impl) {
420     switch (mode) {
421     case Deferred:
422         dbImpl.exec("BEGIN DEFERRED TRANSACTION");
423         break;
424     case Immediate:
425         dbImpl.exec("BEGIN IMMEDIATE TRANSACTION");
426         break;
427     case Exclusive:
428         dbImpl.exec("BEGIN EXCLUSIVE TRANSACTION");
429         break;
430     }
431 }
432 
~Transaction()433 Transaction::~Transaction() {
434     if (needRollback) {
435         try {
436             rollback();
437         } catch (...) {
438             // Ignore failed rollbacks in destructor.
439         }
440     }
441 }
442 
commit()443 void Transaction::commit() {
444     needRollback = false;
445     dbImpl.exec("COMMIT TRANSACTION");
446 }
447 
rollback()448 void Transaction::rollback() {
449     needRollback = false;
450     dbImpl.exec("ROLLBACK TRANSACTION");
451 }
452 
453 } // namespace sqlite
454 } // namespace mapbox
455