diff options
Diffstat (limited to 'platform/default/sqlite3.cpp')
-rw-r--r-- | platform/default/sqlite3.cpp | 94 |
1 files changed, 91 insertions, 3 deletions
diff --git a/platform/default/sqlite3.cpp b/platform/default/sqlite3.cpp index 5122e01015..72296c6843 100644 --- a/platform/default/sqlite3.cpp +++ b/platform/default/sqlite3.cpp @@ -59,6 +59,15 @@ Database::operator bool() const { return db != nullptr; } +void Database::setBusyTimeout(std::chrono::milliseconds timeout) { + assert(db); + const int err = sqlite3_busy_timeout(db, + int(std::min<std::chrono::milliseconds::rep>(timeout.count(), std::numeric_limits<int>::max()))); + if (err != SQLITE_OK) { + throw Exception { err, sqlite3_errmsg(db) }; + } +} + void Database::exec(const std::string &sql) { assert(db); char *msg = nullptr; @@ -77,6 +86,16 @@ Statement Database::prepare(const char *query) { return Statement(db, query); } +int64_t Database::lastInsertRowid() const { + assert(db); + return sqlite3_last_insert_rowid(db); +} + +uint64_t Database::changes() const { + assert(db); + return sqlite3_changes(db); +} + Statement::Statement(sqlite3 *db, const char *sql) { const int err = sqlite3_prepare_v2(db, sql, -1, &stmt, nullptr); if (err != SQLITE_OK) { @@ -115,9 +134,19 @@ template <> void Statement::bind(int offset, std::nullptr_t) { check(sqlite3_bind_null(stmt, offset)); } -template <> void Statement::bind(int offset, int value) { +template <> void Statement::bind(int offset, int8_t value) { assert(stmt); - check(sqlite3_bind_int(stmt, offset, value)); + check(sqlite3_bind_int64(stmt, offset, value)); +} + +template <> void Statement::bind(int offset, int16_t value) { + assert(stmt); + check(sqlite3_bind_int64(stmt, offset, value)); +} + +template <> void Statement::bind(int offset, int32_t value) { + assert(stmt); + check(sqlite3_bind_int64(stmt, offset, value)); } template <> void Statement::bind(int offset, int64_t value) { @@ -125,6 +154,26 @@ template <> void Statement::bind(int offset, int64_t value) { check(sqlite3_bind_int64(stmt, offset, value)); } +template <> void Statement::bind(int offset, uint8_t value) { + assert(stmt); + check(sqlite3_bind_int64(stmt, offset, value)); +} + +template <> void Statement::bind(int offset, uint16_t value) { + assert(stmt); + check(sqlite3_bind_int64(stmt, offset, value)); +} + +template <> void Statement::bind(int offset, uint32_t value) { + assert(stmt); + check(sqlite3_bind_int64(stmt, offset, value)); +} + +template <> void Statement::bind(int offset, float value) { + assert(stmt); + check(sqlite3_bind_double(stmt, offset, value)); +} + template <> void Statement::bind(int offset, double value) { assert(stmt); check(sqlite3_bind_double(stmt, offset, value)); @@ -140,12 +189,39 @@ template <> void Statement::bind(int offset, const char *value) { check(sqlite3_bind_text(stmt, offset, value, -1, SQLITE_STATIC)); } +// We currently cannot use sqlite3_bind_blob64 / sqlite3_bind_text64 because they +// was introduced in SQLite 3.8.7, and we need to support earlier versions: +// iOS 7.0: 3.7.13 +// iOS 8.2: 3.8.5 +// According to http://stackoverflow.com/questions/14288128/what-version-of-sqlite-does-ios-provide, +// the first iOS version with 3.8.7+ was 9.0, with 3.8.10.2. + +void Statement::bind(int offset, const char * value, std::size_t length, bool retain) { + assert(stmt); + if (length > std::numeric_limits<int>::max()) { + throw std::range_error("value too long for sqlite3_bind_text"); + } + check(sqlite3_bind_text(stmt, offset, value, int(length), + retain ? SQLITE_TRANSIENT : SQLITE_STATIC)); +} + void Statement::bind(int offset, const std::string& value, bool retain) { + bind(offset, value.data(), value.size(), retain); +} + +void Statement::bindBlob(int offset, const void * value, std::size_t length, bool retain) { assert(stmt); - check(sqlite3_bind_blob(stmt, offset, value.data(), int(value.size()), + if (length > std::numeric_limits<int>::max()) { + throw std::range_error("value too long for sqlite3_bind_text"); + } + check(sqlite3_bind_blob(stmt, offset, value, int(length), retain ? SQLITE_TRANSIENT : SQLITE_STATIC)); } +void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) { + bindBlob(offset, value.data(), value.size(), retain); +} + template <> void Statement::bind(int offset, std::chrono::system_clock::time_point value) { assert(stmt); check(sqlite3_bind_int64(stmt, offset, std::chrono::system_clock::to_time_t(value))); @@ -204,6 +280,13 @@ template <> std::string Statement::get(int offset) { }; } +template <> std::vector<uint8_t> Statement::get(int offset) { + assert(stmt); + const uint8_t* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt, offset)); + const uint8_t* end = begin + sqlite3_column_bytes(stmt, offset); + return { begin, end }; +} + template <> std::chrono::system_clock::time_point Statement::get(int offset) { assert(stmt); return std::chrono::system_clock::from_time_t(sqlite3_column_int64(stmt, offset)); @@ -232,5 +315,10 @@ void Statement::reset() { sqlite3_reset(stmt); } +void Statement::clearBindings() { + assert(stmt); + sqlite3_clear_bindings(stmt); +} + } // namespace sqlite } // namespace mapbox |