[core, qt] move self-resetting Statement/Query object to shared header
This commit is contained in:
@@ -201,85 +201,93 @@ void Database::exec(const std::string &sql) {
|
||||
}
|
||||
}
|
||||
|
||||
Statement Database::prepare(const char *query) {
|
||||
assert(impl);
|
||||
return Statement(this, query);
|
||||
Statement::Statement(Database& db, const char* sql)
|
||||
: impl(std::make_unique<StatementImpl>(db.impl->db, sql)) {
|
||||
}
|
||||
|
||||
Statement::Statement(Database *db, const char *sql)
|
||||
: impl(std::make_unique<StatementImpl>(db->impl->db, sql))
|
||||
{
|
||||
Statement::~Statement() {
|
||||
#ifndef NDEBUG
|
||||
// Crash if we're destructing this object while we know a Query object references this.
|
||||
assert(!used);
|
||||
#endif
|
||||
}
|
||||
|
||||
Statement::Statement(Statement &&other) {
|
||||
*this = std::move(other);
|
||||
Query::Query(Statement& stmt_) : stmt(stmt_) {
|
||||
assert(stmt.impl);
|
||||
|
||||
#ifndef NDEBUG
|
||||
assert(!stmt.used);
|
||||
stmt.used = true;
|
||||
#endif
|
||||
}
|
||||
|
||||
Statement &Statement::operator=(Statement &&other) {
|
||||
std::swap(impl, other.impl);
|
||||
return *this;
|
||||
Query::~Query() {
|
||||
reset();
|
||||
clearBindings();
|
||||
|
||||
#ifndef NDEBUG
|
||||
stmt.used = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
Statement::~Statement() = default;
|
||||
|
||||
template <> void Statement::bind(int offset, std::nullptr_t) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_null(impl->stmt, offset));
|
||||
template <> void Query::bind(int offset, std::nullptr_t) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_null(stmt.impl->stmt, offset));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, int8_t value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, int8_t value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, int16_t value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, int16_t value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, int32_t value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, int32_t value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, int64_t value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, int64_t value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, uint8_t value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, uint8_t value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, uint16_t value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, uint16_t value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, uint32_t value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_int64(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, uint32_t value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, float value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_double(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, float value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_double(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, double value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_double(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, double value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_double(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, bool value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_int(impl->stmt, offset, value));
|
||||
template <> void Query::bind(int offset, bool value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_int(stmt.impl->stmt, offset, value));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, const char *value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_text(impl->stmt, offset, value, -1, SQLITE_STATIC));
|
||||
template <> void Query::bind(int offset, const char *value) {
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_text(stmt.impl->stmt, offset, value, -1, SQLITE_STATIC));
|
||||
}
|
||||
|
||||
// We currently cannot use sqlite3_bind_blob64 / sqlite3_bind_text64 because they
|
||||
@@ -289,40 +297,40 @@ template <> void Statement::bind(int offset, const char *value) {
|
||||
// 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.8.
|
||||
|
||||
void Statement::bind(int offset, const char * value, std::size_t length, bool retain) {
|
||||
assert(impl);
|
||||
void Query::bind(int offset, const char * value, std::size_t length, bool retain) {
|
||||
assert(stmt.impl);
|
||||
if (length > std::numeric_limits<int>::max()) {
|
||||
throw std::range_error("value too long for sqlite3_bind_text");
|
||||
}
|
||||
impl->check(sqlite3_bind_text(impl->stmt, offset, value, int(length),
|
||||
stmt.impl->check(sqlite3_bind_text(stmt.impl->stmt, offset, value, int(length),
|
||||
retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
|
||||
}
|
||||
|
||||
void Statement::bind(int offset, const std::string& value, bool retain) {
|
||||
void Query::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(impl);
|
||||
void Query::bindBlob(int offset, const void * value, std::size_t length, bool retain) {
|
||||
assert(stmt.impl);
|
||||
if (length > std::numeric_limits<int>::max()) {
|
||||
throw std::range_error("value too long for sqlite3_bind_text");
|
||||
}
|
||||
impl->check(sqlite3_bind_blob(impl->stmt, offset, value, int(length),
|
||||
stmt.impl->check(sqlite3_bind_blob(stmt.impl->stmt, offset, value, int(length),
|
||||
retain ? SQLITE_TRANSIENT : SQLITE_STATIC));
|
||||
}
|
||||
|
||||
void Statement::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
|
||||
void Query::bindBlob(int offset, const std::vector<uint8_t>& value, bool retain) {
|
||||
bindBlob(offset, value.data(), value.size(), retain);
|
||||
}
|
||||
|
||||
template <>
|
||||
void Statement::bind(
|
||||
void Query::bind(
|
||||
int offset, std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds> value) {
|
||||
assert(impl);
|
||||
impl->check(sqlite3_bind_int64(impl->stmt, offset, std::chrono::system_clock::to_time_t(value)));
|
||||
assert(stmt.impl);
|
||||
stmt.impl->check(sqlite3_bind_int64(stmt.impl->stmt, offset, std::chrono::system_clock::to_time_t(value)));
|
||||
}
|
||||
|
||||
template <> void Statement::bind(int offset, optional<std::string> value) {
|
||||
template <> void Query::bind(int offset, optional<std::string> value) {
|
||||
if (!value) {
|
||||
bind(offset, nullptr);
|
||||
} else {
|
||||
@@ -331,7 +339,7 @@ template <> void Statement::bind(int offset, optional<std::string> value) {
|
||||
}
|
||||
|
||||
template <>
|
||||
void Statement::bind(
|
||||
void Query::bind(
|
||||
int offset,
|
||||
optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>> value) {
|
||||
if (!value) {
|
||||
@@ -341,86 +349,86 @@ void Statement::bind(
|
||||
}
|
||||
}
|
||||
|
||||
bool Statement::run() {
|
||||
assert(impl);
|
||||
const int err = sqlite3_step(impl->stmt);
|
||||
impl->lastInsertRowId = sqlite3_last_insert_rowid(sqlite3_db_handle(impl->stmt));
|
||||
impl->changes = sqlite3_changes(sqlite3_db_handle(impl->stmt));
|
||||
bool Query::run() {
|
||||
assert(stmt.impl);
|
||||
const int err = sqlite3_step(stmt.impl->stmt);
|
||||
stmt.impl->lastInsertRowId = sqlite3_last_insert_rowid(sqlite3_db_handle(stmt.impl->stmt));
|
||||
stmt.impl->changes = sqlite3_changes(sqlite3_db_handle(stmt.impl->stmt));
|
||||
if (err == SQLITE_DONE) {
|
||||
return false;
|
||||
} else if (err == SQLITE_ROW) {
|
||||
return true;
|
||||
} else if (err != SQLITE_OK) {
|
||||
throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(impl->stmt)) };
|
||||
throw Exception { err, sqlite3_errmsg(sqlite3_db_handle(stmt.impl->stmt)) };
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
template <> bool Statement::get(int offset) {
|
||||
assert(impl);
|
||||
return sqlite3_column_int(impl->stmt, offset);
|
||||
template <> bool Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
return sqlite3_column_int(stmt.impl->stmt, offset);
|
||||
}
|
||||
|
||||
template <> int Statement::get(int offset) {
|
||||
assert(impl);
|
||||
return sqlite3_column_int(impl->stmt, offset);
|
||||
template <> int Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
return sqlite3_column_int(stmt.impl->stmt, offset);
|
||||
}
|
||||
|
||||
template <> int64_t Statement::get(int offset) {
|
||||
assert(impl);
|
||||
return sqlite3_column_int64(impl->stmt, offset);
|
||||
template <> int64_t Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
return sqlite3_column_int64(stmt.impl->stmt, offset);
|
||||
}
|
||||
|
||||
template <> double Statement::get(int offset) {
|
||||
assert(impl);
|
||||
return sqlite3_column_double(impl->stmt, offset);
|
||||
template <> double Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
return sqlite3_column_double(stmt.impl->stmt, offset);
|
||||
}
|
||||
|
||||
template <> std::string Statement::get(int offset) {
|
||||
assert(impl);
|
||||
template <> std::string Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
return {
|
||||
reinterpret_cast<const char *>(sqlite3_column_blob(impl->stmt, offset)),
|
||||
size_t(sqlite3_column_bytes(impl->stmt, offset))
|
||||
reinterpret_cast<const char *>(sqlite3_column_blob(stmt.impl->stmt, offset)),
|
||||
size_t(sqlite3_column_bytes(stmt.impl->stmt, offset))
|
||||
};
|
||||
}
|
||||
|
||||
template <> std::vector<uint8_t> Statement::get(int offset) {
|
||||
assert(impl);
|
||||
const auto* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(impl->stmt, offset));
|
||||
const uint8_t* end = begin + sqlite3_column_bytes(impl->stmt, offset);
|
||||
template <> std::vector<uint8_t> Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
const auto* begin = reinterpret_cast<const uint8_t*>(sqlite3_column_blob(stmt.impl->stmt, offset));
|
||||
const uint8_t* end = begin + sqlite3_column_bytes(stmt.impl->stmt, offset);
|
||||
return { begin, end };
|
||||
}
|
||||
|
||||
template <>
|
||||
std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>
|
||||
Statement::get(int offset) {
|
||||
assert(impl);
|
||||
Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
return std::chrono::time_point_cast<std::chrono::seconds>(
|
||||
std::chrono::system_clock::from_time_t(sqlite3_column_int64(impl->stmt, offset)));
|
||||
std::chrono::system_clock::from_time_t(sqlite3_column_int64(stmt.impl->stmt, offset)));
|
||||
}
|
||||
|
||||
template <> optional<int64_t> Statement::get(int offset) {
|
||||
assert(impl);
|
||||
if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
|
||||
template <> optional<int64_t> Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
|
||||
return optional<int64_t>();
|
||||
} else {
|
||||
return get<int64_t>(offset);
|
||||
}
|
||||
}
|
||||
|
||||
template <> optional<double> Statement::get(int offset) {
|
||||
assert(impl);
|
||||
if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
|
||||
template <> optional<double> Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
|
||||
return optional<double>();
|
||||
} else {
|
||||
return get<double>(offset);
|
||||
}
|
||||
}
|
||||
|
||||
template <> optional<std::string> Statement::get(int offset) {
|
||||
assert(impl);
|
||||
if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
|
||||
template <> optional<std::string> Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
|
||||
return optional<std::string>();
|
||||
} else {
|
||||
return get<std::string>(offset);
|
||||
@@ -429,9 +437,9 @@ template <> optional<std::string> Statement::get(int offset) {
|
||||
|
||||
template <>
|
||||
optional<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>>
|
||||
Statement::get(int offset) {
|
||||
assert(impl);
|
||||
if (sqlite3_column_type(impl->stmt, offset) == SQLITE_NULL) {
|
||||
Query::get(int offset) {
|
||||
assert(stmt.impl);
|
||||
if (sqlite3_column_type(stmt.impl->stmt, offset) == SQLITE_NULL) {
|
||||
return {};
|
||||
} else {
|
||||
return get<std::chrono::time_point<std::chrono::system_clock, std::chrono::seconds>>(
|
||||
@@ -439,24 +447,24 @@ Statement::get(int offset) {
|
||||
}
|
||||
}
|
||||
|
||||
void Statement::reset() {
|
||||
assert(impl);
|
||||
sqlite3_reset(impl->stmt);
|
||||
void Query::reset() {
|
||||
assert(stmt.impl);
|
||||
sqlite3_reset(stmt.impl->stmt);
|
||||
}
|
||||
|
||||
void Statement::clearBindings() {
|
||||
assert(impl);
|
||||
sqlite3_clear_bindings(impl->stmt);
|
||||
void Query::clearBindings() {
|
||||
assert(stmt.impl);
|
||||
sqlite3_clear_bindings(stmt.impl->stmt);
|
||||
}
|
||||
|
||||
int64_t Statement::lastInsertRowId() const {
|
||||
assert(impl);
|
||||
return impl->lastInsertRowId;
|
||||
int64_t Query::lastInsertRowId() const {
|
||||
assert(stmt.impl);
|
||||
return stmt.impl->lastInsertRowId;
|
||||
}
|
||||
|
||||
uint64_t Statement::changes() const {
|
||||
assert(impl);
|
||||
auto changes_ = impl->changes;
|
||||
uint64_t Query::changes() const {
|
||||
assert(stmt.impl);
|
||||
auto changes_ = stmt.impl->changes;
|
||||
return (changes_ < 0 ? 0 : changes_);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user