diff options
author | Boris Kolpackov <boris@codesynthesis.com> | 2011-03-21 17:24:35 +0200 |
---|---|---|
committer | Boris Kolpackov <boris@codesynthesis.com> | 2011-03-21 17:24:35 +0200 |
commit | dac72baef46897b80fc98632cef182fb266a5d60 (patch) | |
tree | a90f40a5fac59456c6fecf3d31a008c5a061b955 | |
parent | 3af997a875e439e71754fddb67fd60de9f60307b (diff) |
Add base SQLite database classes
-rw-r--r-- | odb/sqlite/connection-factory.cxx | 161 | ||||
-rw-r--r-- | odb/sqlite/connection-factory.hxx | 157 | ||||
-rw-r--r-- | odb/sqlite/connection.cxx | 59 | ||||
-rw-r--r-- | odb/sqlite/connection.hxx | 73 | ||||
-rw-r--r-- | odb/sqlite/database.cxx | 103 | ||||
-rw-r--r-- | odb/sqlite/database.hxx | 108 | ||||
-rw-r--r-- | odb/sqlite/database.ixx | 16 | ||||
-rw-r--r-- | odb/sqlite/error.cxx | 61 | ||||
-rw-r--r-- | odb/sqlite/error.hxx | 29 | ||||
-rw-r--r-- | odb/sqlite/exceptions.cxx | 56 | ||||
-rw-r--r-- | odb/sqlite/exceptions.hxx | 73 | ||||
-rw-r--r-- | odb/sqlite/makefile | 11 | ||||
-rw-r--r-- | odb/sqlite/statement-cache.cxx | 26 | ||||
-rw-r--r-- | odb/sqlite/statement-cache.hxx | 96 | ||||
-rw-r--r-- | odb/sqlite/statement.cxx | 99 | ||||
-rw-r--r-- | odb/sqlite/statement.hxx | 66 | ||||
-rw-r--r-- | odb/sqlite/transaction-impl.cxx | 48 | ||||
-rw-r--r-- | odb/sqlite/transaction-impl.hxx | 55 | ||||
-rw-r--r-- | odb/sqlite/transaction-impl.ixx | 16 | ||||
-rw-r--r-- | odb/sqlite/transaction.cxx | 26 | ||||
-rw-r--r-- | odb/sqlite/transaction.hxx | 59 | ||||
-rw-r--r-- | odb/sqlite/transaction.ixx | 41 | ||||
-rw-r--r-- | odb/sqlite/version.hxx | 6 |
23 files changed, 1441 insertions, 4 deletions
diff --git a/odb/sqlite/connection-factory.cxx b/odb/sqlite/connection-factory.cxx new file mode 100644 index 0000000..4cae67f --- /dev/null +++ b/odb/sqlite/connection-factory.cxx @@ -0,0 +1,161 @@ +// file : odb/sqlite/connection-factory.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/details/lock.hxx> + +#include <odb/sqlite/connection-factory.hxx> + +using namespace std; + +namespace odb +{ + using namespace details; + + namespace sqlite + { + // + // connection_factory + // + + connection_factory:: + ~connection_factory () + { + } + + // + // new_connection_factory + // + + shared_ptr<connection> new_connection_factory:: + connect () + { + return shared_ptr<connection> (new (shared) connection (*db_)); + } + + void new_connection_factory:: + database (database_type& db) + { + db_ = &db; + } + + // + // connection_pool_factory + // + + connection_pool_factory:: + ~connection_pool_factory () + { + // Wait for all the connections currently in use to return to the pool. + // + lock l (mutex_); + while (in_use_ != 0) + { + waiters_++; + cond_.wait (); + waiters_--; + } + } + + shared_ptr<connection> connection_pool_factory:: + connect () + { + lock l (mutex_); + + while (true) + { + // See if we have a spare connection. + // + if (connections_.size () != 0) + { + shared_ptr<pooled_connection> c (connections_.back ()); + connections_.pop_back (); + + c->pool_ = this; + in_use_++; + return c; + } + + // See if we can create a new one. + // + if(max_ == 0 || in_use_ < max_) + { + shared_ptr<pooled_connection> c ( + new (shared) pooled_connection (*db_, this)); + in_use_++; + return c; + } + + // Wait until someone releases a connection. + // + waiters_++; + cond_.wait (); + waiters_--; + } + } + + void connection_pool_factory:: + database (database_type& db) + { + db_ = &db; + + if (min_ > 0) + { + connections_.reserve (min_); + + for(size_t i (0); i < min_; ++i) + { + connections_.push_back ( + shared_ptr<pooled_connection> ( + new (shared) pooled_connection (*db_, 0))); + } + } + } + + bool connection_pool_factory:: + release (pooled_connection* c) + { + c->pool_ = 0; + + lock l (mutex_); + + // Determine if we need to keep or free this connection. + // + bool keep (waiters_ != 0 || + min_ == 0 || + (connections_.size () + in_use_ <= min_)); + + in_use_--; + + if (keep) + connections_.push_back ( + shared_ptr<pooled_connection> (inc_ref (c))); + + if (waiters_ != 0) + cond_.signal (); + + return !keep; + } + + // + // connection_pool_factory::pooled_connection + // + + connection_pool_factory::pooled_connection:: + pooled_connection (database_type& db, connection_pool_factory* pool) + : connection (db), pool_ (pool) + { + callback_.arg = this; + callback_.zero_counter = &zero_counter; + shared_base::callback_ = &callback_; + } + + bool connection_pool_factory::pooled_connection:: + zero_counter (void* arg) + { + pooled_connection* c (static_cast<pooled_connection*> (arg)); + return c->pool_ ? c->pool_->release (c) : true; + } + } +} diff --git a/odb/sqlite/connection-factory.hxx b/odb/sqlite/connection-factory.hxx new file mode 100644 index 0000000..6a42c8f --- /dev/null +++ b/odb/sqlite/connection-factory.hxx @@ -0,0 +1,157 @@ +// file : odb/sqlite/connection-factory.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_CONNECTION_FACTORY_HXX +#define ODB_SQLITE_CONNECTION_FACTORY_HXX + +#include <odb/pre.hxx> + +#include <vector> +#include <cstddef> // std::size_t + +#include <odb/details/mutex.hxx> +#include <odb/details/condition.hxx> +#include <odb/details/shared-ptr.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/forward.hxx> +#include <odb/sqlite/connection.hxx> +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class LIBODB_SQLITE_EXPORT connection_factory + { + public: + virtual details::shared_ptr<connection> + connect () = 0; + + public: + typedef sqlite::database database_type; + + virtual void + database (database_type&) = 0; + + virtual + ~connection_factory (); + }; + + class LIBODB_SQLITE_EXPORT new_connection_factory: + public connection_factory + { + public: + new_connection_factory () + : db_ (0) + { + } + + virtual details::shared_ptr<connection> + connect (); + + virtual void + database (database_type&); + + private: + new_connection_factory (const new_connection_factory&); + new_connection_factory& operator= (const new_connection_factory&); + + private: + database_type* db_; + }; + + class LIBODB_SQLITE_EXPORT connection_pool_factory: + public connection_factory + { + public: + // The max_connections argument specifies the maximum number of + // concurrent connections this pool will maintain. If this value + // is 0 then the pool will create a new connection every time all + // of the existing connections are in use. + // + // The min_connections argument specifies the minimum number of + // connections that should be maintained by the pool. If the + // number of connections maintained by the pool exceeds this + // number and there are no active waiters for a new connection, + // then the pool will release the excess connections. If this + // value is 0 then the pool will maintain all the connections + // that were ever created. + // + // The ping argument specifies whether to ping the connection to + // make sure it is still alive before returning it to the caller. + // + connection_pool_factory (std::size_t max_connections = 0, + std::size_t min_connections = 0) + : max_ (max_connections), + min_ (min_connections), + in_use_ (0), + waiters_ (0), + db_ (0), + cond_ (mutex_) + { + // @@ check min_ <= max_ + } + + virtual details::shared_ptr<connection> + connect (); + + virtual void + database (database_type&); + + virtual + ~connection_pool_factory (); + + private: + connection_pool_factory (const connection_pool_factory&); + connection_pool_factory& operator= (const connection_pool_factory&); + + private: + class pooled_connection: public connection + { + public: + // NULL pool value indicates that the connection is not in use. + // + pooled_connection (database_type&, connection_pool_factory*); + + private: + static bool + zero_counter (void*); + + private: + friend class connection_pool_factory; + + shared_base::refcount_callback callback_; + connection_pool_factory* pool_; + }; + + friend class pooled_connection; + typedef std::vector<details::shared_ptr<pooled_connection> > connections; + + private: + // Return true if the connection should be deleted, false otherwise. + // + bool + release (pooled_connection*); + + private: + const std::size_t max_; + const std::size_t min_; + + std::size_t in_use_; // Number of connections currently in use. + std::size_t waiters_; // Number of threads waiting for a connection. + + database_type* db_; + connections connections_; + + details::mutex mutex_; + details::condition cond_; + }; + } +} + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_CONNECTION_FACTORY_HXX diff --git a/odb/sqlite/connection.cxx b/odb/sqlite/connection.cxx new file mode 100644 index 0000000..37f5e20 --- /dev/null +++ b/odb/sqlite/connection.cxx @@ -0,0 +1,59 @@ +// file : odb/sqlite/connection.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <new> // std::bad_alloc +#include <string> +#include <cassert> + +#include <odb/sqlite/database.hxx> +#include <odb/sqlite/connection.hxx> +#include <odb/sqlite/statement-cache.hxx> +#include <odb/sqlite/error.hxx> + +using namespace std; + +namespace odb +{ + namespace sqlite + { + connection:: + connection (database_type& db) + : db_ (db) + { + int f (db.flags ()); + const string& n (db.name ()); + + // If we are opening a temporary database, then add the create flag. + // + if (n.empty () || n == ":memory:") + f |= SQLITE_OPEN_CREATE; + + // A connection can only be used by a single thread at a time. So + // disable locking in SQLite unless explicitly requested. + // + if ((f & SQLITE_OPEN_FULLMUTEX) == 0) + f |= SQLITE_OPEN_NOMUTEX; + + if (int e = sqlite3_open_v2 (n.c_str (), &handle_, f, 0)) + { + if (handle_ == 0) + throw bad_alloc (); + + translate_error (e, *this); + } + + statement_cache_.reset (new statement_cache_type (*this)); + } + + connection:: + ~connection () + { + statement_cache_.reset (); // Free prepared statements. + + if (sqlite3_close (handle_) == SQLITE_BUSY) + assert (false); // Connection has outstanding prepared statements. + } + } +} diff --git a/odb/sqlite/connection.hxx b/odb/sqlite/connection.hxx new file mode 100644 index 0000000..0df08b3 --- /dev/null +++ b/odb/sqlite/connection.hxx @@ -0,0 +1,73 @@ +// file : odb/sqlite/connection.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_CONNECTION_HXX +#define ODB_SQLITE_CONNECTION_HXX + +#include <odb/pre.hxx> + +#include <sqlite3.h> + +#include <memory> // std::auto_ptr + +#include <odb/forward.hxx> +#include <odb/details/shared-ptr.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/forward.hxx> +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class statement_cache; + + class LIBODB_SQLITE_EXPORT connection: public details::shared_base + { + public: + typedef sqlite::statement_cache statement_cache_type; + typedef sqlite::database database_type; + + virtual + ~connection (); + + connection (database_type&); + + database_type& + database () + { + return db_; + } + + public: + sqlite3* + handle () + { + return handle_; + } + + statement_cache_type& + statement_cache () + { + return *statement_cache_; + } + + private: + connection (const connection&); + connection& operator= (const connection&); + + private: + database_type& db_; + sqlite3* handle_; + + std::auto_ptr<statement_cache_type> statement_cache_; + }; + } +} + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_CONNECTION_HXX diff --git a/odb/sqlite/database.cxx b/odb/sqlite/database.cxx new file mode 100644 index 0000000..176c392 --- /dev/null +++ b/odb/sqlite/database.cxx @@ -0,0 +1,103 @@ +// file : odb/sqlite/database.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <sstream> + +#include <odb/sqlite/database.hxx> +#include <odb/sqlite/transaction.hxx> +#include <odb/sqlite/connection.hxx> +#include <odb/sqlite/connection-factory.hxx> +#include <odb/sqlite/statement.hxx> +#include <odb/sqlite/error.hxx> +#include <odb/sqlite/exceptions.hxx> + +#include <odb/sqlite/details/options.hxx> + +using namespace std; + +namespace odb +{ + namespace sqlite + { + database:: + ~database () + { + } + + database:: + database (const string& name, + int flags, + auto_ptr<connection_factory> factory) + : name_ (name), flags_ (flags), factory_ (factory) + { + if (factory_.get () == 0) + factory_.reset (new connection_pool_factory ()); + + factory_->database (*this); + } + + database:: + database (int& argc, + char* argv[], + bool erase, + int flags, + std::auto_ptr<connection_factory> factory) + : flags_ (flags), factory_ (factory) + { + using namespace details; + + try + { + cli::argv_file_scanner scan (argc, argv, "--options-file", erase); + options ops (scan, cli::unknown_mode::skip, cli::unknown_mode::skip); + + name_ = ops.database (); + + if (ops.create ()) + flags_ |= SQLITE_OPEN_CREATE; + + if (ops.read_only ()) + flags_ = (flags_ & ~SQLITE_OPEN_READWRITE) | SQLITE_OPEN_READONLY; + } + catch (const cli::exception& e) + { + ostringstream ostr; + ostr << e; + throw cli_exception (ostr.str ()); + } + + if (factory_.get () == 0) + factory_.reset (new connection_pool_factory ()); + + factory_->database (*this); + } + + void database:: + print_usage (std::ostream& os) + { + details::options::print_usage (os); + } + + unsigned long long database:: + execute (const char* s, std::size_t n) + { + if (!transaction::has_current ()) + throw not_in_transaction (); + + connection_type& c (transaction::current ().connection ()); + simple_statement st (c, s, n); + return st.execute (); + } + + transaction_impl* database:: + begin () + { + if (transaction::has_current ()) + throw already_in_transaction (); + + return new transaction_impl (*this); + } + } +} diff --git a/odb/sqlite/database.hxx b/odb/sqlite/database.hxx new file mode 100644 index 0000000..121f85c --- /dev/null +++ b/odb/sqlite/database.hxx @@ -0,0 +1,108 @@ +// file : odb/sqlite/database.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_DATABASE_HXX +#define ODB_SQLITE_DATABASE_HXX + +#include <odb/pre.hxx> + +#include <sqlite3.h> + +#include <string> +#include <memory> // std::auto_ptr +#include <iosfwd> // std::ostream + +#include <odb/database.hxx> +#include <odb/details/shared-ptr.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/forward.hxx> +#include <odb/sqlite/connection.hxx> +#include <odb/sqlite/connection-factory.hxx> +#include <odb/sqlite/transaction-impl.hxx> +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class LIBODB_SQLITE_EXPORT database: public odb::database + { + public: + typedef sqlite::connection connection_type; + + public: + database (const std::string& name, + int flags = SQLITE_OPEN_READWRITE, + std::auto_ptr<connection_factory> = + std::auto_ptr<connection_factory> (0)); + + // 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, + std::auto_ptr<connection_factory> = + std::auto_ptr<connection_factory> (0)); + + static void + print_usage (std::ostream&); + + + public: + const std::string& + name () const + { + return name_; + } + + int + flags () const + { + return flags_; + } + + public: + virtual unsigned long long + execute (const char* statement, std::size_t length); + + public: + virtual transaction_impl* + begin (); + + public: + details::shared_ptr<connection_type> + connection (); + + public: + virtual + ~database (); + + private: + std::string name_; + int flags_; + std::auto_ptr<connection_factory> factory_; + }; + } +} + +#include <odb/sqlite/database.ixx> + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_DATABASE_HXX diff --git a/odb/sqlite/database.ixx b/odb/sqlite/database.ixx new file mode 100644 index 0000000..7e34e01 --- /dev/null +++ b/odb/sqlite/database.ixx @@ -0,0 +1,16 @@ +// file : odb/sqlite/database.ixx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace sqlite + { + inline details::shared_ptr<database::connection_type> database:: + connection () + { + return factory_->connect (); + } + } +} diff --git a/odb/sqlite/error.cxx b/odb/sqlite/error.cxx new file mode 100644 index 0000000..d34f55b --- /dev/null +++ b/odb/sqlite/error.cxx @@ -0,0 +1,61 @@ +// file : odb/sqlite/errors.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <sqlite3.h> + +#include <new> // std::bad_alloc +#include <string> + +#include <odb/sqlite/connection.hxx> +#include <odb/sqlite/exceptions.hxx> + +using namespace std; + +namespace odb +{ + namespace sqlite + { + void + translate_error (int e, connection& c) + { + sqlite3* h (c.handle ()); + int ee (sqlite3_extended_errcode (h)); + string m; + + switch (e) + { + case SQLITE_NOMEM: + { + throw bad_alloc (); + } + case SQLITE_MISUSE: + { + // In case of SQLITE_MISUSE, error code/message may or may not + // be set. + // + ee = e; + m = "SQLite API misuse"; + break; + } + case SQLITE_BUSY: + case SQLITE_LOCKED: + case SQLITE_IOERR: + { + if (e != SQLITE_IOERR || ee == SQLITE_IOERR_BLOCKED) + throw deadlock (); + + // Fall throught. + } + default: + { + m = sqlite3_errmsg (h); + break; + } + } + + throw database_exception (e, ee, m); + } + } +} diff --git a/odb/sqlite/error.hxx b/odb/sqlite/error.hxx new file mode 100644 index 0000000..c897988 --- /dev/null +++ b/odb/sqlite/error.hxx @@ -0,0 +1,29 @@ +// file : odb/sqlite/errors.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_ERRORS_HXX +#define ODB_SQLITE_ERRORS_HXX + +#include <odb/pre.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class connection; + + // Translate SQLite error and throw an appropriate exception. + // + LIBODB_SQLITE_EXPORT void + translate_error (int error, connection&); + } +} + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_ERRORS_HXX diff --git a/odb/sqlite/exceptions.cxx b/odb/sqlite/exceptions.cxx new file mode 100644 index 0000000..6801665 --- /dev/null +++ b/odb/sqlite/exceptions.cxx @@ -0,0 +1,56 @@ +// file : odb/sqlite/exceptions.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/sqlite/exceptions.hxx> + +using namespace std; + +namespace odb +{ + namespace sqlite + { + // + // database_exception + // + + database_exception:: + ~database_exception () throw () + { + } + + database_exception:: + database_exception (int e, int ee, const string& m) + : error_ (e), extended_error_ (ee), message_ (m) + { + } + + const char* database_exception:: + what () const throw () + { + return message_.c_str (); + } + + // + // cli_exception + // + + cli_exception:: + cli_exception (const std::string& what) + : what_ (what) + { + } + + cli_exception:: + ~cli_exception () throw () + { + } + + const char* cli_exception:: + what () const throw () + { + return what_.c_str (); + } + } +} diff --git a/odb/sqlite/exceptions.hxx b/odb/sqlite/exceptions.hxx new file mode 100644 index 0000000..5e783a5 --- /dev/null +++ b/odb/sqlite/exceptions.hxx @@ -0,0 +1,73 @@ +// file : odb/sqlite/exceptions.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_EXCEPTIONS_HXX +#define ODB_SQLITE_EXCEPTIONS_HXX + +#include <odb/pre.hxx> + +#include <string> + +#include <odb/exceptions.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + struct LIBODB_SQLITE_EXPORT database_exception: odb::database_exception + { + database_exception (int error, + int extended_error, + const std::string& message); + + ~database_exception () throw (); + + int + error () const + { + return error_; + } + + int + extended_error () const + { + return extended_error_; + } + + const std::string& + message () const + { + return message_; + } + + virtual const char* + what () const throw (); + + private: + int error_; + int extended_error_; + std::string message_; + }; + + struct LIBODB_SQLITE_EXPORT cli_exception: odb::exception + { + cli_exception (const std::string& what); + ~cli_exception () throw (); + + virtual const char* + what () const throw (); + + private: + std::string what_; + }; + } +} + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_EXCEPTIONS_HXX diff --git a/odb/sqlite/makefile b/odb/sqlite/makefile index 6b8c4a2..4f34741 100644 --- a/odb/sqlite/makefile +++ b/odb/sqlite/makefile @@ -5,7 +5,16 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make -cxx := \ +cxx := \ +connection.cxx \ +connection-factory.cxx \ +database.cxx \ +error.cxx \ +exceptions.cxx \ +statement-cache.cxx \ +statement.cxx \ +transaction.cxx \ +transaction-impl.cxx cli_tun := details/options.cli cxx_tun := $(cxx) diff --git a/odb/sqlite/statement-cache.cxx b/odb/sqlite/statement-cache.cxx new file mode 100644 index 0000000..66ef266 --- /dev/null +++ b/odb/sqlite/statement-cache.cxx @@ -0,0 +1,26 @@ +// file : odb/sqlite/statement-cache.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/sqlite/statement-cache.hxx> + +namespace odb +{ + using namespace details; + + namespace sqlite + { + statement_cache:: + statement_cache (connection& conn) + : conn_ (conn), + // String lengths below include '\0', as per SQLite manual + // suggestions. + // + begin_ (new (shared) simple_statement (conn, "BEGIN", 6)), + commit_ (new (shared) simple_statement (conn, "COMMIT", 7)), + rollback_ (new (shared) simple_statement (conn, "ROLLBACK", 9)) + { + } + } +} diff --git a/odb/sqlite/statement-cache.hxx b/odb/sqlite/statement-cache.hxx new file mode 100644 index 0000000..9ef446d --- /dev/null +++ b/odb/sqlite/statement-cache.hxx @@ -0,0 +1,96 @@ +// file : odb/sqlite/statement-cache.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_STATEMENT_CACHE_HXX +#define ODB_SQLITE_STATEMENT_CACHE_HXX + +#include <odb/pre.hxx> + +#include <map> +#include <typeinfo> + +#include <odb/forward.hxx> +#include <odb/details/shared-ptr.hxx> +#include <odb/details/type-info.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/statement.hxx> +/* +#include <odb/sqlite/object-statements.hxx> +*/ + +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class connection; + + class LIBODB_SQLITE_EXPORT statement_cache + { + public: + statement_cache (connection&); + + simple_statement& + begin_statement () const + { + return *begin_; + } + + simple_statement& + commit_statement () const + { + return *commit_; + } + + simple_statement& + rollback_statement () const + { + return *rollback_; + } + +/* + @@ + template <typename T> + object_statements<T>& + find () + { + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast<object_statements<T>&> (*i->second); + + details::shared_ptr<object_statements<T> > p ( + new (details::shared) object_statements<T> (conn_)); + + map_.insert (map::value_type (&typeid (T), p)); + return *p; + } +*/ + + private: + /* + typedef std::map<const std::type_info*, + details::shared_ptr<object_statements_base>, + details::type_info_comparator> map; + */ + + connection& conn_; + + details::shared_ptr<simple_statement> begin_; + details::shared_ptr<simple_statement> commit_; + details::shared_ptr<simple_statement> rollback_; + + /* + map map_; + */ + }; + } +} + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_STATEMENT_CACHE_HXX diff --git a/odb/sqlite/statement.cxx b/odb/sqlite/statement.cxx new file mode 100644 index 0000000..e7d197b --- /dev/null +++ b/odb/sqlite/statement.cxx @@ -0,0 +1,99 @@ +// file : odb/sqlite/statement.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/sqlite/statement.hxx> +#include <odb/sqlite/connection.hxx> +#include <odb/sqlite/error.hxx> + +using namespace std; + +namespace odb +{ + namespace sqlite + { + // statement + // + + statement:: + statement (connection& conn, const string& s) + : conn_ (conn) + { + if (int e = sqlite3_prepare_v2 ( + conn_.handle (), + s.c_str (), + static_cast<int> (s.size () + 1), + &stmt_, + 0)) + { + translate_error (e, conn_); + } + } + + statement:: + statement (connection& conn, const char* s, std::size_t n) + : conn_ (conn) + { + if (int e = sqlite3_prepare_v2 ( + conn_.handle (), + s, + static_cast<int> (n), + &stmt_, + 0)) + { + translate_error (e, conn_); + } + } + + + + statement:: + ~statement () + { + sqlite3_finalize (stmt_); + } + + // simple_statement + // + + simple_statement:: + simple_statement (connection& conn, const string& s) + : statement (conn, s), + result_set_ (stmt_ ? sqlite3_column_count (stmt_) != 0: false) + { + } + + simple_statement:: + simple_statement (connection& conn, const char* s, std::size_t n) + : statement (conn, s, n), + result_set_ (stmt_ ? sqlite3_column_count (stmt_) != 0: false) + { + } + + unsigned long long simple_statement:: + execute () + { + if (stmt_ == 0) // Empty statement or comment. + return 0; + + if (int e = sqlite3_reset (stmt_)) + translate_error (e, conn_); + + unsigned long long r (0); + + int e; + for (e = sqlite3_step (stmt_); e == SQLITE_ROW; e = sqlite3_step (stmt_)) + r++; + + if (e != SQLITE_DONE) + translate_error (e, conn_); + + if (!result_set_) + r = static_cast<unsigned long long> ( + sqlite3_changes (conn_.handle ())); + + return r; + } + } +} diff --git a/odb/sqlite/statement.hxx b/odb/sqlite/statement.hxx new file mode 100644 index 0000000..3c5ea1c --- /dev/null +++ b/odb/sqlite/statement.hxx @@ -0,0 +1,66 @@ +// file : odb/sqlite/statement.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_STATEMENT_HXX +#define ODB_SQLITE_STATEMENT_HXX + +#include <odb/pre.hxx> + +#include <sqlite3.h> + +#include <string> +#include <cstddef> // std::size_t + +#include <odb/forward.hxx> +#include <odb/details/shared-ptr.hxx> + +#include <odb/sqlite/version.hxx> +//@@ #include <odb/sqlite/binding.hxx> + +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class connection; + + class LIBODB_SQLITE_EXPORT statement: public details::shared_base + { + public: + virtual + ~statement () = 0; + + protected: + statement (connection&, const std::string& statement); + statement (connection&, const char* statement, std::size_t n); + + protected: + connection& conn_; + sqlite3_stmt* stmt_; + }; + + class LIBODB_SQLITE_EXPORT simple_statement: public statement + { + public: + simple_statement (connection&, const std::string& statement); + simple_statement (connection&, const char* statement, std::size_t n); + + unsigned long long + execute (); + + private: + simple_statement (const simple_statement&); + simple_statement& operator= (const simple_statement&); + + private: + bool result_set_; + }; + } +} + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_STATEMENT_HXX diff --git a/odb/sqlite/transaction-impl.cxx b/odb/sqlite/transaction-impl.cxx new file mode 100644 index 0000000..3730100 --- /dev/null +++ b/odb/sqlite/transaction-impl.cxx @@ -0,0 +1,48 @@ +// file : odb/sqlite/transaction-impl.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/sqlite/database.hxx> +#include <odb/sqlite/connection.hxx> +#include <odb/sqlite/statement.hxx> +#include <odb/sqlite/statement-cache.hxx> +#include <odb/sqlite/transaction-impl.hxx> + +namespace odb +{ + namespace sqlite + { + transaction_impl:: + transaction_impl (database_type& db) + : odb::transaction_impl (db), connection_ (db.connection ()) + { + connection_->statement_cache ().begin_statement ().execute (); + } + + transaction_impl:: + ~transaction_impl () + { + } + + void transaction_impl:: + commit () + { + connection_->statement_cache ().commit_statement ().execute (); + + // Release the connection. + // + //connection_.reset (); + } + + void transaction_impl:: + rollback () + { + connection_->statement_cache ().rollback_statement ().execute (); + + // Release the connection. + // + //connection_.reset (); + } + } +} diff --git a/odb/sqlite/transaction-impl.hxx b/odb/sqlite/transaction-impl.hxx new file mode 100644 index 0000000..cc38039 --- /dev/null +++ b/odb/sqlite/transaction-impl.hxx @@ -0,0 +1,55 @@ +// file : odb/sqlite/transaction-impl.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_TRANSACTION_IMPL_HXX +#define ODB_SQLITE_TRANSACTION_IMPL_HXX + +#include <odb/pre.hxx> + +#include <odb/transaction.hxx> +#include <odb/details/shared-ptr.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/forward.hxx> +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class LIBODB_SQLITE_EXPORT transaction_impl: public odb::transaction_impl + { + protected: + friend class database; + friend class transaction; + + typedef sqlite::database database_type; + typedef sqlite::connection connection_type; + + transaction_impl (database_type&); + + virtual + ~transaction_impl (); + + virtual void + commit (); + + virtual void + rollback (); + + connection_type& + connection (); + + private: + details::shared_ptr<connection_type> connection_; + }; + } +} + +#include <odb/sqlite/transaction-impl.ixx> + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_TRANSACTION_IMPL_HXX diff --git a/odb/sqlite/transaction-impl.ixx b/odb/sqlite/transaction-impl.ixx new file mode 100644 index 0000000..f31f0ab --- /dev/null +++ b/odb/sqlite/transaction-impl.ixx @@ -0,0 +1,16 @@ +// file : odb/sqlite/transaction-impl.ixx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace sqlite + { + inline transaction_impl::connection_type& transaction_impl:: + connection () + { + return *connection_; + } + } +} diff --git a/odb/sqlite/transaction.cxx b/odb/sqlite/transaction.cxx new file mode 100644 index 0000000..6690d92 --- /dev/null +++ b/odb/sqlite/transaction.cxx @@ -0,0 +1,26 @@ +// file : odb/sqlite/transaction.cxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/sqlite/transaction.hxx> + +namespace odb +{ + namespace sqlite + { + transaction& transaction:: + current () + { + // While the impl type can be of the concrete type, the transaction + // object can be created as either odb:: or odb::sqlite:: type. To + // work around that we are going to hard-cast one two the other + // relying on the fact that they have the same representation and + // no virtual functions. The former is checked in the tests. + // + odb::transaction& b (odb::transaction::current ()); + dynamic_cast<transaction_impl&> (b.implementation ()); + return reinterpret_cast<transaction&> (b); + } + } +} diff --git a/odb/sqlite/transaction.hxx b/odb/sqlite/transaction.hxx new file mode 100644 index 0000000..aecf8aa --- /dev/null +++ b/odb/sqlite/transaction.hxx @@ -0,0 +1,59 @@ +// file : odb/sqlite/transaction.hxx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_SQLITE_TRANSACTION_HXX +#define ODB_SQLITE_TRANSACTION_HXX + +#include <odb/pre.hxx> + +#include <odb/transaction.hxx> + +#include <odb/sqlite/version.hxx> +#include <odb/sqlite/forward.hxx> +#include <odb/sqlite/details/export.hxx> + +namespace odb +{ + namespace sqlite + { + class transaction_impl; + + class LIBODB_SQLITE_EXPORT transaction: public odb::transaction + { + public: + typedef sqlite::database database_type; + typedef sqlite::connection connection_type; + + explicit + transaction (transaction_impl*); + + // Return the database this transaction is on. + // + database_type& + database (); + + // Return the underlying database connection for this transaction. + // + connection_type& + connection (); + + // Return current transaction or throw if there is no transaction + // in effect. + // + static transaction& + current (); + + public: + transaction_impl& + implementation (); + }; + } +} + +#include <odb/sqlite/transaction.ixx> + +#include <odb/post.hxx> + +#endif // ODB_SQLITE_TRANSACTION_HXX diff --git a/odb/sqlite/transaction.ixx b/odb/sqlite/transaction.ixx new file mode 100644 index 0000000..f2c9cc8 --- /dev/null +++ b/odb/sqlite/transaction.ixx @@ -0,0 +1,41 @@ +// file : odb/sqlite/transaction.ixx +// author : Boris Kolpackov <boris@codesynthesis.com> +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/sqlite/database.hxx> +#include <odb/sqlite/transaction-impl.hxx> + +namespace odb +{ + namespace sqlite + { + inline transaction:: + transaction (transaction_impl* impl) + : odb::transaction (impl) + { + } + + inline transaction_impl& transaction:: + implementation () + { + // We can use static_cast here since we have an instance of + // sqlite::transaction. + // + return static_cast<transaction_impl&> ( + odb::transaction::implementation ()); + } + + inline transaction::database_type& transaction:: + database () + { + return static_cast<database_type&> (odb::transaction::database ()); + } + + inline transaction::connection_type& transaction:: + connection () + { + return implementation ().connection (); + } + } +} diff --git a/odb/sqlite/version.hxx b/odb/sqlite/version.hxx index 4759d6d..c308e82 100644 --- a/odb/sqlite/version.hxx +++ b/odb/sqlite/version.hxx @@ -29,15 +29,15 @@ // Check that we have compatible ODB version. // -#if ODB_VERSION != 10100 +#if ODB_VERSION != 10200 # error incompatible odb interface version detected #endif // libodb-sqlite version: odb interface version plus the bugfix // version. // -#define LIBODB_SQLITE_VERSION 1010000 -#define LIBODB_SQLITE_VERSION_STR "1.1.0" +#define LIBODB_SQLITE_VERSION 1020000 +#define LIBODB_SQLITE_VERSION_STR "1.2.0" #include <odb/post.hxx> |