aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2011-03-21 17:24:35 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2011-03-21 17:24:35 +0200
commitdac72baef46897b80fc98632cef182fb266a5d60 (patch)
treea90f40a5fac59456c6fecf3d31a008c5a061b955
parent3af997a875e439e71754fddb67fd60de9f60307b (diff)
Add base SQLite database classes
-rw-r--r--odb/sqlite/connection-factory.cxx161
-rw-r--r--odb/sqlite/connection-factory.hxx157
-rw-r--r--odb/sqlite/connection.cxx59
-rw-r--r--odb/sqlite/connection.hxx73
-rw-r--r--odb/sqlite/database.cxx103
-rw-r--r--odb/sqlite/database.hxx108
-rw-r--r--odb/sqlite/database.ixx16
-rw-r--r--odb/sqlite/error.cxx61
-rw-r--r--odb/sqlite/error.hxx29
-rw-r--r--odb/sqlite/exceptions.cxx56
-rw-r--r--odb/sqlite/exceptions.hxx73
-rw-r--r--odb/sqlite/makefile11
-rw-r--r--odb/sqlite/statement-cache.cxx26
-rw-r--r--odb/sqlite/statement-cache.hxx96
-rw-r--r--odb/sqlite/statement.cxx99
-rw-r--r--odb/sqlite/statement.hxx66
-rw-r--r--odb/sqlite/transaction-impl.cxx48
-rw-r--r--odb/sqlite/transaction-impl.hxx55
-rw-r--r--odb/sqlite/transaction-impl.ixx16
-rw-r--r--odb/sqlite/transaction.cxx26
-rw-r--r--odb/sqlite/transaction.hxx59
-rw-r--r--odb/sqlite/transaction.ixx41
-rw-r--r--odb/sqlite/version.hxx6
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>