aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2010-08-10 11:17:52 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2010-08-10 11:17:52 +0200
commit0a589394a09ce5b3f16d902d657710a2886cc2fc (patch)
tree08f5bfa47a0d07b0dc20352706342e17f277759f
parentc67f076c75a36877ce142dc43a1ed2292ab8117a (diff)
Add query support
-rw-r--r--odb/mysql/connection.cxx2
-rw-r--r--odb/mysql/connection.hxx14
-rw-r--r--odb/mysql/forward.hxx1
-rw-r--r--odb/mysql/makefile3
-rw-r--r--odb/mysql/query.cxx96
-rw-r--r--odb/mysql/query.hxx828
-rw-r--r--odb/mysql/query.txx28
-rw-r--r--odb/mysql/result.hxx51
-rw-r--r--odb/mysql/result.txx63
-rw-r--r--odb/mysql/statement.cxx160
-rw-r--r--odb/mysql/statement.hxx55
-rw-r--r--odb/mysql/traits.hxx169
-rw-r--r--odb/mysql/transaction-impl.cxx6
13 files changed, 1473 insertions, 3 deletions
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 <typename T>
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 <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+#include <cstddef> // std::size_t
+#include <cstring> // std::memset
+
+#include <odb/mysql/query.hxx>
+
+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<query_param> 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<MYSQL_BIND*> (&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 <boris@codesynthesis.com>
+// 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 <mysql/mysql.h>
+
+#include <string>
+#include <vector>
+#include <cstddef> // std::size_t
+
+#include <odb/shared-ptr.hxx>
+
+#include <odb/mysql/version.hxx>
+#include <odb/mysql/forward.hxx>
+#include <odb/mysql/traits.hxx>
+
+namespace odb
+{
+ namespace mysql
+ {
+ template <typename T>
+ class val_bind
+ {
+ public:
+ val_bind (const T& v): val (v) {}
+
+ const T& val;
+ };
+
+ template <typename T>
+ 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 <typename T>
+ static val_bind<T>
+ _val (const T& x)
+ {
+ return val_bind<T> (x);
+ }
+
+ template <typename T>
+ static ref_bind<T>
+ _ref (const T& x)
+ {
+ return ref_bind<T> (x);
+ }
+
+ public:
+ query&
+ operator+= (const query& q)
+ {
+ clause_ += ' ';
+ clause_ += q.clause_;
+ }
+
+ query&
+ operator+= (const std::string& q)
+ {
+ clause_ += ' ';
+ clause_ += q;
+ }
+
+ template <typename T>
+ query&
+ operator+= (val_bind<T>);
+
+ template <typename T>
+ query&
+ operator+= (ref_bind<T>);
+
+ private:
+ void
+ add (shared_ptr<query_param>);
+
+ private:
+ typedef std::vector<shared_ptr<query_param> > parameters_type;
+
+ std::string clause_;
+ parameters_type parameters_;
+ std::vector<MYSQL_BIND> binding_;
+ };
+
+ inline query
+ operator+ (const query& x, const query& y)
+ {
+ query r (x);
+ r += y;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (const query& q, val_bind<T> b)
+ {
+ query r (q);
+ r += b;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (const query& q, ref_bind<T> b)
+ {
+ query r (q);
+ r += b;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (val_bind<T> b, const query& q)
+ {
+ query r;
+ r += b;
+ r += q;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (ref_bind<T> 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 <typename T>
+ inline query
+ operator+ (const std::string& s, val_bind<T> b)
+ {
+ query r (s);
+ r += b;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (const std::string& s, ref_bind<T> b)
+ {
+ query r (s);
+ r += b;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (val_bind<T> b, const std::string& s)
+ {
+ query r;
+ r += b;
+ r += s;
+ return r;
+ }
+
+ template <typename T>
+ inline query
+ operator+ (ref_bind<T> b, const std::string& s)
+ {
+ query r;
+ r += b;
+ r += s;
+ return r;
+ }
+
+ //
+ //
+ template <typename T, image_id_type>
+ struct query_param_impl;
+
+ // TINY
+ //
+ template <typename T>
+ struct query_param_impl<T, id_tiny>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ signed char image_;
+ };
+
+ template <typename T>
+ struct query_param_impl<T, id_utiny>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ unsigned char image_;
+ };
+
+ // SHORT
+ //
+ template <typename T>
+ struct query_param_impl<T, id_short>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ short image_;
+ };
+
+ template <typename T>
+ struct query_param_impl<T, id_ushort>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ unsigned short image_;
+ };
+
+ // LONG
+ //
+ template <typename T>
+ struct query_param_impl<T, id_long>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ int image_;
+ };
+
+ template <typename T>
+ struct query_param_impl<T, id_ulong>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ unsigned int image_;
+ };
+
+ // LONGLONG
+ //
+ template <typename T>
+ struct query_param_impl<T, id_longlong>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ long long image_;
+ };
+
+ template <typename T>
+ struct query_param_impl<T, id_ulonglong>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ unsigned long long image_;
+ };
+
+ // FLOAT
+ //
+ template <typename T>
+ struct query_param_impl<T, id_float>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ float image_;
+ };
+
+ // DOUBLE
+ //
+ template <typename T>
+ struct query_param_impl<T, id_double>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ double image_;
+ };
+
+ // DATE
+ //
+ template <typename T>
+ struct query_param_impl<T, id_date>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ MYSQL_TIME image_;
+ };
+
+ // TIME
+ //
+ template <typename T>
+ struct query_param_impl<T, id_time>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ MYSQL_TIME image_;
+ };
+
+ // DATETIME
+ //
+ template <typename T>
+ struct query_param_impl<T, id_datetime>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ MYSQL_TIME image_;
+ };
+
+ // TIMESTAMP
+ //
+ template <typename T>
+ struct query_param_impl<T, id_timestamp>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ MYSQL_TIME image_;
+ };
+
+ // YEAR
+ //
+ template <typename T>
+ struct query_param_impl<T, id_year>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (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<T>::set_image (image_, dummy, v);
+ }
+
+ private:
+ short image_;
+ };
+
+ // STRING
+ //
+ template <typename T>
+ struct query_param_impl<T, id_string>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ }
+
+ virtual void
+ bind (MYSQL_BIND* b)
+ {
+ b->buffer_type = MYSQL_TYPE_STRING;
+ b->buffer = buffer_.data ();
+ b->buffer_length = static_cast<unsigned long> (buffer_.capacity ());
+ b->length = &size_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ std::size_t size;
+ value_traits<T>::set_image (buffer_, size, dummy, v);
+ size_ = static_cast<unsigned long> (size);
+ }
+
+ private:
+ buffer buffer_;
+ unsigned long size_;
+ };
+
+ // BLOB
+ //
+ template <typename T>
+ struct query_param_impl<T, id_blob>: query_param
+ {
+ 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
+ init ()
+ {
+ init (*static_cast<const T*> (value_));
+ }
+
+ virtual void
+ bind (MYSQL_BIND* b)
+ {
+ b->buffer_type = MYSQL_TYPE_BLOB;
+ b->buffer = buffer_.data ();
+ b->buffer_length = static_cast<unsigned long> (buffer_.capacity ());
+ b->length = &size_;
+ }
+
+ private:
+ void
+ init (const T& v)
+ {
+ bool dummy;
+ std::size_t size;
+ value_traits<T>::set_image (buffer_, size, dummy, v);
+ size_ = static_cast<unsigned long> (size);
+ }
+
+ private:
+ buffer buffer_;
+ unsigned long size_;
+ };
+ }
+}
+
+#include <odb/mysql/query.txx>
+
+#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 <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace mysql
+ {
+ template <typename T>
+ query& query::
+ operator+= (val_bind<T> v)
+ {
+ add (
+ shared_ptr<query_param> (
+ new (shared) query_param_impl<T, value_traits<T>::image_id> (v)));
+ }
+
+ template <typename T>
+ query& query::
+ operator+= (ref_bind<T> r)
+ {
+ add (
+ shared_ptr<query_param> (
+ new (shared) query_param_impl<T, value_traits<T>::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 <boris@codesynthesis.com>
+// 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 <odb/result.hxx>
+#include <odb/shared-ptr.hxx>
+
+#include <odb/mysql/version.hxx>
+#include <odb/mysql/forward.hxx>
+#include <odb/mysql/statement.hxx>
+
+namespace odb
+{
+ namespace mysql
+ {
+ template <typename T>
+ class result_impl: public odb::result_impl<T>
+ {
+ public:
+ typedef object_traits<T> traits;
+ typedef typename traits::pointer_type pointer_type;
+ typedef typename traits::pointer_ops pointer_ops;
+
+ virtual
+ ~result_impl ();
+
+ result_impl (shared_ptr<query_statement> statement,
+ object_statements<T>& statements);
+
+ pointer_type
+ current (bool release);
+
+ void
+ next ();
+
+ private:
+ pointer_type cur_;
+ shared_ptr<query_statement> statement_;
+ object_statements<T>& statements_;
+ query_statement::result state_;
+ };
+ }
+}
+
+#include <odb/mysql/result.txx>
+
+#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 <boris@codesynthesis.com>
+// copyright : Copyright (c) 2009-2010 Code Synthesis Tools CC
+// license : GNU GPL v2; see accompanying LICENSE file
+
+namespace odb
+{
+ namespace mysql
+ {
+ template <typename T>
+ result_impl<T>::
+ ~result_impl ()
+ {
+ statement_->free_result ();
+ }
+
+ template <typename T>
+ result_impl<T>::
+ result_impl (shared_ptr<query_statement> statement,
+ object_statements<T>& statements)
+ : statement_ (statement), statements_ (statements)
+ {
+ next ();
+ }
+
+ template <typename T>
+ typename result_impl<T>::pointer_type result_impl<T>::
+ 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 <typename T>
+ void result_impl<T>::
+ 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<unsigned int> (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 <string>
#include <cstddef> // std::size_t
-#include <cstring> // std::memcpy
+#include <cstring> // std::memcpy, std::strlen
#include <odb/traits.hxx>
@@ -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 <typename T>
class value_traits: public odb::value_traits<T>
{
};
+ // Integral types.
+ //
+ template <>
+ class value_traits<bool>: public odb::value_traits<bool>
+ {
+ public:
+ static const image_id_type image_id = id_tiny;
+ };
+
+ template <>
+ class value_traits<signed char>: public odb::value_traits<signed char>
+ {
+ public:
+ static const image_id_type image_id = id_tiny;
+ };
+
+ template <>
+ class value_traits<unsigned char>: public odb::value_traits<unsigned char>
+ {
+ public:
+ static const image_id_type image_id = id_utiny;
+ };
+
+ template <>
+ class value_traits<short>: public odb::value_traits<short>
+ {
+ public:
+ static const image_id_type image_id = id_short;
+ };
+
+ template <>
+ class value_traits<unsigned short>: public odb::value_traits<unsigned short>
+ {
+ public:
+ static const image_id_type image_id = id_ushort;
+ };
+
+ template <>
+ class value_traits<int>: public odb::value_traits<int>
+ {
+ public:
+ static const image_id_type image_id = id_long;
+ };
+
+ template <>
+ class value_traits<unsigned int>: public odb::value_traits<unsigned int>
+ {
+ public:
+ static const image_id_type image_id = id_ulong;
+ };
+
+ template <>
+ class value_traits<long>: public odb::value_traits<long>
+ {
+ public:
+ static const image_id_type image_id = id_longlong;
+ };
+
+ template <>
+ class value_traits<unsigned long>: public odb::value_traits<unsigned long>
+ {
+ public:
+ static const image_id_type image_id = id_ulonglong;
+ };
+
+ template <>
+ class value_traits<long long>: public odb::value_traits<long long>
+ {
+ public:
+ static const image_id_type image_id = id_longlong;
+ };
+
+ template <>
+ class value_traits<unsigned long long>: public odb::value_traits<unsigned long long>
+ {
+ public:
+ static const image_id_type image_id = id_ulonglong;
+ };
+
+ // Float types.
+ //
+ template <>
+ class value_traits<float>: public odb::value_traits<float>
+ {
+ public:
+ static const image_id_type image_id = id_float;
+ };
+
+ template <>
+ class value_traits<double>: public odb::value_traits<double>
+ {
+ public:
+ static const image_id_type image_id = id_double;
+ };
+
+ // String type.
+ //
template <>
class value_traits<std::string>
{
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<const char*>
+ {
+ 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)