From 0a589394a09ce5b3f16d902d657710a2886cc2fc Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Tue, 10 Aug 2010 11:17:52 +0200 Subject: Add query support --- odb/mysql/connection.cxx | 2 +- odb/mysql/connection.hxx | 14 + odb/mysql/forward.hxx | 1 + odb/mysql/makefile | 3 +- odb/mysql/query.cxx | 96 +++++ odb/mysql/query.hxx | 828 +++++++++++++++++++++++++++++++++++++++++ odb/mysql/query.txx | 28 ++ odb/mysql/result.hxx | 51 +++ odb/mysql/result.txx | 63 ++++ odb/mysql/statement.cxx | 160 ++++++++ odb/mysql/statement.hxx | 55 +++ odb/mysql/traits.hxx | 169 ++++++++- odb/mysql/transaction-impl.cxx | 6 + 13 files changed, 1473 insertions(+), 3 deletions(-) create mode 100644 odb/mysql/query.cxx create mode 100644 odb/mysql/query.hxx create mode 100644 odb/mysql/query.txx create mode 100644 odb/mysql/result.hxx create mode 100644 odb/mysql/result.txx diff --git a/odb/mysql/connection.cxx b/odb/mysql/connection.cxx index 27e3067..7eb1b34 100644 --- a/odb/mysql/connection.cxx +++ b/odb/mysql/connection.cxx @@ -15,7 +15,7 @@ namespace odb { connection:: connection (database& db) - : handle_ (&mysql_), statement_cache_ (*this) + : handle_ (&mysql_), active_ (0), statement_cache_ (*this) { if (mysql_init (handle_) == 0) throw std::bad_alloc (); diff --git a/odb/mysql/connection.hxx b/odb/mysql/connection.hxx index ea94cd0..513abc5 100644 --- a/odb/mysql/connection.hxx +++ b/odb/mysql/connection.hxx @@ -41,6 +41,19 @@ namespace odb return statement_cache_; } + public: + statement* + active () + { + return active_; + } + + void + active (statement* s) + { + active_ = s; + } + private: connection (const connection&); connection& operator= (const connection&); @@ -48,6 +61,7 @@ namespace odb private: MYSQL mysql_; MYSQL* handle_; + statement* active_; statement_cache_type statement_cache_; }; } diff --git a/odb/mysql/forward.hxx b/odb/mysql/forward.hxx index 701627b..54bf7bf 100644 --- a/odb/mysql/forward.hxx +++ b/odb/mysql/forward.hxx @@ -15,6 +15,7 @@ namespace odb class connection_factory; class transaction; class binding; + class query; template class object_statements; diff --git a/odb/mysql/makefile b/odb/mysql/makefile index e577f98..eb510cc 100644 --- a/odb/mysql/makefile +++ b/odb/mysql/makefile @@ -12,7 +12,8 @@ database.cxx \ exceptions.cxx \ transaction.cxx \ transaction-impl.cxx \ -statement.cxx +statement.cxx \ +query.cxx cxx_obj := $(addprefix $(out_base)/,$(cxx_tun:.cxx=.o)) cxx_od := $(cxx_obj:.o=.o.d) diff --git a/odb/mysql/query.cxx b/odb/mysql/query.cxx new file mode 100644 index 0000000..1a2003a --- /dev/null +++ b/odb/mysql/query.cxx @@ -0,0 +1,96 @@ +// file : odb/mysql/query.cxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#include // std::size_t +#include // std::memset + +#include + +using namespace std; + +namespace odb +{ + namespace mysql + { + // query_param + // + query_param:: + ~query_param () + { + } + + query:: + query (const query& q) + : clause_ (q.clause_), + parameters_ (q.parameters_), + binding_ (q.binding_) + { + } + + query& query:: + operator= (const query& q) + { + if (this != &q) + { + clause_ = q.clause_; + parameters_ = q.parameters_; + binding_ = q.binding_; + } + + return *this; + } + + void query:: + add (shared_ptr p) + { + clause_ += '?'; + + parameters_.push_back (p); + binding_.push_back (MYSQL_BIND ()); + MYSQL_BIND* b (&binding_.back ()); + memset (b, 0, sizeof (MYSQL_BIND)); + + if (!p->reference ()) + p->bind (b); + } + + MYSQL_BIND* query:: + parameters () const + { + size_t n (parameters_.size ()); + + if (n == 0) + return 0; + + MYSQL_BIND* b (const_cast (&binding_[0])); + + for (size_t i (0); i < n; ++i) + { + query_param& p (*parameters_[i]); + + if (p.reference ()) + { + p.init (); + p.bind (b + i); + } + } + + return b; + } + + std::string query:: + clause () const + { + if (clause_.empty () || + clause_.compare (0, 6, "WHERE ") == 0 || + clause_.compare (0, 9, "ORDER BY ") == 0 || + clause_.compare (0, 9, "GROUP BY ") == 0 || + clause_.compare (0, 7, "HAVING ") == 0) + return clause_; + else + return "WHERE " + clause_; + } + } +} diff --git a/odb/mysql/query.hxx b/odb/mysql/query.hxx new file mode 100644 index 0000000..c322c3c --- /dev/null +++ b/odb/mysql/query.hxx @@ -0,0 +1,828 @@ +// file : odb/mysql/query.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_QUERY_HXX +#define ODB_MYSQL_QUERY_HXX + +#include + +#include +#include +#include // std::size_t + +#include + +#include +#include +#include + +namespace odb +{ + namespace mysql + { + template + class val_bind + { + public: + val_bind (const T& v): val (v) {} + + const T& val; + }; + + template + class ref_bind + { + public: + ref_bind (const T& r): ref (r) {} + + const T& ref; + }; + + struct query_param: shared_base + { + virtual + ~query_param (); + + bool + reference () const + { + return value_ != 0; + } + + virtual void + init () = 0; + + virtual void + bind (MYSQL_BIND*) = 0; + + protected: + query_param (const void* value) + : value_ (value) + { + } + + protected: + const void* value_; + }; + + class query + { + public: + query () + { + } + + explicit + query (const std::string& q) + : clause_ (q) + { + } + + query (const query&); + + query& + operator= (const query&); + + public: + MYSQL_BIND* + parameters () const; + + std::string + clause () const; + + public: + template + static val_bind + _val (const T& x) + { + return val_bind (x); + } + + template + static ref_bind + _ref (const T& x) + { + return ref_bind (x); + } + + public: + query& + operator+= (const query& q) + { + clause_ += ' '; + clause_ += q.clause_; + } + + query& + operator+= (const std::string& q) + { + clause_ += ' '; + clause_ += q; + } + + template + query& + operator+= (val_bind); + + template + query& + operator+= (ref_bind); + + private: + void + add (shared_ptr); + + private: + typedef std::vector > parameters_type; + + std::string clause_; + parameters_type parameters_; + std::vector binding_; + }; + + inline query + operator+ (const query& x, const query& y) + { + query r (x); + r += y; + return r; + } + + template + inline query + operator+ (const query& q, val_bind b) + { + query r (q); + r += b; + return r; + } + + template + inline query + operator+ (const query& q, ref_bind b) + { + query r (q); + r += b; + return r; + } + + template + inline query + operator+ (val_bind b, const query& q) + { + query r; + r += b; + r += q; + return r; + } + + template + inline query + operator+ (ref_bind b, const query& q) + { + query r; + r += b; + r += q; + return r; + } + + inline query + operator+ (const query& q, const std::string& s) + { + query r (q); + r += s; + return r; + } + + inline query + operator+ (const std::string& s, const query& q) + { + query r (s); + r += q; + return r; + } + + template + inline query + operator+ (const std::string& s, val_bind b) + { + query r (s); + r += b; + return r; + } + + template + inline query + operator+ (const std::string& s, ref_bind b) + { + query r (s); + r += b; + return r; + } + + template + inline query + operator+ (val_bind b, const std::string& s) + { + query r; + r += b; + r += s; + return r; + } + + template + inline query + operator+ (ref_bind b, const std::string& s) + { + query r; + r += b; + r += s; + return r; + } + + // + // + template + struct query_param_impl; + + // TINY + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_TINY; + b->is_unsigned = false; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + signed char image_; + }; + + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_TINY; + b->is_unsigned = true; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + unsigned char image_; + }; + + // SHORT + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_SHORT; + b->is_unsigned = false; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + short image_; + }; + + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_SHORT; + b->is_unsigned = true; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + unsigned short image_; + }; + + // LONG + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_LONG; + b->is_unsigned = false; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + int image_; + }; + + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_LONG; + b->is_unsigned = true; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + unsigned int image_; + }; + + // LONGLONG + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_LONGLONG; + b->is_unsigned = false; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + long long image_; + }; + + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_LONGLONG; + b->is_unsigned = true; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + unsigned long long image_; + }; + + // FLOAT + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_FLOAT; + b->is_unsigned = false; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + float image_; + }; + + // DOUBLE + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_DOUBLE; + b->is_unsigned = false; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + double image_; + }; + + // DATE + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_DATE; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + MYSQL_TIME image_; + }; + + // TIME + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_TIME; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + MYSQL_TIME image_; + }; + + // DATETIME + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_DATETIME; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + MYSQL_TIME image_; + }; + + // TIMESTAMP + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_TIMESTAMP; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + MYSQL_TIME image_; + }; + + // YEAR + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_SHORT; + b->is_unsigned = false; + b->buffer = &image_; + } + + private: + void + init (const T& v) + { + bool dummy; + value_traits::set_image (image_, dummy, v); + } + + private: + short image_; + }; + + // STRING + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_STRING; + b->buffer = buffer_.data (); + b->buffer_length = static_cast (buffer_.capacity ()); + b->length = &size_; + } + + private: + void + init (const T& v) + { + bool dummy; + std::size_t size; + value_traits::set_image (buffer_, size, dummy, v); + size_ = static_cast (size); + } + + private: + buffer buffer_; + unsigned long size_; + }; + + // BLOB + // + template + struct query_param_impl: query_param + { + query_param_impl (ref_bind r) : query_param (&r.ref) {} + query_param_impl (val_bind v) : query_param (0) {init (v.val);} + + virtual void + init () + { + init (*static_cast (value_)); + } + + virtual void + bind (MYSQL_BIND* b) + { + b->buffer_type = MYSQL_TYPE_BLOB; + b->buffer = buffer_.data (); + b->buffer_length = static_cast (buffer_.capacity ()); + b->length = &size_; + } + + private: + void + init (const T& v) + { + bool dummy; + std::size_t size; + value_traits::set_image (buffer_, size, dummy, v); + size_ = static_cast (size); + } + + private: + buffer buffer_; + unsigned long size_; + }; + } +} + +#include + +#endif // ODB_MYSQL_QUERY_HXX diff --git a/odb/mysql/query.txx b/odb/mysql/query.txx new file mode 100644 index 0000000..23d4ba7 --- /dev/null +++ b/odb/mysql/query.txx @@ -0,0 +1,28 @@ +// file : odb/mysql/query.txx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace mysql + { + template + query& query:: + operator+= (val_bind v) + { + add ( + shared_ptr ( + new (shared) query_param_impl::image_id> (v))); + } + + template + query& query:: + operator+= (ref_bind r) + { + add ( + shared_ptr ( + new (shared) query_param_impl::image_id> (r))); + } + } +} diff --git a/odb/mysql/result.hxx b/odb/mysql/result.hxx new file mode 100644 index 0000000..d852bc6 --- /dev/null +++ b/odb/mysql/result.hxx @@ -0,0 +1,51 @@ +// file : odb/mysql/result.hxx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +#ifndef ODB_MYSQL_RESULT_HXX +#define ODB_MYSQL_RESULT_HXX + +#include +#include + +#include +#include +#include + +namespace odb +{ + namespace mysql + { + template + class result_impl: public odb::result_impl + { + public: + typedef object_traits traits; + typedef typename traits::pointer_type pointer_type; + typedef typename traits::pointer_ops pointer_ops; + + virtual + ~result_impl (); + + result_impl (shared_ptr statement, + object_statements& statements); + + pointer_type + current (bool release); + + void + next (); + + private: + pointer_type cur_; + shared_ptr statement_; + object_statements& statements_; + query_statement::result state_; + }; + } +} + +#include + +#endif // ODB_MYSQL_RESULT_HXX diff --git a/odb/mysql/result.txx b/odb/mysql/result.txx new file mode 100644 index 0000000..b27b22e --- /dev/null +++ b/odb/mysql/result.txx @@ -0,0 +1,63 @@ +// file : odb/mysql/result.txx +// author : Boris Kolpackov +// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC +// license : GNU GPL v2; see accompanying LICENSE file + +namespace odb +{ + namespace mysql + { + template + result_impl:: + ~result_impl () + { + statement_->free_result (); + } + + template + result_impl:: + result_impl (shared_ptr statement, + object_statements& statements) + : statement_ (statement), statements_ (statements) + { + next (); + } + + template + typename result_impl::pointer_type result_impl:: + current (bool release) + { + if (!pointer_ops::null_ptr (cur_)) + return cur_; + + if (state_ == query_statement::success) + { + cur_ = traits::create (); + traits::init (pointer_ops::get_ref (cur_), statements_.image ()); + } + + return cur_; + } + + template + void result_impl:: + next () + { + cur_ = pointer_type (); + state_ = statement_->fetch (); + + if (state_ == query_statement::truncated) + { + typename traits::image_type& i (statements_.image ()); + + if (traits::grow (i, statements_.image_error ())) + { + traits::bind (statements_.image_binding (), i); + statement_->refetch (); + } + + state_ == query_statement::success; + } + } + } +} diff --git a/odb/mysql/statement.cxx b/odb/mysql/statement.cxx index e008d17..981c756 100644 --- a/odb/mysql/statement.cxx +++ b/odb/mysql/statement.cxx @@ -36,6 +36,133 @@ namespace odb mysql_stmt_close (stmt_); } + void statement:: + cancel () + { + } + + // query_statement + // + + query_statement:: + ~query_statement () + { + if (conn_.active () == this) + { + try + { + free_result (); + } + catch (...) + { + } + } + } + + query_statement:: + query_statement (connection& conn, + const string& query, + binding& image, + MYSQL_BIND* parameters) + : statement (conn), + image_ (image), + image_version_ (0), + parameters_ (parameters) + { + if (mysql_stmt_prepare (stmt_, query.c_str (), query.size ()) != 0) + throw database_exception (stmt_); + } + + void query_statement:: + execute () + { + if (statement* a = conn_.active ()) + a->cancel (); + + if (mysql_stmt_reset (stmt_)) + throw database_exception (stmt_); + + if (image_version_ != image_.version) + { + if (mysql_stmt_bind_result (stmt_, image_.bind)) + throw database_exception (stmt_); + + image_version_ = image_.version; + } + + if (parameters_ != 0) + { + // @@ versioning + // + if (mysql_stmt_bind_param (stmt_, parameters_)) + throw database_exception (stmt_); + } + + if (mysql_stmt_execute (stmt_)) + throw database_exception (stmt_); + + conn_.active (this); + } + + query_statement::result query_statement:: + fetch () + { + int r (mysql_stmt_fetch (stmt_)); + + switch (r) + { + case 0: + { + return success; + } + case 1: + { + throw database_exception (stmt_); + } + case MYSQL_NO_DATA: + { + return no_data; + } + case MYSQL_DATA_TRUNCATED: + { + return truncated; + } + } + } + + void query_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_); + } + } + } + + void query_statement:: + free_result () + { + if (mysql_stmt_free_result (stmt_)) + throw database_exception (stmt_); + + conn_.active (0); + } + + void query_statement:: + cancel () + { + free_result (); + } + // insert_statement // @@ -57,6 +184,9 @@ namespace odb void insert_statement:: execute () { + if (statement* a = conn_.active ()) + a->cancel (); + if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); @@ -92,6 +222,16 @@ namespace odb select_statement:: ~select_statement () { + if (conn_.active () == this) + { + try + { + free_result (); + } + catch (...) + { + } + } } select_statement:: @@ -112,6 +252,9 @@ namespace odb select_statement::result select_statement:: execute () { + if (statement* a = conn_.active ()) + a->cancel (); + if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); @@ -134,6 +277,8 @@ namespace odb if (mysql_stmt_execute (stmt_)) throw database_exception (stmt_); + conn_.active (this); + int r (mysql_stmt_fetch (stmt_)); switch (r) @@ -181,8 +326,17 @@ namespace odb { if (mysql_stmt_free_result (stmt_)) throw database_exception (stmt_); + + conn_.active (0); } + void select_statement:: + cancel () + { + free_result (); + } + + // update_statement // @@ -209,6 +363,9 @@ namespace odb void update_statement:: execute () { + if (statement* a = conn_.active ()) + a->cancel (); + if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); @@ -259,6 +416,9 @@ namespace odb void delete_statement:: execute () { + if (statement* a = conn_.active ()) + a->cancel (); + if (mysql_stmt_reset (stmt_)) throw database_exception (stmt_); diff --git a/odb/mysql/statement.hxx b/odb/mysql/statement.hxx index b635975..ec79b67 100644 --- a/odb/mysql/statement.hxx +++ b/odb/mysql/statement.hxx @@ -48,6 +48,12 @@ namespace odb virtual ~statement () = 0; + // Cancel the statement execution (e.g., result fetching) so + // that another statement can be executed on the connection. + // + virtual void + cancel (); + protected: statement (connection&); @@ -56,6 +62,49 @@ namespace odb MYSQL_STMT* stmt_; }; + class query_statement: public statement + { + public: + virtual + ~query_statement (); + + query_statement (connection& conn, + const std::string& query, + binding& image, + MYSQL_BIND* parameters); + enum result + { + success, + no_data, + truncated + }; + + void + execute (); + + result + fetch (); + + void + refetch (); + + void + free_result (); + + virtual void + cancel (); + + private: + query_statement (const query_statement&); + query_statement& operator= (const query_statement&); + + private: + binding& image_; + std::size_t image_version_; + + MYSQL_BIND* parameters_; + }; + class insert_statement: public statement { public: @@ -107,6 +156,8 @@ namespace odb void free_result (); + void + cancel (); private: select_statement (const select_statement&); @@ -279,6 +330,10 @@ namespace odb } private: + object_statements (const object_statements&); + object_statements& operator= (const object_statements&); + + private: // The last element is the id parameter. The update statement // depends on this being one contiguous arrays. // diff --git a/odb/mysql/traits.hxx b/odb/mysql/traits.hxx index a8c6c09..7d1caca 100644 --- a/odb/mysql/traits.hxx +++ b/odb/mysql/traits.hxx @@ -10,7 +10,7 @@ #include #include // std::size_t -#include // std::memcpy +#include // std::memcpy, std::strlen #include @@ -20,16 +20,138 @@ namespace odb { namespace mysql { + enum image_id_type + { + id_tiny, + id_utiny, + id_short, + id_ushort, + id_long, + id_ulong, + id_longlong, + id_ulonglong, + + id_float, + id_double, + + id_date, + id_time, + id_datetime, + id_timestamp, + id_year, + + id_string, + id_blob + }; + template class value_traits: public odb::value_traits { }; + // Integral types. + // + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_tiny; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_tiny; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_utiny; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_short; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_ushort; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_long; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_ulong; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_longlong; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_ulonglong; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_longlong; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_ulonglong; + }; + + // Float types. + // + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_float; + }; + + template <> + class value_traits: public odb::value_traits + { + public: + static const image_id_type image_id = id_double; + }; + + // String type. + // template <> class value_traits { public: typedef std::string value_type; + static const image_id_type image_id = id_string; static void set_value (value_type& v, const char* s, std::size_t n, bool is_null) @@ -73,6 +195,51 @@ namespace odb std::memcpy (b.data (), v.c_str (), n); } }; + + // Specialization for const char* which only supports initialization + // of an image from the value but not the other way around. This way + // we can pass such values to the queries. + // + template <> + class value_traits + { + public: + typedef const char* value_type; + static const image_id_type image_id = id_string; + + static void + set_image (char* s, + std::size_t c, + std::size_t& n, + bool& is_null, + value_type v) + { + is_null = false; + n = std::strlen (v); + + if (n > c) + n = c; + + if (n != 0) + std::memcpy (s, v, n); + } + + static void + set_image (buffer& b, + std::size_t& n, + bool& is_null, + const value_type& v) + { + is_null = false; + n = std::strlen (v); + + if (n > b.capacity ()) + b.capacity (n); + + if (n != 0) + std::memcpy (b.data (), v, n); + } + }; } } diff --git a/odb/mysql/transaction-impl.cxx b/odb/mysql/transaction-impl.cxx index 7b47c30..b6dda27 100644 --- a/odb/mysql/transaction-impl.cxx +++ b/odb/mysql/transaction-impl.cxx @@ -32,6 +32,9 @@ namespace odb void transaction_impl:: commit () { + if (statement* a = connection_->active ()) + a->cancel (); + MYSQL* h (connection_->handle ()); if (mysql_real_query (h, "commit", 6) != 0) @@ -41,6 +44,9 @@ namespace odb void transaction_impl:: rollback () { + if (statement* a = connection_->active ()) + a->cancel (); + MYSQL* h (connection_->handle ()); if (mysql_real_query (h, "rollback", 8) != 0) -- cgit v1.1