// 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 "sqlite3.h" #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 {}; extern null_type ignore; 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); 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); 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(); 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; } 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; null_type get(int idx, null_type) const; private: sqlite3_stmt* stmt_; }; class query_iterator : public std::iterator { public: 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 #endif