diff --git a/3rdparty/sqlite3pp/sqlite3pp.h b/3rdparty/sqlite3pp/sqlite3pp.h new file mode 100644 index 0000000..0066376 --- /dev/null +++ b/3rdparty/sqlite3pp/sqlite3pp.h @@ -0,0 +1,362 @@ +// sqlite3pp.h +// +// The MIT License +// +// Copyright (c) 2015 Wongoo Lee (iwongu at gmail dot com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef SQLITE3PP_H +#define SQLITE3PP_H + +#define SQLITE3PP_VERSION "1.0.8" +#define SQLITE3PP_VERSION_MAJOR 1 +#define SQLITE3PP_VERSION_MINOR 0 +#define SQLITE3PP_VERSION_PATCH 8 + +#include +#include +#include +#include +#include + +#ifdef SQLITE3PP_LOADABLE_EXTENSION +#include +SQLITE_EXTENSION_INIT1 +#else +# include +#endif + +namespace sqlite3pp +{ + class database; + + namespace ext + { + class function; + class aggregate; + database borrow(sqlite3* pdb); + } + + template + struct convert { + using to_int = int; + }; + + class null_type {}; + + class noncopyable + { + protected: + noncopyable() = default; + ~noncopyable() = default; + + noncopyable(noncopyable&&) = default; + noncopyable& operator=(noncopyable&&) = default; + + noncopyable(noncopyable const&) = delete; + noncopyable& operator=(noncopyable const&) = delete; + }; + + class database : noncopyable + { + friend class statement; + friend class database_error; + friend class ext::function; + friend class ext::aggregate; + friend database ext::borrow(sqlite3* pdb); + + public: + using busy_handler = std::function; + using commit_handler = std::function; + using rollback_handler = std::function; + using update_handler = std::function; + using authorize_handler = std::function; + using backup_handler = std::function; + + explicit database(char const* dbname = nullptr, int flags = SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, const char* vfs = nullptr); + + database(database&& db); + database& operator=(database&& db); + + ~database(); + + int connect(char const* dbname, int flags, const char* vfs = nullptr); + int disconnect(); + + int attach(char const* dbname, char const* name); + int detach(char const* name); + + int backup(database& destdb, backup_handler h = {}); + int backup(char const* dbname, database& destdb, char const* destdbname, backup_handler h, int step_page = 5); + + long long int last_insert_rowid() const; + + int enable_foreign_keys(bool enable = true); + int enable_triggers(bool enable = true); + int enable_extended_result_codes(bool enable = true); + + int changes() const; + + int error_code() const; + int extended_error_code() const; + char const* error_msg() const; + + int execute(char const* sql); + int executef(char const* sql, ...); + + int set_busy_timeout(int ms); + + void set_busy_handler(busy_handler h); + void set_commit_handler(commit_handler h); + void set_rollback_handler(rollback_handler h); + void set_update_handler(update_handler h); + void set_authorize_handler(authorize_handler h); + + private: + database(sqlite3* pdb) : db_(pdb), borrowing_(true) {} + + private: + sqlite3* db_; + bool borrowing_; + + busy_handler bh_; + commit_handler ch_; + rollback_handler rh_; + update_handler uh_; + authorize_handler ah_; + }; + + class database_error : public std::runtime_error + { + public: + explicit database_error(char const* msg); + explicit database_error(database& db); + }; + + enum copy_semantic { copy, nocopy }; + + class statement : noncopyable + { + public: + int prepare(char const* stmt); + int finish(); + + int bind(int idx, int value); + int bind(int idx, double value); + int bind(int idx, long long int value); + int bind(int idx, char const* value, copy_semantic fcopy); + int bind(int idx, void const* value, int n, copy_semantic fcopy); + int bind(int idx, std::string const& value, copy_semantic fcopy); + int bind(int idx, char16_t const* value, copy_semantic fcopy); + int bind(int idx); + int bind(int idx, null_type); + + int bind(char const* name, int value); + int bind(char const* name, double value); + int bind(char const* name, long long int value); + int bind(char const* name, char const* value, copy_semantic fcopy); + int bind(char const* name, void const* value, int n, copy_semantic fcopy); + int bind(char const* name, std::string const& value, copy_semantic fcopy); + int bind(char const* name); + int bind(char const* name, null_type); + + int step(); + int reset(); + int clear_bindings(); + + protected: + explicit statement(database& db, char const* stmt = nullptr); + ~statement(); + + int prepare_impl(char const* stmt); + int finish_impl(sqlite3_stmt* stmt); + + protected: + database& db_; + sqlite3_stmt* stmt_; + char const* tail_; + }; + + class command : public statement + { + public: + class bindstream + { + public: + bindstream(command& cmd, int idx); + + template + bindstream& operator << (T value) { + auto rc = cmd_.bind(idx_, value); + if (rc != SQLITE_OK) { + throw database_error(cmd_.db_); + } + ++idx_; + return *this; + } + bindstream& operator << (char const* value) { + auto rc = cmd_.bind(idx_, value, copy); + if (rc != SQLITE_OK) { + throw database_error(cmd_.db_); + } + ++idx_; + return *this; + } + bindstream& operator << (std::string const& value) { + auto rc = cmd_.bind(idx_, value, copy); + if (rc != SQLITE_OK) { + throw database_error(cmd_.db_); + } + ++idx_; + return *this; + } + bindstream& operator << (std::nullptr_t value) { + auto rc = cmd_.bind(idx_); + if (rc != SQLITE_OK) { + throw database_error(cmd_.db_); + } + ++idx_; + return *this; + } + + private: + command& cmd_; + int idx_; + }; + + explicit command(database& db, char const* stmt = nullptr); + + bindstream binder(int idx = 1); + + int execute(); + int execute_all(); + }; + + class query : public statement + { + public: + class rows + { + public: + class getstream + { + public: + getstream(rows* rws, int idx); + + template + getstream& operator >> (T& value) { + value = rws_->get(idx_, T()); + ++idx_; + return *this; + } + + private: + rows* rws_; + int idx_; + }; + + explicit rows(sqlite3_stmt* stmt); + + int data_count() const; + int column_type(int idx) const; + + int column_bytes(int idx) const; + + template T get(int idx) const { + return get(idx, T()); + } + + template + std::tuple get_columns(typename convert::to_int... idxs) const { + return std::make_tuple(get(idxs, Ts())...); + } + + getstream getter(int idx = 0); + + private: + int get(int idx, int) const; + double get(int idx, double) const; + long long int get(int idx, long long int) const; + char const* get(int idx, char const*) const; + std::string get(int idx, std::string) const; + void const* get(int idx, void const*) const; + char16_t const* get(int idx, char16_t const*) const; + null_type get(int idx, null_type) const; + + private: + sqlite3_stmt* stmt_; + }; + + class query_iterator + { + public: + typedef std::input_iterator_tag iterator_category; + typedef rows value_type; + typedef std::ptrdiff_t difference_type; + typedef rows* pointer; + typedef rows& reference; + + query_iterator(); + explicit query_iterator(query* cmd); + + bool operator==(query_iterator const&) const; + bool operator!=(query_iterator const&) const; + + query_iterator& operator++(); + + value_type operator*() const; + + private: + query* cmd_; + int rc_; + }; + + explicit query(database& db, char const* stmt = nullptr); + + int column_count() const; + + char const* column_name(int idx) const; + char const* column_decltype(int idx) const; + + using iterator = query_iterator; + + iterator begin(); + iterator end(); + }; + + class transaction : noncopyable + { + public: + explicit transaction(database& db, bool fcommit = false, bool freserve = false); + ~transaction(); + + int commit(); + int rollback(); + + private: + database* db_; + bool fcommit_; + }; + +} // namespace sqlite3pp + +#include "sqlite3pp.ipp" + +#endif diff --git a/3rdparty/sqlite3pp/sqlite3pp.ipp b/3rdparty/sqlite3pp/sqlite3pp.ipp new file mode 100644 index 0000000..e19035d --- /dev/null +++ b/3rdparty/sqlite3pp/sqlite3pp.ipp @@ -0,0 +1,637 @@ +// sqlite3pp.cpp +// +// The MIT License +// +// Copyright (c) 2015 Wongoo Lee (iwongu at gmail dot com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include +#include + +namespace sqlite3pp +{ + + namespace + { + null_type ignore; + + int busy_handler_impl(void* p, int cnt) + { + auto h = static_cast(p); + return (*h)(cnt); + } + + int commit_hook_impl(void* p) + { + auto h = static_cast(p); + return (*h)(); + } + + void rollback_hook_impl(void* p) + { + auto h = static_cast(p); + (*h)(); + } + + void update_hook_impl(void* p, int opcode, char const* dbname, char const* tablename, long long int rowid) + { + auto h = static_cast(p); + (*h)(opcode, dbname, tablename, rowid); + } + + int authorizer_impl(void* p, int evcode, char const* p1, char const* p2, char const* dbname, char const* tvname) + { + auto h = static_cast(p); + return (*h)(evcode, p1, p2, dbname, tvname); + } + + } // namespace + + inline database::database(char const* dbname, int flags, char const* vfs) : db_(nullptr), borrowing_(false) + { + if (dbname) { + auto rc = connect(dbname, flags, vfs); + if (rc != SQLITE_OK) { + // Whether or not an error occurs when it is opened, resources + // associated with the database connection handle should be released + // by passing it to sqlite3_close() when it is no longer required. + disconnect(); + throw database_error("can't connect database"); + } + } + } + + inline database::database(database&& db) : db_(std::move(db.db_)), + borrowing_(std::move(db.borrowing_)), + bh_(std::move(db.bh_)), + ch_(std::move(db.ch_)), + rh_(std::move(db.rh_)), + uh_(std::move(db.uh_)), + ah_(std::move(db.ah_)) + { + db.db_ = nullptr; + } + + inline database& database::operator=(database&& db) + { + db_ = std::move(db.db_); + db.db_ = nullptr; + borrowing_ = std::move(db.borrowing_); + + bh_ = std::move(db.bh_); + ch_ = std::move(db.ch_); + rh_ = std::move(db.rh_); + uh_ = std::move(db.uh_); + ah_ = std::move(db.ah_); + + return *this; + } + + inline database::~database() + { + if (!borrowing_) { + disconnect(); + } + } + + inline int database::connect(char const* dbname, int flags, char const* vfs) + { + if (!borrowing_) { + disconnect(); + } + + return sqlite3_open_v2(dbname, &db_, flags, vfs); + } + + inline int database::disconnect() + { + auto rc = SQLITE_OK; + if (db_) { + rc = sqlite3_close(db_); + if (rc == SQLITE_OK) { + db_ = nullptr; + } + } + + return rc; + } + + inline int database::attach(char const* dbname, char const* name) + { + return executef("ATTACH '%q' AS '%q'", dbname, name); + } + + inline int database::detach(char const* name) + { + return executef("DETACH '%q'", name); + } + + inline int database::backup(database& destdb, backup_handler h) + { + return backup("main", destdb, "main", h); + } + + inline int database::backup(char const* dbname, database& destdb, char const* destdbname, backup_handler h, int step_page) + { + sqlite3_backup* bkup = sqlite3_backup_init(destdb.db_, destdbname, db_, dbname); + if (!bkup) { + return error_code(); + } + auto rc = SQLITE_OK; + do { + rc = sqlite3_backup_step(bkup, step_page); + if (h) { + h(sqlite3_backup_remaining(bkup), sqlite3_backup_pagecount(bkup), rc); + } + } while (rc == SQLITE_OK || rc == SQLITE_BUSY || rc == SQLITE_LOCKED); + sqlite3_backup_finish(bkup); + return rc; + } + + inline void database::set_busy_handler(busy_handler h) + { + bh_ = h; + sqlite3_busy_handler(db_, bh_ ? busy_handler_impl : 0, &bh_); + } + + inline void database::set_commit_handler(commit_handler h) + { + ch_ = h; + sqlite3_commit_hook(db_, ch_ ? commit_hook_impl : 0, &ch_); + } + + inline void database::set_rollback_handler(rollback_handler h) + { + rh_ = h; + sqlite3_rollback_hook(db_, rh_ ? rollback_hook_impl : 0, &rh_); + } + + inline void database::set_update_handler(update_handler h) + { + uh_ = h; + sqlite3_update_hook(db_, uh_ ? update_hook_impl : 0, &uh_); + } + + inline void database::set_authorize_handler(authorize_handler h) + { + ah_ = h; + sqlite3_set_authorizer(db_, ah_ ? authorizer_impl : 0, &ah_); + } + + inline long long int database::last_insert_rowid() const + { + return sqlite3_last_insert_rowid(db_); + } + + inline int database::enable_foreign_keys(bool enable) + { + return sqlite3_db_config(db_, SQLITE_DBCONFIG_ENABLE_FKEY, enable ? 1 : 0, nullptr); + } + + inline int database::enable_triggers(bool enable) + { + return sqlite3_db_config(db_, SQLITE_DBCONFIG_ENABLE_TRIGGER, enable ? 1 : 0, nullptr); + } + + inline int database::enable_extended_result_codes(bool enable) + { + return sqlite3_extended_result_codes(db_, enable ? 1 : 0); + } + + inline int database::changes() const + { + return sqlite3_changes(db_); + } + + inline int database::error_code() const + { + return sqlite3_errcode(db_); + } + + inline int database::extended_error_code() const + { + return sqlite3_extended_errcode(db_); + } + + inline char const* database::error_msg() const + { + return sqlite3_errmsg(db_); + } + + inline int database::execute(char const* sql) + { + return sqlite3_exec(db_, sql, 0, 0, 0); + } + + inline int database::executef(char const* sql, ...) + { + va_list ap; + va_start(ap, sql); + std::shared_ptr msql(sqlite3_vmprintf(sql, ap), sqlite3_free); + va_end(ap); + + return execute(msql.get()); + } + + inline int database::set_busy_timeout(int ms) + { + return sqlite3_busy_timeout(db_, ms); + } + + + inline statement::statement(database& db, char const* stmt) : db_(db), stmt_(0), tail_(0) + { + if (stmt) { + auto rc = prepare(stmt); + if (rc != SQLITE_OK) + throw database_error(db_); + } + } + + inline statement::~statement() + { + // finish() can return error. If you want to check the error, call + // finish() explicitly before this object is destructed. + finish(); + } + + inline int statement::prepare(char const* stmt) + { + auto rc = finish(); + if (rc != SQLITE_OK) + return rc; + + return prepare_impl(stmt); + } + + inline int statement::prepare_impl(char const* stmt) + { + return sqlite3_prepare_v2(db_.db_, stmt, std::strlen(stmt), &stmt_, &tail_); + } + + inline int statement::finish() + { + auto rc = SQLITE_OK; + if (stmt_) { + rc = finish_impl(stmt_); + stmt_ = nullptr; + } + tail_ = nullptr; + + return rc; + } + + inline int statement::finish_impl(sqlite3_stmt* stmt) + { + return sqlite3_finalize(stmt); + } + + inline int statement::step() + { + return sqlite3_step(stmt_); + } + + inline int statement::reset() + { + return sqlite3_reset(stmt_); + } + + inline int statement::clear_bindings() + { + return sqlite3_clear_bindings(stmt_); + } + + inline int statement::bind(int idx, int value) + { + return sqlite3_bind_int(stmt_, idx, value); + } + + inline int statement::bind(int idx, double value) + { + return sqlite3_bind_double(stmt_, idx, value); + } + + inline int statement::bind(int idx, long long int value) + { + return sqlite3_bind_int64(stmt_, idx, value); + } + + inline int statement::bind(int idx, char const* value, copy_semantic fcopy) + { + return sqlite3_bind_text(stmt_, idx, value, std::strlen(value), fcopy == copy ? SQLITE_TRANSIENT : SQLITE_STATIC ); + } + + inline int statement::bind(int idx, char16_t const* value, copy_semantic fcopy) + { + return sqlite3_bind_text16(stmt_, idx, value, std::char_traits::length(value) * sizeof(char16_t), fcopy == copy ? SQLITE_TRANSIENT : SQLITE_STATIC ); + } + + inline int statement::bind(int idx, void const* value, int n, copy_semantic fcopy) + { + return sqlite3_bind_blob(stmt_, idx, value, n, fcopy == copy ? SQLITE_TRANSIENT : SQLITE_STATIC ); + } + + inline int statement::bind(int idx, std::string const& value, copy_semantic fcopy) + { + return sqlite3_bind_text(stmt_, idx, value.c_str(), value.size(), fcopy == copy ? SQLITE_TRANSIENT : SQLITE_STATIC ); + } + + inline int statement::bind(int idx) + { + return sqlite3_bind_null(stmt_, idx); + } + + inline int statement::bind(int idx, null_type) + { + return bind(idx); + } + + inline int statement::bind(char const* name, int value) + { + auto idx = sqlite3_bind_parameter_index(stmt_, name); + return bind(idx, value); + } + + inline int statement::bind(char const* name, double value) + { + auto idx = sqlite3_bind_parameter_index(stmt_, name); + return bind(idx, value); + } + + inline int statement::bind(char const* name, long long int value) + { + auto idx = sqlite3_bind_parameter_index(stmt_, name); + return bind(idx, value); + } + + inline int statement::bind(char const* name, char const* value, copy_semantic fcopy) + { + auto idx = sqlite3_bind_parameter_index(stmt_, name); + return bind(idx, value, fcopy); + } + + inline int statement::bind(char const* name, void const* value, int n, copy_semantic fcopy) + { + auto idx = sqlite3_bind_parameter_index(stmt_, name); + return bind(idx, value, n, fcopy); + } + + inline int statement::bind(char const* name, std::string const& value, copy_semantic fcopy) + { + auto idx = sqlite3_bind_parameter_index(stmt_, name); + return bind(idx, value, fcopy); + } + + inline int statement::bind(char const* name) + { + auto idx = sqlite3_bind_parameter_index(stmt_, name); + return bind(idx); + } + + inline int statement::bind(char const* name, null_type) + { + return bind(name); + } + + + inline command::bindstream::bindstream(command& cmd, int idx) : cmd_(cmd), idx_(idx) + { + } + + inline command::command(database& db, char const* stmt) : statement(db, stmt) + { + } + + inline command::bindstream command::binder(int idx) + { + return bindstream(*this, idx); + } + + inline int command::execute() + { + auto rc = step(); + if (rc == SQLITE_DONE) rc = SQLITE_OK; + + return rc; + } + + inline int command::execute_all() + { + auto rc = execute(); + if (rc != SQLITE_OK) return rc; + + char const* sql = tail_; + + while (std::strlen(sql) > 0) { // sqlite3_complete() is broken. + sqlite3_stmt* old_stmt = stmt_; + + if ((rc = prepare_impl(sql)) != SQLITE_OK) return rc; + + if ((rc = sqlite3_transfer_bindings(old_stmt, stmt_)) != SQLITE_OK) return rc; + + finish_impl(old_stmt); + + if ((rc = execute()) != SQLITE_OK) return rc; + + sql = tail_; + } + + return rc; + } + + + inline query::rows::getstream::getstream(rows* rws, int idx) : rws_(rws), idx_(idx) + { + } + + inline query::rows::rows(sqlite3_stmt* stmt) : stmt_(stmt) + { + } + + inline int query::rows::data_count() const + { + return sqlite3_data_count(stmt_); + } + + inline int query::rows::column_type(int idx) const + { + return sqlite3_column_type(stmt_, idx); + } + + inline int query::rows::column_bytes(int idx) const + { + return sqlite3_column_bytes(stmt_, idx); + } + + inline int query::rows::get(int idx, int) const + { + return sqlite3_column_int(stmt_, idx); + } + + inline double query::rows::get(int idx, double) const + { + return sqlite3_column_double(stmt_, idx); + } + + inline long long int query::rows::get(int idx, long long int) const + { + return sqlite3_column_int64(stmt_, idx); + } + + inline char const* query::rows::get(int idx, char const*) const + { + return reinterpret_cast(sqlite3_column_text(stmt_, idx)); + } + + inline char16_t const* query::rows::get(int idx, char16_t const*) const + { + return reinterpret_cast(sqlite3_column_text16(stmt_, idx)); + } + + inline std::string query::rows::get(int idx, std::string) const + { + char const* c = get(idx, (char const*)0); + return c ? std::string(c) : std::string(); + } + + inline void const* query::rows::get(int idx, void const*) const + { + return sqlite3_column_blob(stmt_, idx); + } + + inline null_type query::rows::get(int /*idx*/, null_type) const + { + return ignore; + } + + inline query::rows::getstream query::rows::getter(int idx) + { + return getstream(this, idx); + } + + inline query::query_iterator::query_iterator() : cmd_(0) + { + rc_ = SQLITE_DONE; + } + + inline query::query_iterator::query_iterator(query* cmd) : cmd_(cmd) + { + rc_ = cmd_->step(); + if (rc_ != SQLITE_ROW && rc_ != SQLITE_DONE) + throw database_error(cmd_->db_); + } + + inline bool query::query_iterator::operator==(query::query_iterator const& other) const + { + return rc_ == other.rc_; + } + + inline bool query::query_iterator::operator!=(query::query_iterator const& other) const + { + return rc_ != other.rc_; + } + + inline query::query_iterator& query::query_iterator::operator++() + { + rc_ = cmd_->step(); + if (rc_ != SQLITE_ROW && rc_ != SQLITE_DONE) + throw database_error(cmd_->db_); + return *this; + } + + inline query::query_iterator::value_type query::query_iterator::operator*() const + { + return rows(cmd_->stmt_); + } + + inline query::query(database& db, char const* stmt) : statement(db, stmt) + { + } + + inline int query::column_count() const + { + return sqlite3_column_count(stmt_); + } + + inline char const* query::column_name(int idx) const + { + return sqlite3_column_name(stmt_, idx); + } + + inline char const* query::column_decltype(int idx) const + { + return sqlite3_column_decltype(stmt_, idx); + } + + + inline query::iterator query::begin() + { + return query_iterator(this); + } + + inline query::iterator query::end() + { + return query_iterator(); + } + + + inline transaction::transaction(database& db, bool fcommit, bool freserve) : db_(&db), fcommit_(fcommit) + { + int rc = db_->execute(freserve ? "BEGIN IMMEDIATE" : "BEGIN"); + if (rc != SQLITE_OK) + throw database_error(*db_); + } + + inline transaction::~transaction() + { + if (db_) { + // execute() can return error. If you want to check the error, + // call commit() or rollback() explicitly before this object is + // destructed. + db_->execute(fcommit_ ? "COMMIT" : "ROLLBACK"); + } + } + + inline int transaction::commit() + { + auto db = db_; + db_ = nullptr; + int rc = db->execute("COMMIT"); + return rc; + } + + inline int transaction::rollback() + { + auto db = db_; + db_ = nullptr; + int rc = db->execute("ROLLBACK"); + return rc; + } + + + inline database_error::database_error(char const* msg) : std::runtime_error(msg) + { + } + + inline database_error::database_error(database& db) : std::runtime_error(sqlite3_errmsg(db.db_)) + { + } + +} // namespace sqlite3pp diff --git a/3rdparty/sqlite3pp/sqlite3ppext.h b/3rdparty/sqlite3pp/sqlite3ppext.h new file mode 100644 index 0000000..6391005 --- /dev/null +++ b/3rdparty/sqlite3pp/sqlite3ppext.h @@ -0,0 +1,236 @@ +// sqlite3ppext.h +// +// The MIT License +// +// Copyright (c) 2015 Wongoo Lee (iwongu at gmail dot com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#ifndef SQLITE3PPEXT_H +#define SQLITE3PPEXT_H + +#include +#include +#include +#include +#include +#include + +#include "sqlite3pp.h" + +namespace sqlite3pp +{ + namespace + { + template + struct Apply { + template + static inline auto apply(F&& f, T&& t, A&&... a) + -> decltype(Apply::apply(std::forward(f), + std::forward(t), + std::get(std::forward(t)), + std::forward(a)...)) + { + return Apply::apply(std::forward(f), + std::forward(t), + std::get(std::forward(t)), + std::forward(a)...); + } + }; + + template<> + struct Apply<0> { + template + static inline auto apply(F&& f, T&&, A&&... a) + -> decltype(std::forward(f)(std::forward(a)...)) + { + return std::forward(f)(std::forward(a)...); + } + }; + + template + inline auto apply_f(F&& f, T&& t) + -> decltype(Apply::type>::value>::apply(std::forward(f), std::forward(t))) + { + return Apply::type>::value>::apply( + std::forward(f), std::forward(t)); + } + } + + + namespace ext + { + database borrow(sqlite3* pdb) { + return database(pdb); + } + + class context : noncopyable + { + public: + explicit context(sqlite3_context* ctx, int nargs = 0, sqlite3_value** values = nullptr); + + int args_count() const; + int args_bytes(int idx) const; + int args_type(int idx) const; + + template T get(int idx) const { + return get(idx, T()); + } + + void result(int value); + void result(double value); + void result(long long int value); + void result(std::string const& value); + void result(char const* value, bool fcopy); + void result(void const* value, int n, bool fcopy); + void result(); + void result(null_type); + void result_copy(int idx); + void result_error(char const* msg); + + void* aggregate_data(int size); + int aggregate_count(); + + template + std::tuple to_tuple() { + return to_tuple_impl(0, *this, std::tuple()); + } + + private: + int get(int idx, int) const; + double get(int idx, double) const; + long long int get(int idx, long long int) const; + char const* get(int idx, char const*) const; + std::string get(int idx, std::string) const; + void const* get(int idx, void const*) const; + + template + static inline std::tuple to_tuple_impl(int index, const context& c, std::tuple&&) + { + auto h = std::make_tuple(c.context::get(index)); + return std::tuple_cat(h, to_tuple_impl(++index, c, std::tuple())); + } + static inline std::tuple<> to_tuple_impl(int /*index*/, const context& /*c*/, std::tuple<>&&) + { + return std::tuple<>(); + } + + private: + sqlite3_context* ctx_; + int nargs_; + sqlite3_value** values_; + }; + + namespace + { + template + void functionx_impl(sqlite3_context* ctx, int nargs, sqlite3_value** values) + { + context c(ctx, nargs, values); + auto f = static_cast*>(sqlite3_user_data(ctx)); + c.result(apply_f(*f, c.to_tuple())); + } + } + + class function : noncopyable + { + public: + using function_handler = std::function; + using pfunction_base = std::shared_ptr; + + explicit function(database& db); + + int create(char const* name, function_handler h, int nargs = 0); + + template int create(char const* name, std::function h) { + fh_[name] = std::shared_ptr(new std::function(h)); + return create_function_impl()(db_, fh_[name].get(), name); + } + + private: + + template + struct create_function_impl; + + template + struct create_function_impl + { + int operator()(sqlite3* db, void* fh, char const* name) { + return sqlite3_create_function(db, name, sizeof...(Ps), SQLITE_UTF8, fh, + functionx_impl, + 0, 0); + } + }; + + private: + sqlite3* db_; + + std::map fh_; + }; + + namespace + { + template + void stepx_impl(sqlite3_context* ctx, int nargs, sqlite3_value** values) + { + context c(ctx, nargs, values); + T* t = static_cast(c.aggregate_data(sizeof(T))); + if (c.aggregate_count() == 1) new (t) T; + apply_f([](T* tt, Ps... ps){tt->step(ps...);}, + std::tuple_cat(std::make_tuple(t), c.to_tuple())); + } + + template + void finishN_impl(sqlite3_context* ctx) + { + context c(ctx); + T* t = static_cast(c.aggregate_data(sizeof(T))); + c.result(t->finish()); + t->~T(); + } + } + + class aggregate : noncopyable + { + public: + using function_handler = std::function; + using pfunction_base = std::shared_ptr; + + explicit aggregate(database& db); + + int create(char const* name, function_handler s, function_handler f, int nargs = 1); + + template + int create(char const* name) { + return sqlite3_create_function(db_, name, sizeof...(Ps), SQLITE_UTF8, 0, 0, stepx_impl, finishN_impl); + } + + private: + sqlite3* db_; + + std::map > ah_; + }; + + } // namespace ext + +} // namespace sqlite3pp + +#include "sqlite3ppext.ipp" + +#endif diff --git a/3rdparty/sqlite3pp/sqlite3ppext.ipp b/3rdparty/sqlite3pp/sqlite3ppext.ipp new file mode 100644 index 0000000..2b683bc --- /dev/null +++ b/3rdparty/sqlite3pp/sqlite3ppext.ipp @@ -0,0 +1,195 @@ +// sqlite3ppext.cpp +// +// The MIT License +// +// Copyright (c) 2015 Wongoo Lee (iwongu at gmail dot com) +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include + +namespace sqlite3pp +{ + namespace ext + { + + namespace + { + + void function_impl(sqlite3_context* ctx, int nargs, sqlite3_value** values) + { + auto f = static_cast(sqlite3_user_data(ctx)); + context c(ctx, nargs, values); + (*f)(c); + } + + void step_impl(sqlite3_context* ctx, int nargs, sqlite3_value** values) + { + auto p = static_cast*>(sqlite3_user_data(ctx)); + auto s = static_cast((*p).first.get()); + context c(ctx, nargs, values); + ((function::function_handler&)*s)(c); + } + + void finalize_impl(sqlite3_context* ctx) + { + auto p = static_cast*>(sqlite3_user_data(ctx)); + auto f = static_cast((*p).second.get()); + context c(ctx); + ((function::function_handler&)*f)(c); + } + + } // namespace + + + inline context::context(sqlite3_context* ctx, int nargs, sqlite3_value** values) + : ctx_(ctx), nargs_(nargs), values_(values) + { + } + + inline int context::args_count() const + { + return nargs_; + } + + inline int context::args_bytes(int idx) const + { + return sqlite3_value_bytes(values_[idx]); + } + + inline int context::args_type(int idx) const + { + return sqlite3_value_type(values_[idx]); + } + + inline int context::get(int idx, int) const + { + return sqlite3_value_int(values_[idx]); + } + + inline double context::get(int idx, double) const + { + return sqlite3_value_double(values_[idx]); + } + + inline long long int context::get(int idx, long long int) const + { + return sqlite3_value_int64(values_[idx]); + } + + inline char const* context::get(int idx, char const*) const + { + return reinterpret_cast(sqlite3_value_text(values_[idx])); + } + + inline std::string context::get(int idx, std::string) const + { + return get(idx, (char const*)0); + } + + inline void const* context::get(int idx, void const*) const + { + return sqlite3_value_blob(values_[idx]); + } + + + + inline void context::result(int value) + { + sqlite3_result_int(ctx_, value); + } + + inline void context::result(double value) + { + sqlite3_result_double(ctx_, value); + } + + inline void context::result(long long int value) + { + sqlite3_result_int64(ctx_, value); + } + + inline void context::result(std::string const& value) + { + result(value.c_str(), false); + } + + inline void context::result(char const* value, bool fcopy) + { + sqlite3_result_text(ctx_, value, std::strlen(value), fcopy ? SQLITE_TRANSIENT : SQLITE_STATIC); + } + + inline void context::result(void const* value, int n, bool fcopy) + { + sqlite3_result_blob(ctx_, value, n, fcopy ? SQLITE_TRANSIENT : SQLITE_STATIC ); + } + + inline void context::result() + { + sqlite3_result_null(ctx_); + } + + inline void context::result(null_type) + { + sqlite3_result_null(ctx_); + } + + inline void context::result_copy(int idx) + { + sqlite3_result_value(ctx_, values_[idx]); + } + + inline void context::result_error(char const* msg) + { + sqlite3_result_error(ctx_, msg, std::strlen(msg)); + } + + inline void* context::aggregate_data(int size) + { + return sqlite3_aggregate_context(ctx_, size); + } + + inline int context::aggregate_count() + { + return sqlite3_aggregate_count(ctx_); + } + + inline function::function(database& db) : db_(db.db_) + { + } + + inline int function::create(char const* name, function_handler h, int nargs) + { + fh_[name] = pfunction_base(new function_handler(h)); + return sqlite3_create_function(db_, name, nargs, SQLITE_UTF8, fh_[name].get(), function_impl, 0, 0); + } + + inline aggregate::aggregate(database& db) : db_(db.db_) + { + } + + inline int aggregate::create(char const* name, function_handler s, function_handler f, int nargs) + { + ah_[name] = std::make_pair(pfunction_base(new function_handler(s)), pfunction_base(new function_handler(f))); + return sqlite3_create_function(db_, name, nargs, SQLITE_UTF8, &ah_[name], 0, step_impl, finalize_impl); + } + + } // namespace ext + +} // namespace sqlite3pp diff --git a/CMakeLists.txt b/CMakeLists.txt index 06427b7..614f46b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -58,6 +58,8 @@ target_include_directories(Satellite PRIVATE ${CMAKE_CURRENT_LIST_DIR}/3rdparty/ target_link_libraries(Satellite PRIVATE ${CMAKE_CURRENT_LIST_DIR}/3rdparty/sqlite3_x64-windows/lib/sqlite3.lib) #sqlite-orm target_include_directories(Satellite PRIVATE ${CMAKE_CURRENT_LIST_DIR}/3rdparty/sqlite-orm_x64-windows/include) +#sqlite3pp +target_include_directories(Satellite PRIVATE ${CMAKE_CURRENT_LIST_DIR}/3rdparty/sqlite3pp) target_compile_definitions(Satellite PRIVATE _SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING) diff --git a/RecordQuery.cpp b/RecordQuery.cpp index 581e313..6264ed9 100644 --- a/RecordQuery.cpp +++ b/RecordQuery.cpp @@ -138,17 +138,26 @@ void RecordQuery::UpdateRecordList(const std::vector& records){ rowIndex++; } } +auto RecordQuery::getQueryCondition(){ + auto cond = where(c(1) == 1); + if(ui->chbTime->isChecked()){ + std::string begin_date_time = ui->dteBeginTime->dateTime().toString("yyyy-MM-dd hh:mm:ss").toStdString(); + std::string end_date_time = ui->dteEndTime->dateTime().toString("yyyy-MM-dd hh:mm:ss").toStdString(); + //cond = cond && (c(&DbRecord::beginTime) >= begin_date_time and c(&DbRecord::beginTime) <= end_date_time); + //cond = cond and (c(2) == 2); + } + return cond; +} //-------------------------------------------------------------------------------------- // 槽函数 //-------------------------------------------------------------------------------------- void RecordQuery::on_btnQuery_clicked() { - std::string begin_date_time = ui->dteBeginTime->dateTime().toString("yyyy-MM-dd hh:mm:ss").toStdString(); - std::string end_date_time = ui->dteEndTime->dateTime().toString("yyyy-MM-dd hh:mm:ss").toStdString(); + auto& storage = GetRecordStorage(); - auto timeCond = c(&DbRecord::beginTime) >= begin_date_time and c(&DbRecord::beginTime) <= end_date_time; - std::vector v = storage.get_all();//where(timeCond) + auto cond = getQueryCondition(); + std::vector v = storage.get_all(cond);//where(timeCond) UpdateRecordList(v); } diff --git a/RecordQuery.h b/RecordQuery.h index b1f4530..2f10ac0 100644 --- a/RecordQuery.h +++ b/RecordQuery.h @@ -93,6 +93,8 @@ private: void InitDatabase(); void UpdateRecordList(const std::vector& r); + + auto getQueryCondition(); }; #endif // RECORDQUERY_H diff --git a/mainwindow.cpp b/mainwindow.cpp index c990384..598643d 100644 --- a/mainwindow.cpp +++ b/mainwindow.cpp @@ -26,6 +26,7 @@ MainWindow::MainWindow(QWidget *parent) m_loggerWidget = std::make_shared();//需要在RecordQuery创建前 m_loggerWidget->hide(); + ui->lblCallDuration->hide(); m_recordQueryWidget = std::make_shared(); m_recordQueryWidget->hide(); diff --git a/mainwindow.ui b/mainwindow.ui index b753f26..17937bf 100644 --- a/mainwindow.ui +++ b/mainwindow.ui @@ -64,7 +64,7 @@ 通话 - + @@ -99,6 +99,13 @@ + + + + 00:00:00 + + +