From 61e6f0fded93f1e2105d7f4734b280712afe0c59 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Thu, 17 Nov 2011 11:31:00 +0200 Subject: Add connection, connection-factory implementations --- odb/mssql/connection-factory.cxx | 174 +++++++++++++++++++++++++++++++++++++++ odb/mssql/connection-factory.hxx | 164 ++++++++++++++++++++++++++++++++++++ odb/mssql/connection.cxx | 110 +++++++++++++++++++++++++ odb/mssql/connection.hxx | 137 ++++++++++++++++++++++++++++++ odb/mssql/database.cxx | 2 - odb/mssql/database.hxx | 16 ++-- odb/mssql/database.ixx | 4 - odb/mssql/makefile | 13 +-- odb/mssql/mssql-fwd.hxx | 15 ++++ odb/mssql/odbc.hxx | 6 ++ odb/mssql/transaction-impl.cxx | 99 ++++++++++++++++++++++ odb/mssql/transaction-impl.hxx | 56 +++++++++++++ odb/mssql/transaction-impl.ixx | 16 ++++ 13 files changed, 793 insertions(+), 19 deletions(-) create mode 100644 odb/mssql/connection-factory.cxx create mode 100644 odb/mssql/connection-factory.hxx create mode 100644 odb/mssql/connection.cxx create mode 100644 odb/mssql/connection.hxx create mode 100644 odb/mssql/transaction-impl.cxx create mode 100644 odb/mssql/transaction-impl.hxx create mode 100644 odb/mssql/transaction-impl.ixx diff --git a/odb/mssql/connection-factory.cxx b/odb/mssql/connection-factory.cxx new file mode 100644 index 0000000..5c91fad --- /dev/null +++ b/odb/mssql/connection-factory.cxx @@ -0,0 +1,174 @@ +// file : odb/mssql/connection-factory.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include +#include + +#include + +using namespace std; + +namespace odb +{ + using namespace details; + + namespace mssql + { + // + // connection_factory + // + + connection_factory:: + ~connection_factory () + { + } + + // + // new_connection_factory + // + + connection_ptr new_connection_factory:: + connect () + { + return connection_ptr (new (shared) connection (*db_)); + } + + void new_connection_factory:: + database (database_type& db) + { + db_ = &db; + } + + // + // connection_pool_factory + // + + connection_pool_factory::pooled_connection_ptr connection_pool_factory:: + create () + { + return pooled_connection_ptr (new (shared) pooled_connection (*db_)); + } + + 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_--; + } + } + + connection_ptr connection_pool_factory:: + connect () + { + lock l (mutex_); + + while (true) + { + // See if we have a spare connection. + // + if (connections_.size () != 0) + { + shared_ptr 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 c (create ()); + c->pool_ = 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 (create ()); + } + } + + 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 (!c->failed () && + (waiters_ != 0 || + min_ == 0 || + (connections_.size () + in_use_ <= min_))); + + in_use_--; + + if (keep) + connections_.push_back (pooled_connection_ptr (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 (db), pool_ (0) + { + callback_.arg = this; + callback_.zero_counter = &zero_counter; + shared_base::callback_ = &callback_; + } + + connection_pool_factory::pooled_connection:: + pooled_connection (database_type& db, SQLHDBC handle) + : connection (db, handle), pool_ (0) + { + 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 (arg)); + return c->pool_ ? c->pool_->release (c) : true; + } + } +} diff --git a/odb/mssql/connection-factory.hxx b/odb/mssql/connection-factory.hxx new file mode 100644 index 0000000..d74fef9 --- /dev/null +++ b/odb/mssql/connection-factory.hxx @@ -0,0 +1,164 @@ +// file : odb/mssql/connection-factory.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MSSQL_CONNECTION_FACTORY_HXX +#define ODB_MSSQL_CONNECTION_FACTORY_HXX + +#include + +#include +#include // std::size_t + +#include +#include +#include + +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class LIBODB_MSSQL_EXPORT connection_factory + { + public: + virtual connection_ptr + connect () = 0; + + public: + typedef mssql::database database_type; + + virtual void + database (database_type&) = 0; + + virtual + ~connection_factory (); + }; + + class LIBODB_MSSQL_EXPORT new_connection_factory: public connection_factory + { + public: + new_connection_factory () + : db_ (0) + { + } + + virtual connection_ptr + 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_MSSQL_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. + // + 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 connection_ptr + 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&); + + protected: + class pooled_connection: public connection + { + public: + pooled_connection (database_type&); + pooled_connection (database_type&, SQLHDBC); + + private: + static bool + zero_counter (void*); + + private: + friend class connection_pool_factory; + + shared_base::refcount_callback callback_; + + // NULL pool value indicates that the connection is not in use. + // + connection_pool_factory* pool_; + }; + + friend class pooled_connection; + + typedef details::shared_ptr pooled_connection_ptr; + typedef std::vector connections; + + // This function is called whenever the pool needs to create a new + // connection. + // + virtual pooled_connection_ptr + create (); + + protected: + // Return true if the connection should be deleted, false otherwise. + // + bool + release (pooled_connection*); + + protected: + 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 + +#endif // ODB_MSSQL_CONNECTION_FACTORY_HXX diff --git a/odb/mssql/connection.cxx b/odb/mssql/connection.cxx new file mode 100644 index 0000000..ff62c49 --- /dev/null +++ b/odb/mssql/connection.cxx @@ -0,0 +1,110 @@ +// file : odb/mssql/connection.cxx +// author : Constantin Michael +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +//@@ disabled functionality + +//#include + +#include +#include +#include +//#include +//#include +//#include +#include + +using namespace std; + +namespace odb +{ + namespace mssql + { + connection:: + connection (database_type& db) + : odb::connection (db), + db_ (db), + state_ (state_disconnected) + // statement_cache_ (new statement_cache_type (*this)) + { + SQLRETURN r; + + // Allocate the connection handle. + // + { + SQLHANDLE h; + r = SQLAllocHandle (SQL_HANDLE_DBC, db_.environment (), &h); + + if (!SQL_SUCCEEDED (r)) + translate_error (db_.environment (), SQL_HANDLE_ENV); + + handle_.reset (h); + } + + // Connect. + // + { + SQLSMALLINT out_conn_str_size; + r = SQLDriverConnect (handle_, + 0, // Parent windows handle. + (SQLCHAR*) db_.connect_string ().c_str (), + SQL_NTS, + 0, // Output connection string buffer. + 0, // Size of output connection string buffer. + &out_conn_str_size, + SQL_DRIVER_NOPROMPT); + + if (!SQL_SUCCEEDED (r)) + // Still use the handle version of translate_error since there + // is no connection. + // + translate_error (handle_, SQL_HANDLE_DBC); + + state_ = state_connected; + } + + // If an exception is thrown after this line, we will not disconnect + // the connection. + // + } + + connection:: + connection (database_type& db, SQLHDBC handle) + : odb::connection (db), + db_ (db), + handle_ (handle), + state_ (state_connected) + // statement_cache_ (new statement_cache_type (*this)) + { + } + + connection:: + ~connection () + { + // Deallocate prepared statements before we close the connection. + // + //statement_cache_.reset (); + + if (state_ != state_disconnected) + SQLDisconnect (handle_); // Ignore any errors. + } + + transaction_impl* connection:: + begin () + { + //@@ + //return new transaction_impl (connection_ptr (inc_ref (this))); + return 0; + } + + unsigned long long connection:: + execute (const char* /*s*/, std::size_t /*n*/) + { + //@@ + //generic_statement st (*this, string (s, n)); + //return st.execute (); + return 0; + } + } +} diff --git a/odb/mssql/connection.hxx b/odb/mssql/connection.hxx new file mode 100644 index 0000000..fea9035 --- /dev/null +++ b/odb/mssql/connection.hxx @@ -0,0 +1,137 @@ +// file : odb/mssql/connection.hxx +// author : Constantin Michael +// copyright : Copyright (c) 2005-2011 Code Synthesis Tools CC +// license : ODB NCUEL; see accompanying LICENSE file + +//@@ disabled functionality + +#ifndef ODB_MSSQL_CONNECTION_HXX +#define ODB_MSSQL_CONNECTION_HXX + +#include + +#include // std::auto_ptr + +#include +#include + +#include + +#include +#include +//#include +#include +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class statement_cache; + + class connection; + typedef details::shared_ptr connection_ptr; + + class LIBODB_MSSQL_EXPORT connection: public odb::connection + { + public: + typedef mssql::statement_cache statement_cache_type; + typedef mssql::database database_type; + + virtual + ~connection (); + + connection (database_type&); + connection (database_type&, SQLHDBC handle); + + database_type& + database () + { + return db_; + } + + public: + virtual transaction_impl* + begin (); + + public: + using odb::connection::execute; + + virtual unsigned long long + execute (const char* statement, std::size_t length); + + // SQL statement tracing. + // + public: + /* + typedef mssql::tracer tracer_type; + + void + tracer (tracer_type& t) + { + odb::connection::tracer (t); + } + + void + tracer (tracer_type* t) + { + odb::connection::tracer (t); + } + + using odb::connection::tracer; + */ + + public: + bool + failed () const + { + return state_ == state_failed; + } + + void + mark_failed () + { + state_ = state_failed; + } + + public: + SQLHDBC + handle () + { + return handle_; + } + + /* + statement_cache_type& + statement_cache () + { + return *statement_cache_; + } + */ + + private: + connection (const connection&); + connection& operator= (const connection&); + + private: + database_type& db_; + auto_handle handle_; + + enum + { + state_disconnected, + state_connected, + state_failed + } state_; + + //std::auto_ptr statement_cache_; + }; + } +} + +#include + +#endif // ODB_MSSQL_CONNECTION_HXX diff --git a/odb/mssql/database.cxx b/odb/mssql/database.cxx index b6ef146..51010ac 100644 --- a/odb/mssql/database.cxx +++ b/odb/mssql/database.cxx @@ -228,7 +228,6 @@ namespace odb { } - /* transaction_impl* database:: begin () { @@ -241,6 +240,5 @@ namespace odb connection_ptr c (factory_->connect ()); return c.release (); } - */ } } diff --git a/odb/mssql/database.hxx b/odb/mssql/database.hxx index d5d5597..f82d7c9 100644 --- a/odb/mssql/database.hxx +++ b/odb/mssql/database.hxx @@ -19,8 +19,8 @@ #include #include //#include -//#include -//#include +#include +#include #include #include @@ -84,12 +84,12 @@ namespace odb public: - //virtual transaction_impl* - //begin (); + virtual transaction_impl* + begin (); public: - //connection_ptr - //connection (); + connection_ptr + connection (); public: /* @@ -168,8 +168,8 @@ namespace odb ~database (); protected: - //virtual odb::connection* - //connection_ (); + virtual odb::connection* + connection_ (); private: /* diff --git a/odb/mssql/database.ixx b/odb/mssql/database.ixx index 3c8bf8e..bd84527 100644 --- a/odb/mssql/database.ixx +++ b/odb/mssql/database.ixx @@ -3,13 +3,10 @@ // copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC // license : ODB NCUEL; see accompanying LICENSE file -//@@ disabled functionality - namespace odb { namespace mssql { - /* inline connection_ptr database:: connection () { @@ -19,6 +16,5 @@ namespace odb return connection_ptr ( static_cast (connection_ ())); } - */ } } diff --git a/odb/mssql/makefile b/odb/mssql/makefile index 70fc9c6..10e9e28 100644 --- a/odb/mssql/makefile +++ b/odb/mssql/makefile @@ -6,11 +6,14 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make -cxx := \ -auto-handle.cxx \ -database.cxx \ -error.cxx \ -exceptions.cxx +cxx := \ +auto-handle.cxx \ +connection.cxx \ +connection-factory.cxx \ +database.cxx \ +error.cxx \ +exceptions.cxx \ +transaction-impl.cxx cli_tun := details/options.cli diff --git a/odb/mssql/mssql-fwd.hxx b/odb/mssql/mssql-fwd.hxx index c837cd5..bee639b 100644 --- a/odb/mssql/mssql-fwd.hxx +++ b/odb/mssql/mssql-fwd.hxx @@ -22,6 +22,21 @@ typedef unsigned short SQLUSMALLINT; typedef void* SQLHANDLE; typedef SQLHANDLE SQLHENV; +typedef SQLHANDLE SQLHDBC; +typedef SQLHANDLE SQLHSTMT; +typedef SQLHANDLE SQLHDESC; + +// If you get a redefinition error or warning for one of these macros, +// then that means you included this header (or one that includes it), +// before or . As a general rule, include or +// before any of the ODB headers. +// +#ifndef SQL_HANDLE_ENV +# define SQL_HANDLE_ENV 1 +# define SQL_HANDLE_DBC 2 +# define SQL_HANDLE_STMT 3 +# define SQL_HANDLE_DESC 4 +#endif #include diff --git a/odb/mssql/odbc.hxx b/odb/mssql/odbc.hxx index 91023b3..7276a40 100644 --- a/odb/mssql/odbc.hxx +++ b/odb/mssql/odbc.hxx @@ -8,6 +8,12 @@ #include +// This file should always be included before mssql-fwd.hxx. +// +#ifdef ODB_MSSQL_MSSQL_FWD_HXX +# error odb/mssql/mssql-fwd.hxx included before odb/mssql/odbc.hxx +#endif + #ifdef _WIN32 # ifndef WIN32_LEAN_AND_MEAN # define WIN32_LEAN_AND_MEAN diff --git a/odb/mssql/transaction-impl.cxx b/odb/mssql/transaction-impl.cxx new file mode 100644 index 0000000..4d0d77f --- /dev/null +++ b/odb/mssql/transaction-impl.cxx @@ -0,0 +1,99 @@ +// file : odb/mssql/transaction-impl.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +#include +#include +#include +#include + +namespace odb +{ + namespace mssql + { + transaction_impl:: + transaction_impl (database_type& db) + : odb::transaction_impl (db) + { + } + + transaction_impl:: + transaction_impl (connection_ptr c) + : odb::transaction_impl (c->database (), *c), connection_ (c) + { + } + + transaction_impl:: + ~transaction_impl () + { + } + + void transaction_impl:: + start () + { + /* + // Grab a connection if we don't already have one. + // + if (connection_ == 0) + { + connection_ = static_cast (database_).connection (); + odb::transaction_impl::connection_ = connection_.get (); + } + + { + odb::tracer* t; + if ((t = connection_->tracer ()) || (t = database_.tracer ())) + t->execute (*connection_, "BEGIN"); + } + + if (mssql_real_query (connection_->handle (), "begin", 5) != 0) + translate_error (*connection_); + */ + } + + void transaction_impl:: + commit () + { + /* + connection_->clear (); + + { + odb::tracer* t; + if ((t = connection_->tracer ()) || (t = database_.tracer ())) + t->execute (*connection_, "COMMIT"); + } + + if (mssql_real_query (connection_->handle (), "commit", 6) != 0) + translate_error (*connection_); + + // Release the connection. + // + //connection_.reset (); + */ + } + + void transaction_impl:: + rollback () + { + /* + connection_->clear (); + + { + odb::tracer* t; + if ((t = connection_->tracer ()) || (t = database_.tracer ())) + t->execute (*connection_, "ROLLBACK"); + } + + if (mssql_real_query (connection_->handle (), "rollback", 8) != 0) + translate_error (*connection_); + + // Release the connection. + // + //connection_.reset (); + */ + } + } +} diff --git a/odb/mssql/transaction-impl.hxx b/odb/mssql/transaction-impl.hxx new file mode 100644 index 0000000..57d9d5b --- /dev/null +++ b/odb/mssql/transaction-impl.hxx @@ -0,0 +1,56 @@ +// file : odb/mssql/transaction-impl.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MSSQL_TRANSACTION_IMPL_HXX +#define ODB_MSSQL_TRANSACTION_IMPL_HXX + +#include + +#include + +#include +#include + +#include + +namespace odb +{ + namespace mssql + { + class LIBODB_MSSQL_EXPORT transaction_impl: public odb::transaction_impl + { + public: + typedef mssql::database database_type; + typedef mssql::connection connection_type; + + transaction_impl (database_type&); + transaction_impl (connection_ptr); + + virtual + ~transaction_impl (); + + virtual void + start (); + + virtual void + commit (); + + virtual void + rollback (); + + connection_type& + connection (); + + private: + connection_ptr connection_; + }; + } +} + +#include + +#include + +#endif // ODB_MSSQL_TRANSACTION_IMPL_HXX diff --git a/odb/mssql/transaction-impl.ixx b/odb/mssql/transaction-impl.ixx new file mode 100644 index 0000000..d675224 --- /dev/null +++ b/odb/mssql/transaction-impl.ixx @@ -0,0 +1,16 @@ +// file : odb/mssql/transaction-impl.ixx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2011 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace mssql + { + inline transaction_impl::connection_type& transaction_impl:: + connection () + { + return *connection_; + } + } +} -- cgit v1.1