// file : odb/sqlite/database.hxx // license : GNU GPL v2; see accompanying LICENSE file #ifndef ODB_SQLITE_DATABASE_HXX #define ODB_SQLITE_DATABASE_HXX #include #include #include #include // std::ostream #include #include // ODB_CXX11 #include #include #include #include #include #include #include #include #include #include // We use the sqlite3_open_v2() flags in our interface. Define them // for SQLite earlier that 3.5.0. // #if SQLITE_VERSION_NUMBER < 3005000 # define SQLITE_OPEN_READONLY 0x00000001 # define SQLITE_OPEN_READWRITE 0x00000002 # define SQLITE_OPEN_CREATE 0x00000004 #endif namespace odb { namespace sqlite { class transaction_impl; class LIBODB_SQLITE_EXPORT database: public odb::database { public: database (const std::string& name, int flags = SQLITE_OPEN_READWRITE, bool foreign_keys = true, const std::string& vfs = "", details::transfer_ptr = details::transfer_ptr ()); #ifdef _WIN32 database (const std::wstring& name, int flags = SQLITE_OPEN_READWRITE, bool foreign_keys = true, const std::string& vfs = "", details::transfer_ptr = details::transfer_ptr ()); #endif // Extract the database parameters from the command line. The // following options are recognized: // // --database // --create // --read-only // --options-file // // For more information, see the output of the print_usage() function // below. If erase is true, the above options are removed from the argv // array and the argc count is updated accordingly. The command line // options override the flags passed as an argument. This constructor // may throw the cli_exception exception. // database (int& argc, char* argv[], bool erase = false, int flags = SQLITE_OPEN_READWRITE, bool foreign_keys = true, const std::string& vfs = "", details::transfer_ptr = details::transfer_ptr ()); // Attach to the specified connection a database with the specified name // as the specified schema. Good understanding of SQLite ATTACH/DETACH // DATABASE statements semantics and ODB connection management is // strongly recommended when using this mechanism. // // The resulting database instance is referred to as an "attached // database" and the connection it returns as an "attached connection" // (which is just a proxy for the main connection). Database operations // executed on the attached database or attached connection are // automatically translated to refer to the specified schema rather than // "main". For uniformity attached databases can also be created for the // pre-attached "main" and "temp" schemas (in this case name can be // anything). // // The automatic translation of the statements relies on their text // having references to top-level database entities (tables, indexes, // etc) qualified with the "main" schema. To achieve this, compile your // headers with `--schema main` and, if using schema migration, with // `--schema-version-table main.schema_version`. You must also not use // "main" as an object/table alias in views of native statements. For // optimal translation performance use 4-character schema names. // // The main connection and attached to it databases and connections are // all meant to be used within the same thread. In particular, the // attached database holds a counted reference to the main connection // which means the connection will not be released until all the // attached to this connection databases are destroyed. // // Note that in this model the attached databases are attached to the // main connection, not to the (main) database, which mimics the // underlying semantics of SQLite. An alternative model would have been // to notionally attach the databases to the main database and under the // hood automatically attach them to each returned connection. While // this may seem like a more convenient model in some cases, it is also // less flexible: the current model allows attaching a different set of // databases to different connections, attaching them on demand as the // transaction progresses, etc. Also, the more convenient model can be // implemented on top of this model by deriving an application-specific // database class and/or providing custom connection factories. // // Note that unless the name is a URI with appropriate mode, it is // opened with the SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE flags. So if // you want just SQLITE_OPEN_READWRITE, then you will need to verify its // existence manually prior to calling this constructor. // // Note that attaching/detaching databases withing a transaction is only // supported since SQLite 3.21.0. // database (const connection_ptr&, const std::string& name, const std::string& schema, details::transfer_ptr = details::transfer_ptr ()); // The database is automatically detached on destruction but a failure // to detach is ignored. To detect such a failure perform explicit // detach. For uniformity detaching a main database is a no-op. // void detach (); // Return the main database of an attached database. If this database // is main, return itself. // database& main_database (); // Move-constructible but not move-assignable. // // Note: noexcept is not specified since odb::database(odb::database&&) // can throw. // #ifdef ODB_CXX11 database (database&&); #endif static void print_usage (std::ostream&); public: const std::string& name () const { return name_; } // Schema name under which this database was attached or empty for the // main database. // const std::string& schema () const { return schema_; } int flags () const { return flags_; } bool foreign_keys () const { return foreign_keys_; } const std::string& vfs () const { return vfs_; } // Object persistence API. // public: // Make the object persistent. // template typename object_traits::id_type persist (T& object); template typename object_traits::id_type persist (const T& object); template typename object_traits::id_type persist (T* obj_ptr); template class P> typename object_traits::id_type persist (const P& obj_ptr); template class P> typename object_traits::id_type persist (const P& obj_ptr); template class P> typename object_traits::id_type persist (P& obj_ptr); template class P> typename object_traits::id_type persist (P& obj_ptr); template typename object_traits::id_type persist (const typename object_traits::pointer_type& obj_ptr); // Load an object. Throw object_not_persistent if not found. // template typename object_traits::pointer_type load (const typename object_traits::id_type& id); template void load (const typename object_traits::id_type& id, T& object); // Load (or reload, if it is already loaded) a section of an object. // template void load (T& object, section&); // Reload an object. // template void reload (T& object); template void reload (T* obj_ptr); template class P> void reload (const P& obj_ptr); template class P> void reload (const P& obj_ptr); template class P> void reload (P& obj_ptr); template class P> void reload (P& obj_ptr); template void reload (const typename object_traits::pointer_type& obj_ptr); // Loan an object if found. Return NULL/false if not found. // template typename object_traits::pointer_type find (const typename object_traits::id_type& id); template bool find (const typename object_traits::id_type& id, T& object); // Update the state of a modified objects. // template void update (T& object); template void update (T* obj_ptr); template class P> void update (const P& obj_ptr); template class P> void update (const P& obj_ptr); template class P> void update (P& obj_ptr); template class P> void update (P& obj_ptr); template void update (const typename object_traits::pointer_type& obj_ptr); // Update a section of an object. Throws the section_not_loaded // exception if the section is not loaded. Note also that this // function does not clear the changed flag if it is set. // template void update (const T& object, const section&); // Make the object transient. Throw object_not_persistent if not // found. // template void erase (const typename object_traits::id_type& id); template void erase (T& object); template void erase (T* obj_ptr); template class P> void erase (const P& obj_ptr); template class P> void erase (const P& obj_ptr); template class P> void erase (P& obj_ptr); template class P> void erase (P& obj_ptr); template void erase (const typename object_traits::pointer_type& obj_ptr); // Erase multiple objects matching a query predicate. // template unsigned long long erase_query (); template unsigned long long erase_query (const char*); template unsigned long long erase_query (const std::string&); template unsigned long long erase_query (const sqlite::query_base&); template unsigned long long erase_query (const odb::query_base&); // Query API. // template result query (); template result query (const char*); template result query (const std::string&); template result query (const sqlite::query_base&); template result query (const odb::query_base&); // Query one API. // template typename result::pointer_type query_one (); template bool query_one (T& object); template T query_value (); template typename result::pointer_type query_one (const char*); template bool query_one (const char*, T& object); template T query_value (const char*); template typename result::pointer_type query_one (const std::string&); template bool query_one (const std::string&, T& object); template T query_value (const std::string&); template typename result::pointer_type query_one (const sqlite::query_base&); template bool query_one (const sqlite::query_base&, T& object); template T query_value (const sqlite::query_base&); template typename result::pointer_type query_one (const odb::query_base&); template bool query_one (const odb::query_base&, T& object); template T query_value (const odb::query_base&); // Query preparation. // template prepared_query prepare_query (const char* name, const char*); template prepared_query prepare_query (const char* name, const std::string&); template prepared_query prepare_query (const char* name, const sqlite::query_base&); template prepared_query prepare_query (const char* name, const odb::query_base&); // Transactions. // public: virtual transaction_impl* begin (); transaction_impl* begin_immediate (); transaction_impl* begin_exclusive (); public: connection_ptr connection (); // SQL statement tracing. // public: typedef sqlite::tracer tracer_type; void tracer (tracer_type& t) { odb::database::tracer (t); } void tracer (tracer_type* t) { odb::database::tracer (t); } using odb::database::tracer; // Database schema version. // protected: virtual const schema_version_info& load_schema_version (const std::string& schema_name) const; // Database id constant (useful for meta-programming). // public: static const odb::database_id database_id = id_sqlite; public: virtual ~database (); protected: virtual odb::connection* connection_ (); private: friend class transaction_impl; // factory_ // Note: remember to update move ctor if adding any new members. // std::string name_; std::string schema_; int flags_; bool foreign_keys_; std::string vfs_; // Note: keep last so that all other database members are still valid // during factory's destruction. // details::unique_ptr factory_; }; } } #include #include #endif // ODB_SQLITE_DATABASE_HXX