diff options
-rw-r--r-- | odb/mysql/binding.hxx | 45 | ||||
-rw-r--r-- | odb/mysql/connection.cxx | 7 | ||||
-rw-r--r-- | odb/mysql/connection.hxx | 9 | ||||
-rw-r--r-- | odb/mysql/container-statements.hxx | 155 | ||||
-rw-r--r-- | odb/mysql/container-statements.txx | 35 | ||||
-rw-r--r-- | odb/mysql/forward.hxx | 6 | ||||
-rw-r--r-- | odb/mysql/makefile | 19 | ||||
-rw-r--r-- | odb/mysql/object-statements.cxx | 17 | ||||
-rw-r--r-- | odb/mysql/object-statements.hxx | 185 | ||||
-rw-r--r-- | odb/mysql/object-statements.txx (renamed from odb/mysql/statement.txx) | 3 | ||||
-rw-r--r-- | odb/mysql/query.cxx | 44 | ||||
-rw-r--r-- | odb/mysql/query.hxx | 106 | ||||
-rw-r--r-- | odb/mysql/query.txx | 2 | ||||
-rw-r--r-- | odb/mysql/result.hxx | 4 | ||||
-rw-r--r-- | odb/mysql/result.txx | 10 | ||||
-rw-r--r-- | odb/mysql/statement-cache.hxx | 83 | ||||
-rw-r--r-- | odb/mysql/statement.cxx | 269 | ||||
-rw-r--r-- | odb/mysql/statement.hxx | 328 | ||||
-rw-r--r-- | odb/mysql/transaction-impl.cxx | 1 |
19 files changed, 756 insertions, 572 deletions
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 <boris@codesynthesis.com> +// 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 <odb/pre.hxx> + +#include <cstddef> // std::size_t + +#include <odb/forward.hxx> + +#include <odb/mysql/mysql.hxx> +#include <odb/mysql/version.hxx> + +#include <odb/mysql/details/export.hxx> + +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 <odb/post.hxx> + +#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 <new> // std::bad_alloc +#include <new> // std::bad_alloc #include <odb/mysql/database.hxx> #include <odb/mysql/connection.hxx> #include <odb/mysql/exceptions.hxx> +#include <odb/mysql/statement-cache.hxx> 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 <odb/pre.hxx> #include <vector> +#include <memory> // std::auto_ptr #include <odb/forward.hxx> #include <odb/mysql/mysql.hxx> #include <odb/mysql/version.hxx> -#include <odb/mysql/statement.hxx> #include <odb/details/shared-ptr.hxx> @@ -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_type> statement_cache_; typedef std::vector<MYSQL_STMT*> 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 <boris@codesynthesis.com> +// 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 <odb/pre.hxx> + +#include <odb/forward.hxx> +#include <odb/traits.hxx> + +#include <odb/mysql/mysql.hxx> +#include <odb/mysql/version.hxx> +#include <odb/mysql/statement.hxx> + +#include <odb/mysql/details/export.hxx> + +namespace odb +{ + namespace mysql + { + class connection; + + // Template argument is the generated container traits type. + // + template <typename T> + 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_statement_type> insert_one_; + details::shared_ptr<select_statement_type> select_all_; + details::shared_ptr<delete_statement_type> delete_all_; + }; + } +} + +#include <odb/mysql/container-statements.txx> + +#include <odb/post.hxx> + +#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 <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <cstddef> // std::size_t +#include <cstring> // std::memset + +namespace odb +{ + namespace mysql + { + // container_statements + // + + template <typename T> + container_statements<T>:: + 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 <typename T> class object_statements; + + template <typename T> + 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 <boris@codesynthesis.com> +// copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include <odb/mysql/object-statements.hxx> + +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 <boris@codesynthesis.com> +// 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 <odb/pre.hxx> + +#include <odb/forward.hxx> +#include <odb/traits.hxx> + +#include <odb/mysql/mysql.hxx> +#include <odb/mysql/version.hxx> +#include <odb/mysql/statement.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/mysql/details/export.hxx> + +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 <typename T> + class object_statements: public object_statements_base + { + public: + typedef odb::object_traits<T> 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_statement_type> persist_; + details::shared_ptr<find_statement_type> find_; + details::shared_ptr<update_statement_type> update_; + details::shared_ptr<erase_statement_type> erase_; + }; + } +} + +#include <odb/mysql/object-statements.txx> + +#include <odb/post.hxx> + +#endif // ODB_MYSQL_OBJECT_STATEMENTS_HXX diff --git a/odb/mysql/statement.txx b/odb/mysql/object-statements.txx index 95579b4..8b2dad1 100644 --- a/odb/mysql/statement.txx +++ b/odb/mysql/object-statements.txx @@ -1,4 +1,4 @@ -// file : odb/mysql/statement.txx +// file : odb/mysql/object-statements.txx // author : Boris Kolpackov <boris@codesynthesis.com> // copyright : Copyright (c) 2005-2010 Code Synthesis Tools CC // license : GNU GPL v2; see accompanying LICENSE file @@ -17,6 +17,7 @@ namespace odb object_statements<T>:: 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) { 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&> (binding_)); if (n == 0) - return 0; + return r; // r.bind and r.count should be 0. - MYSQL_BIND* b (const_cast<MYSQL_BIND*> (&binding_[0])); + MYSQL_BIND* b (const_cast<MYSQL_BIND*> (&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 <odb/mysql/version.hxx> #include <odb/mysql/forward.hxx> #include <odb/mysql/traits.hxx> +#include <odb/mysql/binding.hxx> #include <odb/details/buffer.hxx> #include <odb/details/shared-ptr.hxx> @@ -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 <typename T> explicit query (val_bind<T> v) + : binding_ (0, 0) { append<T, type_traits<T>::db_type_id> (v); } @@ -103,6 +106,7 @@ namespace odb template <typename T> explicit query (ref_bind<T> r) + : binding_ (0, 0) { append<T, type_traits<T>::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<MYSQL_BIND> binding_; + std::vector<MYSQL_BIND> bind_; + binding binding_; }; inline query @@ -1005,10 +1010,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1037,10 +1043,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1071,10 +1078,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1103,10 +1111,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1138,10 +1147,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1170,10 +1180,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1204,10 +1215,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1236,10 +1248,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1271,10 +1284,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1305,10 +1319,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1339,10 +1354,10 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast<const T*> (value_)); + return init (*static_cast<const T*> (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<T, details::buffer, id_decimal>::set_image ( buffer_, size, dummy, v); size_ = static_cast<unsigned long> (size); + return cap != buffer_.capacity (); } private: @@ -1378,10 +1394,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1411,10 +1428,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1444,10 +1462,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1477,10 +1496,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1511,10 +1531,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1545,10 +1566,10 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast<const T*> (value_)); + return init (*static_cast<const T*> (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<T, details::buffer, id_string>::set_image ( buffer_, size, dummy, v); size_ = static_cast<unsigned long> (size); + return cap != buffer_.capacity (); } private: @@ -1584,10 +1606,10 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast<const T*> (value_)); + return init (*static_cast<const T*> (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<T, details::buffer, id_blob>::set_image ( buffer_, size, dummy, v); size_ = static_cast<unsigned long> (size); + return cap != buffer_.capacity (); } private: @@ -1623,10 +1646,11 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { init (*static_cast<const T*> (value_)); + return false; } virtual void @@ -1664,10 +1688,10 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast<const T*> (value_)); + return init (*static_cast<const T*> (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<T, details::buffer, id_enum>::set_image ( buffer_, size, dummy, v); size_ = static_cast<unsigned long> (size); + return cap != buffer_.capacity (); } private: @@ -1703,10 +1728,10 @@ namespace odb query_param_impl (ref_bind<T> r) : query_param (&r.ref) {} query_param_impl (val_bind<T> v) : query_param (0) {init (v.val);} - virtual void + virtual bool init () { - init (*static_cast<const T*> (value_)); + return init (*static_cast<const T*> (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<T, details::buffer, id_set>::set_image ( buffer_, size, dummy, v); size_ = static_cast<unsigned long> (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 <database_type_id ID> query:: query (const query_column<bool, ID>& 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<query_statement> statement, + result_impl (details::shared_ptr<select_statement> statement, object_statements<T>& statements); virtual void @@ -49,7 +49,7 @@ namespace odb using odb::result_impl<T>::current; private: - details::shared_ptr<query_statement> statement_; + details::shared_ptr<select_statement> statement_; object_statements<T>& 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 <typename T> result_impl<T>:: - result_impl (details::shared_ptr<query_statement> statement, + result_impl (details::shared_ptr<select_statement> statement, object_statements<T>& 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 <boris@codesynthesis.com> +// 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 <odb/pre.hxx> + +#include <map> +#include <typeinfo> + +#include <odb/forward.hxx> + +#include <odb/mysql/version.hxx> +#include <odb/mysql/object-statements.hxx> + +#include <odb/details/shared-ptr.hxx> + +#include <odb/mysql/details/export.hxx> + +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 <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>, + type_info_comparator> map; + + connection& conn_; + map map_; + }; + } +} + +#include <odb/post.hxx> + +#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<std::size_t> (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<unsigned int> (i), 0)) + stmt_, data_.bind + i, static_cast<unsigned int> (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<unsigned int> (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<my_ulonglong> (-1)) throw database_exception (stmt_); - } - - // object_statements_base - // - object_statements_base:: - ~object_statements_base () - { + return static_cast<unsigned long long> (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 <odb/pre.hxx> -#include <map> #include <string> #include <cstddef> // std::size_t -#include <typeinfo> #include <odb/forward.hxx> -#include <odb/traits.hxx> #include <odb/mysql/mysql.hxx> #include <odb/mysql/version.hxx> +#include <odb/mysql/binding.hxx> #include <odb/details/shared-ptr.hxx> @@ -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<unsigned long long> ( + 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 <typename T> - class object_statements: public object_statements_base - { - public: - typedef odb::object_traits<T> 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_statement_type> persist_; - details::shared_ptr<find_statement_type> find_; - details::shared_ptr<update_statement_type> update_; - details::shared_ptr<erase_statement_type> 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 <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>, - type_info_comparator> map; - - connection& conn_; - map map_; + binding& cond_; + std::size_t cond_version_; }; } } -#include <odb/mysql/statement.txx> - #include <odb/post.hxx> #endif // ODB_MYSQL_STATEMENT_HXX 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 <odb/mysql/mysql.hxx> #include <odb/mysql/database.hxx> #include <odb/mysql/connection.hxx> +#include <odb/mysql/statement.hxx> #include <odb/mysql/exceptions.hxx> #include <odb/mysql/transaction-impl.hxx> |