From 5daaa1a6d9c8f5d3a4ad3d7009df564bc6506424 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Sat, 6 Nov 2010 18:00:43 +0200 Subject: Add support for container persistence Generalize statements that were used for persisting objects to work for both objects and containers. Implement a cache for container statements. --- odb/mysql/binding.hxx | 45 +++++ odb/mysql/connection.cxx | 7 +- odb/mysql/connection.hxx | 9 +- odb/mysql/container-statements.hxx | 155 ++++++++++++++++++ odb/mysql/container-statements.txx | 35 ++++ odb/mysql/forward.hxx | 6 +- odb/mysql/makefile | 19 ++- odb/mysql/object-statements.cxx | 17 ++ odb/mysql/object-statements.hxx | 185 +++++++++++++++++++++ odb/mysql/object-statements.txx | 31 ++++ odb/mysql/query.cxx | 44 +++-- odb/mysql/query.hxx | 106 +++++++----- odb/mysql/query.txx | 2 +- odb/mysql/result.hxx | 4 +- odb/mysql/result.txx | 10 +- odb/mysql/statement-cache.hxx | 83 ++++++++++ odb/mysql/statement.cxx | 269 ++++++++---------------------- odb/mysql/statement.hxx | 328 +++++-------------------------------- odb/mysql/statement.txx | 30 ---- odb/mysql/transaction-impl.cxx | 1 + 20 files changed, 785 insertions(+), 601 deletions(-) create mode 100644 odb/mysql/binding.hxx create mode 100644 odb/mysql/container-statements.hxx create mode 100644 odb/mysql/container-statements.txx create mode 100644 odb/mysql/object-statements.cxx create mode 100644 odb/mysql/object-statements.hxx create mode 100644 odb/mysql/object-statements.txx create mode 100644 odb/mysql/statement-cache.hxx delete mode 100644 odb/mysql/statement.txx diff --git a/odb/mysql/binding.hxx b/odb/mysql/binding.hxx new file mode 100644 index 0000000..1aa7c6e --- /dev/null +++ b/odb/mysql/binding.hxx @@ -0,0 +1,45 @@ +// file : odb/mysql/binding.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_BINDING_HXX +#define ODB_MYSQL_BINDING_HXX + +#include + +#include // std::size_t + +#include + +#include +#include + +#include + +namespace odb +{ + namespace mysql + { + class LIBODB_MYSQL_EXPORT binding + { + public: + binding (MYSQL_BIND* b, std::size_t n) + : bind (b), count (n), version (0) + { + } + + MYSQL_BIND* bind; + std::size_t count; + std::size_t version; + + private: + binding (const binding&); + binding& operator= (const binding&); + }; + } +} + +#include + +#endif // ODB_MYSQL_BINDING_HXX diff --git a/odb/mysql/connection.cxx b/odb/mysql/connection.cxx index 3c17869..0b38d35 100644 --- a/odb/mysql/connection.cxx +++ b/odb/mysql/connection.cxx @@ -3,11 +3,12 @@ // copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file -#include // std::bad_alloc +#include // std::bad_alloc #include #include #include +#include using namespace std; @@ -17,7 +18,9 @@ namespace odb { connection:: connection (database& db) - : handle_ (&mysql_), active_ (0), statement_cache_ (*this) + : handle_ (&mysql_), + active_ (0), + statement_cache_ (new statement_cache_type (*this)) { if (mysql_init (handle_) == 0) throw bad_alloc (); diff --git a/odb/mysql/connection.hxx b/odb/mysql/connection.hxx index 7bbc335..7696909 100644 --- a/odb/mysql/connection.hxx +++ b/odb/mysql/connection.hxx @@ -9,12 +9,12 @@ #include #include +#include // std::auto_ptr #include #include #include -#include #include @@ -24,6 +24,9 @@ namespace odb { namespace mysql { + class statement; + class statement_cache; + class LIBODB_MYSQL_EXPORT connection: public details::shared_base { public: @@ -44,7 +47,7 @@ namespace odb statement_cache_type& statement_cache () { - return statement_cache_; + return *statement_cache_; } public: @@ -82,7 +85,7 @@ namespace odb MYSQL mysql_; MYSQL* handle_; statement* active_; - statement_cache_type statement_cache_; + std::auto_ptr statement_cache_; typedef std::vector stmt_handles; stmt_handles stmt_handles_; diff --git a/odb/mysql/container-statements.hxx b/odb/mysql/container-statements.hxx new file mode 100644 index 0000000..322129f --- /dev/null +++ b/odb/mysql/container-statements.hxx @@ -0,0 +1,155 @@ +// file : odb/mysql/container-statements.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_CONTAINER_STATEMENTS_HXX +#define ODB_MYSQL_CONTAINER_STATEMENTS_HXX + +#include + +#include +#include + +#include +#include +#include + +#include + +namespace odb +{ + namespace mysql + { + class connection; + + // Template argument is the generated container traits type. + // + template + class container_statements + { + public: + typedef T traits; + + typedef typename traits::data_image_type data_image_type; + typedef typename traits::cond_image_type cond_image_type; + + typedef typename traits::functions_type functions_type; + + typedef mysql::insert_statement insert_statement_type; + typedef mysql::select_statement select_statement_type; + typedef mysql::delete_statement delete_statement_type; + + container_statements (connection&); + + // Functions. + // + const functions_type& + functions () const + { + return functions_; + } + + // Condition image. + // + cond_image_type& + cond_image () + { + return cond_image_; + } + + binding& + cond_image_binding () + { + return cond_image_binding_; + } + + // Data image. + // + data_image_type& + data_image () + { + return data_image_; + } + + binding& + data_image_binding () + { + return data_image_binding_; + } + + my_bool* + data_image_error () + { + return data_image_error_; + } + + // + // Statements. + // + + insert_statement_type& + insert_one_statement () + { + if (insert_one_ == 0) + insert_one_.reset ( + new (details::shared) insert_statement_type ( + conn_, traits::insert_one_statement, data_image_binding_)); + + return *insert_one_; + } + + select_statement_type& + select_all_statement () + { + if (select_all_ == 0) + select_all_.reset ( + new (details::shared) select_statement_type ( + conn_, + traits::select_all_statement, + cond_image_binding_, + data_image_binding_)); + + return *select_all_; + } + + delete_statement_type& + delete_all_statement () + { + if (delete_all_ == 0) + delete_all_.reset ( + new (details::shared) delete_statement_type ( + conn_, traits::delete_all_statement, cond_image_binding_)); + + return *delete_all_; + } + + private: + container_statements (const container_statements&); + container_statements& operator= (const container_statements&); + + private: + connection& conn_; + functions_type functions_; + + cond_image_type cond_image_; + binding cond_image_binding_; + MYSQL_BIND cond_image_bind_[traits::cond_column_count]; + + data_image_type data_image_; + binding data_image_binding_; + MYSQL_BIND data_image_bind_[traits::data_column_count]; + my_bool data_image_error_[traits::data_column_count]; + + details::shared_ptr insert_one_; + details::shared_ptr select_all_; + details::shared_ptr delete_all_; + }; + } +} + +#include + +#include + +#endif // ODB_MYSQL_CONTAINER_STATEMENTS_HXX diff --git a/odb/mysql/container-statements.txx b/odb/mysql/container-statements.txx new file mode 100644 index 0000000..a4bb7e5 --- /dev/null +++ b/odb/mysql/container-statements.txx @@ -0,0 +1,35 @@ +// file : odb/mysql/container-statements.txx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // std::size_t +#include // std::memset + +namespace odb +{ + namespace mysql + { + // container_statements + // + + template + container_statements:: + container_statements (connection& conn) + : conn_ (conn), + functions_ (this, + &traits::insert_one, + &traits::load_all, + &traits::delete_all), + cond_image_binding_ (cond_image_bind_, traits::cond_column_count), + data_image_binding_ (data_image_bind_, traits::data_column_count) + { + std::memset (cond_image_bind_, 0, sizeof (cond_image_bind_)); + std::memset (data_image_bind_, 0, sizeof (data_image_bind_)); + std::memset (data_image_error_, 0, sizeof (data_image_error_)); + + for (std::size_t i (0); i < traits::data_column_count; ++i) + data_image_bind_[i].error = data_image_error_ + i; + } + } +} diff --git a/odb/mysql/forward.hxx b/odb/mysql/forward.hxx index 095b857..3b36780 100644 --- a/odb/mysql/forward.hxx +++ b/odb/mysql/forward.hxx @@ -16,11 +16,15 @@ namespace odb class connection; class connection_factory; class transaction; - class binding; class query; + // Implementation details. + // template class object_statements; + + template + class container_statements; } } diff --git a/odb/mysql/makefile b/odb/mysql/makefile index 8bec46b..53d2302 100644 --- a/odb/mysql/makefile +++ b/odb/mysql/makefile @@ -5,15 +5,16 @@ include $(dir $(lastword $(MAKEFILE_LIST)))../../build/bootstrap.make -cxx := \ -connection.cxx \ -connection-factory.cxx \ -database.cxx \ -exceptions.cxx \ -transaction.cxx \ -transaction-impl.cxx \ -statement.cxx \ -query.cxx \ +cxx := \ +connection.cxx \ +connection-factory.cxx \ +database.cxx \ +exceptions.cxx \ +object-statements.cxx \ +transaction.cxx \ +transaction-impl.cxx \ +statement.cxx \ +query.cxx \ traits.cxx cli_tun := details/options.cli diff --git a/odb/mysql/object-statements.cxx b/odb/mysql/object-statements.cxx new file mode 100644 index 0000000..f732fb8 --- /dev/null +++ b/odb/mysql/object-statements.cxx @@ -0,0 +1,17 @@ +// file : odb/mysql/object-statements.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include + +namespace odb +{ + namespace mysql + { + object_statements_base:: + ~object_statements_base () + { + } + } +} diff --git a/odb/mysql/object-statements.hxx b/odb/mysql/object-statements.hxx new file mode 100644 index 0000000..a16af88 --- /dev/null +++ b/odb/mysql/object-statements.hxx @@ -0,0 +1,185 @@ +// file : odb/mysql/object-statements.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_OBJECT_STATEMENTS_HXX +#define ODB_MYSQL_OBJECT_STATEMENTS_HXX + +#include + +#include +#include + +#include +#include +#include + +#include + +#include + +namespace odb +{ + namespace mysql + { + class connection; + + class LIBODB_MYSQL_EXPORT object_statements_base: + public details::shared_base + { + public: + virtual + ~object_statements_base (); + + protected: + object_statements_base (connection& conn) + : conn_ (conn) + { + } + + protected: + connection& conn_; + }; + + template + class object_statements: public object_statements_base + { + public: + typedef odb::object_traits object_traits; + typedef typename object_traits::image_type image_type; + typedef typename object_traits::id_image_type id_image_type; + + typedef + typename object_traits::container_statement_cache_type + container_statement_cache_type; + + typedef mysql::insert_statement persist_statement_type; + typedef mysql::select_statement find_statement_type; + typedef mysql::update_statement update_statement_type; + typedef mysql::delete_statement erase_statement_type; + + object_statements (connection&); + + image_type& + image () + { + return image_; + } + + binding& + image_binding () + { + return image_binding_; + } + + my_bool* + image_error () + { + return image_error_; + } + + id_image_type& + id_image () + { + return id_image_; + } + + binding& + id_image_binding () + { + return id_image_binding_; + } + + persist_statement_type& + persist_statement () + { + if (persist_ == 0) + persist_.reset ( + new (details::shared) persist_statement_type ( + conn_, object_traits::persist_statement, image_binding_)); + + return *persist_; + } + + find_statement_type& + find_statement () + { + if (find_ == 0) + find_.reset ( + new (details::shared) find_statement_type ( + conn_, + object_traits::find_statement, + id_image_binding_, + image_binding_)); + + return *find_; + } + + update_statement_type& + update_statement () + { + if (update_ == 0) + update_.reset ( + new (details::shared) update_statement_type ( + conn_, + object_traits::update_statement, + id_image_binding_, + image_binding_)); + + return *update_; + } + + erase_statement_type& + erase_statement () + { + if (erase_ == 0) + erase_.reset ( + new (details::shared) erase_statement_type ( + conn_, + object_traits::erase_statement, + id_image_binding_)); + + return *erase_; + } + + // Container statement cache. + // + container_statement_cache_type& + container_statment_cache () + { + return container_statement_cache_; + } + + private: + object_statements (const object_statements&); + object_statements& operator= (const object_statements&); + + private: + container_statement_cache_type container_statement_cache_; + + // The last element is the id parameter. The update statement + // depends on this being one contiguous arrays. + // + MYSQL_BIND image_bind_[object_traits::column_count + 1]; + + image_type image_; + my_bool image_error_[object_traits::column_count]; + binding image_binding_; + + id_image_type id_image_; + binding id_image_binding_; + + details::shared_ptr persist_; + details::shared_ptr find_; + details::shared_ptr update_; + details::shared_ptr erase_; + }; + } +} + +#include + +#include + +#endif // ODB_MYSQL_OBJECT_STATEMENTS_HXX diff --git a/odb/mysql/object-statements.txx b/odb/mysql/object-statements.txx new file mode 100644 index 0000000..8b2dad1 --- /dev/null +++ b/odb/mysql/object-statements.txx @@ -0,0 +1,31 @@ +// file : odb/mysql/object-statements.txx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // std::size_t +#include // std::memset + +namespace odb +{ + namespace mysql + { + // object_statements + // + + template + object_statements:: + object_statements (connection& conn) + : object_statements_base (conn), + container_statement_cache_ (conn), + image_binding_ (image_bind_, object_traits::column_count), + id_image_binding_ (image_bind_ + object_traits::column_count, 1) + { + std::memset (image_bind_, 0, sizeof (image_bind_)); + std::memset (image_error_, 0, sizeof (image_error_)); + + for (std::size_t i (0); i < object_traits::column_count; ++i) + image_bind_[i].error = image_error_ + i; + } + } +} diff --git a/odb/mysql/query.cxx b/odb/mysql/query.cxx index b159c2a..2aefeea 100644 --- a/odb/mysql/query.cxx +++ b/odb/mysql/query.cxx @@ -25,7 +25,8 @@ namespace odb query (const query& q) : clause_ (q.clause_), parameters_ (q.parameters_), - binding_ (q.binding_) + bind_ (q.bind_), + binding_ (0, 0) { } @@ -36,7 +37,7 @@ namespace odb { clause_ = q.clause_; parameters_ = q.parameters_; - binding_ = q.binding_; + bind_ = q.bind_; } return *this; @@ -56,8 +57,8 @@ namespace odb parameters_.insert ( parameters_.end (), q.parameters_.begin (), q.parameters_.end ()); - binding_.insert ( - binding_.end (), q.binding_.begin (), q.binding_.end ()); + bind_.insert ( + bind_.end (), q.bind_.begin (), q.bind_.end ()); return *this; } @@ -73,23 +74,32 @@ namespace odb clause_ += '?'; parameters_.push_back (p); - binding_.push_back (MYSQL_BIND ()); - MYSQL_BIND* b (&binding_.back ()); + bind_.push_back (MYSQL_BIND ()); + MYSQL_BIND* b (&bind_.back ()); memset (b, 0, sizeof (MYSQL_BIND)); - if (!p->reference ()) - p->bind (b); + p->bind (b); } - MYSQL_BIND* query:: + binding& query:: parameters () const { size_t n (parameters_.size ()); + binding& r (const_cast (binding_)); if (n == 0) - return 0; + return r; // r.bind and r.count should be 0. - MYSQL_BIND* b (const_cast (&binding_[0])); + MYSQL_BIND* b (const_cast (&bind_[0])); + + bool inc_ver (false); + + if (r.bind != b || r.count != bind_.size ()) + { + r.bind = b; + r.count = bind_.size (); + inc_ver = true; + } for (size_t i (0); i < n; ++i) { @@ -97,12 +107,18 @@ namespace odb if (p.reference ()) { - p.init (); - p.bind (b + i); + if (p.init ()) + { + p.bind (b + i); + inc_ver = true; + } } } - return b; + if (inc_ver) + r.version++; + + return r; } std::string query:: diff --git a/odb/mysql/query.hxx b/odb/mysql/query.hxx index e0a6884..9deb6a7 100644 --- a/odb/mysql/query.hxx +++ b/odb/mysql/query.hxx @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -59,7 +60,7 @@ namespace odb return value_ != 0; } - virtual void + virtual bool init () = 0; virtual void @@ -84,18 +85,20 @@ namespace odb { public: query () + : binding_ (0, 0) { } explicit query (const std::string& q) - : clause_ (q) + : clause_ (q), binding_ (0, 0) { } template explicit query (val_bind v) + : binding_ (0, 0) { append::db_type_id> (v); } @@ -103,6 +106,7 @@ namespace odb template explicit query (ref_bind r) + : binding_ (0, 0) { append::db_type_id> (r); } @@ -116,7 +120,7 @@ namespace odb operator= (const query&); public: - MYSQL_BIND* + binding& parameters () const; std::string @@ -187,7 +191,8 @@ namespace odb std::string clause_; parameters_type parameters_; - std::vector binding_; + std::vector bind_; + binding binding_; }; inline query @@ -1005,10 +1010,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1037,10 +1043,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1071,10 +1078,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1103,10 +1111,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1138,10 +1147,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1170,10 +1180,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1204,10 +1215,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1236,10 +1248,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1271,10 +1284,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1305,10 +1319,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1339,10 +1354,10 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast (value_)); + return init (*static_cast (value_)); } virtual void @@ -1355,14 +1370,15 @@ namespace odb } private: - void + bool init (const T& v) { bool dummy; - std::size_t size; + std::size_t size, cap (buffer_.capacity ()); value_traits::set_image ( buffer_, size, dummy, v); size_ = static_cast (size); + return cap != buffer_.capacity (); } private: @@ -1378,10 +1394,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1411,10 +1428,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1444,10 +1462,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1477,10 +1496,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1511,10 +1531,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1545,10 +1566,10 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast (value_)); + return init (*static_cast (value_)); } virtual void @@ -1561,14 +1582,15 @@ namespace odb } private: - void + bool init (const T& v) { bool dummy; - std::size_t size; + std::size_t size, cap (buffer_.capacity ()); value_traits::set_image ( buffer_, size, dummy, v); size_ = static_cast (size); + return cap != buffer_.capacity (); } private: @@ -1584,10 +1606,10 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast (value_)); + return init (*static_cast (value_)); } virtual void @@ -1600,14 +1622,15 @@ namespace odb } private: - void + bool init (const T& v) { bool dummy; - std::size_t size; + std::size_t size, cap (buffer_.capacity ()); value_traits::set_image ( buffer_, size, dummy, v); size_ = static_cast (size); + return cap != buffer_.capacity (); } private: @@ -1623,10 +1646,11 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast (value_)); + return false; } virtual void @@ -1664,10 +1688,10 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast (value_)); + return init (*static_cast (value_)); } virtual void @@ -1680,14 +1704,15 @@ namespace odb } private: - void + bool init (const T& v) { bool dummy; - std::size_t size; + std::size_t size, cap (buffer_.capacity ()); value_traits::set_image ( buffer_, size, dummy, v); size_ = static_cast (size); + return cap != buffer_.capacity (); } private: @@ -1703,10 +1728,10 @@ namespace odb query_param_impl (ref_bind r) : query_param (&r.ref) {} query_param_impl (val_bind v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast (value_)); + return init (*static_cast (value_)); } virtual void @@ -1719,14 +1744,15 @@ namespace odb } private: - void + bool init (const T& v) { bool dummy; - std::size_t size; + std::size_t size, cap (buffer_.capacity ()); value_traits::set_image ( buffer_, size, dummy, v); size_ = static_cast (size); + return cap != buffer_.capacity (); } private: diff --git a/odb/mysql/query.txx b/odb/mysql/query.txx index deafad0..5cc1fc1 100644 --- a/odb/mysql/query.txx +++ b/odb/mysql/query.txx @@ -13,7 +13,7 @@ namespace odb template query:: query (const query_column& c) - : clause_ (c.name ()) + : clause_ (c.name ()), binding_ (0, 0) { // Cannot use IS TRUE here since database type can be a non- // integral type. diff --git a/odb/mysql/result.hxx b/odb/mysql/result.hxx index 8c2469f..fe4fcfb 100644 --- a/odb/mysql/result.hxx +++ b/odb/mysql/result.hxx @@ -31,7 +31,7 @@ namespace odb virtual ~result_impl (); - result_impl (details::shared_ptr statement, + result_impl (details::shared_ptr statement, object_statements& statements); virtual void @@ -49,7 +49,7 @@ namespace odb using odb::result_impl::current; private: - details::shared_ptr statement_; + details::shared_ptr statement_; object_statements& statements_; }; } diff --git a/odb/mysql/result.txx b/odb/mysql/result.txx index ca27dd1..f06ee46 100644 --- a/odb/mysql/result.txx +++ b/odb/mysql/result.txx @@ -15,7 +15,7 @@ namespace odb template result_impl:: - result_impl (details::shared_ptr statement, + result_impl (details::shared_ptr statement, object_statements& statements) : statement_ (statement), statements_ (statements) { @@ -35,11 +35,11 @@ namespace odb next () { this->current (pointer_type ()); - query_statement::result r (statement_->fetch ()); + select_statement::result r (statement_->fetch ()); switch (r) { - case query_statement::truncated: + case select_statement::truncated: { typename traits::image_type& i (statements_.image ()); @@ -52,11 +52,11 @@ namespace odb } // Fall throught. } - case query_statement::success: + case select_statement::success: { break; } - case query_statement::no_data: + case select_statement::no_data: { this->end_ = true; break; diff --git a/odb/mysql/statement-cache.hxx b/odb/mysql/statement-cache.hxx new file mode 100644 index 0000000..480f30d --- /dev/null +++ b/odb/mysql/statement-cache.hxx @@ -0,0 +1,83 @@ +// file : odb/mysql/statement-cache.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_STATEMENT_CACHE_HXX +#define ODB_MYSQL_STATEMENT_CACHE_HXX + +#include + +#include +#include + +#include + +#include +#include + +#include + +#include + +namespace odb +{ + namespace mysql + { + class connection; + + struct LIBODB_MYSQL_EXPORT type_info_comparator + { + bool + operator() (const std::type_info* x, const std::type_info* y) const + { + // XL C++ on AIX has buggy type_info::before() in that + // it returns true for two different type_info objects + // that happened to be for the same type. + // +#if defined(__xlC__) && defined(_AIX) + return *x != *y && x->before (*y); +#else + return x->before (*y); +#endif + } + }; + + class LIBODB_MYSQL_EXPORT statement_cache + { + public: + statement_cache (connection& conn) + : conn_ (conn) + { + } + + template + object_statements& + find () + { + map::iterator i (map_.find (&typeid (T))); + + if (i != map_.end ()) + return static_cast&> (*i->second); + + details::shared_ptr > p ( + new (details::shared) object_statements (conn_)); + + map_.insert (map::value_type (&typeid (T), p)); + return *p; + } + + private: + typedef std::map, + type_info_comparator> map; + + connection& conn_; + map map_; + }; + } +} + +#include + +#endif // ODB_MYSQL_STATEMENT_CACHE_HXX diff --git a/odb/mysql/statement.cxx b/odb/mysql/statement.cxx index 6193f39..0f21917 100644 --- a/odb/mysql/statement.cxx +++ b/odb/mysql/statement.cxx @@ -35,15 +35,13 @@ namespace odb { } - // query_statement + // select_statement // - query_statement:: - ~query_statement () + select_statement:: + ~select_statement () { - statement* as (conn_.active ()); - - if (cached_ || as == this) + if (cached_ || conn_.active () == this) { try { @@ -53,23 +51,21 @@ namespace odb { } } - - if (as == this) - conn_.active (0); } - query_statement:: - query_statement (connection& conn, - const string& s, - binding& image, - MYSQL_BIND* parameters) + select_statement:: + select_statement (connection& conn, + const string& s, + binding& cond, + binding& data) : statement (conn), end_ (false), cached_ (false), rows_ (0), - image_ (image), - image_version_ (0), - parameters_ (parameters) + cond_ (cond), + cond_version_ (0), + data_ (data), + data_version_ (0) { if (statement* a = conn_.active ()) a->cancel (); @@ -78,7 +74,7 @@ namespace odb throw database_exception (stmt_); } - void query_statement:: + void select_statement:: execute () { if (statement* a = conn_.active ()) @@ -93,20 +89,20 @@ namespace odb if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); - if (image_version_ != image_.version) + if (cond_version_ != cond_.version) { - if (mysql_stmt_bind_result (stmt_, image_.bind)) + if (mysql_stmt_bind_param (stmt_, cond_.bind)) throw database_exception (stmt_); - image_version_ = image_.version; + cond_version_ = cond_.version; } - if (parameters_ != 0) + if (data_version_ != data_.version) { - // @@ versioning - // - if (mysql_stmt_bind_param (stmt_, parameters_)) + if (mysql_stmt_bind_result (stmt_, data_.bind)) throw database_exception (stmt_); + + data_version_ = data_.version; } if (mysql_stmt_execute (stmt_)) @@ -122,7 +118,7 @@ namespace odb conn_.active (this); } - void query_statement:: + void select_statement:: cache () { if (!cached_) @@ -139,7 +135,7 @@ namespace odb } } - std::size_t query_statement:: + std::size_t select_statement:: result_size () { if (!cached_) @@ -151,18 +147,18 @@ namespace odb return rows_ + static_cast (mysql_stmt_num_rows (stmt_)); } - query_statement::result query_statement:: + select_statement::result select_statement:: fetch () { - // If the result was cached the image can grow between calls + // If the result was cached the data image can grow between calls // to fetch() as a result of other statements execution. // - if (cached_ && image_version_ != image_.version) + if (cached_ && data_version_ != data_.version) { - if (mysql_stmt_bind_result (stmt_, image_.bind)) + if (mysql_stmt_bind_result (stmt_, data_.bind)) throw database_exception (stmt_); - image_version_ = image_.version; + data_version_ = data_.version; } int r (mysql_stmt_fetch (stmt_)); @@ -195,25 +191,25 @@ namespace odb } } - void query_statement:: + void select_statement:: refetch () { // Re-fetch columns that were truncated. // - for (size_t i (0); i < image_.count; ++i) + for (size_t i (0); i < data_.count; ++i) { - if (*image_.bind[i].error) + if (*data_.bind[i].error) { - *image_.bind[i].error = 0; + *data_.bind[i].error = 0; if (mysql_stmt_fetch_column ( - stmt_, image_.bind + i, static_cast (i), 0)) + stmt_, data_.bind + i, static_cast (i), 0)) throw database_exception (stmt_); } } } - void query_statement:: + void select_statement:: free_result () { end_ = true; @@ -222,30 +218,33 @@ namespace odb if (mysql_stmt_free_result (stmt_)) throw database_exception (stmt_); + + if (conn_.active () == this) + conn_.active (0); } - void query_statement:: + void select_statement:: cancel () { // If we cached the result, don't free it just yet. // if (!cached_) free_result (); - - conn_.active (0); + else + conn_.active (0); } - // persist_statement + // insert_statement // - persist_statement:: - ~persist_statement () + insert_statement:: + ~insert_statement () { } - persist_statement:: - persist_statement (connection& conn, const string& s, binding& image) - : statement (conn), image_ (image), version_ (0) + insert_statement:: + insert_statement (connection& conn, const string& s, binding& data) + : statement (conn), data_ (data), data_version_ (0) { if (statement* a = conn_.active ()) a->cancel (); @@ -254,7 +253,7 @@ namespace odb throw database_exception (stmt_); } - void persist_statement:: + bool insert_statement:: execute () { if (statement* a = conn_.active ()) @@ -263,12 +262,12 @@ namespace odb if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); - if (version_ != image_.version) + if (data_version_ != data_.version) { - if (mysql_stmt_bind_param (stmt_, image_.bind)) + if (mysql_stmt_bind_param (stmt_, data_.bind)) throw database_exception (stmt_); - version_ = image_.version; + data_version_ = data_.version; } if (mysql_stmt_execute (stmt_)) @@ -277,7 +276,7 @@ namespace odb { case ER_DUP_ENTRY: { - throw object_already_persistent (); + return false; } case ER_LOCK_DEADLOCK: { @@ -289,139 +288,10 @@ namespace odb } } } - } - - // find_statement - // - - find_statement:: - ~find_statement () - { - if (conn_.active () == this) - { - try - { - free_result (); - } - catch (...) - { - } - } - } - - find_statement:: - find_statement (connection& conn, - const string& s, - binding& id, - binding& image) - : statement (conn), - id_ (id), - id_version_ (0), - image_ (image), - image_version_ (0) - { - if (statement* a = conn_.active ()) - a->cancel (); - - if (mysql_stmt_prepare (stmt_, s.c_str (), s.size ()) != 0) - throw database_exception (stmt_); - } - - find_statement::result find_statement:: - execute () - { - if (statement* a = conn_.active ()) - a->cancel (); - - if (mysql_stmt_reset (stmt_)) - throw database_exception (stmt_); - - if (id_version_ != id_.version) - { - if (mysql_stmt_bind_param (stmt_, id_.bind)) - throw database_exception (stmt_); - - id_version_ = id_.version; - } - - if (image_version_ != image_.version) - { - if (mysql_stmt_bind_result (stmt_, image_.bind)) - throw database_exception (stmt_); - - image_version_ = image_.version; - } - - if (mysql_stmt_execute (stmt_)) - { - unsigned int e (mysql_stmt_errno (stmt_)); - - if (e == ER_LOCK_DEADLOCK) - throw deadlock (); - else - throw database_exception (stmt_); - } - - conn_.active (this); - - int r (mysql_stmt_fetch (stmt_)); - - switch (r) - { - case 0: - { - return success; - } - case MYSQL_NO_DATA: - { - free_result (); - return no_data; - } - case MYSQL_DATA_TRUNCATED: - { - return truncated; - } - default: - { - throw database_exception (stmt_); - } - } - } - void find_statement:: - refetch () - { - // Re-fetch columns that were truncated. - // - for (size_t i (0); i < image_.count; ++i) - { - if (*image_.bind[i].error) - { - *image_.bind[i].error = 0; - - if (mysql_stmt_fetch_column ( - stmt_, image_.bind + i, static_cast (i), 0)) - throw database_exception (stmt_); - } - } + return true; } - void find_statement:: - free_result () - { - if (mysql_stmt_free_result (stmt_)) - throw database_exception (stmt_); - - conn_.active (0); - } - - void find_statement:: - cancel () - { - free_result (); - } - - // update_statement // @@ -490,17 +360,17 @@ namespace odb throw database_exception (stmt_); } - // erase_statement + // delete_statement // - erase_statement:: - ~erase_statement () + delete_statement:: + ~delete_statement () { } - erase_statement:: - erase_statement (connection& conn, const string& s, binding& id) - : statement (conn), id_ (id), version_ (0) + delete_statement:: + delete_statement (connection& conn, const string& s, binding& cond) + : statement (conn), cond_ (cond), cond_version_ (0) { if (statement* a = conn_.active ()) a->cancel (); @@ -509,7 +379,7 @@ namespace odb throw database_exception (stmt_); } - void erase_statement:: + unsigned long long delete_statement:: execute () { if (statement* a = conn_.active ()) @@ -518,12 +388,12 @@ namespace odb if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); - if (version_ != id_.version) + if (cond_version_ != cond_.version) { - if (mysql_stmt_bind_param (stmt_, id_.bind)) + if (mysql_stmt_bind_param (stmt_, cond_.bind)) throw database_exception (stmt_); - version_ = id_.version; + cond_version_ = cond_.version; } if (mysql_stmt_execute (stmt_)) @@ -538,21 +408,10 @@ namespace odb my_ulonglong r (mysql_stmt_affected_rows (stmt_)); - if (r > 0) - return; - - if (r == 0) - throw object_not_persistent (); - else + if (r == static_cast (-1)) throw database_exception (stmt_); - } - - // object_statements_base - // - object_statements_base:: - ~object_statements_base () - { + return static_cast (r); } } } diff --git a/odb/mysql/statement.hxx b/odb/mysql/statement.hxx index bdeee7a..3df86c0 100644 --- a/odb/mysql/statement.hxx +++ b/odb/mysql/statement.hxx @@ -8,16 +8,14 @@ #include -#include #include #include // std::size_t -#include #include -#include #include #include +#include #include @@ -29,23 +27,6 @@ namespace odb { class connection; - class LIBODB_MYSQL_EXPORT binding - { - public: - binding (MYSQL_BIND* b, std::size_t n) - : bind (b), count (n), version (0) - { - } - - MYSQL_BIND* bind; - std::size_t count; - std::size_t version; - - private: - binding (const binding&); - binding& operator= (const binding&); - }; - class LIBODB_MYSQL_EXPORT statement: public details::shared_base { public: @@ -66,16 +47,16 @@ namespace odb MYSQL_STMT* stmt_; }; - class LIBODB_MYSQL_EXPORT query_statement: public statement + class LIBODB_MYSQL_EXPORT select_statement: public statement { public: virtual - ~query_statement (); + ~select_statement (); - query_statement (connection& conn, - const std::string& statement, - binding& image, - MYSQL_BIND* parameters); + select_statement (connection& conn, + const std::string& statement, + binding& cond, + binding& data); enum result { success, @@ -105,90 +86,51 @@ namespace odb cancel (); private: - query_statement (const query_statement&); - query_statement& operator= (const query_statement&); + select_statement (const select_statement&); + select_statement& operator= (const select_statement&); private: bool end_; bool cached_; std::size_t rows_; - binding& image_; - std::size_t image_version_; + binding& cond_; + std::size_t cond_version_; - MYSQL_BIND* parameters_; + binding& data_; + std::size_t data_version_; }; - class LIBODB_MYSQL_EXPORT persist_statement: public statement + class LIBODB_MYSQL_EXPORT insert_statement: public statement { public: virtual - ~persist_statement (); + ~insert_statement (); - persist_statement (connection& conn, - const std::string& statement, - binding& image); + insert_statement (connection& conn, + const std::string& statement, + binding& data); - void - execute (); + // Return true if successful and false if the row is a duplicate. + // All other errors are reported by throwing exceptions. + // + bool + execute (); unsigned long long id () { - return mysql_stmt_insert_id (stmt_); + return static_cast ( + mysql_stmt_insert_id (stmt_)); } private: - persist_statement (const persist_statement&); - persist_statement& operator= (const persist_statement&); + insert_statement (const insert_statement&); + insert_statement& operator= (const insert_statement&); private: - binding& image_; - std::size_t version_; - }; - - class LIBODB_MYSQL_EXPORT find_statement: public statement - { - public: - virtual - ~find_statement (); - - find_statement (connection& conn, - const std::string& statement, - binding& id, - binding& image); - enum result - { - success, - no_data, - truncated - }; - - // You are expected to call free_result() if this function - // returns success or truncated. - // - result - execute (); - - void - refetch (); - - void - free_result (); - - void - cancel (); - - private: - find_statement (const find_statement&); - find_statement& operator= (const find_statement&); - - private: - binding& id_; - std::size_t id_version_; - - binding& image_; - std::size_t image_version_; + binding& data_; + std::size_t data_version_; }; class LIBODB_MYSQL_EXPORT update_statement: public statement @@ -216,222 +158,30 @@ namespace odb std::size_t image_version_; }; - class LIBODB_MYSQL_EXPORT erase_statement: public statement + class LIBODB_MYSQL_EXPORT delete_statement: public statement { public: virtual - ~erase_statement (); + ~delete_statement (); - erase_statement (connection& conn, - const std::string& statement, - binding& id); + delete_statement (connection& conn, + const std::string& statement, + binding& cond); - void + unsigned long long execute (); private: - erase_statement (const erase_statement&); - erase_statement& operator= (const erase_statement&); - - private: - binding& id_; - std::size_t version_; - }; - - // Statement cache. - // - - class LIBODB_MYSQL_EXPORT object_statements_base: - public details::shared_base - { - public: - virtual - ~object_statements_base (); - - protected: - object_statements_base (connection& conn) - : conn_ (conn) - { - } - - protected: - connection& conn_; - }; - - template - class object_statements: public object_statements_base - { - public: - typedef odb::object_traits object_traits; - typedef typename object_traits::image_type image_type; - typedef typename object_traits::id_image_type id_image_type; - - typedef mysql::persist_statement persist_statement_type; - typedef mysql::find_statement find_statement_type; - typedef mysql::update_statement update_statement_type; - typedef mysql::erase_statement erase_statement_type; - - object_statements (connection&); - - image_type& - image () - { - return image_; - } - - binding& - image_binding () - { - return image_binding_; - } - - my_bool* - image_error () - { - return image_error_; - } - - id_image_type& - id_image () - { - return id_image_; - } - - binding& - id_image_binding () - { - return id_image_binding_; - } - - persist_statement_type& - persist_statement () - { - if (persist_ == 0) - persist_.reset ( - new (details::shared) persist_statement_type ( - conn_, object_traits::persist_statement, image_binding_)); - - return *persist_; - } - - find_statement_type& - find_statement () - { - if (find_ == 0) - find_.reset ( - new (details::shared) find_statement_type ( - conn_, - object_traits::find_statement, - id_image_binding_, - image_binding_)); - - return *find_; - } - - update_statement_type& - update_statement () - { - if (update_ == 0) - update_.reset ( - new (details::shared) update_statement_type ( - conn_, - object_traits::update_statement, - id_image_binding_, - image_binding_)); - - return *update_; - } - - erase_statement_type& - erase_statement () - { - if (erase_ == 0) - erase_.reset ( - new (details::shared) erase_statement_type ( - conn_, - object_traits::erase_statement, - id_image_binding_)); - - return *erase_; - } - - private: - object_statements (const object_statements&); - object_statements& operator= (const object_statements&); + delete_statement (const delete_statement&); + delete_statement& operator= (const delete_statement&); private: - // The last element is the id parameter. The update statement - // depends on this being one contiguous arrays. - // - MYSQL_BIND image_bind_[object_traits::column_count + 1]; - - image_type image_; - my_bool image_error_[object_traits::column_count]; - binding image_binding_; - - id_image_type id_image_; - binding id_image_binding_; - - details::shared_ptr persist_; - details::shared_ptr find_; - details::shared_ptr update_; - details::shared_ptr erase_; - }; - - struct LIBODB_MYSQL_EXPORT type_info_comparator - { - bool - operator() (const std::type_info* x, const std::type_info* y) const - { - // XL C++ on AIX has buggy type_info::before() in that - // it returns true for two different type_info objects - // that happened to be for the same type. - // -#if defined(__xlC__) && defined(_AIX) - return *x != *y && x->before (*y); -#else - return x->before (*y); -#endif - } - }; - - class LIBODB_MYSQL_EXPORT statement_cache - { - public: - statement_cache (connection& conn) - : conn_ (conn) - { - } - - template - object_statements& - find () - { - map::iterator i (map_.find (&typeid (T))); - - if (i != map_.end ()) - return static_cast&> (*i->second); - - details::shared_ptr > p ( - new (details::shared) object_statements (conn_)); - - map_.insert (map::value_type (&typeid (T), p)); - return *p; - } - - private: - typedef std::map, - type_info_comparator> map; - - connection& conn_; - map map_; + binding& cond_; + std::size_t cond_version_; }; } } -#include - #include #endif // ODB_MYSQL_STATEMENT_HXX diff --git a/odb/mysql/statement.txx b/odb/mysql/statement.txx deleted file mode 100644 index 95579b4..0000000 --- a/odb/mysql/statement.txx +++ /dev/null @@ -1,30 +0,0 @@ -// file : odb/mysql/statement.txx -// author : Boris Kolpackov -// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC -// license : GNU GPL v2; see accompanying LICENSE file - -#include // std::size_t -#include // std::memset - -namespace odb -{ - namespace mysql - { - // object_statements - // - - template - object_statements:: - object_statements (connection& conn) - : object_statements_base (conn), - image_binding_ (image_bind_, object_traits::column_count), - id_image_binding_ (image_bind_ + object_traits::column_count, 1) - { - std::memset (image_bind_, 0, sizeof (image_bind_)); - std::memset (image_error_, 0, sizeof (image_error_)); - - for (std::size_t i (0); i < object_traits::column_count; ++i) - image_bind_[i].error = image_error_ + i; - } - } -} diff --git a/odb/mysql/transaction-impl.cxx b/odb/mysql/transaction-impl.cxx index df41015..6348001 100644 --- a/odb/mysql/transaction-impl.cxx +++ b/odb/mysql/transaction-impl.cxx @@ -6,6 +6,7 @@ #include #include #include +#include #include #include -- cgit v1.1